]> git.pld-linux.org Git - packages/php-pecl-ssh2.git/commitdiff
- add branch.diff, builds with php53; rel 3 auto/ac/php-pecl-ssh2-0_11_0-3 auto/th/php-pecl-ssh2-0_11_0-3
authorElan Ruusamäe <glen@pld-linux.org>
Sun, 6 Jun 2010 17:27:38 +0000 (17:27 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    branch.diff -> 1.1
    branch.sh -> 1.1
    php-pecl-ssh2.spec -> 1.24

branch.diff [new file with mode: 0644]
branch.sh [new file with mode: 0644]
php-pecl-ssh2.spec

diff --git a/branch.diff b/branch.diff
new file mode 100644 (file)
index 0000000..6375c0c
--- /dev/null
@@ -0,0 +1,19467 @@
+Index: config.w32
+===================================================================
+--- config.w32 (.../tags/RELEASE_0_11_0)
++++ config.w32 (.../trunk)
+@@ -0,0 +1,37 @@
++// $Id$
++// vim:ft=javascript
++
++ARG_WITH("ssh2", "SSH2 support", "no");
++
++if (PHP_SSH2 != "no") {
++      if ((((PHP_ZLIB=="no") && (CHECK_LIB("zlib_a.lib", "ssh2", PHP_SSH2) ||  CHECK_LIB("zlib.lib", "ssh2", PHP_SSH2))) || 
++              (PHP_ZLIB_SHARED && CHECK_LIB("zlib.lib", "ssh2", PHP_SSH2)) || (PHP_ZLIB == "yes" && (!PHP_ZLIB_SHARED))) &&
++              CHECK_LIB("libeay32.lib", "ssh2", PHP_SSH2) &&
++              CHECK_LIB("ssleay32.lib", "ssh2", PHP_SSH2) &&
++              CHECK_LIB("ws2_32.lib", "ssh2", PHP_SSH2)) {
++
++              // Use bundled lib if none installed, even if it is outdated.
++              if (!(CHECK_LIB("libssh2_a.lib;libssh2.lib", "ssh2", PHP_SSH2) &&
++                              CHECK_HEADER_ADD_INCLUDE("libssh2.h", "CFLAGS_SSH2", PHP_PHP_BUILD + "\\include\\libssh2"))) {
++                      FSO.CopyFile(configure_module_dirname + "\\libssh2\\src\\libssh2_config.h.in.w32",
++                                      configure_module_dirname + "\\libssh2\\src\\libssh2_config.h");
++
++                      ADD_FLAG('CFLAGS_SSH2', '/DLIBSSH2_WIN32=1 /DLIBSSH2_API= /I ' + 
++                                      configure_module_dirname + '/libssh2/include');
++              }
++
++              AC_DEFINE('HAVE_SSH2LIB', 1);
++              AC_DEFINE('PHP_SSH2_REMOTE_FORWARDING', 1);
++              AC_DEFINE('PHP_SSH2_HOSTBASED_AUTH', 1);
++              AC_DEFINE('PHP_SSH2_POLL', 1);
++              AC_DEFINE('PHP_SSH2_PUBLICKEY_SUBSYSTEM', 1);
++
++              EXTENSION("ssh2", "ssh2.c ssh2_fopen_wrappers.c ssh2_sftp.c");
++
++              ADD_SOURCES(configure_module_dirname + "/libssh2/src", "channel.c comp.c crypt.c \
++                              hostkey.c kex.c mac.c misc.c openssl.c packet.c pem.c publickey.c scp.c \
++                              session.c sftp.c transport.c userauth.c", "ssh2");
++      } else {
++              WARNING("ssh2 not enabled: libraries or headers not found");
++      }
++}
+
+Property changes on: config.w32
+___________________________________________________________________
+Added: svn:eol-style
+   + native
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.11
+
+Index: ssh2.c
+===================================================================
+--- ssh2.c     (.../tags/RELEASE_0_11_0)
++++ ssh2.c     (.../trunk)
+@@ -47,14 +47,9 @@
+ int le_ssh2_pkey_subsys;
+ #endif
+-#ifdef ZEND_ENGINE_2
+-static
+-    ZEND_BEGIN_ARG_INFO(php_ssh2_first_arg_force_ref, 0)
+-        ZEND_ARG_PASS_INFO(1)
+-    ZEND_END_ARG_INFO()
+-#else
+-static unsigned char php_ssh2_first_arg_force_ref[] = { 1, BYREF_FORCE };
+-#endif
++ZEND_BEGIN_ARG_INFO(php_ssh2_first_arg_force_ref, 0)
++    ZEND_ARG_PASS_INFO(1)
++ZEND_END_ARG_INFO()
+ /* *************
+    * Callbacks *
+@@ -248,7 +243,7 @@
+ /* {{{ php_ssh2_set_callback
+  * Try to set a method if it's passed in with the hash table
+  */
+-static int php_ssh2_set_callback(LIBSSH2_SESSION *session, HashTable *ht, char *callback, int callback_len, int callback_type, php_ssh2_session_data *data)
++static int php_ssh2_set_callback(LIBSSH2_SESSION *session, HashTable *ht, char *callback, int callback_len, int callback_type, php_ssh2_session_data *data TSRMLS_DC)
+ {
+       zval **handler, *copyval;
+       void *internal_handler;
+@@ -257,7 +252,7 @@
+               return 0;
+       }
+-      if (!handler || !*handler || !zend_is_callable(*handler, 0, NULL)) {
++      if (!handler || !*handler || !zend_is_callable(*handler, 0, NULL ZEND_IS_CALLABLE_TSRMLS_CC)) {
+               return -1;
+       }
+@@ -358,7 +353,7 @@
+       if (!session) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to initialize SSH2 session");
+               efree(data);
+-              close(socket);
++              closesocket(socket);
+               return NULL;
+       }
+       libssh2_banner_set(session, LIBSSH2_SSH_DEFAULT_BANNER " PHP");
+@@ -411,19 +406,19 @@
+       if (callbacks) {
+               /* ignore debug disconnect macerror */
+-              if (php_ssh2_set_callback(session, HASH_OF(callbacks), "ignore", sizeof("ignore") - 1, LIBSSH2_CALLBACK_IGNORE, data)) {
++              if (php_ssh2_set_callback(session, HASH_OF(callbacks), "ignore", sizeof("ignore") - 1, LIBSSH2_CALLBACK_IGNORE, data TSRMLS_CC)) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting IGNORE callback");
+               }
+-              if (php_ssh2_set_callback(session, HASH_OF(callbacks), "debug", sizeof("debug") - 1, LIBSSH2_CALLBACK_DEBUG, data)) {
++              if (php_ssh2_set_callback(session, HASH_OF(callbacks), "debug", sizeof("debug") - 1, LIBSSH2_CALLBACK_DEBUG, data TSRMLS_CC)) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting DEBUG callback");
+               }
+-              if (php_ssh2_set_callback(session, HASH_OF(callbacks), "macerror", sizeof("macerror") - 1, LIBSSH2_CALLBACK_MACERROR, data)) {
++              if (php_ssh2_set_callback(session, HASH_OF(callbacks), "macerror", sizeof("macerror") - 1, LIBSSH2_CALLBACK_MACERROR, data TSRMLS_CC)) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting MACERROR callback");
+               }
+-              if (php_ssh2_set_callback(session, HASH_OF(callbacks), "disconnect", sizeof("disconnect") - 1, LIBSSH2_CALLBACK_DISCONNECT, data)) {
++              if (php_ssh2_set_callback(session, HASH_OF(callbacks), "disconnect", sizeof("disconnect") - 1, LIBSSH2_CALLBACK_DISCONNECT, data TSRMLS_CC)) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed setting DISCONNECT callback");
+               }
+       }
+@@ -434,7 +429,7 @@
+               last_error = libssh2_session_last_error(session, &error_msg, NULL, 0);
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error starting up SSH connection(%d): %s", last_error, error_msg);
+-              close(socket);
++              closesocket(socket);
+               libssh2_session_free(session);
+               efree(data);
+               return NULL;
+@@ -1148,7 +1143,7 @@
+                       zval_ptr_dtor(&(*data)->disconnect_cb);
+               }
+-              close((*data)->socket);
++              closesocket((*data)->socket);
+               efree(*data);
+               *data = NULL;
+@@ -1274,7 +1269,7 @@
+ /* {{{ ssh2_functions[]
+  */
+-function_entry ssh2_functions[] = {
++zend_function_entry ssh2_functions[] = {
+       PHP_FE(ssh2_connect,                                            NULL)
+       PHP_FE(ssh2_methods_negotiated,                         NULL)
+       PHP_FE(ssh2_fingerprint,                                        NULL)
+
+Property changes on: ssh2.c
+___________________________________________________________________
+Modified: cvs2svn:cvs-rev
+   - 1.22
+   + 1.25
+
+Index: libssh2/include/libssh2_publickey.h
+===================================================================
+--- libssh2/include/libssh2_publickey.h        (.../tags/RELEASE_0_11_0)
++++ libssh2/include/libssh2_publickey.h        (.../trunk)
+@@ -0,0 +1,101 @@
++/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
++ */
++
++/* Note: This include file is only needed for using the
++ * publickey SUBSYSTEM which is not the same as publickey
++ * authentication.  For authentication you only need libssh2.h
++ *
++ * For more information on the publickey subsystem,
++ * refer to IETF draft: secsh-publickey
++ */
++
++#ifndef LIBSSH2_PUBLICKEY_H
++#define LIBSSH2_PUBLICKEY_H 1
++
++typedef struct _LIBSSH2_PUBLICKEY               LIBSSH2_PUBLICKEY;
++
++typedef struct _libssh2_publickey_attribute {
++    const char *name;
++    unsigned long name_len;
++    const char *value;
++    unsigned long value_len;
++    char mandatory;
++} libssh2_publickey_attribute;
++
++typedef struct _libssh2_publickey_list {
++    unsigned char *packet; /* For freeing */
++
++    const unsigned char *name;
++    unsigned long name_len;
++    const unsigned char *blob;
++    unsigned long blob_len;
++    unsigned long num_attrs;
++    libssh2_publickey_attribute *attrs; /* free me */
++} libssh2_publickey_list;
++
++/* Generally use the first macro here, but if both name and value are string literals, you can use _fast() to take advantage of preprocessing */
++#define libssh2_publickey_attribute(name, value, mandatory)         { (name), strlen(name), (value), strlen(value), (mandatory) },
++#define libssh2_publickey_attribute_fast(name, value, mandatory)    { (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) },
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* Publickey Subsystem */
++LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session);
++
++LIBSSH2_API int libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
++                                                            const unsigned char *blob, unsigned long blob_len, char overwrite,
++                                                            unsigned long num_attrs, const libssh2_publickey_attribute attrs[]);
++#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, num_attrs, attrs) \
++        libssh2_publickey_add_ex((pkey), (name), strlen(name), (blob), (blob_len), (overwrite), (num_attrs), (attrs))
++
++LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
++                                                            const unsigned char *blob, unsigned long blob_len);
++#define libssh2_publickey_remove(pkey, name, blob, blob_len) \
++        libssh2_publickey_remove_ex((pkey), (name), strlen(name), (blob), (blob_len))
++
++LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned long *num_keys, libssh2_publickey_list **pkey_list);
++LIBSSH2_API void libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey, libssh2_publickey_list *pkey_list);
++
++LIBSSH2_API int libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey);
++
++#ifdef __cplusplus
++} /* extern "C" */
++#endif
++
++#endif /* ndef: LIBSSH2_PUBLICKEY_H */
+
+Property changes on: libssh2/include/libssh2_publickey.h
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.2
+Added: svn:eol-style
+   + native
+
+Index: libssh2/include/libssh2_sftp.h
+===================================================================
+--- libssh2/include/libssh2_sftp.h     (.../tags/RELEASE_0_11_0)
++++ libssh2/include/libssh2_sftp.h     (.../trunk)
+@@ -0,0 +1,251 @@
++/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
++ */
++
++#ifndef LIBSSH2_SFTP_H
++#define LIBSSH2_SFTP_H 1
++
++#ifndef WIN32
++#include <unistd.h>
++#endif
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* Note: Version 6 was documented at the time of writing
++ * However it was marked as "DO NOT IMPLEMENT" due to pending changes
++ *
++ * Let's start with Version 3 (The version found in OpenSSH) and go from there
++ */
++#define LIBSSH2_SFTP_VERSION        3
++#define LIBSSH2_SFTP_PACKET_MAXLEN  40000
++
++typedef struct _LIBSSH2_SFTP                LIBSSH2_SFTP;
++typedef struct _LIBSSH2_SFTP_HANDLE         LIBSSH2_SFTP_HANDLE;
++typedef struct _LIBSSH2_SFTP_ATTRIBUTES     LIBSSH2_SFTP_ATTRIBUTES;
++
++/* Flags for open_ex() */
++#define LIBSSH2_SFTP_OPENFILE           0
++#define LIBSSH2_SFTP_OPENDIR            1
++
++/* Flags for rename_ex() */
++#define LIBSSH2_SFTP_RENAME_OVERWRITE   0x00000001
++#define LIBSSH2_SFTP_RENAME_ATOMIC      0x00000002
++#define LIBSSH2_SFTP_RENAME_NATIVE      0x00000004
++
++/* Flags for stat_ex() */
++#define LIBSSH2_SFTP_STAT               0
++#define LIBSSH2_SFTP_LSTAT              1
++#define LIBSSH2_SFTP_SETSTAT            2
++
++/* Flags for symlink_ex() */
++#define LIBSSH2_SFTP_SYMLINK            0
++#define LIBSSH2_SFTP_READLINK           1
++#define LIBSSH2_SFTP_REALPATH           2
++
++/* SFTP attribute flag bits */
++#define LIBSSH2_SFTP_ATTR_SIZE              0x00000001
++#define LIBSSH2_SFTP_ATTR_UIDGID            0x00000002
++#define LIBSSH2_SFTP_ATTR_PERMISSIONS       0x00000004
++#define LIBSSH2_SFTP_ATTR_ACMODTIME         0x00000008
++#define LIBSSH2_SFTP_ATTR_EXTENDED          0x80000000
++
++struct _LIBSSH2_SFTP_ATTRIBUTES {
++    /* If flags & ATTR_* bit is set, then the value in this struct will be meaningful
++     * Otherwise it should be ignored
++     */
++    unsigned long flags;
++
++    libssh2_uint64_t filesize;
++    unsigned long uid, gid;
++    unsigned long permissions;
++    unsigned long atime, mtime;
++};
++
++/* SFTP filetypes */
++#define LIBSSH2_SFTP_TYPE_REGULAR           1
++#define LIBSSH2_SFTP_TYPE_DIRECTORY         2
++#define LIBSSH2_SFTP_TYPE_SYMLINK           3
++#define LIBSSH2_SFTP_TYPE_SPECIAL           4
++#define LIBSSH2_SFTP_TYPE_UNKNOWN           5
++#define LIBSSH2_SFTP_TYPE_SOCKET            6
++#define LIBSSH2_SFTP_TYPE_CHAR_DEVICE       7
++#define LIBSSH2_SFTP_TYPE_BLOCK_DEVICE      8
++#define LIBSSH2_SFTP_TYPE_FIFO              9
++
++/*
++ * Reproduce the POSIX file modes here for systems that are not
++ * POSIX compliant.  
++ *
++ * These is used in "permissions" of "struct _LIBSSH2_SFTP_ATTRIBUTES"
++ */
++/* File type */
++#define LIBSSH2_SFTP_S_IFMT         0170000     /* type of file mask */
++#define LIBSSH2_SFTP_S_IFIFO        0010000     /* named pipe (fifo) */
++#define LIBSSH2_SFTP_S_IFCHR        0020000     /* character special */
++#define LIBSSH2_SFTP_S_IFDIR        0040000     /* directory */
++#define LIBSSH2_SFTP_S_IFBLK        0060000     /* block special */
++#define LIBSSH2_SFTP_S_IFREG        0100000     /* regular */
++#define LIBSSH2_SFTP_S_IFLNK        0120000     /* symbolic link */
++#define LIBSSH2_SFTP_S_IFSOCK       0140000     /* socket */
++
++/* File mode */
++/* Read, write, execute/search by owner */
++#define LIBSSH2_SFTP_S_IRWXU        0000700     /* RWX mask for owner */
++#define LIBSSH2_SFTP_S_IRUSR        0000400     /* R for owner */
++#define LIBSSH2_SFTP_S_IWUSR        0000200     /* W for owner */
++#define LIBSSH2_SFTP_S_IXUSR        0000100     /* X for owner */
++/* Read, write, execute/search by group */
++#define LIBSSH2_SFTP_S_IRWXG        0000070     /* RWX mask for group */
++#define LIBSSH2_SFTP_S_IRGRP        0000040     /* R for group */
++#define LIBSSH2_SFTP_S_IWGRP        0000020     /* W for group */
++#define LIBSSH2_SFTP_S_IXGRP        0000010     /* X for group */
++/* Read, write, execute/search by others */
++#define LIBSSH2_SFTP_S_IRWXO        0000007     /* RWX mask for other */
++#define LIBSSH2_SFTP_S_IROTH        0000004     /* R for other */
++#define LIBSSH2_SFTP_S_IWOTH        0000002     /* W for other */
++#define LIBSSH2_SFTP_S_IXOTH        0000001     /* X for other */
++
++/* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open())
++ * Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */
++#define LIBSSH2_FXF_READ                        0x00000001
++#define LIBSSH2_FXF_WRITE                       0x00000002
++#define LIBSSH2_FXF_APPEND                      0x00000004
++#define LIBSSH2_FXF_CREAT                       0x00000008
++#define LIBSSH2_FXF_TRUNC                       0x00000010
++#define LIBSSH2_FXF_EXCL                        0x00000020
++
++/* SFTP Status Codes (returned by libssh2_sftp_last_error() ) */
++#define LIBSSH2_FX_OK                       0
++#define LIBSSH2_FX_EOF                      1
++#define LIBSSH2_FX_NO_SUCH_FILE             2
++#define LIBSSH2_FX_PERMISSION_DENIED        3
++#define LIBSSH2_FX_FAILURE                  4
++#define LIBSSH2_FX_BAD_MESSAGE              5
++#define LIBSSH2_FX_NO_CONNECTION            6
++#define LIBSSH2_FX_CONNECTION_LOST          7
++#define LIBSSH2_FX_OP_UNSUPPORTED           8
++#define LIBSSH2_FX_INVALID_HANDLE           9
++#define LIBSSH2_FX_NO_SUCH_PATH             10
++#define LIBSSH2_FX_FILE_ALREADY_EXISTS      11
++#define LIBSSH2_FX_WRITE_PROTECT            12
++#define LIBSSH2_FX_NO_MEDIA                 13
++#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM   14
++#define LIBSSH2_FX_QUOTA_EXCEEDED           15
++#define LIBSSH2_FX_UNKNOWN_PRINCIPLE        16 /* Initial mis-spelling */
++#define LIBSSH2_FX_UNKNOWN_PRINCIPAL        16
++#define LIBSSH2_FX_LOCK_CONFlICT            17 /* Initial mis-spelling */
++#define LIBSSH2_FX_LOCK_CONFLICT            17
++#define LIBSSH2_FX_DIR_NOT_EMPTY            18
++#define LIBSSH2_FX_NOT_A_DIRECTORY          19
++#define LIBSSH2_FX_INVALID_FILENAME         20
++#define LIBSSH2_FX_LINK_LOOP                21
++
++/* Returned by any function that would block during a read/write opperation */
++#define LIBSSH2SFTP_EAGAIN LIBSSH2_ERROR_EAGAIN
++
++/* SFTP API */
++LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session);
++LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp);
++LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp);
++
++/* File / Directory Ops */
++LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, const char *filename, unsigned int filename_len,
++                                                      unsigned long flags, long mode, int open_type);
++#define libssh2_sftp_open(sftp, filename, flags, mode) \
++                    libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), (mode), LIBSSH2_SFTP_OPENFILE)
++#define libssh2_sftp_opendir(sftp, path) \
++                    libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, LIBSSH2_SFTP_OPENDIR)
++
++LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen);
++
++LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, 
++                                        char *longentry, size_t longentry_maxlen, 
++                                        LIBSSH2_SFTP_ATTRIBUTES *attrs);
++#define libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs) \
++                    libssh2_sftp_readdir_ex((handle), (buffer), (buffer_maxlen), NULL, 0, (attrs))
++
++LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, size_t count);
++
++LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle);
++#define libssh2_sftp_close(handle)                  libssh2_sftp_close_handle(handle)
++#define libssh2_sftp_closedir(handle)               libssh2_sftp_close_handle(handle)
++
++LIBSSH2_API void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset);
++LIBSSH2_API void libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle, libssh2_uint64_t offset);
++#define libssh2_sftp_rewind(handle)         libssh2_sftp_seek64((handle), 0)
++
++LIBSSH2_API size_t libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle);
++LIBSSH2_API libssh2_uint64_t libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE *handle);
++
++LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_ATTRIBUTES *attrs, int setstat);
++#define libssh2_sftp_fstat(handle, attrs)               libssh2_sftp_fstat_ex((handle), (attrs), 0)
++#define libssh2_sftp_fsetstat(handle, attrs)            libssh2_sftp_fstat_ex((handle), (attrs), 1)
++
++
++
++/* Miscellaneous Ops */
++LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp,  const char *source_filename,    unsigned int srouce_filename_len,
++                                                            const char *dest_filename,      unsigned int dest_filename_len,
++                                                            long flags);
++#define libssh2_sftp_rename(sftp, sourcefile, destfile)     libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), (destfile), strlen(destfile), \
++                                                            LIBSSH2_SFTP_RENAME_OVERWRITE | LIBSSH2_SFTP_RENAME_ATOMIC | LIBSSH2_SFTP_RENAME_NATIVE)
++
++LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, const char *filename, unsigned int filename_len);
++#define libssh2_sftp_unlink(sftp, filename)                 libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename))
++
++LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, long mode);
++#define libssh2_sftp_mkdir(sftp, path, mode)                libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode))
++
++LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len);
++#define libssh2_sftp_rmdir(sftp, path)                      libssh2_sftp_rmdir_ex((sftp), (path), strlen(path))
++
++LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs);
++#define libssh2_sftp_stat(sftp, path, attrs)                libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, (attrs))
++#define libssh2_sftp_lstat(sftp, path, attrs)               libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, (attrs))
++#define libssh2_sftp_setstat(sftp, path, attrs)             libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, (attrs))
++
++LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, char *target, unsigned int target_len, int link_type);
++#define libssh2_sftp_symlink(sftp, orig, linkpath)          libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), strlen(linkpath), LIBSSH2_SFTP_SYMLINK)
++#define libssh2_sftp_readlink(sftp, path, target, maxlen)   libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), LIBSSH2_SFTP_READLINK)
++#define libssh2_sftp_realpath(sftp, path, target, maxlen)   libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), LIBSSH2_SFTP_REALPATH)
++
++#ifdef __cplusplus
++} /* extern "C" */
++#endif
++
++#endif /* LIBSSH2_SFTP_H */
+
+Property changes on: libssh2/include/libssh2_sftp.h
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.2
+Added: svn:eol-style
+   + native
+
+Index: libssh2/include/libssh2.h
+===================================================================
+--- libssh2/include/libssh2.h  (.../tags/RELEASE_0_11_0)
++++ libssh2/include/libssh2.h  (.../trunk)
+@@ -0,0 +1,489 @@
++/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
++ */
++
++#ifndef LIBSSH2_H
++#define LIBSSH2_H 1
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include <stddef.h>
++#include <string.h>
++#include <sys/stat.h>
++#include <sys/types.h>
++
++/* Allow alternate API prefix from CFLAGS or calling app */
++#ifndef LIBSSH2_API
++# ifdef LIBSSH2_WIN32
++#  ifdef LIBSSH2_LIBRARY
++#   define LIBSSH2_API __declspec(dllexport)
++#  else
++#   define LIBSSH2_API __declspec(dllimport)
++#  endif /* LIBSSH2_LIBRARY */
++# else /* !LIBSSH2_WIN32 */
++#  define LIBSSH2_API
++# endif /* LIBSSH2_WIN32 */
++#endif /* LIBSSH2_API */
++
++#if defined(LIBSSH2_DARWIN) || (defined(LIBSSH2_WIN32) && !defined(_MSC_VER) && !defined(__MINGW32__))
++# include <sys/uio.h>
++#endif
++
++#if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
++# include <sys/bsdskt.h>
++typedef unsigned int uint32_t;
++#endif
++
++#if defined(LIBSSH2_WIN32) && defined(_MSC_VER) && (_MSC_VER <= 1400)
++typedef unsigned __int64 libssh2_uint64_t;
++typedef __int64 libssh2_int64_t;
++typedef unsigned int uint32_t;
++#ifndef _SSIZE_T_DEFINED
++typedef int ssize_t;
++#define _SSIZE_T_DEFINED
++#endif
++#else
++typedef unsigned long long libssh2_uint64_t;
++typedef long long libssh2_int64_t;
++#endif
++
++/* We use underscore instead of dash when appending CVS in dev versions just
++   to make the BANNER define (used by src/session.c) be a valid SSH
++   banner. Release versions have no appended strings and may of coruse not
++   have dashes either. */
++#define LIBSSH2_VERSION "1.0"
++
++/* The numeric version number is also available "in parts" by using these
++   defines: */
++#define LIBSSH2_VERSION_MAJOR 1
++#define LIBSSH2_VERSION_MINOR 0
++#define LIBSSH2_VERSION_PATCH 
++
++/* This is the numeric version of the libssh2 version number, meant for easier
++   parsing and comparions by programs. The LIBSSH2_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 LIBSSH2_VERSION_NUM 0x010000
++
++/*
++ * This is the date and time when the full source package was created. The
++ * timestamp is not stored in CVS, 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 LIBSSH2_TIMESTAMP "Fri Dec 26 21:35:07 UTC 2008"
++
++/* Part of every banner, user specified or not */
++#define LIBSSH2_SSH_BANNER                  "SSH-2.0-libssh2_" LIBSSH2_VERSION
++
++/* We *could* add a comment here if we so chose */
++#define LIBSSH2_SSH_DEFAULT_BANNER                  LIBSSH2_SSH_BANNER
++#define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF        LIBSSH2_SSH_DEFAULT_BANNER "\r\n"
++
++/* Default generate and safe prime sizes for diffie-hellman-group-exchange-sha1 */
++#define LIBSSH2_DH_GEX_MINGROUP     1024
++#define LIBSSH2_DH_GEX_OPTGROUP     1536
++#define LIBSSH2_DH_GEX_MAXGROUP     2048
++
++/* Defaults for pty requests */
++#define LIBSSH2_TERM_WIDTH      80
++#define LIBSSH2_TERM_HEIGHT     24
++#define LIBSSH2_TERM_WIDTH_PX   0
++#define LIBSSH2_TERM_HEIGHT_PX  0
++
++/* 1/4 second */
++#define LIBSSH2_SOCKET_POLL_UDELAY      250000
++/* 0.25 * 120 == 30 seconds */
++#define LIBSSH2_SOCKET_POLL_MAXLOOPS    120
++
++/* Maximum size to allow a payload to compress to, plays it safe by falling short of spec limits */
++#define LIBSSH2_PACKET_MAXCOMP      32000
++
++/* Maximum size to allow a payload to deccompress to, plays it safe by allowing more than spec requires */
++#define LIBSSH2_PACKET_MAXDECOMP    40000
++
++/* Maximum size for an inbound compressed payload, plays it safe by overshooting spec limits */
++#define LIBSSH2_PACKET_MAXPAYLOAD   40000
++
++/* Malloc callbacks */
++#define LIBSSH2_ALLOC_FUNC(name)                    void *name(size_t count, void **abstract)
++#define LIBSSH2_REALLOC_FUNC(name)                  void *name(void *ptr, size_t count, void **abstract)
++#define LIBSSH2_FREE_FUNC(name)                     void name(void *ptr, void **abstract)
++
++typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT
++{
++    char* text;
++    unsigned int length;
++    unsigned char echo;
++} LIBSSH2_USERAUTH_KBDINT_PROMPT;
++
++typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
++{
++    char* text;
++    unsigned int length;
++} LIBSSH2_USERAUTH_KBDINT_RESPONSE;
++
++/* 'keyboard-interactive' authentication callback */
++#define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) void name_(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)
++
++/* Callbacks for special SSH packets */
++#define LIBSSH2_IGNORE_FUNC(name)                   void name(LIBSSH2_SESSION *session, const char *message, int message_len, void **abstract)
++#define LIBSSH2_DEBUG_FUNC(name)                    void name(LIBSSH2_SESSION *session, int always_display, const char *message, int message_len, const char *language, int language_len,void **abstract)
++#define LIBSSH2_DISCONNECT_FUNC(name)               void name(LIBSSH2_SESSION *session, int reason, const char *message, int message_len, const char *language, int language_len, void **abstract)
++#define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name)         void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, void **abstract)
++#define LIBSSH2_MACERROR_FUNC(name)                 int  name(LIBSSH2_SESSION *session, const char *packet, int packet_len, void **abstract)
++#define LIBSSH2_X11_OPEN_FUNC(name)                 void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, const char *shost, int sport, void **abstract)
++
++#define LIBSSH2_CHANNEL_CLOSE_FUNC(name)            void name(LIBSSH2_SESSION *session, void **session_abstract, LIBSSH2_CHANNEL *channel, void **channel_abstract)
++
++/* libssh2_session_callback_set() constants */
++#define LIBSSH2_CALLBACK_IGNORE             0
++#define LIBSSH2_CALLBACK_DEBUG              1
++#define LIBSSH2_CALLBACK_DISCONNECT         2
++#define LIBSSH2_CALLBACK_MACERROR           3
++#define LIBSSH2_CALLBACK_X11                4
++
++/* libssh2_session_method_pref() constants */
++#define LIBSSH2_METHOD_KEX          0
++#define LIBSSH2_METHOD_HOSTKEY      1
++#define LIBSSH2_METHOD_CRYPT_CS     2
++#define LIBSSH2_METHOD_CRYPT_SC     3
++#define LIBSSH2_METHOD_MAC_CS       4
++#define LIBSSH2_METHOD_MAC_SC       5
++#define LIBSSH2_METHOD_COMP_CS      6
++#define LIBSSH2_METHOD_COMP_SC      7
++#define LIBSSH2_METHOD_LANG_CS      8
++#define LIBSSH2_METHOD_LANG_SC      9
++
++/* session.flags bits */
++#define LIBSSH2_FLAG_SIGPIPE        0x00000001
++
++typedef struct _LIBSSH2_SESSION                     LIBSSH2_SESSION;
++typedef struct _LIBSSH2_CHANNEL                     LIBSSH2_CHANNEL;
++typedef struct _LIBSSH2_LISTENER                    LIBSSH2_LISTENER;
++
++typedef struct _LIBSSH2_POLLFD {
++    unsigned char type; /* LIBSSH2_POLLFD_* below */
++
++    union {
++        int socket; /* File descriptors -- examined with system select() call */
++        LIBSSH2_CHANNEL *channel; /* Examined by checking internal state */
++        LIBSSH2_LISTENER *listener; /* Read polls only -- are inbound connections waiting to be accepted? */
++    } fd;
++
++    unsigned long events; /* Requested Events */
++    unsigned long revents; /* Returned Events */
++} LIBSSH2_POLLFD;
++
++/* Poll FD Descriptor Types */
++#define LIBSSH2_POLLFD_SOCKET       1
++#define LIBSSH2_POLLFD_CHANNEL      2
++#define LIBSSH2_POLLFD_LISTENER     3
++
++/* Note: Win32 Doesn't actually have a poll() implementation, so some of these values are faked with select() data */
++/* Poll FD events/revents -- Match sys/poll.h where possible */
++#define LIBSSH2_POLLFD_POLLIN           0x0001      /* Data available to be read or connection available -- All */
++#define LIBSSH2_POLLFD_POLLPRI          0x0002      /* Priority data available to be read -- Socket only */
++#define LIBSSH2_POLLFD_POLLEXT          0x0002      /* Extended data available to be read -- Channel only */
++#define LIBSSH2_POLLFD_POLLOUT          0x0004      /* Can may be written -- Socket/Channel */
++/* revents only */
++#define LIBSSH2_POLLFD_POLLERR          0x0008      /* Error Condition -- Socket */
++#define LIBSSH2_POLLFD_POLLHUP          0x0010      /* HangUp/EOF -- Socket */
++#define LIBSSH2_POLLFD_SESSION_CLOSED   0x0010      /* Session Disconnect */
++#define LIBSSH2_POLLFD_POLLNVAL         0x0020      /* Invalid request -- Socket Only */
++#define LIBSSH2_POLLFD_POLLEX           0x0040      /* Exception Condition -- Socket/Win32 */
++#define LIBSSH2_POLLFD_CHANNEL_CLOSED   0x0080      /* Channel Disconnect */
++#define LIBSSH2_POLLFD_LISTENER_CLOSED  0x0080      /* Listener Disconnect */
++
++#define HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
++/* Block Direction Types */
++#define LIBSSH2_SESSION_BLOCK_INBOUND                  0x0001
++#define LIBSSH2_SESSION_BLOCK_OUTBOUND                 0x0002
++
++/* Hash Types */
++#define LIBSSH2_HOSTKEY_HASH_MD5                            1
++#define LIBSSH2_HOSTKEY_HASH_SHA1                           2
++
++/* Disconnect Codes (defined by SSH protocol) */
++#define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT          1
++#define SSH_DISCONNECT_PROTOCOL_ERROR                       2
++#define SSH_DISCONNECT_KEY_EXCHANGE_FAILED                  3
++#define SSH_DISCONNECT_RESERVED                             4
++#define SSH_DISCONNECT_MAC_ERROR                            5
++#define SSH_DISCONNECT_COMPRESSION_ERROR                    6
++#define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE                7
++#define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED       8
++#define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE              9
++#define SSH_DISCONNECT_CONNECTION_LOST                      10
++#define SSH_DISCONNECT_BY_APPLICATION                       11
++#define SSH_DISCONNECT_TOO_MANY_CONNECTIONS                 12
++#define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER               13
++#define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE       14
++#define SSH_DISCONNECT_ILLEGAL_USER_NAME                    15
++
++/* Error Codes (defined by libssh2) */
++#define LIBSSH2_ERROR_NONE                      0
++#define LIBSSH2_ERROR_SOCKET_NONE               -1
++#define LIBSSH2_ERROR_BANNER_NONE               -2
++#define LIBSSH2_ERROR_BANNER_SEND               -3
++#define LIBSSH2_ERROR_INVALID_MAC               -4
++#define LIBSSH2_ERROR_KEX_FAILURE               -5
++#define LIBSSH2_ERROR_ALLOC                     -6
++#define LIBSSH2_ERROR_SOCKET_SEND               -7
++#define LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE      -8
++#define LIBSSH2_ERROR_TIMEOUT                   -9
++#define LIBSSH2_ERROR_HOSTKEY_INIT              -10
++#define LIBSSH2_ERROR_HOSTKEY_SIGN              -11
++#define LIBSSH2_ERROR_DECRYPT                   -12
++#define LIBSSH2_ERROR_SOCKET_DISCONNECT         -13
++#define LIBSSH2_ERROR_PROTO                     -14
++#define LIBSSH2_ERROR_PASSWORD_EXPIRED          -15
++#define LIBSSH2_ERROR_FILE                      -16
++#define LIBSSH2_ERROR_METHOD_NONE               -17
++#define LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED    -18
++#define LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED      -19
++#define LIBSSH2_ERROR_CHANNEL_OUTOFORDER        -20
++#define LIBSSH2_ERROR_CHANNEL_FAILURE           -21
++#define LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED    -22
++#define LIBSSH2_ERROR_CHANNEL_UNKNOWN           -23
++#define LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED   -24
++#define LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED   -25
++#define LIBSSH2_ERROR_CHANNEL_CLOSED            -26
++#define LIBSSH2_ERROR_CHANNEL_EOF_SENT          -27
++#define LIBSSH2_ERROR_SCP_PROTOCOL              -28
++#define LIBSSH2_ERROR_ZLIB                      -29
++#define LIBSSH2_ERROR_SOCKET_TIMEOUT            -30
++#define LIBSSH2_ERROR_SFTP_PROTOCOL             -31
++#define LIBSSH2_ERROR_REQUEST_DENIED            -32
++#define LIBSSH2_ERROR_METHOD_NOT_SUPPORTED      -33
++#define LIBSSH2_ERROR_INVAL                     -34
++#define LIBSSH2_ERROR_INVALID_POLL_TYPE         -35
++#define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL        -36
++#define LIBSSH2_ERROR_EAGAIN                    -37
++
++/* Session API */
++LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), LIBSSH2_FREE_FUNC((*my_free)), LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract);
++#define libssh2_session_init()                      libssh2_session_init_ex(NULL, NULL, NULL, NULL)
++LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session);
++
++LIBSSH2_API void *libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbtype, void *callback);
++LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, const char *banner);
++
++LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int sock);
++LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, const char *description, const char *lang);
++#define libssh2_session_disconnect(session, description)    libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, (description), "")
++LIBSSH2_API int libssh2_session_free(LIBSSH2_SESSION *session);
++
++LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
++
++LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, const char *prefs);
++LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type);
++LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf);
++LIBSSH2_API int libssh2_session_last_errno(LIBSSH2_SESSION *session);
++LIBSSH2_API int libssh2_session_block_directions(LIBSSH2_SESSION *session);
++
++LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value);
++
++/* Userauth API */
++LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len);
++LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
++LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len, const char *password, unsigned int password_len, LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)));
++#define libssh2_userauth_password(session, username, password)  libssh2_userauth_password_ex((session), (username), strlen(username), (password), strlen(password), NULL)
++
++LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
++                                                                                 const char *publickey, const char *privatekey,
++                                                                                 const char *passphrase);
++#define libssh2_userauth_publickey_fromfile(session, username, publickey, privatekey, passphrase)   \
++        libssh2_userauth_publickey_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase))
++LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
++                                                                                 const char *publickey, const char *privatekey,
++                                                                                 const char *passphrase,
++                                                                                 const char *hostname, unsigned int hostname_len,
++                                                                                 const char *local_username, unsigned int local_username_len);
++#define libssh2_userauth_hostbased_fromfile(session, username, publickey, privatekey, passphrase, hostname) \
++        libssh2_userauth_hostbased_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase), (hostname), strlen(hostname), (username), strlen(username))
++
++/*
++ * response_callback is provided with filled by library prompts array,
++ * but client must allocate and fill individual responses. Responses
++ * array is already allocated. Responses data will be freed by libssh2
++ * after callback return, but before subsequent callback invokation.
++ */
++LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session, const char *username, unsigned int username_len,
++                                                         LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)));
++#define libssh2_userauth_keyboard_interactive(session, username, response_callback) \
++        libssh2_userauth_keyboard_interactive_ex((session), (username), strlen(username), (response_callback))
++
++LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout);
++
++/* Channel API */
++#define LIBSSH2_CHANNEL_WINDOW_DEFAULT  65536
++#define LIBSSH2_CHANNEL_PACKET_DEFAULT  16384
++#define LIBSSH2_CHANNEL_MINADJUST       1024
++
++/* Extended Data Handling */
++#define LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL        0
++#define LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE        1
++#define LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE         2
++
++#define SSH_EXTENDED_DATA_STDERR 1
++
++/* Returned by any function that would block during a read/write opperation */
++#define LIBSSH2CHANNEL_EAGAIN LIBSSH2_ERROR_EAGAIN
++
++LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type, unsigned int channel_type_len, unsigned int window_size, unsigned int packet_size, const char *message, unsigned int message_len);
++#define libssh2_channel_open_session(session)   libssh2_channel_open_ex((session), "session", sizeof("session") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0)
++
++LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, int port, const char *shost, int sport);
++#define libssh2_channel_direct_tcpip(session, host, port)   libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22)
++
++LIBSSH2_API LIBSSH2_LISTENER *libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host, int port, int *bound_port, int queue_maxsize);
++#define libssh2_channel_forward_listen(session, port)           libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16)
++
++LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener);
++
++LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener);
++
++LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, const char *varname, unsigned int varname_len, const char *value, unsigned int value_len);
++#define libssh2_channel_setenv(channel, varname, value) libssh2_channel_setenv_ex((channel), (varname), strlen(varname), (value), strlen(value))
++
++LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, const char *term, unsigned int term_len, const char *modes, unsigned int modes_len, int width, int height, int width_px, int height_px);
++#define libssh2_channel_request_pty(channel, term)  libssh2_channel_request_pty_ex((channel), (term), strlen(term), NULL, 0, LIBSSH2_TERM_WIDTH, LIBSSH2_TERM_HEIGHT, LIBSSH2_TERM_WIDTH_PX, LIBSSH2_TERM_HEIGHT_PX)
++
++LIBSSH2_API int libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL * channel, int width, int height, int width_px, int height_px);
++#define libssh2_channel_request_pty_size(channel, width, height) libssh2_channel_request_pty_size_ex( (channel), (width), (height), 0, 0)
++
++LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, const char *auth_proto, const char *auth_cookie, int screen_number);
++#define libssh2_channel_x11_req(channel, screen_number) libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number))
++
++LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const char *request, unsigned int request_len, const char *message, unsigned int message_len);
++#define libssh2_channel_shell(channel)                  libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, NULL, 0)
++#define libssh2_channel_exec(channel, command)          libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, (command), strlen(command))
++#define libssh2_channel_subsystem(channel, subsystem)   libssh2_channel_process_startup((channel), "subsystem", sizeof("subsystem") - 1, (subsystem), strlen(subsystem))
++
++LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, size_t buflen);
++#define libssh2_channel_read(channel, buf, buflen) \
++                                libssh2_channel_read_ex((channel), 0, (buf), (buflen))
++#define libssh2_channel_read_stderr(channel, buf, buflen) \
++                                libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
++
++LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended);
++
++LIBSSH2_API unsigned long libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, unsigned long *read_avail, unsigned long *window_size_initial);
++#define libssh2_channel_window_read(channel) \
++            libssh2_channel_window_read_ex((channel), NULL, NULL)
++
++LIBSSH2_API unsigned long libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, unsigned long adjustment, unsigned char force);
++
++LIBSSH2_API ssize_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id, const char *buf, size_t buflen);
++
++#define libssh2_channel_write(channel, buf, buflen) \
++                                libssh2_channel_write_ex((channel), 0, (buf), (buflen))
++#define libssh2_channel_write_stderr(channel, buf, buflen)  \
++                                libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
++
++LIBSSH2_API unsigned long libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, unsigned long *window_size_initial);
++#define libssh2_channel_window_write(channel)           libssh2_channel_window_write_ex((channel), NULL)
++
++LIBSSH2_API void libssh2_session_set_blocking(LIBSSH2_SESSION* session, int blocking);
++LIBSSH2_API int libssh2_session_get_blocking(LIBSSH2_SESSION* session);
++
++LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
++
++LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode);
++LIBSSH2_API int libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, int ignore_mode);
++/* libssh2_channel_ignore_extended_data() is defined below for BC with version 0.1
++ * Future uses should use libssh2_channel_handle_extended_data() directly
++ * if LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE is passed, extended data will be read (FIFO) from the standard data channel
++ */
++/* DEPRECATED */
++#define libssh2_channel_ignore_extended_data(channel, ignore)       libssh2_channel_handle_extended_data((channel), (ignore) ? LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE : LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL )
++
++#define LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA     -1
++#define LIBSSH2_CHANNEL_FLUSH_ALL               -2
++LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid);
++#define libssh2_channel_flush(channel)          libssh2_channel_flush_ex((channel), 0)
++#define libssh2_channel_flush_stderr(channel)   libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR)
++LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel);
++
++LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel);
++LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel);
++LIBSSH2_API int libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel);
++LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel);
++LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel);
++LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel);
++
++LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb);
++LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime);
++#define libssh2_scp_send(session, path, mode, size)                 libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0)
++
++LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, unsigned int *dest_len, const char *src, unsigned int src_len);
++
++/* NOTE NOTE NOTE
++   libssh2_trace() has no function in builds that aren't built with debug
++   enabled
++ */
++LIBSSH2_API int libssh2_trace(LIBSSH2_SESSION *session, int bitmask);
++#define LIBSSH2_TRACE_TRANS (1<<1)
++#define LIBSSH2_TRACE_KEX   (1<<2)
++#define LIBSSH2_TRACE_AUTH  (1<<3)
++#define LIBSSH2_TRACE_CONN  (1<<4)
++#define LIBSSH2_TRACE_SCP   (1<<5)
++#define LIBSSH2_TRACE_SFTP  (1<<6)
++#define LIBSSH2_TRACE_ERROR (1<<7)
++#define LIBSSH2_TRACE_PUBLICKEY (1<<8)
++
++#ifdef __cplusplus
++} /* extern "C" */
++#endif
++
++#endif /* LIBSSH2_H */
+
+Property changes on: libssh2/include/libssh2.h
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.3
+Added: svn:eol-style
+   + native
+
+Index: libssh2/src/comp.c
+===================================================================
+--- libssh2/src/comp.c (.../tags/RELEASE_0_11_0)
++++ libssh2/src/comp.c (.../trunk)
+@@ -0,0 +1,340 @@
++/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++#ifdef LIBSSH2_HAVE_ZLIB
++# include <zlib.h>
++#endif
++
++/* ********
++   * none *
++   ******** */
++
++/* {{{ libssh2_comp_method_none_comp
++ * Minimalist compression: Absolutely none
++ */
++static int
++libssh2_comp_method_none_comp(LIBSSH2_SESSION * session,
++                              int compress,
++                              unsigned char **dest,
++                              unsigned long *dest_len,
++                              unsigned long payload_limit,
++                              int *free_dest,
++                              const unsigned char *src,
++                              unsigned long src_len, void **abstract)
++{
++    (void) session;
++    (void) compress;
++    (void) payload_limit;
++    (void) abstract;
++    *dest = (unsigned char *) src;
++    *dest_len = src_len;
++
++    *free_dest = 0;
++
++    return 0;
++}
++
++/* }}} */
++
++static const LIBSSH2_COMP_METHOD libssh2_comp_method_none = {
++    "none",
++    NULL,
++    libssh2_comp_method_none_comp,
++    NULL
++};
++
++#ifdef LIBSSH2_HAVE_ZLIB
++/* ********
++   * zlib *
++   ******** */
++
++/* {{{ Memory management wrappers
++ * Yes, I realize we're doing a callback to a callback,
++ * Deal...
++ */
++
++static voidpf
++libssh2_comp_method_zlib_alloc(voidpf opaque, uInt items, uInt size)
++{
++    LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;
++
++    return (voidpf) LIBSSH2_ALLOC(session, items * size);
++}
++
++static void
++libssh2_comp_method_zlib_free(voidpf opaque, voidpf address)
++{
++    LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;
++
++    LIBSSH2_FREE(session, address);
++}
++
++/* }}} */
++
++/* {{{ libssh2_comp_method_zlib_init
++ * All your bandwidth are belong to us (so save some)
++ */
++static int
++libssh2_comp_method_zlib_init(LIBSSH2_SESSION * session, int compress,
++                              void **abstract)
++{
++    z_stream *strm;
++    int status;
++
++    strm = LIBSSH2_ALLOC(session, sizeof(z_stream));
++    if (!strm) {
++        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                      "Unable to allocate memory for zlib compression/decompression",
++                      0);
++        return -1;
++    }
++    memset(strm, 0, sizeof(z_stream));
++
++    strm->opaque = (voidpf) session;
++    strm->zalloc = (alloc_func) libssh2_comp_method_zlib_alloc;
++    strm->zfree = (free_func) libssh2_comp_method_zlib_free;
++    if (compress) {
++        /* deflate */
++        status = deflateInit(strm, Z_DEFAULT_COMPRESSION);
++    } else {
++        /* inflate */
++        status = inflateInit(strm);
++    }
++
++    if (status != Z_OK) {
++        LIBSSH2_FREE(session, strm);
++        return -1;
++    }
++    *abstract = strm;
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_comp_method_zlib_comp
++ * zlib, a compression standard for all occasions
++ */
++static int
++libssh2_comp_method_zlib_comp(LIBSSH2_SESSION * session,
++                              int compress,
++                              unsigned char **dest,
++                              unsigned long *dest_len,
++                              unsigned long payload_limit,
++                              int *free_dest,
++                              const unsigned char *src,
++                              unsigned long src_len, void **abstract)
++{
++    z_stream *strm = *abstract;
++    /* A short-term alloc of a full data chunk is better than a series of
++       reallocs */
++    char *out;
++    int out_maxlen = compress ? (src_len + 4) : (2 * src_len);
++    int limiter = 0;
++
++    /* In practice they never come smaller than this */
++    if (out_maxlen < 25) {
++        out_maxlen = 25;
++    }
++
++    if (out_maxlen > (int) payload_limit) {
++        out_maxlen = payload_limit;
++    }
++
++    strm->next_in = (unsigned char *) src;
++    strm->avail_in = src_len;
++    strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen);
++    out = (char *) strm->next_out;
++    strm->avail_out = out_maxlen;
++    if (!strm->next_out) {
++        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                      "Unable to allocate compression/decompression buffer",
++                      0);
++        return -1;
++    }
++    while (strm->avail_in) {
++        int status;
++
++        if (compress) {
++            status = deflate(strm, Z_PARTIAL_FLUSH);
++        } else {
++            status = inflate(strm, Z_PARTIAL_FLUSH);
++        }
++        if (status != Z_OK) {
++            libssh2_error(session, LIBSSH2_ERROR_ZLIB,
++                          "compress/decompression failure", 0);
++            LIBSSH2_FREE(session, out);
++            return -1;
++        }
++        if (strm->avail_in) {
++            unsigned long out_ofs = out_maxlen - strm->avail_out;
++            char *newout;
++
++            out_maxlen +=
++                compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
++
++            if ((out_maxlen > (int) payload_limit) && !compress && limiter++) {
++                libssh2_error(session, LIBSSH2_ERROR_ZLIB,
++                              "Excessive growth in decompression phase", 0);
++                LIBSSH2_FREE(session, out);
++                return -1;
++            }
++
++            newout = LIBSSH2_REALLOC(session, out, out_maxlen);
++            if (!newout) {
++                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                              "Unable to expand compress/decompression buffer",
++                              0);
++                LIBSSH2_FREE(session, out);
++                return -1;
++            }
++            out = newout;
++            strm->next_out = (unsigned char *) out + out_ofs;
++            strm->avail_out +=
++                compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
++        } else
++            while (!strm->avail_out) {
++                /* Done with input, might be a byte or two in internal buffer during compress
++                 * Or potentially many bytes if it's a decompress
++                 */
++                int grow_size = compress ? 8 : 1024;
++                char *newout;
++
++                if (out_maxlen >= (int) payload_limit) {
++                    libssh2_error(session, LIBSSH2_ERROR_ZLIB,
++                                  "Excessive growth in decompression phase",
++                                  0);
++                    LIBSSH2_FREE(session, out);
++                    return -1;
++                }
++
++                if (grow_size > (int) (payload_limit - out_maxlen)) {
++                    grow_size = payload_limit - out_maxlen;
++                }
++
++                out_maxlen += grow_size;
++                strm->avail_out = grow_size;
++
++                newout = LIBSSH2_REALLOC(session, out, out_maxlen);
++                if (!newout) {
++                    libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                                  "Unable to expand final compress/decompress buffer",
++                                  0);
++                    LIBSSH2_FREE(session, out);
++                    return -1;
++                }
++                out = newout;
++                strm->next_out = (unsigned char *) out + out_maxlen -
++                    grow_size;
++
++                if (compress) {
++                    status = deflate(strm, Z_PARTIAL_FLUSH);
++                } else {
++                    status = inflate(strm, Z_PARTIAL_FLUSH);
++                }
++                if (status != Z_OK) {
++                    libssh2_error(session, LIBSSH2_ERROR_ZLIB,
++                                  "compress/decompression failure", 0);
++                    LIBSSH2_FREE(session, out);
++                    return -1;
++                }
++            }
++    }
++
++    *dest = (unsigned char *) out;
++    *dest_len = out_maxlen - strm->avail_out;
++    *free_dest = 1;
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_comp_method_zlib_dtor
++ * All done, no more compression for you
++ */
++static int
++libssh2_comp_method_zlib_dtor(LIBSSH2_SESSION * session, int compress,
++                              void **abstract)
++{
++    z_stream *strm = *abstract;
++
++    if (strm) {
++        if (compress) {
++            /* deflate */
++            deflateEnd(strm);
++        } else {
++            /* inflate */
++            inflateEnd(strm);
++        }
++
++        LIBSSH2_FREE(session, strm);
++    }
++
++    *abstract = NULL;
++
++    return 0;
++}
++
++/* }}} */
++
++static const LIBSSH2_COMP_METHOD libssh2_comp_method_zlib = {
++    "zlib",
++    libssh2_comp_method_zlib_init,
++    libssh2_comp_method_zlib_comp,
++    libssh2_comp_method_zlib_dtor,
++};
++#endif /* LIBSSH2_HAVE_ZLIB */
++
++/* ***********************
++   * Compression Methods *
++   *********************** */
++
++static const LIBSSH2_COMP_METHOD *_libssh2_comp_methods[] = {
++    &libssh2_comp_method_none,
++#ifdef LIBSSH2_HAVE_ZLIB
++    &libssh2_comp_method_zlib,
++#endif /* LIBSSH2_HAVE_ZLIB */
++    NULL
++};
++
++const LIBSSH2_COMP_METHOD **
++libssh2_comp_methods(void)
++{
++    return _libssh2_comp_methods;
++}
+
+Property changes on: libssh2/src/comp.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.2
+Added: svn:eol-style
+   + native
+
+Index: libssh2/src/libgcrypt.c
+===================================================================
+--- libssh2/src/libgcrypt.c    (.../tags/RELEASE_0_11_0)
++++ libssh2/src/libgcrypt.c    (.../trunk)
+@@ -0,0 +1,560 @@
++/* Copyright (C) 2006, 2007, The Written Word, Inc.
++ * Copyright (C) 2008, Simon Josefsson
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++#include <string.h>
++
++int
++_libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
++                 const unsigned char *edata,
++                 unsigned long elen,
++                 const unsigned char *ndata,
++                 unsigned long nlen,
++                 const unsigned char *ddata,
++                 unsigned long dlen,
++                 const unsigned char *pdata,
++                 unsigned long plen,
++                 const unsigned char *qdata,
++                 unsigned long qlen,
++                 const unsigned char *e1data,
++                 unsigned long e1len,
++                 const unsigned char *e2data,
++                 unsigned long e2len,
++                 const unsigned char *coeffdata, unsigned long coefflen)
++{
++    int rc;
++    (void) e1data;
++    (void) e1len;
++    (void) e2data;
++    (void) e2len;
++
++    if (ddata) {
++        rc = gcry_sexp_build
++            (rsa, NULL,
++             "(private-key(rsa(n%b)(e%b)(d%b)(q%b)(p%b)(u%b)))",
++             nlen, ndata, elen, edata, dlen, ddata, plen, pdata,
++             qlen, qdata, coefflen, coeffdata);
++    } else {
++        rc = gcry_sexp_build(rsa, NULL, "(public-key(rsa(n%b)(e%b)))",
++                             nlen, ndata, elen, edata);
++    }
++    if (rc) {
++        *rsa = NULL;
++        return -1;
++    }
++
++    return 0;
++}
++
++int
++_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
++                         const unsigned char *sig,
++                         unsigned long sig_len,
++                         const unsigned char *m, unsigned long m_len)
++{
++    unsigned char hash[SHA_DIGEST_LENGTH];
++    gcry_sexp_t s_sig, s_hash;
++    int rc = -1;
++
++    libssh2_sha1(m, m_len, hash);
++
++    rc = gcry_sexp_build(&s_hash, NULL,
++                         "(data (flags pkcs1) (hash sha1 %b))",
++                         SHA_DIGEST_LENGTH, hash);
++    if (rc != 0) {
++        return -1;
++    }
++
++    rc = gcry_sexp_build(&s_sig, NULL, "(sig-val(rsa(s %b)))", sig_len, sig);
++    if (rc != 0) {
++        gcry_sexp_release(s_hash);
++        return -1;
++    }
++
++    rc = gcry_pk_verify(s_sig, s_hash, rsa);
++    gcry_sexp_release(s_sig);
++    gcry_sexp_release(s_hash);
++
++    return (rc == 0) ? 0 : -1;
++}
++
++int
++_libssh2_dsa_new(libssh2_dsa_ctx ** dsactx,
++                 const unsigned char *p,
++                 unsigned long p_len,
++                 const unsigned char *q,
++                 unsigned long q_len,
++                 const unsigned char *g,
++                 unsigned long g_len,
++                 const unsigned char *y,
++                 unsigned long y_len,
++                 const unsigned char *x, unsigned long x_len)
++{
++    int rc;
++
++    if (x_len) {
++        rc = gcry_sexp_build
++            (dsactx, NULL,
++             "(private-key(dsa(p%b)(q%b)(g%b)(y%b)(x%b)))",
++             p_len, p, q_len, q, g_len, g, y_len, y, x_len, x);
++    } else {
++        rc = gcry_sexp_build(dsactx, NULL,
++                             "(public-key(dsa(p%b)(q%b)(g%b)(y%b)))",
++                             p_len, p, q_len, q, g_len, g, y_len, y);
++    }
++
++    if (rc) {
++        *dsactx = NULL;
++        return -1;
++    }
++
++    return 0;
++}
++
++int
++_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
++                         LIBSSH2_SESSION * session,
++                         FILE * fp, unsigned const char *passphrase)
++{
++    unsigned char *data, *save_data;
++    unsigned int datalen;
++    int ret;
++    unsigned char *n, *e, *d, *p, *q, *e1, *e2, *coeff;
++    unsigned int nlen, elen, dlen, plen, qlen, e1len, e2len, coefflen;
++
++    (void) passphrase;
++
++    ret = _libssh2_pem_parse(session,
++                             "-----BEGIN RSA PRIVATE KEY-----",
++                             "-----END RSA PRIVATE KEY-----",
++                             fp, &data, &datalen);
++    if (ret) {
++        return -1;
++    }
++
++    save_data = data;
++
++    if (_libssh2_pem_decode_sequence(&data, &datalen)) {
++        ret = -1;
++        goto fail;
++    }
++/* First read Version field (should be 0). */
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen);
++    if (ret != 0 || (nlen != 1 && *n != '\0')) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen);
++    if (ret != 0) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &e, &elen);
++    if (ret != 0) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &d, &dlen);
++    if (ret != 0) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen);
++    if (ret != 0) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen);
++    if (ret != 0) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &e1, &e1len);
++    if (ret != 0) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &e2, &e2len);
++    if (ret != 0) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &coeff, &coefflen);
++    if (ret != 0) {
++        ret = -1;
++        goto fail;
++    }
++
++    if (_libssh2_rsa_new(rsa, e, elen, n, nlen, d, dlen, p, plen,
++                         q, qlen, e1, e1len, e2, e2len, coeff, coefflen)) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = 0;
++
++  fail:
++    LIBSSH2_FREE(session, save_data);
++    return ret;
++}
++
++int
++_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
++                         LIBSSH2_SESSION * session,
++                         FILE * fp, unsigned const char *passphrase)
++{
++    unsigned char *data, *save_data;
++    unsigned int datalen;
++    int ret;
++    unsigned char *p, *q, *g, *y, *x;
++    unsigned int plen, qlen, glen, ylen, xlen;
++
++    (void) passphrase;
++
++    ret = _libssh2_pem_parse(session,
++                             "-----BEGIN DSA PRIVATE KEY-----",
++                             "-----END DSA PRIVATE KEY-----",
++                             fp, &data, &datalen);
++    if (ret) {
++        return -1;
++    }
++
++    save_data = data;
++
++    if (_libssh2_pem_decode_sequence(&data, &datalen)) {
++        ret = -1;
++        goto fail;
++    }
++
++/* First read Version field (should be 0). */
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen);
++    if (ret != 0 || (plen != 1 && *p != '\0')) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen);
++    if (ret != 0) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen);
++    if (ret != 0) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &g, &glen);
++    if (ret != 0) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &y, &ylen);
++    if (ret != 0) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = _libssh2_pem_decode_integer(&data, &datalen, &x, &xlen);
++    if (ret != 0) {
++        ret = -1;
++        goto fail;
++    }
++
++    if (datalen != 0) {
++        ret = -1;
++        goto fail;
++    }
++
++    if (_libssh2_dsa_new(dsa, p, plen, q, qlen, g, glen, y, ylen, x, xlen)) {
++        ret = -1;
++        goto fail;
++    }
++
++    ret = 0;
++
++  fail:
++    LIBSSH2_FREE(session, save_data);
++    return ret;
++}
++
++int
++_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
++                       libssh2_dsa_ctx * rsactx,
++                       const unsigned char *hash,
++                       unsigned long hash_len,
++                       unsigned char **signature, unsigned long *signature_len)
++{
++    gcry_sexp_t sig_sexp;
++    gcry_sexp_t data;
++    int rc;
++    const char *tmp;
++    size_t size;
++
++    if (hash_len != SHA_DIGEST_LENGTH) {
++        return -1;
++    }
++
++    if (gcry_sexp_build(&data, NULL,
++                        "(data (flags pkcs1) (hash sha1 %b))",
++                        hash_len, hash)) {
++        return -1;
++    }
++
++    rc = gcry_pk_sign(&sig_sexp, data, rsactx);
++
++    gcry_sexp_release(data);
++
++    if (rc != 0) {
++        return -1;
++    }
++
++    data = gcry_sexp_find_token(sig_sexp, "s", 0);
++    if (!data) {
++        return -1;
++    }
++
++    tmp = gcry_sexp_nth_data(data, 1, &size);
++    if (!tmp) {
++        return -1;
++    }
++
++    if (tmp[0] == '\0') {
++        tmp++;
++        size--;
++    }
++
++    *signature = LIBSSH2_ALLOC(session, size);
++    memcpy(*signature, tmp, size);
++    *signature_len = size;
++
++    return rc;
++}
++
++int
++_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
++                       const unsigned char *hash,
++                       unsigned long hash_len, unsigned char *sig)
++{
++    unsigned char zhash[SHA_DIGEST_LENGTH + 1];
++    gcry_sexp_t sig_sexp;
++    gcry_sexp_t data;
++    int ret;
++    const char *tmp;
++    size_t size;
++
++    if (hash_len != SHA_DIGEST_LENGTH) {
++        return -1;
++    }
++
++    memcpy(zhash + 1, hash, hash_len);
++    zhash[0] = 0;
++
++    if (gcry_sexp_build(&data, NULL, "(data (value %b))", hash_len + 1, zhash)) {
++        return -1;
++    }
++
++    ret = gcry_pk_sign(&sig_sexp, data, dsactx);
++
++    gcry_sexp_release(data);
++
++    if (ret != 0) {
++        return -1;
++    }
++
++/* Extract R. */
++
++    data = gcry_sexp_find_token(sig_sexp, "r", 0);
++    if (!data) {
++        ret = -1;
++        goto out;
++    }
++
++    tmp = gcry_sexp_nth_data(data, 1, &size);
++    if (!tmp) {
++        ret = -1;
++        goto out;
++    }
++
++    if (tmp[0] == '\0') {
++        tmp++;
++        size--;
++    }
++
++    if (size != 20) {
++        ret = -1;
++        goto out;
++    }
++
++    memcpy(sig, tmp, 20);
++
++    gcry_sexp_release(data);
++
++/* Extract S. */
++
++    data = gcry_sexp_find_token(sig_sexp, "s", 0);
++    if (!data) {
++        ret = -1;
++        goto out;
++    }
++
++    tmp = gcry_sexp_nth_data(data, 1, &size);
++    if (!tmp) {
++        ret = -1;
++        goto out;
++    }
++
++    if (tmp[0] == '\0') {
++        tmp++;
++        size--;
++    }
++
++    if (size != 20) {
++        ret = -1;
++        goto out;
++    }
++
++    memcpy(sig + 20, tmp, 20);
++
++    ret = 0;
++  out:
++    if (sig_sexp) {
++        gcry_sexp_release(sig_sexp);
++    }
++    if (data) {
++        gcry_sexp_release(data);
++    }
++    return ret;
++}
++
++int
++_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
++                         const unsigned char *sig,
++                         const unsigned char *m, unsigned long m_len)
++{
++    unsigned char hash[SHA_DIGEST_LENGTH + 1];
++    gcry_sexp_t s_sig, s_hash;
++    int rc = -1;
++
++    libssh2_sha1(m, m_len, hash + 1);
++    hash[0] = 0;
++
++    if (gcry_sexp_build(&s_hash, NULL, "(data(flags raw)(value %b))",
++                        SHA_DIGEST_LENGTH + 1, hash)) {
++        return -1;
++    }
++
++    if (gcry_sexp_build(&s_sig, NULL, "(sig-val(dsa(r %b)(s %b)))",
++                        20, sig, 20, sig + 20)) {
++        gcry_sexp_release(s_hash);
++        return -1;
++    }
++
++    rc = gcry_pk_verify(s_sig, s_hash, dsactx);
++    gcry_sexp_release(s_sig);
++    gcry_sexp_release(s_hash);
++
++    return (rc == 0) ? 0 : -1;
++}
++
++int
++_libssh2_cipher_init(_libssh2_cipher_ctx * h,
++                     _libssh2_cipher_type(algo),
++                     unsigned char *iv, unsigned char *secret, int encrypt)
++{
++    int mode = 0, ret;
++    int keylen = gcry_cipher_get_algo_keylen(algo);
++
++    (void) encrypt;
++
++    if (algo != GCRY_CIPHER_ARCFOUR) {
++        mode = GCRY_CIPHER_MODE_CBC;
++    }
++
++    ret = gcry_cipher_open(h, algo, mode, 0);
++    if (ret) {
++        return -1;
++    }
++
++    ret = gcry_cipher_setkey(*h, secret, keylen);
++    if (ret) {
++        gcry_cipher_close(*h);
++        return -1;
++    }
++
++    if (algo != GCRY_CIPHER_ARCFOUR) {
++        int blklen = gcry_cipher_get_algo_blklen(algo);
++        ret = gcry_cipher_setiv(*h, iv, blklen);
++        if (ret) {
++            gcry_cipher_close(*h);
++            return -1;
++        }
++    }
++
++    return 0;
++}
++
++int
++_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
++                      _libssh2_cipher_type(algo),
++                      int encrypt, unsigned char *block)
++{
++    size_t blklen = gcry_cipher_get_algo_blklen(algo);
++    int ret;
++    if (blklen == 1) {
++/* Hack for arcfour. */
++        blklen = 8;
++    }
++
++    if (encrypt) {
++        ret = gcry_cipher_encrypt(*ctx, block, blklen, block, blklen);
++    } else {
++        ret = gcry_cipher_decrypt(*ctx, block, blklen, block, blklen);
++    }
++    return ret;
++}
+
+Property changes on: libssh2/src/libgcrypt.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.1
+Added: svn:eol-style
+   + native
+Added: svn:executable
+   + *
+
+Index: libssh2/src/userauth.c
+===================================================================
+--- libssh2/src/userauth.c     (.../tags/RELEASE_0_11_0)
++++ libssh2/src/userauth.c     (.../trunk)
+@@ -0,0 +1,1473 @@
++/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++
++#include <ctype.h>
++#include <stdio.h>
++
++/* Needed for struct iovec on some platforms */
++#ifdef HAVE_SYS_UIO_H
++#include <sys/uio.h>
++#endif
++
++
++/* {{{ proto libssh2_userauth_list
++ * List authentication methods
++ * Will yield successful login if "none" happens to be allowable for this user
++ * Not a common configuration for any SSH server though
++ * username should be NULL, or a null terminated string
++ */
++LIBSSH2_API char *
++libssh2_userauth_list(LIBSSH2_SESSION * session, const char *username,
++                      unsigned int username_len)
++{
++    static const unsigned char reply_codes[3] =
++        { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
++    /* packet_type(1) + username_len(4) + service_len(4) +
++       service(14)"ssh-connection" + method_len(4) + method(4)"none" */
++    unsigned long methods_len;
++    unsigned char *s;
++    int rc;
++
++    if (session->userauth_list_state == libssh2_NB_state_idle) {
++        /* Zero the whole thing out */
++        memset(&session->userauth_list_packet_requirev_state, 0,
++               sizeof(session->userauth_list_packet_requirev_state));
++
++        session->userauth_list_data_len = username_len + 31;
++
++        s = session->userauth_list_data =
++            LIBSSH2_ALLOC(session, session->userauth_list_data_len);
++        if (!session->userauth_list_data) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for userauth_list", 0);
++            return NULL;
++        }
++
++        *(s++) = SSH_MSG_USERAUTH_REQUEST;
++        libssh2_htonu32(s, username_len);
++        s += 4;
++        if (username) {
++            memcpy(s, username, username_len);
++            s += username_len;
++        }
++
++        libssh2_htonu32(s, 14);
++        s += 4;
++        memcpy(s, "ssh-connection", 14);
++        s += 14;
++
++        libssh2_htonu32(s, 4);
++        s += 4;
++        memcpy(s, "none", 4);
++        s += 4;
++
++        session->userauth_list_state = libssh2_NB_state_created;
++    }
++
++    if (session->userauth_list_state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, session->userauth_list_data,
++                                  session->userauth_list_data_len);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block requesting userauth list", 0);
++            return NULL;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send userauth-none request", 0);
++            LIBSSH2_FREE(session, session->userauth_list_data);
++            session->userauth_list_data = NULL;
++            session->userauth_list_state = libssh2_NB_state_idle;
++            return NULL;
++        }
++        LIBSSH2_FREE(session, session->userauth_list_data);
++        session->userauth_list_data = NULL;
++
++        session->userauth_list_state = libssh2_NB_state_sent;
++    }
++
++    if (session->userauth_list_state == libssh2_NB_state_sent) {
++        rc = libssh2_packet_requirev_ex(session, reply_codes,
++                                        &session->userauth_list_data,
++                                        &session->userauth_list_data_len, 0,
++                                        NULL, 0,
++                                        &session->
++                                        userauth_list_packet_requirev_state);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block requesting userauth list", 0);
++            return NULL;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_NONE, "No error", 0);
++            session->userauth_list_state = libssh2_NB_state_idle;
++            return NULL;
++        }
++
++        if (session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
++            /* Wow, who'dve thought... */
++            libssh2_error(session, LIBSSH2_ERROR_NONE, "No error", 0);
++            LIBSSH2_FREE(session, session->userauth_list_data);
++            session->userauth_list_data = NULL;
++            session->state |= LIBSSH2_STATE_AUTHENTICATED;
++            session->userauth_list_state = libssh2_NB_state_idle;
++            return NULL;
++        }
++
++        methods_len = libssh2_ntohu32(session->userauth_list_data + 1);
++
++        /* Do note that the memory areas overlap! */
++        memmove(session->userauth_list_data, session->userauth_list_data + 5,
++               methods_len);
++        session->userauth_list_data[methods_len] = '\0';
++        _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Permitted auth methods: %s",
++                       session->userauth_list_data);
++    }
++
++    session->userauth_list_state = libssh2_NB_state_idle;
++    return (char *) session->userauth_list_data;
++}
++
++/* }}} */
++
++/* {{{ libssh2_userauth_authenticated
++ * 0 if not yet authenticated
++ * non-zero is already authenticated
++ */
++LIBSSH2_API int
++libssh2_userauth_authenticated(LIBSSH2_SESSION * session)
++{
++    return session->state & LIBSSH2_STATE_AUTHENTICATED;
++}
++
++/* }}} */
++
++/* {{{ libssh2_userauth_password
++ * Plain ol' login
++ */
++LIBSSH2_API int
++libssh2_userauth_password_ex(LIBSSH2_SESSION * session, const char *username,
++                             unsigned int username_len, const char *password,
++                             unsigned int password_len,
++                             LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
++{
++    unsigned char *s;
++    static const unsigned char reply_codes[4] =
++        { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
++        SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0
++    };
++    int rc;
++
++    if (session->userauth_pswd_state == libssh2_NB_state_idle) {
++        /* Zero the whole thing out */
++        memset(&session->userauth_pswd_packet_requirev_state, 0,
++               sizeof(session->userauth_pswd_packet_requirev_state));
++
++        /*
++         * 40 = acket_type(1) + username_len(4) + service_len(4) + 
++         * service(14)"ssh-connection" + method_len(4) + method(8)"password" +
++         * chgpwdbool(1) + password_len(4) */
++        session->userauth_pswd_data_len = username_len + password_len + 40;
++
++        session->userauth_pswd_data0 = ~SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
++
++        s = session->userauth_pswd_data =
++            LIBSSH2_ALLOC(session, session->userauth_pswd_data_len);
++        if (!session->userauth_pswd_data) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for userauth-password request",
++                          0);
++            return -1;
++        }
++
++        *(s++) = SSH_MSG_USERAUTH_REQUEST;
++        libssh2_htonu32(s, username_len);
++        s += 4;
++        memcpy(s, username, username_len);
++        s += username_len;
++
++        libssh2_htonu32(s, sizeof("ssh-connection") - 1);
++        s += 4;
++        memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1);
++        s += sizeof("ssh-connection") - 1;
++
++        libssh2_htonu32(s, sizeof("password") - 1);
++        s += 4;
++        memcpy(s, "password", sizeof("password") - 1);
++        s += sizeof("password") - 1;
++
++        *s = '\0';
++        s++;
++
++        libssh2_htonu32(s, password_len);
++        s += 4;
++        memcpy(s, password, password_len);
++        s += password_len;
++
++        _libssh2_debug(session, LIBSSH2_DBG_AUTH,
++                       "Attempting to login using password authentication");
++
++        session->userauth_pswd_state = libssh2_NB_state_created;
++    }
++
++    if (session->userauth_pswd_state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, session->userauth_pswd_data,
++                                  session->userauth_pswd_data_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send userauth-password request", 0);
++            LIBSSH2_FREE(session, session->userauth_pswd_data);
++            session->userauth_pswd_data = NULL;
++            session->userauth_pswd_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, session->userauth_pswd_data);
++        session->userauth_pswd_data = NULL;
++
++        session->userauth_pswd_state = libssh2_NB_state_sent;
++    }
++
++  password_response:
++
++    if ((session->userauth_pswd_state == libssh2_NB_state_sent)
++        || (session->userauth_pswd_state == libssh2_NB_state_sent1)
++        || (session->userauth_pswd_state == libssh2_NB_state_sent2)) {
++        if (session->userauth_pswd_state == libssh2_NB_state_sent) {
++            rc = libssh2_packet_requirev_ex(session, reply_codes,
++                                            &session->userauth_pswd_data,
++                                            &session->userauth_pswd_data_len,
++                                            0, NULL, 0,
++                                            &session->
++                                            userauth_pswd_packet_requirev_state);
++            if (rc == PACKET_EAGAIN) {
++                return PACKET_EAGAIN;
++            } else if (rc) {
++                session->userauth_pswd_state = libssh2_NB_state_idle;
++                return -1;
++            }
++
++            if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
++                _libssh2_debug(session, LIBSSH2_DBG_AUTH,
++                               "Password authentication successful");
++                LIBSSH2_FREE(session, session->userauth_pswd_data);
++                session->userauth_pswd_data = NULL;
++                session->state |= LIBSSH2_STATE_AUTHENTICATED;
++                session->userauth_pswd_state = libssh2_NB_state_idle;
++                return 0;
++            }
++
++            session->userauth_pswd_newpw = NULL;
++            session->userauth_pswd_newpw_len = 0;
++
++            session->userauth_pswd_state = libssh2_NB_state_sent1;
++        }
++
++        if ((session->userauth_pswd_data[0] ==
++             SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)
++            || (session->userauth_pswd_data0 ==
++                SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)) {
++            session->userauth_pswd_data0 = SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
++
++            if ((session->userauth_pswd_state == libssh2_NB_state_sent1) ||
++                (session->userauth_pswd_state == libssh2_NB_state_sent2)) {
++                if (session->userauth_pswd_state == libssh2_NB_state_sent1) {
++                    _libssh2_debug(session, LIBSSH2_DBG_AUTH,
++                                   "Password change required");
++                    LIBSSH2_FREE(session, session->userauth_pswd_data);
++                    session->userauth_pswd_data = NULL;
++                }
++                if (passwd_change_cb) {
++                    if (session->userauth_pswd_state == libssh2_NB_state_sent1) {
++                        passwd_change_cb(session,
++                                         &session->userauth_pswd_newpw,
++                                         &session->userauth_pswd_newpw_len,
++                                         &session->abstract);
++                        if (!session->userauth_pswd_newpw) {
++                            libssh2_error(session,
++                                          LIBSSH2_ERROR_PASSWORD_EXPIRED,
++                                          "Password expired, and callback failed",
++                                          0);
++                            return -1;
++                        }
++
++                        /* basic data_len + newpw_len(4) */
++                        session->userauth_pswd_data_len =
++                            username_len + password_len + 44 +
++                            session->userauth_pswd_newpw_len;
++
++                        s = session->userauth_pswd_data =
++                            LIBSSH2_ALLOC(session,
++                                          session->userauth_pswd_data_len);
++                        if (!session->userauth_pswd_data) {
++                            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                                          "Unable to allocate memory for userauth-password-change request",
++                                          0);
++                            LIBSSH2_FREE(session,
++                                         session->userauth_pswd_newpw);
++                            session->userauth_pswd_newpw = NULL;
++                            return -1;
++                        }
++
++                        *(s++) = SSH_MSG_USERAUTH_REQUEST;
++                        libssh2_htonu32(s, username_len);
++                        s += 4;
++                        memcpy(s, username, username_len);
++                        s += username_len;
++
++                        libssh2_htonu32(s, sizeof("ssh-connection") - 1);
++                        s += 4;
++                        memcpy(s, "ssh-connection",
++                               sizeof("ssh-connection") - 1);
++                        s += sizeof("ssh-connection") - 1;
++
++                        libssh2_htonu32(s, sizeof("password") - 1);
++                        s += 4;
++                        memcpy(s, "password", sizeof("password") - 1);
++                        s += sizeof("password") - 1;
++
++                        *s = 0x01;
++                        s++;
++
++                        libssh2_htonu32(s, password_len);
++                        s += 4;
++                        memcpy(s, password, password_len);
++                        s += password_len;
++
++                        libssh2_htonu32(s, session->userauth_pswd_newpw_len);
++                        s += 4;
++                        memcpy(s, session->userauth_pswd_newpw,
++                               session->userauth_pswd_newpw_len);
++                        s += session->userauth_pswd_newpw_len;
++
++                        session->userauth_pswd_state = libssh2_NB_state_sent2;
++                    }
++
++                    if (session->userauth_pswd_state == libssh2_NB_state_sent2) {
++                        rc = libssh2_packet_write(session,
++                                                  session->userauth_pswd_data,
++                                                  session->
++                                                  userauth_pswd_data_len);
++                        if (rc == PACKET_EAGAIN) {
++                            return PACKET_EAGAIN;
++                        } else if (rc) {
++                            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                                          "Unable to send userauth-password-change request",
++                                          0);
++                            LIBSSH2_FREE(session, session->userauth_pswd_data);
++                            session->userauth_pswd_data = NULL;
++                            LIBSSH2_FREE(session,
++                                         session->userauth_pswd_newpw);
++                            session->userauth_pswd_newpw = NULL;
++                            return -1;
++                        }
++                        LIBSSH2_FREE(session, session->userauth_pswd_data);
++                        session->userauth_pswd_data = NULL;
++                        LIBSSH2_FREE(session, session->userauth_pswd_newpw);
++                        session->userauth_pswd_newpw = NULL;
++
++                        /*
++                         * Ugliest use of goto ever.  Blame it on the
++                         * askN => requirev migration.
++                         */
++                        session->userauth_pswd_state = libssh2_NB_state_sent;
++                        goto password_response;
++                    }
++                }
++            } else {
++                libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED,
++                              "Password Expired, and no callback specified",
++                              0);
++                session->userauth_pswd_state = libssh2_NB_state_idle;
++                return -1;
++            }
++        }
++    }
++
++    /* FAILURE */
++    LIBSSH2_FREE(session, session->userauth_pswd_data);
++    session->userauth_pswd_data = NULL;
++    session->userauth_pswd_state = libssh2_NB_state_idle;
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_file_read_publickey
++ * Read a public key from an id_???.pub style file
++ */
++static int
++libssh2_file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
++                            unsigned long *method_len,
++                            unsigned char **pubkeydata,
++                            unsigned long *pubkeydata_len,
++                            const char *pubkeyfile)
++{
++    FILE *fd;
++    char c;
++    unsigned char *pubkey = NULL, *sp1, *sp2, *tmp;
++    size_t pubkey_len = 0;
++    unsigned int tmp_len;
++
++    _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading public key file: %s",
++                   pubkeyfile);
++    /* Read Public Key */
++    fd = fopen(pubkeyfile, "r");
++    if (!fd) {
++        libssh2_error(session, LIBSSH2_ERROR_FILE,
++                      "Unable to open public key file", 0);
++        return -1;
++    }
++    while (!feof(fd) && (c = fgetc(fd)) != '\r' && c != '\n')
++        pubkey_len++;
++    if (feof(fd)) {
++        /* the last character was EOF */
++        pubkey_len--;
++    }
++    rewind(fd);
++
++    if (pubkey_len <= 1) {
++        libssh2_error(session, LIBSSH2_ERROR_FILE,
++                      "Invalid data in public key file", 0);
++        fclose(fd);
++        return -1;
++    }
++
++    pubkey = LIBSSH2_ALLOC(session, pubkey_len);
++    if (!pubkey) {
++        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                      "Unable to allocate memory for public key data", 0);
++        fclose(fd);
++        return -1;
++    }
++    if (fread(pubkey, 1, pubkey_len, fd) != pubkey_len) {
++        libssh2_error(session, LIBSSH2_ERROR_FILE,
++                      "Unable to read public key from file", 0);
++        LIBSSH2_FREE(session, pubkey);
++        fclose(fd);
++        return -1;
++    }
++    fclose(fd);
++    /*
++     * Remove trailing whitespace
++     */
++    while (pubkey_len && isspace(pubkey[pubkey_len - 1]))
++        pubkey_len--;
++
++    if (!pubkey_len) {
++        libssh2_error(session, LIBSSH2_ERROR_FILE, "Missing public key data",
++                      0);
++        LIBSSH2_FREE(session, pubkey);
++        return -1;
++    }
++
++    if ((sp1 = memchr(pubkey, ' ', pubkey_len)) == NULL) {
++        libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid public key data",
++                      0);
++        LIBSSH2_FREE(session, pubkey);
++        return -1;
++    }
++    /* Wasting some bytes here (okay, more than some),
++     * but since it's likely to be freed soon anyway, 
++     * we'll just avoid the extra free/alloc and call it a wash */
++    *method = pubkey;
++    *method_len = sp1 - pubkey;
++
++    sp1++;
++
++    if ((sp2 = memchr(sp1, ' ', pubkey_len - *method_len)) == NULL) {
++        /* Assume that the id string is missing, but that it's okay */
++        sp2 = pubkey + pubkey_len;
++    }
++
++    if (libssh2_base64_decode
++        (session, (char **) &tmp, &tmp_len, (char *) sp1, sp2 - sp1)) {
++        libssh2_error(session, LIBSSH2_ERROR_FILE,
++                      "Invalid key data, not base64 encoded", 0);
++        LIBSSH2_FREE(session, pubkey);
++        return -1;
++    }
++    *pubkeydata = tmp;
++    *pubkeydata_len = tmp_len;
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_file_read_privatekey
++ * Read a PEM encoded private key from an id_??? style file
++ */
++static int
++libssh2_file_read_privatekey(LIBSSH2_SESSION * session,
++                             const LIBSSH2_HOSTKEY_METHOD ** hostkey_method,
++                             void **hostkey_abstract,
++                             const unsigned char *method, int method_len,
++                             const char *privkeyfile, const char *passphrase)
++{
++    const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail =
++        libssh2_hostkey_methods();
++
++    _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading private key file: %s",
++                   privkeyfile);
++    *hostkey_method = NULL;
++    *hostkey_abstract = NULL;
++    while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) {
++        if ((*hostkey_methods_avail)->initPEM
++            && strncmp((*hostkey_methods_avail)->name, (const char *) method,
++                       method_len) == 0) {
++            *hostkey_method = *hostkey_methods_avail;
++            break;
++        }
++        hostkey_methods_avail++;
++    }
++    if (!*hostkey_method) {
++        libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
++                      "No handler for specified private key", 0);
++        return -1;
++    }
++
++    if ((*hostkey_method)->
++        initPEM(session, privkeyfile, (unsigned char *) passphrase,
++                hostkey_abstract)) {
++        libssh2_error(session, LIBSSH2_ERROR_FILE,
++                      "Unable to initialize private key from file", 0);
++        return -1;
++    }
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_userauth_hostbased_fromfile_ex
++ * Authenticate using a keypair found in the named files
++ */
++LIBSSH2_API int
++libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION * session,
++                                       const char *username,
++                                       unsigned int username_len,
++                                       const char *publickey,
++                                       const char *privatekey,
++                                       const char *passphrase,
++                                       const char *hostname,
++                                       unsigned int hostname_len,
++                                       const char *local_username,
++                                       unsigned int local_username_len)
++{
++    static const unsigned char reply_codes[3] =
++        { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
++    int rc;
++
++    if (session->userauth_host_state == libssh2_NB_state_idle) {
++        const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
++        unsigned char *pubkeydata, *sig;
++        unsigned long pubkeydata_len;
++        unsigned long sig_len;
++        void *abstract;
++        unsigned char buf[5];
++        struct iovec datavec[4];
++
++        /* Zero the whole thing out */
++        memset(&session->userauth_host_packet_requirev_state, 0,
++               sizeof(session->userauth_host_packet_requirev_state));
++
++        if (libssh2_file_read_publickey
++            (session, &session->userauth_host_method,
++             &session->userauth_host_method_len, &pubkeydata, &pubkeydata_len,
++             publickey)) {
++            return -1;
++        }
++
++        /*
++         * 48 = packet_type(1) + username_len(4) + servicename_len(4) + 
++         * service_name(14)"ssh-connection" + authmethod_len(4) +
++         * authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) + 
++         * local_username_len(4)
++         */
++        session->userauth_host_packet_len =
++            username_len + session->userauth_host_method_len + hostname_len +
++            local_username_len + pubkeydata_len + 48;
++
++        /*
++         * Preallocate space for an overall length,  method name again,
++         * and the signature, which won't be any larger than the size of 
++         * the publickeydata itself
++         */
++        session->userauth_host_s = session->userauth_host_packet =
++            LIBSSH2_ALLOC(session,
++                          session->userauth_host_packet_len + 4 + (4 +
++                                                                   session->
++                                                                   userauth_host_method_len)
++                          + (4 + pubkeydata_len));
++        if (!session->userauth_host_packet) {
++            LIBSSH2_FREE(session, session->userauth_host_method);
++            session->userauth_host_method = NULL;
++            return -1;
++        }
++
++        *(session->userauth_host_s++) = SSH_MSG_USERAUTH_REQUEST;
++        libssh2_htonu32(session->userauth_host_s, username_len);
++        session->userauth_host_s += 4;
++        memcpy(session->userauth_host_s, username, username_len);
++        session->userauth_host_s += username_len;
++
++        libssh2_htonu32(session->userauth_host_s, 14);
++        session->userauth_host_s += 4;
++        memcpy(session->userauth_host_s, "ssh-connection", 14);
++        session->userauth_host_s += 14;
++
++        libssh2_htonu32(session->userauth_host_s, 9);
++        session->userauth_host_s += 4;
++        memcpy(session->userauth_host_s, "hostbased", 9);
++        session->userauth_host_s += 9;
++
++        libssh2_htonu32(session->userauth_host_s,
++                        session->userauth_host_method_len);
++        session->userauth_host_s += 4;
++        memcpy(session->userauth_host_s, session->userauth_host_method,
++               session->userauth_host_method_len);
++        session->userauth_host_s += session->userauth_host_method_len;
++
++        libssh2_htonu32(session->userauth_host_s, pubkeydata_len);
++        session->userauth_host_s += 4;
++        memcpy(session->userauth_host_s, pubkeydata, pubkeydata_len);
++        session->userauth_host_s += pubkeydata_len;
++
++        libssh2_htonu32(session->userauth_host_s, hostname_len);
++        session->userauth_host_s += 4;
++        memcpy(session->userauth_host_s, hostname, hostname_len);
++        session->userauth_host_s += hostname_len;
++
++        libssh2_htonu32(session->userauth_host_s, local_username_len);
++        session->userauth_host_s += 4;
++        memcpy(session->userauth_host_s, local_username, local_username_len);
++        session->userauth_host_s += local_username_len;
++
++        if (libssh2_file_read_privatekey
++            (session, &privkeyobj, &abstract, session->userauth_host_method,
++             session->userauth_host_method_len, privatekey, passphrase)) {
++            LIBSSH2_FREE(session, session->userauth_host_method);
++            session->userauth_host_method = NULL;
++            LIBSSH2_FREE(session, session->userauth_host_packet);
++            session->userauth_host_packet = NULL;
++            return -1;
++        }
++
++        libssh2_htonu32(buf, session->session_id_len);
++        datavec[0].iov_base = buf;
++        datavec[0].iov_len = 4;
++        datavec[1].iov_base = session->session_id;
++        datavec[1].iov_len = session->session_id_len;
++        datavec[2].iov_base = session->userauth_host_packet;
++        datavec[2].iov_len = session->userauth_host_packet_len;
++
++        if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
++            LIBSSH2_FREE(session, session->userauth_host_method);
++            session->userauth_host_method = NULL;
++            LIBSSH2_FREE(session, session->userauth_host_packet);
++            session->userauth_host_packet = NULL;
++            if (privkeyobj->dtor) {
++                privkeyobj->dtor(session, &abstract);
++            }
++            return -1;
++        }
++
++        if (privkeyobj->dtor) {
++            privkeyobj->dtor(session, &abstract);
++        }
++
++        if (sig_len > pubkeydata_len) {
++            unsigned char *newpacket;
++            /* Should *NEVER* happen, but...well.. better safe than sorry */
++            newpacket = LIBSSH2_REALLOC(session, session->userauth_host_packet, session->userauth_host_packet_len + 4 + (4 + session->userauth_host_method_len) + (4 + sig_len));       /* PK sigblob */
++            if (!newpacket) {
++                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                              "Failed allocating additional space for userauth-hostbased packet",
++                              0);
++                LIBSSH2_FREE(session, sig);
++                LIBSSH2_FREE(session, session->userauth_host_packet);
++                session->userauth_host_packet = NULL;
++                LIBSSH2_FREE(session, session->userauth_host_method);
++                session->userauth_host_method = NULL;
++                return -1;
++            }
++            session->userauth_host_packet = newpacket;
++        }
++
++        session->userauth_host_s =
++            session->userauth_host_packet + session->userauth_host_packet_len;
++
++        libssh2_htonu32(session->userauth_host_s,
++                        4 + session->userauth_host_method_len + 4 + sig_len);
++        session->userauth_host_s += 4;
++
++        libssh2_htonu32(session->userauth_host_s,
++                        session->userauth_host_method_len);
++        session->userauth_host_s += 4;
++        memcpy(session->userauth_host_s, session->userauth_host_method,
++               session->userauth_host_method_len);
++        session->userauth_host_s += session->userauth_host_method_len;
++        LIBSSH2_FREE(session, session->userauth_host_method);
++        session->userauth_host_method = NULL;
++
++        libssh2_htonu32(session->userauth_host_s, sig_len);
++        session->userauth_host_s += 4;
++        memcpy(session->userauth_host_s, sig, sig_len);
++        session->userauth_host_s += sig_len;
++        LIBSSH2_FREE(session, sig);
++
++        _libssh2_debug(session, LIBSSH2_DBG_AUTH,
++                       "Attempting hostbased authentication");
++
++        session->userauth_host_state = libssh2_NB_state_created;
++    }
++
++    if (session->userauth_host_state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, session->userauth_host_packet,
++                                  session->userauth_host_s -
++                                  session->userauth_host_packet);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send userauth-hostbased request", 0);
++            LIBSSH2_FREE(session, session->userauth_host_packet);
++            session->userauth_host_packet = NULL;
++            session->userauth_host_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, session->userauth_host_packet);
++        session->userauth_host_packet = NULL;
++
++        session->userauth_host_state = libssh2_NB_state_sent;
++    }
++
++    if (session->userauth_host_state == libssh2_NB_state_sent) {
++        unsigned long data_len;
++        rc = libssh2_packet_requirev_ex(session, reply_codes,
++                                        &session->userauth_host_data,
++                                        &data_len, 0, NULL, 0,
++                                        &session->
++                                        userauth_host_packet_requirev_state);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            session->userauth_host_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        if (session->userauth_host_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
++            _libssh2_debug(session, LIBSSH2_DBG_AUTH,
++                           "Hostbased authentication successful");
++            /* We are us and we've proved it. */
++            LIBSSH2_FREE(session, session->userauth_host_data);
++            session->userauth_host_data = NULL;
++            session->state |= LIBSSH2_STATE_AUTHENTICATED;
++            session->userauth_host_state = libssh2_NB_state_idle;
++            return 0;
++        }
++    }
++
++    /* This public key is not allowed for this user on this server */
++    LIBSSH2_FREE(session, session->userauth_host_data);
++    session->userauth_host_data = NULL;
++    libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
++                  "Invalid signature for supplied public key, or bad username/public key combination",
++                  0);
++    session->userauth_host_state = libssh2_NB_state_idle;
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_userauth_publickey_fromfile_ex
++ * Authenticate using a keypair found in the named files
++ */
++LIBSSH2_API int
++libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION * session,
++                                       const char *username,
++                                       unsigned int username_len,
++                                       const char *publickey,
++                                       const char *privatekey,
++                                       const char *passphrase)
++{
++    unsigned long pubkeydata_len = 0;
++    unsigned char reply_codes[4] =
++        { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
++        SSH_MSG_USERAUTH_PK_OK, 0
++    };
++    int rc;
++
++    if (session->userauth_pblc_state == libssh2_NB_state_idle) {
++        unsigned char *pubkeydata;
++
++        /* Zero the whole thing out */
++        memset(&session->userauth_pblc_packet_requirev_state, 0,
++               sizeof(session->userauth_pblc_packet_requirev_state));
++
++        if (libssh2_file_read_publickey
++            (session, &session->userauth_pblc_method,
++             &session->userauth_pblc_method_len, &pubkeydata, &pubkeydata_len,
++             publickey)) {
++            return -1;
++        }
++
++        /*
++         * 45 = packet_type(1) + username_len(4) + servicename_len(4) + 
++         * service_name(14)"ssh-connection" + authmethod_len(4) + 
++         * authmethod(9)"publickey" + sig_included(1)'\0' + algmethod_len(4) +
++         * publickey_len(4)
++         */
++        session->userauth_pblc_packet_len =
++            username_len + session->userauth_pblc_method_len + pubkeydata_len +
++            45;
++
++        /*
++         * Preallocate space for an overall length,  method name again, and
++         * the signature, which won't be any larger than the size of the 
++         * publickeydata itself
++         */
++        session->userauth_pblc_s = session->userauth_pblc_packet =
++            LIBSSH2_ALLOC(session,
++                          session->userauth_pblc_packet_len + 4 + (4 +
++                                                                   session->
++                                                                   userauth_pblc_method_len)
++                          + (4 + pubkeydata_len));
++        if (!session->userauth_pblc_packet) {
++            LIBSSH2_FREE(session, session->userauth_pblc_method);
++            session->userauth_pblc_method = NULL;
++            LIBSSH2_FREE(session, pubkeydata);
++            return -1;
++        }
++
++        *(session->userauth_pblc_s++) = SSH_MSG_USERAUTH_REQUEST;
++        libssh2_htonu32(session->userauth_pblc_s, username_len);
++        session->userauth_pblc_s += 4;
++        memcpy(session->userauth_pblc_s, username, username_len);
++        session->userauth_pblc_s += username_len;
++
++        libssh2_htonu32(session->userauth_pblc_s, 14);
++        session->userauth_pblc_s += 4;
++        memcpy(session->userauth_pblc_s, "ssh-connection", 14);
++        session->userauth_pblc_s += 14;
++
++        libssh2_htonu32(session->userauth_pblc_s, 9);
++        session->userauth_pblc_s += 4;
++        memcpy(session->userauth_pblc_s, "publickey", 9);
++        session->userauth_pblc_s += 9;
++
++        session->userauth_pblc_b = session->userauth_pblc_s;
++        /* Not sending signature with *this* packet */
++        *(session->userauth_pblc_s++) = 0;
++
++        libssh2_htonu32(session->userauth_pblc_s,
++                        session->userauth_pblc_method_len);
++        session->userauth_pblc_s += 4;
++        memcpy(session->userauth_pblc_s, session->userauth_pblc_method,
++               session->userauth_pblc_method_len);
++        session->userauth_pblc_s += session->userauth_pblc_method_len;
++
++        libssh2_htonu32(session->userauth_pblc_s, pubkeydata_len);
++        session->userauth_pblc_s += 4;
++        memcpy(session->userauth_pblc_s, pubkeydata, pubkeydata_len);
++        session->userauth_pblc_s += pubkeydata_len;
++        LIBSSH2_FREE(session, pubkeydata);
++
++        _libssh2_debug(session, LIBSSH2_DBG_AUTH,
++                       "Attempting publickey authentication");
++
++        session->userauth_pblc_state = libssh2_NB_state_created;
++    }
++
++    if (session->userauth_pblc_state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, session->userauth_pblc_packet,
++                                  session->userauth_pblc_packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send userauth-publickey request", 0);
++            LIBSSH2_FREE(session, session->userauth_pblc_packet);
++            session->userauth_pblc_packet = NULL;
++            LIBSSH2_FREE(session, session->userauth_pblc_method);
++            session->userauth_pblc_method = NULL;
++            session->userauth_pblc_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        session->userauth_pblc_state = libssh2_NB_state_sent;
++    }
++
++    if (session->userauth_pblc_state == libssh2_NB_state_sent) {
++        const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
++        void *abstract;
++        unsigned char buf[5];
++        struct iovec datavec[4];
++        unsigned char *sig;
++        unsigned long sig_len;
++
++        rc = libssh2_packet_requirev_ex(session, reply_codes,
++                                        &session->userauth_pblc_data,
++                                        &session->userauth_pblc_data_len, 0,
++                                        NULL, 0,
++                                        &session->
++                                        userauth_pblc_packet_requirev_state);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            LIBSSH2_FREE(session, session->userauth_pblc_packet);
++            session->userauth_pblc_packet = NULL;
++            LIBSSH2_FREE(session, session->userauth_pblc_method);
++            session->userauth_pblc_method = NULL;
++            session->userauth_pblc_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
++            _libssh2_debug(session, LIBSSH2_DBG_AUTH,
++                           "Pubkey authentication prematurely successful");
++            /*
++             * God help any SSH server that allows an UNVERIFIED
++             * public key to validate the user
++             */
++            LIBSSH2_FREE(session, session->userauth_pblc_data);
++            session->userauth_pblc_data = NULL;
++            LIBSSH2_FREE(session, session->userauth_pblc_packet);
++            session->userauth_pblc_packet = NULL;
++            LIBSSH2_FREE(session, session->userauth_pblc_method);
++            session->userauth_pblc_method = NULL;
++            session->state |= LIBSSH2_STATE_AUTHENTICATED;
++            session->userauth_pblc_state = libssh2_NB_state_idle;
++            return 0;
++        }
++
++        if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_FAILURE) {
++            /* This public key is not allowed for this user on this server */
++            LIBSSH2_FREE(session, session->userauth_pblc_data);
++            session->userauth_pblc_data = NULL;
++            LIBSSH2_FREE(session, session->userauth_pblc_packet);
++            session->userauth_pblc_packet = NULL;
++            LIBSSH2_FREE(session, session->userauth_pblc_method);
++            session->userauth_pblc_method = NULL;
++            libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED,
++                          "Username/PublicKey combination invalid", 0);
++            session->userauth_pblc_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        /* Semi-Success! */
++        LIBSSH2_FREE(session, session->userauth_pblc_data);
++        session->userauth_pblc_data = NULL;
++
++        if (libssh2_file_read_privatekey
++            (session, &privkeyobj, &abstract, session->userauth_pblc_method,
++             session->userauth_pblc_method_len, privatekey, passphrase)) {
++            LIBSSH2_FREE(session, session->userauth_pblc_method);
++            session->userauth_pblc_method = NULL;
++            LIBSSH2_FREE(session, session->userauth_pblc_packet);
++            session->userauth_pblc_packet = NULL;
++            session->userauth_pblc_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        *session->userauth_pblc_b = 0x01;
++
++        libssh2_htonu32(buf, session->session_id_len);
++        datavec[0].iov_base = buf;
++        datavec[0].iov_len = 4;
++        datavec[1].iov_base = session->session_id;
++        datavec[1].iov_len = session->session_id_len;
++        datavec[2].iov_base = session->userauth_pblc_packet;
++        datavec[2].iov_len = session->userauth_pblc_packet_len;
++
++        if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
++            LIBSSH2_FREE(session, session->userauth_pblc_method);
++            session->userauth_pblc_method = NULL;
++            LIBSSH2_FREE(session, session->userauth_pblc_packet);
++            session->userauth_pblc_packet = NULL;
++            if (privkeyobj->dtor) {
++                privkeyobj->dtor(session, &abstract);
++            }
++            session->userauth_pblc_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        if (privkeyobj->dtor) {
++            privkeyobj->dtor(session, &abstract);
++        }
++
++      /* 
++       * If this function was restarted, pubkeydata_len might still be 0
++       * which will cause an unnecessary but harmless realloc here.
++       */
++        if (sig_len > pubkeydata_len) {
++            unsigned char *newpacket;
++            /* Should *NEVER* happen, but...well.. better safe than sorry */
++            newpacket = LIBSSH2_REALLOC(session, session->userauth_pblc_packet, session->userauth_pblc_packet_len + 4 + (4 + session->userauth_pblc_method_len) + (4 + sig_len));       /* PK sigblob */
++            if (!newpacket) {
++                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                              "Failed allocating additional space for userauth-publickey packet",
++                              0);
++                LIBSSH2_FREE(session, sig);
++                LIBSSH2_FREE(session, session->userauth_pblc_packet);
++                session->userauth_pblc_packet = NULL;
++                LIBSSH2_FREE(session, session->userauth_pblc_method);
++                session->userauth_pblc_method = NULL;
++                session->userauth_pblc_state = libssh2_NB_state_idle;
++                return -1;
++            }
++            session->userauth_pblc_packet = newpacket;
++        }
++
++        session->userauth_pblc_s =
++            session->userauth_pblc_packet + session->userauth_pblc_packet_len;
++        session->userauth_pblc_b = NULL;
++
++        libssh2_htonu32(session->userauth_pblc_s,
++                        4 + session->userauth_pblc_method_len + 4 + sig_len);
++        session->userauth_pblc_s += 4;
++
++        libssh2_htonu32(session->userauth_pblc_s,
++                        session->userauth_pblc_method_len);
++        session->userauth_pblc_s += 4;
++        memcpy(session->userauth_pblc_s, session->userauth_pblc_method,
++               session->userauth_pblc_method_len);
++        session->userauth_pblc_s += session->userauth_pblc_method_len;
++        LIBSSH2_FREE(session, session->userauth_pblc_method);
++        session->userauth_pblc_method = NULL;
++
++        libssh2_htonu32(session->userauth_pblc_s, sig_len);
++        session->userauth_pblc_s += 4;
++        memcpy(session->userauth_pblc_s, sig, sig_len);
++        session->userauth_pblc_s += sig_len;
++        LIBSSH2_FREE(session, sig);
++
++        _libssh2_debug(session, LIBSSH2_DBG_AUTH,
++                       "Attempting publickey authentication -- phase 2");
++
++        session->userauth_pblc_state = libssh2_NB_state_sent1;
++    }
++
++    if (session->userauth_pblc_state == libssh2_NB_state_sent1) {
++        rc = libssh2_packet_write(session, session->userauth_pblc_packet,
++                                  session->userauth_pblc_s -
++                                  session->userauth_pblc_packet);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send userauth-publickey request", 0);
++            LIBSSH2_FREE(session, session->userauth_pblc_packet);
++            session->userauth_pblc_packet = NULL;
++            session->userauth_pblc_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, session->userauth_pblc_packet);
++        session->userauth_pblc_packet = NULL;
++
++        session->userauth_pblc_state = libssh2_NB_state_sent2;
++    }
++
++    /* PK_OK is no longer valid */
++    reply_codes[2] = 0;
++
++    rc = libssh2_packet_requirev_ex(session, reply_codes,
++                                    &session->userauth_pblc_data,
++                                    &session->userauth_pblc_data_len, 0, NULL,
++                                    0,
++                                    &session->
++                                    userauth_pblc_packet_requirev_state);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    } else if (rc) {
++        session->userauth_pblc_state = libssh2_NB_state_idle;
++        return -1;
++    }
++
++    if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
++        _libssh2_debug(session, LIBSSH2_DBG_AUTH,
++                       "Publickey authentication successful");
++        /* We are us and we've proved it. */
++        LIBSSH2_FREE(session, session->userauth_pblc_data);
++        session->userauth_pblc_data = NULL;
++        session->state |= LIBSSH2_STATE_AUTHENTICATED;
++        session->userauth_pblc_state = libssh2_NB_state_idle;
++        return 0;
++    }
++
++    /* This public key is not allowed for this user on this server */
++    LIBSSH2_FREE(session, session->userauth_pblc_data);
++    session->userauth_pblc_data = NULL;
++    libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
++                  "Invalid signature for supplied public key, or bad username/public key combination",
++                  0);
++    session->userauth_pblc_state = libssh2_NB_state_idle;
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_userauth_keyboard_interactive
++ * Authenticate using a challenge-response authentication
++ */
++LIBSSH2_API int
++libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
++                                         const char *username,
++                                         unsigned int username_len,
++                                         LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
++{
++    unsigned char *s;
++    int rc;
++
++    static const unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS,
++        SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0
++    };
++    unsigned int language_tag_len;
++    unsigned int i;
++
++    if (session->userauth_kybd_state == libssh2_NB_state_idle) {
++        session->userauth_kybd_auth_name = NULL;
++        session->userauth_kybd_auth_instruction = NULL;
++        session->userauth_kybd_num_prompts = 0;
++        session->userauth_kybd_auth_failure = 1;
++        session->userauth_kybd_prompts = NULL;
++        session->userauth_kybd_responses = NULL;
++
++        /* Zero the whole thing out */
++        memset(&session->userauth_kybd_packet_requirev_state, 0,
++               sizeof(session->userauth_kybd_packet_requirev_state));
++
++        session->userauth_kybd_packet_len = 1   /* byte      SSH_MSG_USERAUTH_REQUEST */
++            + 4 + username_len  /* string    user name (ISO-10646 UTF-8, as defined in [RFC-3629]) */
++            + 4 + 14            /* string    service name (US-ASCII) */
++            + 4 + 20            /* string    "keyboard-interactive" (US-ASCII) */
++            + 4 + 0             /* string    language tag (as defined in [RFC-3066]) */
++            + 4 + 0             /* string    submethods (ISO-10646 UTF-8) */
++            ;
++
++        session->userauth_kybd_data = s =
++            LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
++        if (!s) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for keyboard-interactive authentication",
++                          0);
++            return -1;
++        }
++
++        *s++ = SSH_MSG_USERAUTH_REQUEST;
++
++        /* user name */
++        libssh2_htonu32(s, username_len);
++        s += 4;
++        memcpy(s, username, username_len);
++        s += username_len;
++
++        /* service name */
++        libssh2_htonu32(s, sizeof("ssh-connection") - 1);
++        s += 4;
++        memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1);
++        s += sizeof("ssh-connection") - 1;
++
++        /* "keyboard-interactive" */
++        libssh2_htonu32(s, sizeof("keyboard-interactive") - 1);
++        s += 4;
++        memcpy(s, "keyboard-interactive", sizeof("keyboard-interactive") - 1);
++        s += sizeof("keyboard-interactive") - 1;
++
++        /* language tag */
++        libssh2_htonu32(s, 0);
++        s += 4;
++
++        /* submethods */
++        libssh2_htonu32(s, 0);
++        s += 4;
++
++        _libssh2_debug(session, LIBSSH2_DBG_AUTH,
++                       "Attempting keyboard-interactive authentication");
++
++        session->userauth_kybd_state = libssh2_NB_state_created;
++    }
++
++    if (session->userauth_kybd_state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, session->userauth_kybd_data,
++                                  session->userauth_kybd_packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send keyboard-interactive request", 0);
++            LIBSSH2_FREE(session, session->userauth_kybd_data);
++            session->userauth_kybd_data = NULL;
++            session->userauth_kybd_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, session->userauth_kybd_data);
++        session->userauth_kybd_data = NULL;
++
++        session->userauth_kybd_state = libssh2_NB_state_sent;
++    }
++
++    for(;;) {
++        if (session->userauth_kybd_state == libssh2_NB_state_sent) {
++            rc = libssh2_packet_requirev_ex(session, reply_codes,
++                                            &session->userauth_kybd_data,
++                                            &session->userauth_kybd_data_len,
++                                            0, NULL, 0,
++                                            &session->
++                                            userauth_kybd_packet_requirev_state);
++            if (rc == PACKET_EAGAIN) {
++                return PACKET_EAGAIN;
++            } else if (rc) {
++                session->userauth_kybd_state = libssh2_NB_state_idle;
++                return -1;
++            }
++
++            if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
++                _libssh2_debug(session, LIBSSH2_DBG_AUTH,
++                               "Keyboard-interactive authentication successful");
++                LIBSSH2_FREE(session, session->userauth_kybd_data);
++                session->userauth_kybd_data = NULL;
++                session->state |= LIBSSH2_STATE_AUTHENTICATED;
++                session->userauth_kybd_state = libssh2_NB_state_idle;
++                return 0;
++            }
++
++            if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) {
++                LIBSSH2_FREE(session, session->userauth_kybd_data);
++                session->userauth_kybd_data = NULL;
++                session->userauth_kybd_state = libssh2_NB_state_idle;
++                return -1;
++            }
++
++            /* server requested PAM-like conversation */
++
++            s = session->userauth_kybd_data + 1;
++
++            /* string    name (ISO-10646 UTF-8) */
++            session->userauth_kybd_auth_name_len = libssh2_ntohu32(s);
++            s += 4;
++            session->userauth_kybd_auth_name =
++                LIBSSH2_ALLOC(session, session->userauth_kybd_auth_name_len);
++            if (!session->userauth_kybd_auth_name) {
++                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                              "Unable to allocate memory for keyboard-interactive 'name' request field",
++                              0);
++                goto cleanup;
++            }
++            memcpy(session->userauth_kybd_auth_name, s,
++                   session->userauth_kybd_auth_name_len);
++            s += session->userauth_kybd_auth_name_len;
++
++            /* string    instruction (ISO-10646 UTF-8) */
++            session->userauth_kybd_auth_instruction_len = libssh2_ntohu32(s);
++            s += 4;
++            session->userauth_kybd_auth_instruction =
++                LIBSSH2_ALLOC(session,
++                              session->userauth_kybd_auth_instruction_len);
++            if (!session->userauth_kybd_auth_instruction) {
++                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                              "Unable to allocate memory for keyboard-interactive 'instruction' request field",
++                              0);
++                goto cleanup;
++            }
++            memcpy(session->userauth_kybd_auth_instruction, s,
++                   session->userauth_kybd_auth_instruction_len);
++            s += session->userauth_kybd_auth_instruction_len;
++
++            /* string    language tag (as defined in [RFC-3066]) */
++            language_tag_len = libssh2_ntohu32(s);
++            s += 4;
++            /* ignoring this field as deprecated */
++            s += language_tag_len;
++
++            /* int       num-prompts */
++            session->userauth_kybd_num_prompts = libssh2_ntohu32(s);
++            s += 4;
++
++            session->userauth_kybd_prompts =
++                LIBSSH2_ALLOC(session,
++                              sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
++                              session->userauth_kybd_num_prompts);
++            if (!session->userauth_kybd_prompts) {
++                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                              "Unable to allocate memory for keyboard-interactive prompts array",
++                              0);
++                goto cleanup;
++            }
++            memset(session->userauth_kybd_prompts, 0,
++                   sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
++                   session->userauth_kybd_num_prompts);
++
++            session->userauth_kybd_responses =
++                LIBSSH2_ALLOC(session,
++                              sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
++                              session->userauth_kybd_num_prompts);
++            if (!session->userauth_kybd_responses) {
++                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                              "Unable to allocate memory for keyboard-interactive responses array",
++                              0);
++                goto cleanup;
++            }
++            memset(session->userauth_kybd_responses, 0,
++                   sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
++                   session->userauth_kybd_num_prompts);
++
++            for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
++                /* string    prompt[1] (ISO-10646 UTF-8) */
++                session->userauth_kybd_prompts[i].length = libssh2_ntohu32(s);
++                s += 4;
++                session->userauth_kybd_prompts[i].text =
++                    LIBSSH2_ALLOC(session,
++                                  session->userauth_kybd_prompts[i].length);
++                if (!session->userauth_kybd_prompts[i].text) {
++                    libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                                  "Unable to allocate memory for keyboard-interactive prompt message",
++                                  0);
++                    goto cleanup;
++                }
++                memcpy(session->userauth_kybd_prompts[i].text, s,
++                       session->userauth_kybd_prompts[i].length);
++                s += session->userauth_kybd_prompts[i].length;
++
++                /* boolean   echo[1] */
++                session->userauth_kybd_prompts[i].echo = *s++;
++            }
++
++            response_callback(session->userauth_kybd_auth_name,
++                              session->userauth_kybd_auth_name_len,
++                              session->userauth_kybd_auth_instruction,
++                              session->userauth_kybd_auth_instruction_len,
++                              session->userauth_kybd_num_prompts,
++                              session->userauth_kybd_prompts,
++                              session->userauth_kybd_responses,
++                              &session->abstract);
++
++            _libssh2_debug(session, LIBSSH2_DBG_AUTH,
++                           "Keyboard-interactive response callback function invoked");
++
++            session->userauth_kybd_packet_len = 1       /* byte      SSH_MSG_USERAUTH_INFO_RESPONSE */
++                + 4             /* int       num-responses */
++                ;
++
++            for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
++                /* string    response[1] (ISO-10646 UTF-8) */
++                session->userauth_kybd_packet_len +=
++                    4 + session->userauth_kybd_responses[i].length;
++            }
++
++            session->userauth_kybd_data = s =
++                LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
++            if (!s) {
++                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                              "Unable to allocate memory for keyboard-interactive response packet",
++                              0);
++                goto cleanup;
++            }
++
++            *s = SSH_MSG_USERAUTH_INFO_RESPONSE;
++            s++;
++            libssh2_htonu32(s, session->userauth_kybd_num_prompts);
++            s += 4;
++
++            for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
++                libssh2_htonu32(s, session->userauth_kybd_responses[i].length);
++                s += 4;
++                memcpy(s, session->userauth_kybd_responses[i].text,
++                       session->userauth_kybd_responses[i].length);
++                s += session->userauth_kybd_responses[i].length;
++            }
++
++            session->userauth_kybd_state = libssh2_NB_state_sent1;
++        }
++
++        if (session->userauth_kybd_state == libssh2_NB_state_sent1) {
++            rc = libssh2_packet_write(session, session->userauth_kybd_data,
++                                      session->userauth_kybd_packet_len);
++            if (rc == PACKET_EAGAIN) {
++                return PACKET_EAGAIN;
++            }
++            if (rc) {
++                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                              "Unable to send userauth-keyboard-interactive request",
++                              0);
++                goto cleanup;
++            }
++
++            session->userauth_kybd_auth_failure = 0;
++        }
++
++      cleanup:
++        /*
++         * It's safe to clean all the data here, because unallocated pointers
++         * are filled by zeroes
++         */
++
++        LIBSSH2_FREE(session, session->userauth_kybd_data);
++        session->userauth_kybd_data = NULL;
++
++        if (session->userauth_kybd_prompts) {
++            for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
++                LIBSSH2_FREE(session, session->userauth_kybd_prompts[i].text);
++                session->userauth_kybd_prompts[i].text = NULL;
++            }
++        }
++
++        if (session->userauth_kybd_responses) {
++            for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
++                LIBSSH2_FREE(session,
++                             session->userauth_kybd_responses[i].text);
++                session->userauth_kybd_responses[i].text = NULL;
++            }
++        }
++
++        LIBSSH2_FREE(session, session->userauth_kybd_prompts);
++        session->userauth_kybd_prompts = NULL;
++        LIBSSH2_FREE(session, session->userauth_kybd_responses);
++        session->userauth_kybd_responses = NULL;
++
++        if (session->userauth_kybd_auth_failure) {
++            session->userauth_kybd_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        session->userauth_kybd_state = libssh2_NB_state_sent;
++    }
++}
++
++/* }}} */
+
+Property changes on: libssh2/src/userauth.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.2
+Added: svn:eol-style
+   + native
+
+Index: libssh2/src/mac.c
+===================================================================
+--- libssh2/src/mac.c  (.../tags/RELEASE_0_11_0)
++++ libssh2/src/mac.c  (.../trunk)
+@@ -0,0 +1,311 @@
++/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++
++#ifdef LIBSSH2_MAC_NONE
++/* {{{ libssh2_mac_none_MAC
++ * Minimalist MAC: No MAC
++ */
++static int
++libssh2_mac_none_MAC(LIBSSH2_SESSION * session, unsigned char *buf,
++                     unsigned long seqno, const unsigned char *packet,
++                     unsigned long packet_len, const unsigned char *addtl,
++                     unsigned long addtl_len, void **abstract)
++{
++    return 0;
++}
++
++/* }}} */
++
++
++static LIBSSH2_MAC_METHOD libssh2_mac_method_none = {
++    "none",
++    0,
++    0,
++    NULL,
++    libssh2_mac_none_MAC,
++    NULL
++};
++#endif /* LIBSSH2_MAC_NONE */
++
++/* {{{ libssh2_mac_method_common_init
++ * Initialize simple mac methods
++ */
++static int
++libssh2_mac_method_common_init(LIBSSH2_SESSION * session, unsigned char *key,
++                               int *free_key, void **abstract)
++{
++    *abstract = key;
++    *free_key = 0;
++    (void) session;
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_mac_method_common_dtor
++ * Cleanup simple mac methods
++ */
++static int
++libssh2_mac_method_common_dtor(LIBSSH2_SESSION * session, void **abstract)
++{
++    if (*abstract) {
++        LIBSSH2_FREE(session, *abstract);
++    }
++    *abstract = NULL;
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_mac_method_hmac_sha1_hash
++ * Calculate hash using full sha1 value
++ */
++static int
++libssh2_mac_method_hmac_sha1_hash(LIBSSH2_SESSION * session,
++                                  unsigned char *buf, unsigned long seqno,
++                                  const unsigned char *packet,
++                                  unsigned long packet_len,
++                                  const unsigned char *addtl,
++                                  unsigned long addtl_len, void **abstract)
++{
++    libssh2_hmac_ctx ctx;
++    unsigned char seqno_buf[4];
++    (void) session;
++
++    libssh2_htonu32(seqno_buf, seqno);
++
++    libssh2_hmac_sha1_init(&ctx, *abstract, 20);
++    libssh2_hmac_update(ctx, seqno_buf, 4);
++    libssh2_hmac_update(ctx, packet, packet_len);
++    if (addtl && addtl_len) {
++        libssh2_hmac_update(ctx, addtl, addtl_len);
++    }
++    libssh2_hmac_final(ctx, buf);
++    libssh2_hmac_cleanup(&ctx);
++
++    return 0;
++}
++
++/* }}} */
++
++static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1 = {
++    "hmac-sha1",
++    20,
++    20,
++    libssh2_mac_method_common_init,
++    libssh2_mac_method_hmac_sha1_hash,
++    libssh2_mac_method_common_dtor,
++};
++
++/* {{{ libssh2_mac_method_hmac_sha1_96_hash
++ * Calculate hash using first 96 bits of sha1 value
++ */
++static int
++libssh2_mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION * session,
++                                     unsigned char *buf, unsigned long seqno,
++                                     const unsigned char *packet,
++                                     unsigned long packet_len,
++                                     const unsigned char *addtl,
++                                     unsigned long addtl_len, void **abstract)
++{
++    unsigned char temp[SHA_DIGEST_LENGTH];
++
++    libssh2_mac_method_hmac_sha1_hash(session, temp, seqno, packet, packet_len,
++                                      addtl, addtl_len, abstract);
++    memcpy(buf, (char *) temp, 96 / 8);
++
++    return 0;
++}
++
++/* }}} */
++
++static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1_96 = {
++    "hmac-sha1-96",
++    12,
++    20,
++    libssh2_mac_method_common_init,
++    libssh2_mac_method_hmac_sha1_96_hash,
++    libssh2_mac_method_common_dtor,
++};
++
++/* {{{ libssh2_mac_method_hmac_md5_hash
++ * Calculate hash using full md5 value
++ */
++static int
++libssh2_mac_method_hmac_md5_hash(LIBSSH2_SESSION * session, unsigned char *buf,
++                                 unsigned long seqno,
++                                 const unsigned char *packet,
++                                 unsigned long packet_len,
++                                 const unsigned char *addtl,
++                                 unsigned long addtl_len, void **abstract)
++{
++    libssh2_hmac_ctx ctx;
++    unsigned char seqno_buf[4];
++    (void) session;
++
++    libssh2_htonu32(seqno_buf, seqno);
++
++    libssh2_hmac_md5_init(&ctx, *abstract, 16);
++    libssh2_hmac_update(ctx, seqno_buf, 4);
++    libssh2_hmac_update(ctx, packet, packet_len);
++    if (addtl && addtl_len) {
++        libssh2_hmac_update(ctx, addtl, addtl_len);
++    }
++    libssh2_hmac_final(ctx, buf);
++    libssh2_hmac_cleanup(&ctx);
++
++    return 0;
++}
++
++/* }}} */
++
++static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5 = {
++    "hmac-md5",
++    16,
++    16,
++    libssh2_mac_method_common_init,
++    libssh2_mac_method_hmac_md5_hash,
++    libssh2_mac_method_common_dtor,
++};
++
++/* {{{ libssh2_mac_method_hmac_md5_96_hash
++ * Calculate hash using first 96 bits of md5 value
++ */
++static int
++libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION * session,
++                                    unsigned char *buf, unsigned long seqno,
++                                    const unsigned char *packet,
++                                    unsigned long packet_len,
++                                    const unsigned char *addtl,
++                                    unsigned long addtl_len, void **abstract)
++{
++    unsigned char temp[MD5_DIGEST_LENGTH];
++
++    libssh2_mac_method_hmac_md5_hash(session, temp, seqno, packet, packet_len,
++                                     addtl, addtl_len, abstract);
++    memcpy(buf, (char *) temp, 96 / 8);
++
++    return 0;
++}
++
++/* }}} */
++
++static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5_96 = {
++    "hmac-md5-96",
++    12,
++    16,
++    libssh2_mac_method_common_init,
++    libssh2_mac_method_hmac_md5_96_hash,
++    libssh2_mac_method_common_dtor,
++};
++
++#if LIBSSH2_HMAC_RIPEMD
++/* {{{ libssh2_mac_method_hmac_ripemd160_hash
++ * Calculate hash using ripemd160 value
++ */
++static int
++libssh2_mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION * session,
++                                       unsigned char *buf, unsigned long seqno,
++                                       const unsigned char *packet,
++                                       unsigned long packet_len,
++                                       const unsigned char *addtl,
++                                       unsigned long addtl_len,
++                                       void **abstract)
++{
++    libssh2_hmac_ctx ctx;
++    unsigned char seqno_buf[4];
++    (void) session;
++
++    libssh2_htonu32(seqno_buf, seqno);
++
++    libssh2_hmac_ripemd160_init(&ctx, *abstract, 20);
++    libssh2_hmac_update(ctx, seqno_buf, 4);
++    libssh2_hmac_update(ctx, packet, packet_len);
++    if (addtl && addtl_len) {
++        libssh2_hmac_update(ctx, addtl, addtl_len);
++    }
++    libssh2_hmac_final(ctx, buf);
++    libssh2_hmac_cleanup(&ctx);
++
++    return 0;
++}
++
++/* }}} */
++
++static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160 = {
++    "hmac-ripemd160",
++    20,
++    20,
++    libssh2_mac_method_common_init,
++    libssh2_mac_method_hmac_ripemd160_hash,
++    libssh2_mac_method_common_dtor,
++};
++
++static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160_openssh_com = {
++    "hmac-ripemd160@openssh.com",
++    20,
++    20,
++    libssh2_mac_method_common_init,
++    libssh2_mac_method_hmac_ripemd160_hash,
++    libssh2_mac_method_common_dtor,
++};
++#endif /* LIBSSH2_HMAC_RIPEMD */
++
++static const LIBSSH2_MAC_METHOD *_libssh2_mac_methods[] = {
++    &libssh2_mac_method_hmac_sha1,
++    &libssh2_mac_method_hmac_sha1_96,
++    &libssh2_mac_method_hmac_md5,
++    &libssh2_mac_method_hmac_md5_96,
++#if LIBSSH2_HMAC_RIPEMD
++    &libssh2_mac_method_hmac_ripemd160,
++    &libssh2_mac_method_hmac_ripemd160_openssh_com,
++#endif /* LIBSSH2_HMAC_RIPEMD */
++#ifdef LIBSSH2_MAC_NONE
++    &libssh2_mac_method_none,
++#endif /* LIBSSH2_MAC_NONE */
++    NULL
++};
++
++const LIBSSH2_MAC_METHOD **
++libssh2_mac_methods(void)
++{
++    return _libssh2_mac_methods;
++}
+
+Property changes on: libssh2/src/mac.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.2
+Added: svn:eol-style
+   + native
+
+Index: libssh2/src/crypt.c
+===================================================================
+--- libssh2/src/crypt.c        (.../tags/RELEASE_0_11_0)
++++ libssh2/src/crypt.c        (.../trunk)
+@@ -0,0 +1,256 @@
++/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++
++#ifdef LIBSSH2_CRYPT_NONE
++/* {{{ libssh2_crypt_none_crypt
++ * Minimalist cipher: VERY secure *wink*
++ */
++static int
++libssh2_crypt_none_crypt(LIBSSH2_SESSION * session, unsigned char *buf,
++                         void **abstract)
++{
++    /* Do nothing to the data! */
++    return 0;
++}
++
++/* }}} */
++
++static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = {
++    "none",
++    8,                          /* blocksize (SSH2 defines minimum blocksize as 8) */
++    0,                          /* iv_len */
++    0,                          /* secret_len */
++    0,                          /* flags */
++    NULL,
++    libssh2_crypt_none_crypt,
++    NULL
++};
++#endif /* LIBSSH2_CRYPT_NONE */
++
++struct crypt_ctx
++{
++    int encrypt;
++      _libssh2_cipher_type(algo);
++    _libssh2_cipher_ctx h;
++};
++
++static int
++_libssh2_init(LIBSSH2_SESSION * session,
++              const LIBSSH2_CRYPT_METHOD * method,
++              unsigned char *iv, int *free_iv,
++              unsigned char *secret, int *free_secret,
++              int encrypt, void **abstract)
++{
++    struct crypt_ctx *ctx = LIBSSH2_ALLOC(session,
++                                          sizeof(struct crypt_ctx));
++    if (!ctx) {
++        return -1;
++    }
++    ctx->encrypt = encrypt;
++    ctx->algo = method->algo;
++    if (_libssh2_cipher_init(&ctx->h, ctx->algo, iv, secret, encrypt)) {
++        LIBSSH2_FREE(session, ctx);
++        return -1;
++    }
++    *abstract = ctx;
++    *free_iv = 1;
++    *free_secret = 1;
++    return 0;
++}
++
++static int
++_libssh2_encrypt(LIBSSH2_SESSION * session, unsigned char *block,
++                 void **abstract)
++{
++    struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract;
++    (void) session;
++    return _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block);
++}
++
++static int
++_libssh2_dtor(LIBSSH2_SESSION * session, void **abstract)
++{
++    struct crypt_ctx **cctx = (struct crypt_ctx **) abstract;
++    if (cctx && *cctx) {
++        _libssh2_cipher_dtor(&(*cctx)->h);
++        LIBSSH2_FREE(session, *cctx);
++        *abstract = NULL;
++    }
++    return 0;
++}
++
++#if LIBSSH2_AES
++static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = {
++    "aes128-cbc",
++    16,                         /* blocksize */
++    16,                         /* initial value length */
++    16,                         /* secret length -- 16*8 == 128bit */
++    0,                          /* flags */
++    &_libssh2_init,
++    &_libssh2_encrypt,
++    &_libssh2_dtor,
++    _libssh2_cipher_aes128
++};
++
++static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = {
++    "aes192-cbc",
++    16,                         /* blocksize */
++    16,                         /* initial value length */
++    24,                         /* secret length -- 24*8 == 192bit */
++    0,                          /* flags */
++    &_libssh2_init,
++    &_libssh2_encrypt,
++    &_libssh2_dtor,
++    _libssh2_cipher_aes192
++};
++
++static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = {
++    "aes256-cbc",
++    16,                         /* blocksize */
++    16,                         /* initial value length */
++    32,                         /* secret length -- 32*8 == 256bit */
++    0,                          /* flags */
++    &_libssh2_init,
++    &_libssh2_encrypt,
++    &_libssh2_dtor,
++    _libssh2_cipher_aes256
++};
++
++/* rijndael-cbc@lysator.liu.se == aes256-cbc */
++static const LIBSSH2_CRYPT_METHOD
++    libssh2_crypt_method_rijndael_cbc_lysator_liu_se = {
++    "rijndael-cbc@lysator.liu.se",
++    16,                         /* blocksize */
++    16,                         /* initial value length */
++    32,                         /* secret length -- 32*8 == 256bit */
++    0,                          /* flags */
++    &_libssh2_init,
++    &_libssh2_encrypt,
++    &_libssh2_dtor,
++    _libssh2_cipher_aes256
++};
++#endif /* LIBSSH2_AES */
++
++#if LIBSSH2_BLOWFISH
++static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = {
++    "blowfish-cbc",
++    8,                          /* blocksize */
++    8,                          /* initial value length */
++    16,                         /* secret length */
++    0,                          /* flags */
++    &_libssh2_init,
++    &_libssh2_encrypt,
++    &_libssh2_dtor,
++    _libssh2_cipher_blowfish
++};
++#endif /* LIBSSH2_BLOWFISH */
++
++#if LIBSSH2_RC4
++static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = {
++    "arcfour",
++    8,                          /* blocksize */
++    8,                          /* initial value length */
++    16,                         /* secret length */
++    0,                          /* flags */
++    &_libssh2_init,
++    &_libssh2_encrypt,
++    &_libssh2_dtor,
++    _libssh2_cipher_arcfour
++};
++#endif /* LIBSSH2_RC4 */
++
++#if LIBSSH2_CAST
++static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = {
++    "cast128-cbc",
++    8,                          /* blocksize */
++    8,                          /* initial value length */
++    16,                         /* secret length */
++    0,                          /* flags */
++    &_libssh2_init,
++    &_libssh2_encrypt,
++    &_libssh2_dtor,
++    _libssh2_cipher_cast5
++};
++#endif /* LIBSSH2_CAST */
++
++#if LIBSSH2_3DES
++static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = {
++    "3des-cbc",
++    8,                          /* blocksize */
++    8,                          /* initial value length */
++    24,                         /* secret length */
++    0,                          /* flags */
++    &_libssh2_init,
++    &_libssh2_encrypt,
++    &_libssh2_dtor,
++    _libssh2_cipher_3des
++};
++#endif
++
++static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = {
++#if LIBSSH2_AES
++    &libssh2_crypt_method_aes256_cbc,
++    &libssh2_crypt_method_rijndael_cbc_lysator_liu_se,  /* == aes256-cbc */
++    &libssh2_crypt_method_aes192_cbc,
++    &libssh2_crypt_method_aes128_cbc,
++#endif /* LIBSSH2_AES */
++#if LIBSSH2_BLOWFISH
++    &libssh2_crypt_method_blowfish_cbc,
++#endif /* LIBSSH2_BLOWFISH */
++#if LIBSSH2_RC4
++    &libssh2_crypt_method_arcfour,
++#endif /* LIBSSH2_RC4 */
++#if LIBSSH2_CAST
++    &libssh2_crypt_method_cast128_cbc,
++#endif /* LIBSSH2_CAST */
++#if LIBSSH2_3DES
++    &libssh2_crypt_method_3des_cbc,
++#endif /*  LIBSSH2_DES */
++#ifdef LIBSSH2_CRYPT_NONE
++    &libssh2_crypt_method_none,
++#endif
++    NULL
++};
++
++/* Expose to kex.c */
++const LIBSSH2_CRYPT_METHOD **
++libssh2_crypt_methods(void)
++{
++    return _libssh2_crypt_methods;
++}
+
+Property changes on: libssh2/src/crypt.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.2
+Added: svn:eol-style
+   + native
+
+Index: libssh2/src/libgcrypt.h
+===================================================================
+--- libssh2/src/libgcrypt.h    (.../tags/RELEASE_0_11_0)
++++ libssh2/src/libgcrypt.h    (.../trunk)
+@@ -0,0 +1,187 @@
++/* Copyright (C) 2006, 2007, The Written Word, Inc.
++ * Copyright (C) 2008, Simon Josefsson
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 <gcrypt.h>
++
++#define LIBSSH2_MD5 1
++
++#define LIBSSH2_HMAC_RIPEMD 1
++
++#define LIBSSH2_AES 1
++#define LIBSSH2_BLOWFISH 1
++#define LIBSSH2_RC4 1
++#define LIBSSH2_CAST 1
++#define LIBSSH2_3DES 1
++
++#define LIBSSH2_RSA 1
++#define LIBSSH2_DSA 1
++
++#define MD5_DIGEST_LENGTH 16
++#define SHA_DIGEST_LENGTH 20
++
++#define libssh2_random(buf, len)                \
++  (gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1)
++
++#define libssh2_sha1_ctx gcry_md_hd_t
++#define libssh2_sha1_init(ctx) gcry_md_open (ctx,  GCRY_MD_SHA1, 0);
++#define libssh2_sha1_update(ctx, data, len) gcry_md_write (ctx, data, len)
++#define libssh2_sha1_final(ctx, out) \
++  memcpy (out, gcry_md_read (ctx, 0), 20), gcry_md_close (ctx)
++#define libssh2_sha1(message, len, out) \
++  gcry_md_hash_buffer (GCRY_MD_SHA1, out, message, len)
++
++#define libssh2_md5_ctx gcry_md_hd_t
++#define libssh2_md5_init(ctx) gcry_md_open (ctx,  GCRY_MD_MD5, 0);
++#define libssh2_md5_update(ctx, data, len) gcry_md_write (ctx, data, len)
++#define libssh2_md5_final(ctx, out) \
++  memcpy (out, gcry_md_read (ctx, 0), 20), gcry_md_close (ctx)
++#define libssh2_md5(message, len, out) \
++  gcry_md_hash_buffer (GCRY_MD_MD5, out, message, len)
++
++#define libssh2_hmac_ctx gcry_md_hd_t
++#define libssh2_hmac_sha1_init(ctx, key, keylen) \
++  gcry_md_open (ctx, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC), \
++    gcry_md_setkey (*ctx, key, keylen)
++#define libssh2_hmac_md5_init(ctx, key, keylen) \
++  gcry_md_open (ctx, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC), \
++    gcry_md_setkey (*ctx, key, keylen)
++#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
++  gcry_md_open (ctx, GCRY_MD_RMD160, GCRY_MD_FLAG_HMAC), \
++    gcry_md_setkey (*ctx, key, keylen)
++#define libssh2_hmac_update(ctx, data, datalen) \
++  gcry_md_write (ctx, data, datalen)
++#define libssh2_hmac_final(ctx, data) \
++  memcpy (data, gcry_md_read (ctx, 0), \
++      gcry_md_get_algo_dlen (gcry_md_get_algo (ctx)))
++#define libssh2_hmac_cleanup(ctx) gcry_md_close (*ctx);
++
++#define libssh2_crypto_init() gcry_control (GCRYCTL_DISABLE_SECMEM)
++
++#define libssh2_rsa_ctx struct gcry_sexp
++
++int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
++                     const unsigned char *edata,
++                     unsigned long elen,
++                     const unsigned char *ndata,
++                     unsigned long nlen,
++                     const unsigned char *ddata,
++                     unsigned long dlen,
++                     const unsigned char *pdata,
++                     unsigned long plen,
++                     const unsigned char *qdata,
++                     unsigned long qlen,
++                     const unsigned char *e1data,
++                     unsigned long e1len,
++                     const unsigned char *e2data,
++                     unsigned long e2len,
++                     const unsigned char *coeffdata, unsigned long coefflen);
++int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
++                             LIBSSH2_SESSION * session,
++                             FILE * fp, unsigned const char *passphrase);
++int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
++                             const unsigned char *sig,
++                             unsigned long sig_len,
++                             const unsigned char *m, unsigned long m_len);
++int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
++                           libssh2_rsa_ctx * rsactx,
++                           const unsigned char *hash,
++                           unsigned long hash_len,
++                           unsigned char **signature,
++                           unsigned long *signature_len);
++
++#define _libssh2_rsa_free(rsactx)  gcry_sexp_release (rsactx)
++
++#define libssh2_dsa_ctx struct gcry_sexp
++
++int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
++                     const unsigned char *pdata,
++                     unsigned long plen,
++                     const unsigned char *qdata,
++                     unsigned long qlen,
++                     const unsigned char *gdata,
++                     unsigned long glen,
++                     const unsigned char *ydata,
++                     unsigned long ylen,
++                     const unsigned char *x, unsigned long x_len);
++int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
++                             LIBSSH2_SESSION * session,
++                             FILE * fp, unsigned const char *passphrase);
++int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsa,
++                             const unsigned char *sig,
++                             const unsigned char *m, unsigned long m_len);
++int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
++                           const unsigned char *hash,
++                           unsigned long hash_len, unsigned char *sig);
++
++#define _libssh2_dsa_free(dsactx)  gcry_sexp_release (dsactx)
++
++#define _libssh2_cipher_type(name) int name
++#define _libssh2_cipher_ctx gcry_cipher_hd_t
++
++#define _libssh2_cipher_aes256 GCRY_CIPHER_AES256
++#define _libssh2_cipher_aes192 GCRY_CIPHER_AES192
++#define _libssh2_cipher_aes128 GCRY_CIPHER_AES128
++#define _libssh2_cipher_blowfish GCRY_CIPHER_BLOWFISH
++#define _libssh2_cipher_arcfour GCRY_CIPHER_ARCFOUR
++#define _libssh2_cipher_cast5 GCRY_CIPHER_CAST5
++#define _libssh2_cipher_3des GCRY_CIPHER_3DES
++
++int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
++                         _libssh2_cipher_type(algo),
++                         unsigned char *iv,
++                         unsigned char *secret, int encrypt);
++
++int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
++                          _libssh2_cipher_type(algo),
++                          int encrypt, unsigned char *block);
++
++#define _libssh2_cipher_dtor(ctx) gcry_cipher_close(*(ctx))
++
++#define _libssh2_bn struct gcry_mpi
++#define _libssh2_bn_ctx int
++#define _libssh2_bn_ctx_new() 0
++#define _libssh2_bn_ctx_free(bnctx) ((void)0)
++#define _libssh2_bn_init() gcry_mpi_new(0)
++#define _libssh2_bn_rand(bn, bits, top, bottom) gcry_mpi_randomize (bn, bits, GCRY_WEAK_RANDOM)
++#define _libssh2_bn_mod_exp(r, a, p, m, ctx) gcry_mpi_powm (r, a, p, m)
++#define _libssh2_bn_set_word(bn, val) gcry_mpi_set_ui(bn, val)
++#define _libssh2_bn_from_bin(bn, len, val) gcry_mpi_scan(&((bn)), GCRYMPI_FMT_USG, val, len, NULL)
++#define _libssh2_bn_to_bin(bn, val) gcry_mpi_print (GCRYMPI_FMT_USG, val, _libssh2_bn_bytes(bn), NULL, bn)
++#define _libssh2_bn_bytes(bn) (gcry_mpi_get_nbits (bn) / 8 + ((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1))
++#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn)
++#define _libssh2_bn_free(bn) gcry_mpi_release(bn)
+
+Property changes on: libssh2/src/libgcrypt.h
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.1
+Added: svn:eol-style
+   + native
+Added: svn:executable
+   + *
+
+Index: libssh2/src/packet.c
+===================================================================
+--- libssh2/src/packet.c       (.../tags/RELEASE_0_11_0)
++++ libssh2/src/packet.c       (.../trunk)
+@@ -0,0 +1,1270 @@
++/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++#include <errno.h>
++#include <fcntl.h>
++
++#ifdef HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++#ifdef HAVE_SYS_TIME_H
++#include <sys/time.h>
++#endif
++
++#ifdef HAVE_INTTYPES_H
++#include <inttypes.h>
++#endif
++
++/* Needed for struct iovec on some platforms */
++#ifdef HAVE_SYS_UIO_H
++#include <sys/uio.h>
++#endif
++
++#include <sys/types.h>
++
++/* {{{ libssh2_packet_queue_listener
++ * Queue a connection request for a listener
++ */
++static inline int
++libssh2_packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
++                              unsigned long datalen,
++                              packet_queue_listener_state_t * listen_state)
++{
++    /*
++     * Look for a matching listener
++     */
++    unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5;
++    /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
++    unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1);
++    unsigned char *p;
++    LIBSSH2_LISTENER *listen = session->listeners;
++    char failure_code = 1;      /* SSH_OPEN_ADMINISTRATIVELY_PROHIBITED */
++    int rc;
++
++    (void) datalen;
++
++    if (listen_state->state == libssh2_NB_state_idle) {
++        listen_state->sender_channel = libssh2_ntohu32(s);
++        s += 4;
++
++        listen_state->initial_window_size = libssh2_ntohu32(s);
++        s += 4;
++        listen_state->packet_size = libssh2_ntohu32(s);
++        s += 4;
++
++        listen_state->host_len = libssh2_ntohu32(s);
++        s += 4;
++        listen_state->host = s;
++        s += listen_state->host_len;
++        listen_state->port = libssh2_ntohu32(s);
++        s += 4;
++
++        listen_state->shost_len = libssh2_ntohu32(s);
++        s += 4;
++        listen_state->shost = s;
++        s += listen_state->shost_len;
++        listen_state->sport = libssh2_ntohu32(s);
++        s += 4;
++
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "Remote received connection from %s:%ld to %s:%ld",
++                       listen_state->shost, listen_state->sport,
++                       listen_state->host, listen_state->port);
++
++        listen_state->state = libssh2_NB_state_allocated;
++    }
++
++    if (listen_state->state != libssh2_NB_state_sent) {
++        while (listen) {
++            if ((listen->port == (int) listen_state->port) &&
++                (strlen(listen->host) == listen_state->host_len) &&
++                (memcmp
++                 (listen->host, listen_state->host,
++                  listen_state->host_len) == 0)) {
++                /* This is our listener */
++                LIBSSH2_CHANNEL *channel, *last_queued = listen->queue;
++
++                last_queued = listen->queue;
++                if (listen_state->state == libssh2_NB_state_allocated) {
++                    if (listen->queue_maxsize &&
++                        (listen->queue_maxsize <= listen->queue_size)) {
++                        /* Queue is full */
++                        failure_code = 4;       /* SSH_OPEN_RESOURCE_SHORTAGE */
++                        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                                       "Listener queue full, ignoring");
++                        listen_state->state = libssh2_NB_state_sent;
++                        break;
++                    }
++
++                    channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
++                    if (!channel) {
++                        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                                      "Unable to allocate a channel for new connection",
++                                      0);
++                        failure_code = 4;       /* SSH_OPEN_RESOURCE_SHORTAGE */
++                        listen_state->state = libssh2_NB_state_sent;
++                        break;
++                    }
++                    memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
++
++                    channel->session = session;
++                    channel->channel_type_len = sizeof("forwarded-tcpip") - 1;
++                    channel->channel_type = LIBSSH2_ALLOC(session,
++                                                          channel->
++                                                          channel_type_len +
++                                                          1);
++                    if (!channel->channel_type) {
++                        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                                      "Unable to allocate a channel for new connection",
++                                      0);
++                        LIBSSH2_FREE(session, channel);
++                        failure_code = 4;       /* SSH_OPEN_RESOURCE_SHORTAGE */
++                        listen_state->state = libssh2_NB_state_sent;
++                        break;
++                    }
++                    memcpy(channel->channel_type, "forwarded-tcpip",
++                           channel->channel_type_len + 1);
++
++                    channel->remote.id = listen_state->sender_channel;
++                    channel->remote.window_size_initial =
++                        LIBSSH2_CHANNEL_WINDOW_DEFAULT;
++                    channel->remote.window_size =
++                        LIBSSH2_CHANNEL_WINDOW_DEFAULT;
++                    channel->remote.packet_size =
++                        LIBSSH2_CHANNEL_PACKET_DEFAULT;
++
++                    channel->local.id = libssh2_channel_nextid(session);
++                    channel->local.window_size_initial =
++                        listen_state->initial_window_size;
++                    channel->local.window_size =
++                        listen_state->initial_window_size;
++                    channel->local.packet_size = listen_state->packet_size;
++
++                    _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                                   "Connection queued: channel %lu/%lu win %lu/%lu packet %lu/%lu",
++                                   channel->local.id, channel->remote.id,
++                                   channel->local.window_size,
++                                   channel->remote.window_size,
++                                   channel->local.packet_size,
++                                   channel->remote.packet_size);
++
++                    p = listen_state->packet;
++                    *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
++                    libssh2_htonu32(p, channel->remote.id);
++                    p += 4;
++                    libssh2_htonu32(p, channel->local.id);
++                    p += 4;
++                    libssh2_htonu32(p, channel->remote.window_size_initial);
++                    p += 4;
++                    libssh2_htonu32(p, channel->remote.packet_size);
++                    p += 4;
++
++                    listen_state->state = libssh2_NB_state_created;
++                }
++
++                if (listen_state->state == libssh2_NB_state_created) {
++                    rc = libssh2_packet_write(session, listen_state->packet,
++                                              17);
++                    if (rc == PACKET_EAGAIN) {
++                        return PACKET_EAGAIN;
++                    } else if (rc) {
++                        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                                      "Unable to send channel open confirmation",
++                                      0);
++                        listen_state->state = libssh2_NB_state_idle;
++                        return -1;
++                    }
++
++                    /* Link the channel into the end of the queue list */
++
++                    if (!last_queued) {
++                        listen->queue = channel;
++                        listen_state->state = libssh2_NB_state_idle;
++                        return 0;
++                    }
++
++                    while (last_queued->next) {
++                        last_queued = last_queued->next;
++                    }
++
++                    last_queued->next = channel;
++                    channel->prev = last_queued;
++
++                    listen->queue_size++;
++
++                    listen_state->state = libssh2_NB_state_idle;
++                    return 0;
++                }
++            }
++
++            listen = listen->next;
++        }
++
++        listen_state->state = libssh2_NB_state_sent;
++    }
++
++    /* We're not listening to you */
++    {
++        p = listen_state->packet;
++        *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
++        libssh2_htonu32(p, listen_state->sender_channel);
++        p += 4;
++        libssh2_htonu32(p, failure_code);
++        p += 4;
++        libssh2_htonu32(p, sizeof(FwdNotReq) - 1);
++        p += 4;
++        memcpy(s, FwdNotReq, sizeof(FwdNotReq) - 1);
++        p += sizeof(FwdNotReq) - 1;
++        libssh2_htonu32(p, 0);
++
++        rc = libssh2_packet_write(session, listen_state->packet, packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send open failure", 0);
++            listen_state->state = libssh2_NB_state_idle;
++            return -1;
++        }
++        listen_state->state = libssh2_NB_state_idle;
++        return 0;
++    }
++}
++
++/* }}} */
++
++/* {{{ libssh2_packet_x11_open
++ * Accept a forwarded X11 connection
++ */
++static inline int
++libssh2_packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
++                        unsigned long datalen,
++                        packet_x11_open_state_t * x11open_state)
++{
++    int failure_code = 2;       /* SSH_OPEN_CONNECT_FAILED */
++    unsigned char *s = data + (sizeof("x11") - 1) + 5;
++    /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
++    unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1);
++    unsigned char *p;
++    LIBSSH2_CHANNEL *channel;
++    int rc;
++
++    (void) datalen;
++
++    if (x11open_state->state == libssh2_NB_state_idle) {
++        x11open_state->sender_channel = libssh2_ntohu32(s);
++        s += 4;
++        x11open_state->initial_window_size = libssh2_ntohu32(s);
++        s += 4;
++        x11open_state->packet_size = libssh2_ntohu32(s);
++        s += 4;
++        x11open_state->shost_len = libssh2_ntohu32(s);
++        s += 4;
++        x11open_state->shost = s;
++        s += x11open_state->shost_len;
++        x11open_state->sport = libssh2_ntohu32(s);
++        s += 4;
++
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "X11 Connection Received from %s:%ld on channel %lu",
++                       x11open_state->shost, x11open_state->sport,
++                       x11open_state->sender_channel);
++
++        x11open_state->state = libssh2_NB_state_allocated;
++    }
++
++    if (session->x11) {
++        if (x11open_state->state == libssh2_NB_state_allocated) {
++            channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
++            if (!channel) {
++                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                              "Unable to allocate a channel for new connection",
++                              0);
++                failure_code = 4;       /* SSH_OPEN_RESOURCE_SHORTAGE */
++                goto x11_exit;
++            }
++            memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
++
++            channel->session = session;
++            channel->channel_type_len = sizeof("x11") - 1;
++            channel->channel_type = LIBSSH2_ALLOC(session,
++                                                  channel->channel_type_len +
++                                                  1);
++            if (!channel->channel_type) {
++                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                              "Unable to allocate a channel for new connection",
++                              0);
++                LIBSSH2_FREE(session, channel);
++                failure_code = 4;       /* SSH_OPEN_RESOURCE_SHORTAGE */
++                goto x11_exit;
++            }
++            memcpy(channel->channel_type, "x11",
++                   channel->channel_type_len + 1);
++
++            channel->remote.id = x11open_state->sender_channel;
++            channel->remote.window_size_initial =
++                LIBSSH2_CHANNEL_WINDOW_DEFAULT;
++            channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
++            channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT;
++
++            channel->local.id = libssh2_channel_nextid(session);
++            channel->local.window_size_initial =
++                x11open_state->initial_window_size;
++            channel->local.window_size = x11open_state->initial_window_size;
++            channel->local.packet_size = x11open_state->packet_size;
++
++            _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                           "X11 Connection established: channel %lu/%lu win %lu/%lu packet %lu/%lu",
++                           channel->local.id, channel->remote.id,
++                           channel->local.window_size,
++                           channel->remote.window_size,
++                           channel->local.packet_size,
++                           channel->remote.packet_size);
++            p = x11open_state->packet;
++            *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
++            libssh2_htonu32(p, channel->remote.id);
++            p += 4;
++            libssh2_htonu32(p, channel->local.id);
++            p += 4;
++            libssh2_htonu32(p, channel->remote.window_size_initial);
++            p += 4;
++            libssh2_htonu32(p, channel->remote.packet_size);
++            p += 4;
++
++            x11open_state->state = libssh2_NB_state_created;
++        }
++
++        if (x11open_state->state == libssh2_NB_state_created) {
++            rc = libssh2_packet_write(session, x11open_state->packet, 17);
++            if (rc == PACKET_EAGAIN) {
++                return PACKET_EAGAIN;
++            } else if (rc) {
++                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                              "Unable to send channel open confirmation", 0);
++                x11open_state->state = libssh2_NB_state_idle;
++                return -1;
++            }
++
++            /* Link the channel into the session */
++            if (session->channels.tail) {
++                session->channels.tail->next = channel;
++                channel->prev = session->channels.tail;
++            } else {
++                session->channels.head = channel;
++                channel->prev = NULL;
++            }
++            channel->next = NULL;
++            session->channels.tail = channel;
++
++            /*
++             * Pass control to the callback, they may turn right around and
++             * free the channel, or actually use it
++             */
++            LIBSSH2_X11_OPEN(channel, (char *) x11open_state->shost,
++                             x11open_state->sport);
++
++            x11open_state->state = libssh2_NB_state_idle;
++            return 0;
++        }
++    } else {
++        failure_code = 4;       /* SSH_OPEN_RESOURCE_SHORTAGE */
++    }
++
++  x11_exit:
++    p = x11open_state->packet;
++    *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
++    libssh2_htonu32(p, x11open_state->sender_channel);
++    p += 4;
++    libssh2_htonu32(p, failure_code);
++    p += 4;
++    libssh2_htonu32(p, sizeof(X11FwdUnAvil) - 1);
++    p += 4;
++    memcpy(s, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1);
++    p += sizeof(X11FwdUnAvil) - 1;
++    libssh2_htonu32(p, 0);
++
++    rc = libssh2_packet_write(session, x11open_state->packet, packet_len);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    } else if (rc) {
++        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                      "Unable to send open failure", 0);
++        x11open_state->state = libssh2_NB_state_idle;
++        return -1;
++    }
++    x11open_state->state = libssh2_NB_state_idle;
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_packet_new
++ * Create a new packet and attach it to the brigade
++ */
++int
++libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
++                   size_t datalen, int macstate)
++{
++    int rc;
++
++    if (session->packAdd_state == libssh2_NB_state_idle) {
++        session->packAdd_data_head = 0;
++
++        /* Zero the whole thing out */
++        memset(&session->packAdd_key_state, 0,
++               sizeof(session->packAdd_key_state));
++
++        /* Zero the whole thing out */
++        memset(&session->packAdd_Qlstn_state, 0,
++               sizeof(session->packAdd_Qlstn_state));
++
++        /* Zero the whole thing out */
++        memset(&session->packAdd_x11open_state, 0,
++               sizeof(session->packAdd_x11open_state));
++
++        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
++                       "Packet type %d received, length=%d",
++                       (int) data[0], (int) datalen);
++        if (macstate == LIBSSH2_MAC_INVALID) {
++            if (session->macerror) {
++                if (LIBSSH2_MACERROR(session, (char *) data, datalen) == 0) {
++                    /* Calling app has given the OK, Process it anyway */
++                    macstate = LIBSSH2_MAC_CONFIRMED;
++                } else {
++                    libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
++                                  "Invalid Message Authentication Code received",
++                                  0);
++                    if (session->ssh_msg_disconnect) {
++                        LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR,
++                                           "Invalid MAC received",
++                                           sizeof("Invalid MAC received") - 1,
++                                           "", 0);
++                    }
++                    LIBSSH2_FREE(session, data);
++                    return -1;
++                }
++            } else {
++                libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
++                              "Invalid Message Authentication Code received",
++                              0);
++                if (session->ssh_msg_disconnect) {
++                    LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR,
++                                       "Invalid MAC received",
++                                       sizeof("Invalid MAC received") - 1,
++                                       "", 0);
++                }
++                LIBSSH2_FREE(session, data);
++                return -1;
++            }
++        }
++
++        session->packAdd_state = libssh2_NB_state_allocated;
++    }
++
++    /*
++     * =============================== NOTE ===============================
++     * I know this is very ugly and not a really good use of "goto", but
++     * this case statement would be even uglier to do it any other way
++     */
++    if (session->packAdd_state == libssh2_NB_state_jump1) {
++        goto libssh2_packet_add_jump_point1;
++    } else if (session->packAdd_state == libssh2_NB_state_jump2) {
++        goto libssh2_packet_add_jump_point2;
++    } else if (session->packAdd_state == libssh2_NB_state_jump3) {
++        goto libssh2_packet_add_jump_point3;
++    }
++
++    if (session->packAdd_state == libssh2_NB_state_allocated) {
++        /* A couple exceptions to the packet adding rule: */
++        switch (data[0]) {
++        case SSH_MSG_DISCONNECT:
++            {
++                char *message, *language;
++                int reason, message_len, language_len;
++
++                reason = libssh2_ntohu32(data + 1);
++                message_len = libssh2_ntohu32(data + 5);
++                /* 9 = packet_type(1) + reason(4) + message_len(4) */
++                message = (char *) data + 9;
++                language_len = libssh2_ntohu32(data + 9 + message_len);
++                /*
++                 * This is where we hack on the data a little,
++                 * Use the MSB of language_len to to a terminating NULL
++                 * (In all liklihood it is already)
++                 * Shift the language tag back a byte (In all likelihood
++                 * it's zero length anyway)
++                 * Store a NULL in the last byte of the packet to terminate
++                 * the language string
++                 * With the lengths passed this isn't *REALLY* necessary,
++                 * but it's "kind"
++                 */
++                message[message_len] = '\0';
++                language = (char *) data + 9 + message_len + 3;
++                if (language_len) {
++                    memcpy(language, language + 1, language_len);
++                }
++                language[language_len] = '\0';
++
++                if (session->ssh_msg_disconnect) {
++                    LIBSSH2_DISCONNECT(session, reason, message,
++                                       message_len, language, language_len);
++                }
++                _libssh2_debug(session, LIBSSH2_DBG_TRANS,
++                               "Disconnect(%d): %s(%s)", reason,
++                               message, language);
++                LIBSSH2_FREE(session, data);
++                session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
++                session->packAdd_state = libssh2_NB_state_idle;
++                return -1;
++            }
++            break;
++
++        case SSH_MSG_IGNORE:
++            /* As with disconnect, back it up one and add a trailing NULL */
++            memcpy(data + 4, data + 5, datalen - 5);
++            data[datalen] = '\0';
++            if (session->ssh_msg_ignore) {
++                LIBSSH2_IGNORE(session, (char *) data + 4, datalen - 5);
++            }
++            LIBSSH2_FREE(session, data);
++            session->packAdd_state = libssh2_NB_state_idle;
++            return 0;
++            break;
++
++        case SSH_MSG_DEBUG:
++            {
++                int always_display = data[0];
++                char *message, *language;
++                int message_len, language_len;
++
++                message_len = libssh2_ntohu32(data + 2);
++                /* 6 = packet_type(1) + display(1) + message_len(4) */
++                message = (char *) data + 6;
++                language_len = libssh2_ntohu32(data + 6 + message_len);
++                /*
++                 * This is where we hack on the data a little,
++                 * Use the MSB of language_len to to a terminating NULL
++                 * (In all liklihood it is already)
++                 * Shift the language tag back a byte (In all likelihood
++                 * it's zero length anyway)
++                 * Store a NULL in the last byte of the packet to terminate
++                 * the language string
++                 * With the lengths passed this isn't *REALLY* necessary,
++                 * but it's "kind"
++                 */
++                message[message_len] = '\0';
++                language = (char *) data + 6 + message_len + 3;
++                if (language_len) {
++                    memcpy(language, language + 1, language_len);
++                }
++                language[language_len] = '\0';
++
++                if (session->ssh_msg_debug) {
++                    LIBSSH2_DEBUG(session, always_display, message,
++                                  message_len, language, language_len);
++                }
++                /*
++                 * _libssh2_debug will actually truncate this for us so
++                 * that it's not an inordinate about of data
++                 */
++                _libssh2_debug(session, LIBSSH2_DBG_TRANS,
++                               "Debug Packet: %s", message);
++                LIBSSH2_FREE(session, data);
++                session->packAdd_state = libssh2_NB_state_idle;
++                return 0;
++            }
++            break;
++
++        case SSH_MSG_CHANNEL_EXTENDED_DATA:
++            /* streamid(4) */
++            session->packAdd_data_head += 4;
++        case SSH_MSG_CHANNEL_DATA:
++            /* packet_type(1) + channelno(4) + datalen(4) */
++            session->packAdd_data_head += 9;
++            {
++                session->packAdd_channel = libssh2_channel_locate(session,
++                                                                  libssh2_ntohu32
++                                                                  (data + 1));
++
++                if (!session->packAdd_channel) {
++                    libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN,
++                                  "Packet received for unknown channel, ignoring",
++                                  0);
++                    LIBSSH2_FREE(session, data);
++                    session->packAdd_state = libssh2_NB_state_idle;
++                    return 0;
++                }
++#ifdef LIBSSH2DEBUG
++                {
++                    unsigned long stream_id = 0;
++
++                    if (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) {
++                        stream_id = libssh2_ntohu32(data + 5);
++                    }
++
++                    _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                                   "%d bytes received for channel %lu/%lu stream #%lu",
++                                   (int) (datalen -
++                                          session->packAdd_data_head),
++                                   session->packAdd_channel->local.id,
++                                   session->packAdd_channel->remote.id,
++                                   stream_id);
++                }
++#endif
++                if ((session->packAdd_channel->remote.
++                     extended_data_ignore_mode ==
++                     LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE)
++                    && (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) {
++                    /* Pretend we didn't receive this */
++                    LIBSSH2_FREE(session, data);
++
++                    _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                                   "Ignoring extended data and refunding %d bytes",
++                                   (int) (datalen - 13));
++                    /* Adjust the window based on the block we just freed */
++                  libssh2_packet_add_jump_point1:
++                    session->packAdd_state = libssh2_NB_state_jump1;
++                    rc = libssh2_channel_receive_window_adjust(session->
++                                                               packAdd_channel,
++                                                               datalen - 13,
++                                                               0);
++                    if (rc == PACKET_EAGAIN) {
++                        session->socket_block_directions =
++                            LIBSSH2_SESSION_BLOCK_OUTBOUND;
++                        return PACKET_EAGAIN;
++                    }
++                    session->packAdd_state = libssh2_NB_state_idle;
++                    return 0;
++                }
++
++                /*
++                 * REMEMBER! remote means remote as source of data,
++                 * NOT remote window!
++                 */
++                if (session->packAdd_channel->remote.packet_size <
++                    (datalen - session->packAdd_data_head)) {
++                    /*
++                     * Spec says we MAY ignore bytes sent beyond 
++                     * packet_size
++                     */
++                    libssh2_error(session,
++                                  LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
++                                  "Packet contains more data than we offered to receive, truncating",
++                                  0);
++                    datalen =
++                        session->packAdd_channel->remote.packet_size +
++                        session->packAdd_data_head;
++                }
++                if (session->packAdd_channel->remote.window_size <= 0) {
++                    /*
++                     * Spec says we MAY ignore bytes sent beyond
++                     * window_size
++                     */
++                    libssh2_error(session,
++                                  LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
++                                  "The current receive window is full, data ignored",
++                                  0);
++                    LIBSSH2_FREE(session, data);
++                    session->packAdd_state = libssh2_NB_state_idle;
++                    return 0;
++                }
++                /* Reset EOF status */
++                session->packAdd_channel->remote.eof = 0;
++
++                if ((datalen - session->packAdd_data_head) >
++                    session->packAdd_channel->remote.window_size) {
++                    libssh2_error(session,
++                                  LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
++                                  "Remote sent more data than current window allows, truncating",
++                                  0);
++                    datalen =
++                        session->packAdd_channel->remote.window_size +
++                        session->packAdd_data_head;
++                } else {
++                    /* Now that we've received it, shrink our window */
++                    session->packAdd_channel->remote.window_size -=
++                        datalen - session->packAdd_data_head;
++                }
++            }
++            break;
++
++        case SSH_MSG_CHANNEL_EOF:
++            {
++                session->packAdd_channel = libssh2_channel_locate(session,
++                                                                  libssh2_ntohu32
++                                                                  (data + 1));
++
++                if (!session->packAdd_channel) {
++                    /* We may have freed already, just quietly ignore this... */
++                    LIBSSH2_FREE(session, data);
++                    session->packAdd_state = libssh2_NB_state_idle;
++                    return 0;
++                }
++
++                _libssh2_debug(session,
++                               LIBSSH2_DBG_CONN,
++                               "EOF received for channel %lu/%lu",
++                               session->packAdd_channel->local.id,
++                               session->packAdd_channel->remote.id);
++                session->packAdd_channel->remote.eof = 1;
++
++                LIBSSH2_FREE(session, data);
++                session->packAdd_state = libssh2_NB_state_idle;
++                return 0;
++            }
++            break;
++
++        case SSH_MSG_CHANNEL_REQUEST:
++            {
++                if (libssh2_ntohu32(data + 5) == sizeof("exit-status") - 1
++                    && !memcmp("exit-status", data + 9,
++                               sizeof("exit-status") - 1)) {
++
++                    /* we've got "exit-status" packet. Set the session value */
++                    session->packAdd_channel =
++                        libssh2_channel_locate(session,
++                                               libssh2_ntohu32(data + 1));
++
++                    if (session->packAdd_channel) {
++                        session->packAdd_channel->exit_status =
++                            libssh2_ntohu32(data + 9 + sizeof("exit-status"));
++                        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                                       "Exit status %lu received for channel %lu/%lu",
++                                       session->packAdd_channel->exit_status,
++                                       session->packAdd_channel->local.id,
++                                       session->packAdd_channel->remote.id);
++                    }
++
++                    LIBSSH2_FREE(session, data);
++                    session->packAdd_state = libssh2_NB_state_idle;
++                    return 0;
++                }
++            }
++            break;
++
++        case SSH_MSG_CHANNEL_CLOSE:
++            {
++                session->packAdd_channel = libssh2_channel_locate(session,
++                                                                  libssh2_ntohu32
++                                                                  (data + 1));
++
++                if (!session->packAdd_channel) {
++                    /* We may have freed already, just quietly ignore this... */
++                    LIBSSH2_FREE(session, data);
++                    session->packAdd_state = libssh2_NB_state_idle;
++                    return 0;
++                }
++                _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                               "Close received for channel %lu/%lu",
++                               session->packAdd_channel->local.id,
++                               session->packAdd_channel->remote.id);
++
++                session->packAdd_channel->remote.close = 1;
++                session->packAdd_channel->remote.eof = 1;
++                /* TODO: Add a callback for this */
++
++                LIBSSH2_FREE(session, data);
++                session->packAdd_state = libssh2_NB_state_idle;
++                return 0;
++            }
++            break;
++
++        case SSH_MSG_CHANNEL_OPEN:
++            if ((datalen >= (sizeof("forwarded-tcpip") + 4)) &&
++                ((sizeof("forwarded-tcpip") - 1) == libssh2_ntohu32(data + 1))
++                &&
++                (memcmp
++                 (data + 5, "forwarded-tcpip",
++                  sizeof("forwarded-tcpip") - 1) == 0)) {
++
++              libssh2_packet_add_jump_point2:
++                session->packAdd_state = libssh2_NB_state_jump2;
++                rc = libssh2_packet_queue_listener(session, data, datalen,
++                                                   &session->
++                                                   packAdd_Qlstn_state);
++                if (rc == PACKET_EAGAIN) {
++                    session->socket_block_directions =
++                        LIBSSH2_SESSION_BLOCK_OUTBOUND;
++                    return PACKET_EAGAIN;
++                }
++
++                LIBSSH2_FREE(session, data);
++                session->packAdd_state = libssh2_NB_state_idle;
++                return rc;
++            }
++            if ((datalen >= (sizeof("x11") + 4)) &&
++                ((sizeof("x11") - 1) == libssh2_ntohu32(data + 1)) &&
++                (memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {
++
++              libssh2_packet_add_jump_point3:
++                session->packAdd_state = libssh2_NB_state_jump3;
++                rc = libssh2_packet_x11_open(session, data, datalen,
++                                             &session->packAdd_x11open_state);
++                if (rc == PACKET_EAGAIN) {
++                    session->socket_block_directions =
++                        LIBSSH2_SESSION_BLOCK_OUTBOUND;
++                    return PACKET_EAGAIN;
++                }
++
++                LIBSSH2_FREE(session, data);
++                session->packAdd_state = libssh2_NB_state_idle;
++                return rc;
++            }
++            break;
++
++        case SSH_MSG_CHANNEL_WINDOW_ADJUST:
++            {
++                unsigned long bytestoadd = libssh2_ntohu32(data + 5);
++                session->packAdd_channel = libssh2_channel_locate(session,
++                                                                  libssh2_ntohu32
++                                                                  (data + 1));
++
++                if (session->packAdd_channel && bytestoadd) {
++                    session->packAdd_channel->local.window_size += bytestoadd;
++                }
++                _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                               "Window adjust received for channel %lu/%lu, adding %lu bytes, new window_size=%lu",
++                               session->packAdd_channel->local.id,
++                               session->packAdd_channel->remote.id,
++                               bytestoadd,
++                               session->packAdd_channel->local.window_size);
++
++                LIBSSH2_FREE(session, data);
++                session->packAdd_state = libssh2_NB_state_idle;
++                return 0;
++            }
++            break;
++        }
++
++        session->packAdd_state = libssh2_NB_state_sent;
++    }
++
++    if (session->packAdd_state == libssh2_NB_state_sent) {
++        session->packAdd_packet =
++            LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
++        if (!session->packAdd_packet) {
++            _libssh2_debug(session, LIBSSH2_ERROR_ALLOC,
++                           "Unable to allocate memory for LIBSSH2_PACKET");
++            LIBSSH2_FREE(session, data);
++            session->packAdd_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        memset(session->packAdd_packet, 0, sizeof(LIBSSH2_PACKET));
++
++        session->packAdd_packet->data = data;
++        session->packAdd_packet->data_len = datalen;
++        session->packAdd_packet->data_head = session->packAdd_data_head;
++        session->packAdd_packet->mac = macstate;
++        session->packAdd_packet->brigade = &session->packets;
++        session->packAdd_packet->next = NULL;
++
++        if (session->packets.tail) {
++            session->packAdd_packet->prev = session->packets.tail;
++            session->packAdd_packet->prev->next = session->packAdd_packet;
++            session->packets.tail = session->packAdd_packet;
++        } else {
++            session->packets.head = session->packAdd_packet;
++            session->packets.tail = session->packAdd_packet;
++            session->packAdd_packet->prev = NULL;
++        }
++
++        session->packAdd_state = libssh2_NB_state_sent1;
++    }
++
++    if ((data[0] == SSH_MSG_KEXINIT &&
++         !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) ||
++        (session->packAdd_state == libssh2_NB_state_sent2)) {
++        if (session->packAdd_state == libssh2_NB_state_sent1) {
++            /*
++             * Remote wants new keys
++             * Well, it's already in the brigade,
++             * let's just call back into ourselves
++             */
++            _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Renegotiating Keys");
++
++            session->packAdd_state = libssh2_NB_state_sent2;
++        }
++
++        /*
++         * The KEXINIT message has been added to the queue.
++         * The packAdd and readPack states need to be reset
++         * because libssh2_kex_exchange (eventually) calls upon
++         * libssh2_packet_read to read the rest of the key exchange
++         * conversation.
++         */
++        session->readPack_state = libssh2_NB_state_idle;
++        session->packet.total_num = 0;
++        session->packAdd_state = libssh2_NB_state_idle;
++        session->fullpacket_state = libssh2_NB_state_idle;
++
++        /*
++         * Also, don't use packAdd_key_state for key re-exchange,
++         * as it will be wiped out in the middle of the exchange.
++         * How about re-using the startup_key_state?
++         */
++        memset(&session->startup_key_state, 0, sizeof(key_exchange_state_t));
++ 
++        /*
++         * If there was a key reexchange failure, let's just hope we didn't
++         * send NEWKEYS yet, otherwise remote will drop us like a rock
++         */
++        rc = libssh2_kex_exchange(session, 1, &session->startup_key_state);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        }
++    }
++
++    session->packAdd_state = libssh2_NB_state_idle;
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_packet_ask
++ * Scan the brigade for a matching packet type, optionally poll the socket for
++ * a packet first
++ */
++int
++libssh2_packet_ask_ex(LIBSSH2_SESSION * session, unsigned char packet_type,
++                      unsigned char **data, unsigned long *data_len,
++                      unsigned long match_ofs, const unsigned char *match_buf,
++                      unsigned long match_len, int poll_socket)
++{
++    LIBSSH2_PACKET *packet = session->packets.head;
++
++    if (poll_socket) {
++        /*
++         * XXX CHECK ***
++         * When "poll_socket" is "1" libhss2_packet_read() can return
++         * PACKET_EAGAIN.  I am not sure what should happen, but internally
++         * there is only one location that might do so, libssh2_packet_askv_ex()
++         */
++        libssh2pack_t rc = libssh2_packet_read(session);
++        if ((rc < 0) && !packet) {
++            return rc;
++        }
++    }
++    _libssh2_debug(session, LIBSSH2_DBG_TRANS,
++                   "Looking for packet of type: %d", (int) packet_type);
++
++    while (packet) {
++        if (packet->data[0] == packet_type
++            && (packet->data_len >= (match_ofs + match_len)) && (!match_buf
++                                                                 ||
++                                                                 (memcmp
++                                                                  (packet->
++                                                                   data +
++                                                                   match_ofs,
++                                                                   match_buf,
++                                                                   match_len)
++                                                                  == 0))) {
++            *data = packet->data;
++            *data_len = packet->data_len;
++
++            if (packet->prev) {
++                packet->prev->next = packet->next;
++            } else {
++                session->packets.head = packet->next;
++            }
++
++            if (packet->next) {
++                packet->next->prev = packet->prev;
++            } else {
++                session->packets.tail = packet->prev;
++            }
++
++            LIBSSH2_FREE(session, packet);
++
++            return 0;
++        }
++        packet = packet->next;
++    }
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_packet_askv
++ * Scan for any of a list of packet types in the brigade, optionally poll the
++ * socket for a packet first
++ */
++int
++libssh2_packet_askv_ex(LIBSSH2_SESSION * session,
++                       const unsigned char *packet_types,
++                       unsigned char **data, unsigned long *data_len,
++                       unsigned long match_ofs,
++                       const unsigned char *match_buf,
++                       unsigned long match_len, int poll_socket)
++{
++    int i, packet_types_len = strlen((char *) packet_types);
++
++    for(i = 0; i < packet_types_len; i++) {
++        /*
++         * XXX CHECK XXX
++         * When "poll_socket" is "1" libssh2_packet_ask_ex() could
++         * return PACKET_EAGAIN.  Not sure the correct action, I 
++         * think it is right as is.
++         */
++        if (0 == libssh2_packet_ask_ex(session, packet_types[i], data,
++                                       data_len, match_ofs, match_buf,
++                                       match_len, i ? 0 : poll_socket)) {
++            return 0;
++        }
++    }
++
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ waitsocket
++ * Returns
++ * negative on error
++ * >0 on incoming data
++ * 0 on timeout
++ *
++ * FIXME: convert to use poll on systems that have it.
++ */
++int
++libssh2_waitsocket(LIBSSH2_SESSION * session, long seconds)
++{
++    struct timeval timeout;
++    int rc;
++    fd_set fd;
++
++    timeout.tv_sec = seconds;
++    timeout.tv_usec = 0;
++
++    FD_ZERO(&fd);
++
++    FD_SET(session->socket_fd, &fd);
++
++    rc = select(session->socket_fd + 1, &fd, NULL, NULL, &timeout);
++
++    return rc;
++}
++
++/* {{{ libssh2_packet_require
++ * Loops libssh2_packet_read() until the packet requested is available
++ * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
++ *
++ * Returns negative on error
++ * Returns 0 when it has taken care of the requested packet.
++ */
++int
++libssh2_packet_require_ex(LIBSSH2_SESSION * session, unsigned char packet_type,
++                          unsigned char **data, unsigned long *data_len,
++                          unsigned long match_ofs,
++                          const unsigned char *match_buf,
++                          unsigned long match_len,
++                          packet_require_state_t * state)
++{
++    if (state->start == 0) {
++        if (libssh2_packet_ask_ex
++            (session, packet_type, data, data_len, match_ofs, match_buf,
++             match_len, 0) == 0) {
++            /* A packet was available in the packet brigade */
++            return 0;
++        }
++
++        state->start = time(NULL);
++
++        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
++                       "May block until packet of type %d becomes available",
++                       (int) packet_type);
++    }
++
++    while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
++        libssh2pack_t ret = libssh2_packet_read(session);
++        if (ret == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if ((ret == 0) && (!session->socket_block)) {
++            /* If we are in non-blocking and there is no data, return that */
++            return PACKET_EAGAIN;
++        } else if (ret < 0) {
++            state->start = 0;
++            /* an error which is not just because of blocking */
++            return ret;
++        } else if (ret == packet_type) {
++            /* Be lazy, let packet_ask pull it out of the brigade */
++            ret =
++                libssh2_packet_ask_ex(session, packet_type, data, data_len,
++                                      match_ofs, match_buf, match_len, 0);
++            state->start = 0;
++            return ret;
++        } else if (ret == 0) {
++            /* nothing available, wait until data arrives or we time out */
++            long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start);
++
++            if ((left <= 0) || (libssh2_waitsocket(session, left) <= 0)) {
++                state->start = 0;
++                return PACKET_TIMEOUT;
++            }
++        }
++    }
++
++    /* Only reached if the socket died */
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_packet_burn
++ * Loops libssh2_packet_read() until any packet is available and promptly 
++ * discards it
++ * Used during KEX exchange to discard badly guessed KEX_INIT packets
++ */
++int
++libssh2_packet_burn(LIBSSH2_SESSION * session,
++                    libssh2_nonblocking_states * state)
++{
++    unsigned char *data;
++    unsigned long data_len;
++    unsigned char all_packets[255];
++    int i;
++    int ret;
++
++    if (*state == libssh2_NB_state_idle) {
++        for(i = 1; i < 256; i++) {
++            all_packets[i - 1] = i;
++        }
++
++        if (libssh2_packet_askv_ex
++            (session, all_packets, &data, &data_len, 0, NULL, 0, 0) == 0) {
++            i = data[0];
++            /* A packet was available in the packet brigade, burn it */
++            LIBSSH2_FREE(session, data);
++            return i;
++        }
++
++        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
++                       "Blocking until packet becomes available to burn");
++        *state = libssh2_NB_state_created;
++    }
++
++    while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
++        if ((ret = libssh2_packet_read(session)) == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (ret < 0) {
++            *state = libssh2_NB_state_idle;
++            return ret;
++        } else if (ret == 0) {
++            /* FIXME: this might busyloop */
++            continue;
++        }
++
++        /* Be lazy, let packet_ask pull it out of the brigade */
++        if (0 ==
++            libssh2_packet_ask_ex(session, ret, &data, &data_len, 0, NULL, 0,
++                                  0)) {
++            /* Smoke 'em if you got 'em */
++            LIBSSH2_FREE(session, data);
++            *state = libssh2_NB_state_idle;
++            return ret;
++        }
++    }
++
++    /* Only reached if the socket died */
++    return -1;
++}
++
++/* }}} */
++
++/*
++ * {{{ libssh2_packet_requirev
++ *
++ * Loops libssh2_packet_read() until one of a list of packet types requested is
++ * available
++ * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
++ * packet_types is a null terminated list of packet_type numbers
++ */
++
++int
++libssh2_packet_requirev_ex(LIBSSH2_SESSION * session,
++                           const unsigned char *packet_types,
++                           unsigned char **data, unsigned long *data_len,
++                           unsigned long match_ofs,
++                           const unsigned char *match_buf,
++                           unsigned long match_len,
++                           packet_requirev_state_t * state)
++{
++    if (libssh2_packet_askv_ex
++        (session, packet_types, data, data_len, match_ofs, match_buf,
++         match_len, 0) == 0) {
++        /* One of the packets listed was available in the packet
++           brigade */
++        state->start = 0;
++        return 0;
++    }
++
++    if (state->start == 0) {
++        state->start = time(NULL);
++    }
++
++    while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
++        int ret = libssh2_packet_read(session);
++        if ((ret < 0) && (ret != PACKET_EAGAIN)) {
++            state->start = 0;
++            return ret;
++        }
++        if (ret <= 0) {
++            long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start);
++
++            if ((left <= 0) || (libssh2_waitsocket(session, left) <= 0)) {
++                state->start = 0;
++                return PACKET_TIMEOUT;
++            } else if (ret == PACKET_EAGAIN) {
++                return PACKET_EAGAIN;
++            }
++        }
++
++        if (strchr((char *) packet_types, ret)) {
++            /* Be lazy, let packet_ask pull it out of the brigade */
++            return libssh2_packet_askv_ex(session, packet_types, data,
++                                          data_len, match_ofs, match_buf,
++                                          match_len, 0);
++        }
++    }
++
++    /* Only reached if the socket died */
++    state->start = 0;
++    return -1;
++}
++
++/* }}} */
+
+Property changes on: libssh2/src/packet.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.2
+Added: svn:eol-style
+   + native
+
+Index: libssh2/src/channel.c
+===================================================================
+--- libssh2/src/channel.c      (.../tags/RELEASE_0_11_0)
++++ libssh2/src/channel.c      (.../trunk)
+@@ -0,0 +1,2260 @@
++/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
++ * Copyright (c) 2008 by 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:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++#ifdef HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <fcntl.h>
++#ifdef HAVE_INTTYPES_H
++#include <inttypes.h>
++#endif
++
++
++/* {{{ libssh2_channel_nextid
++ * Determine the next channel ID we can use at our end
++ */
++unsigned long
++libssh2_channel_nextid(LIBSSH2_SESSION * session)
++{
++    unsigned long id = session->next_channel;
++    LIBSSH2_CHANNEL *channel;
++
++    channel = session->channels.head;
++
++    while (channel) {
++        if (channel->local.id > id) {
++            id = channel->local.id;
++        }
++        channel = channel->next;
++    }
++
++    /* This is a shortcut to avoid waiting for close packets on channels we've
++     * forgotten about, This *could* be a problem if we request and close 4
++     * billion or so channels in too rapid succession for the remote end to
++     * respond, but the worst case scenario is that some data meant for
++     * another channel Gets picked up by the new one.... Pretty unlikely all
++     * told...
++     */
++    session->next_channel = id + 1;
++    _libssh2_debug(session, LIBSSH2_DBG_CONN, "Allocated new channel ID#%lu",
++                   id);
++    return id;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_locate
++ * Locate a channel pointer by number
++ */
++LIBSSH2_CHANNEL *
++libssh2_channel_locate(LIBSSH2_SESSION * session, unsigned long channel_id)
++{
++    LIBSSH2_CHANNEL *channel = session->channels.head;
++    while (channel) {
++        if (channel->local.id == channel_id) {
++            return channel;
++        }
++        channel = channel->next;
++    }
++
++    return NULL;
++}
++
++/* }}} */
++
++#define CHANNEL_ADD(session, channel)   \
++{   \
++    if ((session)->channels.tail) { \
++        (session)->channels.tail->next = (channel); \
++        (channel)->prev = (session)->channels.tail; \
++    } else {    \
++        (session)->channels.head = (channel);   \
++        (channel)->prev = NULL; \
++    }   \
++    (channel)->next = NULL; \
++    (session)->channels.tail = (channel);   \
++    (channel)->session = (session); \
++}
++
++/* {{{ libssh2_channel_open_ex
++ * Establish a generic session channel
++ */
++LIBSSH2_API LIBSSH2_CHANNEL *
++libssh2_channel_open_ex(LIBSSH2_SESSION * session, const char *channel_type,
++                        unsigned int channel_type_len,
++                        unsigned int window_size, unsigned int packet_size,
++                        const char *message, unsigned int message_len)
++{
++    static const unsigned char reply_codes[3] = {
++        SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
++        SSH_MSG_CHANNEL_OPEN_FAILURE,
++        0
++    };
++    unsigned char *s;
++    int rc;
++
++    if (session->open_state == libssh2_NB_state_idle) {
++        session->open_channel = NULL;
++        session->open_packet = NULL;
++        session->open_data = NULL;
++        /* 17 = packet_type(1) + channel_type_len(4) + sender_channel(4) +
++         * window_size(4) + packet_size(4) */
++        session->open_packet_len = channel_type_len + message_len + 17;
++        session->open_local_channel = libssh2_channel_nextid(session);
++
++        /* Zero the whole thing out */
++        memset(&session->open_packet_requirev_state, 0,
++               sizeof(session->open_packet_requirev_state));
++
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "Opening Channel - win %d pack %d", window_size,
++                       packet_size);
++        session->open_channel =
++            LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
++        if (!session->open_channel) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate space for channel data", 0);
++            return NULL;
++        }
++        memset(session->open_channel, 0, sizeof(LIBSSH2_CHANNEL));
++
++        session->open_channel->channel_type_len = channel_type_len;
++        session->open_channel->channel_type =
++            LIBSSH2_ALLOC(session, channel_type_len);
++        if (!session->open_channel->channel_type) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Failed allocating memory for channel type name", 0);
++            LIBSSH2_FREE(session, session->open_channel);
++            session->open_channel = NULL;
++            return NULL;
++        }
++        memcpy(session->open_channel->channel_type, channel_type,
++               channel_type_len);
++
++        /* REMEMBER: local as in locally sourced */
++        session->open_channel->local.id = session->open_local_channel;
++        session->open_channel->remote.window_size = window_size;
++        session->open_channel->remote.window_size_initial = window_size;
++        session->open_channel->remote.packet_size = packet_size;
++
++        CHANNEL_ADD(session, session->open_channel);
++
++        s = session->open_packet =
++            LIBSSH2_ALLOC(session, session->open_packet_len);
++        if (!session->open_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate temporary space for packet", 0);
++            goto channel_error;
++        }
++        *(s++) = SSH_MSG_CHANNEL_OPEN;
++        libssh2_htonu32(s, channel_type_len);
++        s += 4;
++
++        memcpy(s, channel_type, channel_type_len);
++        s += channel_type_len;
++
++        libssh2_htonu32(s, session->open_local_channel);
++        s += 4;
++
++        libssh2_htonu32(s, window_size);
++        s += 4;
++
++        libssh2_htonu32(s, packet_size);
++        s += 4;
++
++        if (message && message_len) {
++            memcpy(s, message, message_len);
++            s += message_len;
++        }
++
++        session->open_state = libssh2_NB_state_created;
++    }
++
++    if (session->open_state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, session->open_packet,
++                                  session->open_packet_len);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block sending channel-open request", 0);
++            return NULL;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send channel-open request", 0);
++            goto channel_error;
++        }
++
++        session->open_state = libssh2_NB_state_sent;
++    }
++
++    if (session->open_state == libssh2_NB_state_sent) {
++        rc = libssh2_packet_requirev_ex(session, reply_codes,
++                                        &session->open_data,
++                                        &session->open_data_len, 1,
++                                        session->open_packet + 5 +
++                                        channel_type_len, 4,
++                                        &session->open_packet_requirev_state);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block", 0);
++            return NULL;
++        } else if (rc) {
++            goto channel_error;
++        }
++
++        if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
++            session->open_channel->remote.id =
++                libssh2_ntohu32(session->open_data + 5);
++            session->open_channel->local.window_size =
++                libssh2_ntohu32(session->open_data + 9);
++            session->open_channel->local.window_size_initial =
++                libssh2_ntohu32(session->open_data + 9);
++            session->open_channel->local.packet_size =
++                libssh2_ntohu32(session->open_data + 13);
++            _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                           "Connection Established - ID: %lu/%lu win: %lu/%lu"
++                           " pack: %lu/%lu",
++                           session->open_channel->local.id,
++                           session->open_channel->remote.id,
++                           session->open_channel->local.window_size,
++                           session->open_channel->remote.window_size,
++                           session->open_channel->local.packet_size,
++                           session->open_channel->remote.packet_size);
++            LIBSSH2_FREE(session, session->open_packet);
++            session->open_packet = NULL;
++            LIBSSH2_FREE(session, session->open_data);
++            session->open_data = NULL;
++
++            session->open_state = libssh2_NB_state_idle;
++            return session->open_channel;
++        }
++
++        if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_FAILURE) {
++            libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
++                          "Channel open failure", 0);
++        }
++    }
++
++  channel_error:
++
++    if (session->open_data) {
++        LIBSSH2_FREE(session, session->open_data);
++        session->open_data = NULL;
++    }
++    if (session->open_packet) {
++        LIBSSH2_FREE(session, session->open_packet);
++        session->open_packet = NULL;
++    }
++    if (session->open_channel) {
++        unsigned char channel_id[4];
++        LIBSSH2_FREE(session, session->open_channel->channel_type);
++
++        if (session->open_channel->next) {
++            session->open_channel->next->prev = session->open_channel->prev;
++        }
++        if (session->open_channel->prev) {
++            session->open_channel->prev->next = session->open_channel->next;
++        }
++        if (session->channels.head == session->open_channel) {
++            session->channels.head = session->open_channel->next;
++        }
++        if (session->channels.tail == session->open_channel) {
++            session->channels.tail = session->open_channel->prev;
++        }
++
++        /* Clear out packets meant for this channel */
++        libssh2_htonu32(channel_id, session->open_channel->local.id);
++        while ((libssh2_packet_ask_ex
++                (session, SSH_MSG_CHANNEL_DATA, &session->open_data,
++                 &session->open_data_len, 1, channel_id, 4, 0) >= 0)
++               ||
++               (libssh2_packet_ask_ex
++                (session, SSH_MSG_CHANNEL_EXTENDED_DATA, &session->open_data,
++                 &session->open_data_len, 1, channel_id, 4, 0) >= 0)) {
++            LIBSSH2_FREE(session, session->open_data);
++            session->open_data = NULL;
++        }
++
++        /* Free any state variables still holding data */
++        if (session->open_channel->write_packet) {
++            LIBSSH2_FREE(session, session->open_channel->write_packet);
++            session->open_channel->write_packet = NULL;
++        }
++
++        LIBSSH2_FREE(session, session->open_channel);
++        session->open_channel = NULL;
++    }
++
++    session->open_state = libssh2_NB_state_idle;
++    return NULL;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_direct_tcpip_ex
++ * Tunnel TCP/IP connect through the SSH session to direct host/port
++ */
++LIBSSH2_API LIBSSH2_CHANNEL *
++libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION * session, const char *host,
++                                int port, const char *shost, int sport)
++{
++    LIBSSH2_CHANNEL *channel;
++    unsigned char *s;
++
++    if (session->direct_state == libssh2_NB_state_idle) {
++        session->direct_host_len = strlen(host);
++        session->direct_shost_len = strlen(shost);
++        /* host_len(4) + port(4) + shost_len(4) + sport(4) */
++        session->direct_message_len =
++            session->direct_host_len + session->direct_shost_len + 16;
++
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "Requesting direct-tcpip session to from %s:%d to %s:%d",
++                       shost, sport, host, port);
++
++        s = session->direct_message =
++            LIBSSH2_ALLOC(session, session->direct_message_len);
++        if (!session->direct_message) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for direct-tcpip connection",
++                          0);
++            return NULL;
++        }
++        libssh2_htonu32(s, session->direct_host_len);
++        s += 4;
++        memcpy(s, host, session->direct_host_len);
++        s += session->direct_host_len;
++        libssh2_htonu32(s, port);
++        s += 4;
++
++        libssh2_htonu32(s, session->direct_shost_len);
++        s += 4;
++        memcpy(s, shost, session->direct_shost_len);
++        s += session->direct_shost_len;
++        libssh2_htonu32(s, sport);
++        s += 4;
++
++        session->direct_state = libssh2_NB_state_created;
++    }
++
++    channel =
++        libssh2_channel_open_ex(session, "direct-tcpip",
++                                sizeof("direct-tcpip") - 1,
++                                LIBSSH2_CHANNEL_WINDOW_DEFAULT,
++                                LIBSSH2_CHANNEL_PACKET_DEFAULT,
++                                (char *) session->direct_message,
++                                session->direct_message_len);
++    if (!channel) {
++        if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
++            /* The error code is still set to LIBSSH2_ERROR_EAGAIN */
++            return NULL;
++        } else {
++            LIBSSH2_FREE(session, session->direct_message);
++            session->direct_message = NULL;
++            return NULL;
++        }
++    }
++
++    LIBSSH2_FREE(session, session->direct_message);
++    session->direct_message = NULL;
++
++    return channel;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_forward_listen_ex
++ * Bind a port on the remote host and listen for connections
++ */
++LIBSSH2_API LIBSSH2_LISTENER *
++libssh2_channel_forward_listen_ex(LIBSSH2_SESSION * session, const char *host,
++                                  int port, int *bound_port, int queue_maxsize)
++{
++    unsigned char *s, *data;
++    static const unsigned char reply_codes[3] =
++        { SSH_MSG_REQUEST_SUCCESS, SSH_MSG_REQUEST_FAILURE, 0 };
++    unsigned long data_len;
++    int rc;
++
++    if (session->fwdLstn_state == libssh2_NB_state_idle) {
++        session->fwdLstn_host_len =
++            (host ? strlen(host) : (sizeof("0.0.0.0") - 1));
++        /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4)
++           + port(4) */
++        session->fwdLstn_packet_len =
++            session->fwdLstn_host_len + (sizeof("tcpip-forward") - 1) + 14;
++
++        /* Zero the whole thing out */
++        memset(&session->fwdLstn_packet_requirev_state, 0,
++               sizeof(session->fwdLstn_packet_requirev_state));
++
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "Requesting tcpip-forward session for %s:%d", host,
++                       port);
++
++        s = session->fwdLstn_packet =
++            LIBSSH2_ALLOC(session, session->fwdLstn_packet_len);
++        if (!session->fwdLstn_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memeory for setenv packet", 0);
++            return NULL;
++        }
++
++        *(s++) = SSH_MSG_GLOBAL_REQUEST;
++        libssh2_htonu32(s, sizeof("tcpip-forward") - 1);
++        s += 4;
++        memcpy(s, "tcpip-forward", sizeof("tcpip-forward") - 1);
++        s += sizeof("tcpip-forward") - 1;
++        *(s++) = 0x01;          /* want_reply */
++
++        libssh2_htonu32(s, session->fwdLstn_host_len);
++        s += 4;
++        memcpy(s, host ? host : "0.0.0.0", session->fwdLstn_host_len);
++        s += session->fwdLstn_host_len;
++        libssh2_htonu32(s, port);
++        s += 4;
++
++        session->fwdLstn_state = libssh2_NB_state_created;
++    }
++
++    if (session->fwdLstn_state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, session->fwdLstn_packet,
++                                  session->fwdLstn_packet_len);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block sending global-request packet for "
++                          "forward listen request",
++                          0);
++            return NULL;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send global-request packet for forward "
++                          "listen request",
++                          0);
++            LIBSSH2_FREE(session, session->fwdLstn_packet);
++            session->fwdLstn_packet = NULL;
++            session->fwdLstn_state = libssh2_NB_state_idle;
++            return NULL;
++        }
++        LIBSSH2_FREE(session, session->fwdLstn_packet);
++        session->fwdLstn_packet = NULL;
++
++        session->fwdLstn_state = libssh2_NB_state_sent;
++    }
++
++    if (session->fwdLstn_state == libssh2_NB_state_sent) {
++        rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
++                                        0, NULL, 0,
++                                        &session->
++                                        fwdLstn_packet_requirev_state);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block", 0);
++            return NULL;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_PROTO, "Unknown", 0);
++            session->fwdLstn_state = libssh2_NB_state_idle;
++            return NULL;
++        }
++
++        if (data[0] == SSH_MSG_REQUEST_SUCCESS) {
++            LIBSSH2_LISTENER *listener;
++
++            listener = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_LISTENER));
++            if (!listener) {
++                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                              "Unable to allocate memory for listener queue",
++                              0);
++                LIBSSH2_FREE(session, data);
++                session->fwdLstn_state = libssh2_NB_state_idle;
++                return NULL;
++            }
++            memset(listener, 0, sizeof(LIBSSH2_LISTENER));
++            listener->session = session;
++            listener->host =
++                LIBSSH2_ALLOC(session, session->fwdLstn_host_len + 1);
++            if (!listener->host) {
++                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                              "Unable to allocate memory for listener queue",
++                              0);
++                LIBSSH2_FREE(session, listener);
++                LIBSSH2_FREE(session, data);
++                session->fwdLstn_state = libssh2_NB_state_idle;
++                return NULL;
++            }
++            memcpy(listener->host, host ? host : "0.0.0.0",
++                   session->fwdLstn_host_len);
++            listener->host[session->fwdLstn_host_len] = 0;
++            if (data_len >= 5 && !port) {
++                listener->port = libssh2_ntohu32(data + 1);
++                _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                               "Dynamic tcpip-forward port allocated: %d",
++                               listener->port);
++            } else {
++                listener->port = port;
++            }
++
++            listener->queue_size = 0;
++            listener->queue_maxsize = queue_maxsize;
++
++            listener->next = session->listeners;
++            listener->prev = NULL;
++            if (session->listeners) {
++                session->listeners->prev = listener;
++            }
++            session->listeners = listener;
++
++            if (bound_port) {
++                *bound_port = listener->port;
++            }
++
++            LIBSSH2_FREE(session, data);
++            session->fwdLstn_state = libssh2_NB_state_idle;
++            return listener;
++        }
++
++        if (data[0] == SSH_MSG_REQUEST_FAILURE) {
++            LIBSSH2_FREE(session, data);
++            libssh2_error(session, LIBSSH2_ERROR_REQUEST_DENIED,
++                          "Unable to complete request for forward-listen", 0);
++            session->fwdLstn_state = libssh2_NB_state_idle;
++            return NULL;
++        }
++    }
++
++    session->fwdLstn_state = libssh2_NB_state_idle;
++
++    return NULL;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_forward_cancel
++ * Stop listening on a remote port and free the listener
++ * Toss out any pending (un-accept()ed) connections
++ *
++ * Return 0 on success, PACKET_EAGAIN if would block, -1 on error
++ */
++LIBSSH2_API int
++libssh2_channel_forward_cancel(LIBSSH2_LISTENER * listener)
++{
++    LIBSSH2_SESSION *session = listener->session;
++    LIBSSH2_CHANNEL *queued = listener->queue;
++    unsigned char *packet, *s;
++    unsigned long host_len = strlen(listener->host);
++    /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) +
++       port(4) */
++    unsigned long packet_len =
++        host_len + 14 + sizeof("cancel-tcpip-forward") - 1;
++    int rc;
++
++    if (listener->chanFwdCncl_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "Cancelling tcpip-forward session for %s:%d",
++                       listener->host, listener->port);
++
++        s = packet = LIBSSH2_ALLOC(session, packet_len);
++        if (!packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memeory for setenv packet", 0);
++            return -1;
++        }
++
++        *(s++) = SSH_MSG_GLOBAL_REQUEST;
++        libssh2_htonu32(s, sizeof("cancel-tcpip-forward") - 1);
++        s += 4;
++        memcpy(s, "cancel-tcpip-forward", sizeof("cancel-tcpip-forward") - 1);
++        s += sizeof("cancel-tcpip-forward") - 1;
++        *(s++) = 0x00;          /* want_reply */
++
++        libssh2_htonu32(s, host_len);
++        s += 4;
++        memcpy(s, listener->host, host_len);
++        s += host_len;
++        libssh2_htonu32(s, listener->port);
++        s += 4;
++
++        listener->chanFwdCncl_state = libssh2_NB_state_created;
++    } else {
++        packet = listener->chanFwdCncl_data;
++    }
++
++    if (listener->chanFwdCncl_state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, packet, packet_len);
++        if (rc == PACKET_EAGAIN) {
++            listener->chanFwdCncl_data = packet;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send global-request packet for forward "
++                          "listen request",
++                          0);
++            LIBSSH2_FREE(session, packet);
++            listener->chanFwdCncl_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, packet);
++
++        listener->chanFwdCncl_state = libssh2_NB_state_sent;
++    }
++
++    while (queued) {
++        LIBSSH2_CHANNEL *next = queued->next;
++
++        rc = libssh2_channel_free(queued);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        }
++        queued = next;
++    }
++    LIBSSH2_FREE(session, listener->host);
++
++    if (listener->next) {
++        listener->next->prev = listener->prev;
++    }
++    if (listener->prev) {
++        listener->prev->next = listener->next;
++    } else {
++        session->listeners = listener->next;
++    }
++
++    LIBSSH2_FREE(session, listener);
++
++    listener->chanFwdCncl_state = libssh2_NB_state_idle;
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_forward_accept
++ * Accept a connection
++ */
++LIBSSH2_API LIBSSH2_CHANNEL *
++libssh2_channel_forward_accept(LIBSSH2_LISTENER * listener)
++{
++    libssh2pack_t rc;
++
++    do {
++        rc = libssh2_packet_read(listener->session);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(listener->session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block waiting for packet", 0);
++            return NULL;
++        }
++    } while (rc > 0);
++
++    if (listener->queue) {
++        LIBSSH2_SESSION *session = listener->session;
++        LIBSSH2_CHANNEL *channel;
++
++        channel = listener->queue;
++
++        listener->queue = listener->queue->next;
++        if (listener->queue) {
++            listener->queue->prev = NULL;
++        }
++
++        channel->prev = NULL;
++        channel->next = session->channels.head;
++        session->channels.head = channel;
++
++        if (channel->next) {
++            channel->next->prev = channel;
++        } else {
++            session->channels.tail = channel;
++        }
++        listener->queue_size--;
++
++        return channel;
++    }
++
++    return NULL;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_setenv_ex
++ * Set an environment variable prior to requesting a shell/program/subsystem
++ */
++LIBSSH2_API int
++libssh2_channel_setenv_ex(LIBSSH2_CHANNEL * channel, const char *varname,
++                          unsigned int varname_len, const char *value,
++                          unsigned int value_len)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned char *s, *data;
++    static const unsigned char reply_codes[3] =
++        { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
++    unsigned long data_len;
++    int rc;
++
++    if (channel->setenv_state == libssh2_NB_state_idle) {
++        /* 21 = packet_type(1) + channel_id(4) + request_len(4) +
++         * request(3)"env" + want_reply(1) + varname_len(4) + value_len(4) */
++        channel->setenv_packet_len = varname_len + value_len + 21;
++
++        /* Zero the whole thing out */
++        memset(&channel->setenv_packet_requirev_state, 0,
++               sizeof(channel->setenv_packet_requirev_state));
++
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "Setting remote environment variable: %s=%s on "
++                       "channel %lu/%lu",
++                       varname, value, channel->local.id, channel->remote.id);
++
++        s = channel->setenv_packet =
++            LIBSSH2_ALLOC(session, channel->setenv_packet_len);
++        if (!channel->setenv_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memeory for setenv packet", 0);
++            return -1;
++        }
++
++        *(s++) = SSH_MSG_CHANNEL_REQUEST;
++        libssh2_htonu32(s, channel->remote.id);
++        s += 4;
++        libssh2_htonu32(s, sizeof("env") - 1);
++        s += 4;
++        memcpy(s, "env", sizeof("env") - 1);
++        s += sizeof("env") - 1;
++
++        *(s++) = 0x01;
++
++        libssh2_htonu32(s, varname_len);
++        s += 4;
++        memcpy(s, varname, varname_len);
++        s += varname_len;
++
++        libssh2_htonu32(s, value_len);
++        s += 4;
++        memcpy(s, value, value_len);
++        s += value_len;
++
++        channel->setenv_state = libssh2_NB_state_created;
++    }
++
++    if (channel->setenv_state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, channel->setenv_packet,
++                                  channel->setenv_packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send channel-request packet for "
++                          "setenv request",
++                          0);
++            LIBSSH2_FREE(session, channel->setenv_packet);
++            channel->setenv_packet = NULL;
++            channel->setenv_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, channel->setenv_packet);
++        channel->setenv_packet = NULL;
++
++        libssh2_htonu32(channel->setenv_local_channel, channel->local.id);
++
++        channel->setenv_state = libssh2_NB_state_sent;
++    }
++
++    if (channel->setenv_state == libssh2_NB_state_sent) {
++        rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
++                                        1, channel->setenv_local_channel, 4,
++                                        &channel->
++                                        setenv_packet_requirev_state);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        }
++        if (rc) {
++            channel->setenv_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
++            LIBSSH2_FREE(session, data);
++            channel->setenv_state = libssh2_NB_state_idle;
++            return 0;
++        }
++
++        LIBSSH2_FREE(session, data);
++    }
++
++    libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
++                  "Unable to complete request for channel-setenv", 0);
++    channel->setenv_state = libssh2_NB_state_idle;
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_request_pty_ex
++ * Duh... Request a PTY
++ */
++LIBSSH2_API int
++libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL * channel, const char *term,
++                               unsigned int term_len, const char *modes,
++                               unsigned int modes_len, int width, int height,
++                               int width_px, int height_px)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned char *s, *data;
++    static const unsigned char reply_codes[3] =
++        { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
++    unsigned long data_len;
++    int rc;
++
++    if (channel->reqPTY_state == libssh2_NB_state_idle) {
++        /* 41 = packet_type(1) + channel(4) + pty_req_len(4) + "pty_req"(7) +
++         * want_reply(1) + term_len(4) + width(4) + height(4) + width_px(4) +
++         * height_px(4) + modes_len(4) */
++        channel->reqPTY_packet_len = term_len + modes_len + 41;
++
++        /* Zero the whole thing out */
++        memset(&channel->reqPTY_packet_requirev_state, 0,
++               sizeof(channel->reqPTY_packet_requirev_state));
++
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "Allocating tty on channel %lu/%lu", channel->local.id,
++                       channel->remote.id);
++
++        s = channel->reqPTY_packet =
++            LIBSSH2_ALLOC(session, channel->reqPTY_packet_len);
++        if (!channel->reqPTY_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for pty-request", 0);
++            return -1;
++        }
++
++        *(s++) = SSH_MSG_CHANNEL_REQUEST;
++        libssh2_htonu32(s, channel->remote.id);
++        s += 4;
++        libssh2_htonu32(s, sizeof("pty-req") - 1);
++        s += 4;
++        memcpy(s, "pty-req", sizeof("pty-req") - 1);
++        s += sizeof("pty-req") - 1;
++
++        *(s++) = 0x01;
++
++        libssh2_htonu32(s, term_len);
++        s += 4;
++        if (term) {
++            memcpy(s, term, term_len);
++            s += term_len;
++        }
++
++        libssh2_htonu32(s, width);
++        s += 4;
++        libssh2_htonu32(s, height);
++        s += 4;
++        libssh2_htonu32(s, width_px);
++        s += 4;
++        libssh2_htonu32(s, height_px);
++        s += 4;
++
++        libssh2_htonu32(s, modes_len);
++        s += 4;
++        if (modes) {
++            memcpy(s, modes, modes_len);
++            s += modes_len;
++        }
++
++        channel->reqPTY_state = libssh2_NB_state_created;
++    }
++
++    if (channel->reqPTY_state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, channel->reqPTY_packet,
++                                  channel->reqPTY_packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send pty-request packet", 0);
++            LIBSSH2_FREE(session, channel->reqPTY_packet);
++            channel->reqPTY_packet = NULL;
++            channel->reqPTY_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, channel->reqPTY_packet);
++        channel->reqPTY_packet = NULL;
++
++        libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id);
++
++        channel->reqPTY_state = libssh2_NB_state_sent;
++    }
++
++    if (channel->reqPTY_state == libssh2_NB_state_sent) {
++        rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
++                                        1, channel->reqPTY_local_channel, 4,
++                                        &channel->
++                                        reqPTY_packet_requirev_state);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            channel->reqPTY_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
++            LIBSSH2_FREE(session, data);
++            channel->reqPTY_state = libssh2_NB_state_idle;
++            return 0;
++        }
++    }
++
++    LIBSSH2_FREE(session, data);
++    libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
++                  "Unable to complete request for channel request-pty", 0);
++    channel->reqPTY_state = libssh2_NB_state_idle;
++    return -1;
++}
++
++/* }}} */
++
++LIBSSH2_API int
++libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL * channel, int width,
++                                    int height, int width_px, int height_px)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned char *s;
++    int rc;
++
++    if (channel->reqPTY_state == libssh2_NB_state_idle) {
++        channel->reqPTY_packet_len = 39;
++
++        /* Zero the whole thing out */
++        memset(&channel->reqPTY_packet_requirev_state, 0,
++            sizeof(channel->reqPTY_packet_requirev_state));
++
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++            "changing tty size on channel %lu/%lu",
++            channel->local.id,
++            channel->remote.id);
++
++        s = channel->reqPTY_packet =
++            LIBSSH2_ALLOC(session, channel->reqPTY_packet_len);
++
++        if (!channel->reqPTY_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++            "Unable to allocate memory for pty-request", 0);
++            return -1;
++        }
++
++        *(s++) = SSH_MSG_CHANNEL_REQUEST;
++        libssh2_htonu32(s, channel->remote.id);
++        s += 4;
++        libssh2_htonu32(s, sizeof("window-change") - 1);
++        s += 4;
++        memcpy(s, "window-change", sizeof("window-change") - 1);
++        s += sizeof("window-change") - 1;
++
++        *(s++) = 0x00; /* Don't reply */
++        libssh2_htonu32(s, width);
++        s += 4;
++        libssh2_htonu32(s, height);
++        s += 4;
++        libssh2_htonu32(s, width_px);
++        s += 4;
++        libssh2_htonu32(s, height_px);
++        s += 4;
++
++        channel->reqPTY_state = libssh2_NB_state_created;
++    }
++
++    if (channel->reqPTY_state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, channel->reqPTY_packet,
++        channel->reqPTY_packet_len);
++        if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    } else if (rc) {
++        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++        "Unable to send window-change packet", 0);
++        LIBSSH2_FREE(session, channel->reqPTY_packet);
++        channel->reqPTY_packet = NULL;
++        channel->reqPTY_state = libssh2_NB_state_idle;
++        return -1;
++    }
++    LIBSSH2_FREE(session, channel->reqPTY_packet);
++    channel->reqPTY_packet = NULL;
++    libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id);
++    channel->reqPTY_state = libssh2_NB_state_sent;
++
++    return 0;
++    }
++
++    channel->reqPTY_state = libssh2_NB_state_idle;
++    return -1;
++}
++
++/* Keep this an even number */
++#define LIBSSH2_X11_RANDOM_COOKIE_LEN       32
++
++/* {{{ libssh2_channel_x11_req_ex
++ * Request X11 forwarding
++ */
++LIBSSH2_API int
++libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL * channel, int single_connection,
++                           const char *auth_proto, const char *auth_cookie,
++                           int screen_number)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned char *s, *data;
++    static const unsigned char reply_codes[3] =
++        { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
++    unsigned long data_len;
++    unsigned long proto_len =
++        auth_proto ? strlen(auth_proto) : (sizeof("MIT-MAGIC-COOKIE-1") - 1);
++    unsigned long cookie_len =
++        auth_cookie ? strlen(auth_cookie) : LIBSSH2_X11_RANDOM_COOKIE_LEN;
++    int rc;
++
++    if (channel->reqX11_state == libssh2_NB_state_idle) {
++        /* 30 = packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) +
++         * want_reply(1) + single_cnx(1) + proto_len(4) + cookie_len(4) +
++         * screen_num(4) */
++        channel->reqX11_packet_len = proto_len + cookie_len + 30;
++
++        /* Zero the whole thing out */
++        memset(&channel->reqX11_packet_requirev_state, 0,
++               sizeof(channel->reqX11_packet_requirev_state));
++
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "Requesting x11-req for channel %lu/%lu: single=%d "
++                       "proto=%s cookie=%s screen=%d",
++                       channel->local.id, channel->remote.id,
++                       single_connection,
++                       auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1",
++                       auth_cookie ? auth_cookie : "<random>", screen_number);
++
++        s = channel->reqX11_packet =
++            LIBSSH2_ALLOC(session, channel->reqX11_packet_len);
++        if (!channel->reqX11_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for pty-request", 0);
++            return -1;
++        }
++
++        *(s++) = SSH_MSG_CHANNEL_REQUEST;
++        libssh2_htonu32(s, channel->remote.id);
++        s += 4;
++        libssh2_htonu32(s, sizeof("x11-req") - 1);
++        s += 4;
++        memcpy(s, "x11-req", sizeof("x11-req") - 1);
++        s += sizeof("x11-req") - 1;
++
++        *(s++) = 0x01;          /* want_reply */
++        *(s++) = single_connection ? 0x01 : 0x00;
++
++        libssh2_htonu32(s, proto_len);
++        s += 4;
++        memcpy(s, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", proto_len);
++        s += proto_len;
++
++        libssh2_htonu32(s, cookie_len);
++        s += 4;
++        if (auth_cookie) {
++            memcpy(s, auth_cookie, cookie_len);
++        } else {
++            int i;
++            unsigned char buffer[LIBSSH2_X11_RANDOM_COOKIE_LEN / 2];
++
++            libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2);
++            for(i = 0; i < (LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); i++) {
++                snprintf((char *) s + (i * 2), 2, "%02X", buffer[i]);
++            }
++        }
++        s += cookie_len;
++
++        libssh2_htonu32(s, screen_number);
++        s += 4;
++
++        channel->reqX11_state = libssh2_NB_state_created;
++    }
++
++    if (channel->reqX11_state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, channel->reqX11_packet,
++                                  channel->reqX11_packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        }
++        if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send x11-req packet", 0);
++            LIBSSH2_FREE(session, channel->reqX11_packet);
++            channel->reqX11_packet = NULL;
++            channel->reqX11_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, channel->reqX11_packet);
++        channel->reqX11_packet = NULL;
++
++        libssh2_htonu32(channel->reqX11_local_channel, channel->local.id);
++
++        channel->reqX11_state = libssh2_NB_state_sent;
++    }
++
++    if (channel->reqX11_state == libssh2_NB_state_sent) {
++        rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
++                                        1, channel->reqX11_local_channel, 4,
++                                        &channel->
++                                        reqX11_packet_requirev_state);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            channel->reqX11_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
++            LIBSSH2_FREE(session, data);
++            channel->reqX11_state = libssh2_NB_state_idle;
++            return 0;
++        }
++    }
++
++    LIBSSH2_FREE(session, data);
++    libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
++                  "Unable to complete request for channel x11-req", 0);
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_process_startup
++ * Primitive for libssh2_channel_(shell|exec|subsystem)
++ */
++LIBSSH2_API int
++libssh2_channel_process_startup(LIBSSH2_CHANNEL * channel, const char *request,
++                                unsigned int request_len, const char *message,
++                                unsigned int message_len)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned char *s, *data;
++    static const unsigned char reply_codes[3] =
++        { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
++    unsigned long data_len;
++    libssh2pack_t rc;
++
++    if (channel->process_state == libssh2_NB_state_idle) {
++        /* 10 = packet_type(1) + channel(4) + request_len(4) + want_reply(1) */
++        channel->process_packet_len = request_len + 10;
++
++        /* Zero the whole thing out */
++        memset(&channel->process_packet_requirev_state, 0,
++               sizeof(channel->process_packet_requirev_state));
++
++        if (message) {
++            channel->process_packet_len += message_len + 4;
++        }
++
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "starting request(%s) on channel %lu/%lu, message=%s",
++                       request, channel->local.id, channel->remote.id,
++                       message);
++        s = channel->process_packet =
++            LIBSSH2_ALLOC(session, channel->process_packet_len);
++        if (!channel->process_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for channel-process request",
++                          0);
++            return -1;
++        }
++
++        *(s++) = SSH_MSG_CHANNEL_REQUEST;
++        libssh2_htonu32(s, channel->remote.id);
++        s += 4;
++        libssh2_htonu32(s, request_len);
++        s += 4;
++        memcpy(s, request, request_len);
++        s += request_len;
++
++        *(s++) = 0x01;
++
++        if (message) {
++            libssh2_htonu32(s, message_len);
++            s += 4;
++            memcpy(s, message, message_len);
++            s += message_len;
++        }
++
++        channel->process_state = libssh2_NB_state_created;
++    }
++
++    if (channel->process_state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, channel->process_packet,
++                                  channel->process_packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send channel request", 0);
++            LIBSSH2_FREE(session, channel->process_packet);
++            channel->process_packet = NULL;
++            channel->process_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, channel->process_packet);
++        channel->process_packet = NULL;
++
++        libssh2_htonu32(channel->process_local_channel, channel->local.id);
++
++        channel->process_state = libssh2_NB_state_sent;
++    }
++
++    if (channel->process_state == libssh2_NB_state_sent) {
++        rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
++                                        1, channel->process_local_channel, 4,
++                                        &channel->
++                                        process_packet_requirev_state);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            channel->process_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
++            LIBSSH2_FREE(session, data);
++            channel->process_state = libssh2_NB_state_idle;
++            return 0;
++        }
++    }
++
++    LIBSSH2_FREE(session, data);
++    libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
++                  "Unable to complete request for channel-process-startup", 0);
++    channel->process_state = libssh2_NB_state_idle;
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_set_blocking
++ * Set a channel's blocking mode on or off, similar to a socket's
++ * fcntl(fd, F_SETFL, O_NONBLOCK); type command
++ */
++LIBSSH2_API void
++libssh2_channel_set_blocking(LIBSSH2_CHANNEL * channel, int blocking)
++{
++    (void) _libssh2_session_set_blocking(channel->session, blocking);
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_flush_ex
++ * Flush data from one (or all) stream
++ * Returns number of bytes flushed, or -1 on failure
++ */
++LIBSSH2_API int
++libssh2_channel_flush_ex(LIBSSH2_CHANNEL * channel, int streamid)
++{
++    LIBSSH2_PACKET *packet = channel->session->packets.head;
++
++    if (channel->flush_state == libssh2_NB_state_idle) {
++        channel->flush_refund_bytes = 0;
++        channel->flush_flush_bytes = 0;
++
++        while (packet) {
++            LIBSSH2_PACKET *next = packet->next;
++            unsigned char packet_type = packet->data[0];
++
++            if (((packet_type == SSH_MSG_CHANNEL_DATA)
++                 || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
++                && (libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
++                /* It's our channel at least */
++                long packet_stream_id =
++                    (packet_type ==
++                     SSH_MSG_CHANNEL_DATA) ? 0 : libssh2_ntohu32(packet->data +
++                                                                 5);
++                if ((streamid == LIBSSH2_CHANNEL_FLUSH_ALL)
++                    || ((packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)
++                        && ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA)
++                            || (streamid == packet_stream_id)))
++                    || ((packet_type == SSH_MSG_CHANNEL_DATA)
++                        && (streamid == 0))) {
++                    int bytes_to_flush = packet->data_len - packet->data_head;
++
++                    _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
++                                   "Flushing %d bytes of data from stream "
++                                   "%lu on channel %lu/%lu",
++                                   bytes_to_flush, packet_stream_id,
++                                   channel->local.id, channel->remote.id);
++
++                    /* It's one of the streams we wanted to flush */
++                    channel->flush_refund_bytes += packet->data_len - 13;
++                    channel->flush_flush_bytes += bytes_to_flush;
++
++                    LIBSSH2_FREE(channel->session, packet->data);
++                    if (packet->prev) {
++                        packet->prev->next = packet->next;
++                    } else {
++                        channel->session->packets.head = packet->next;
++                    }
++                    if (packet->next) {
++                        packet->next->prev = packet->prev;
++                    } else {
++                        channel->session->packets.tail = packet->prev;
++                    }
++                    LIBSSH2_FREE(channel->session, packet);
++                }
++            }
++            packet = next;
++        }
++
++        channel->flush_state = libssh2_NB_state_created;
++    }
++
++    if (channel->flush_refund_bytes) {
++        int rc;
++
++        rc = libssh2_channel_receive_window_adjust(channel,
++                                                   channel->flush_refund_bytes,
++                                                   0);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        }
++    }
++
++    channel->flush_state = libssh2_NB_state_idle;
++
++    return channel->flush_flush_bytes;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_get_exit_status
++ * Return the channel's program exit status
++ */
++LIBSSH2_API int
++libssh2_channel_get_exit_status(LIBSSH2_CHANNEL * channel)
++{
++    return channel->exit_status;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_receive_window_adjust
++ * Adjust the receive window for a channel by adjustment bytes
++ * If the amount to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and
++ * force is 0 the adjustment amount will be queued for a later packet
++ *
++ * Returns the new size of the receive window (as understood by remote end)
++ */
++LIBSSH2_API unsigned long
++libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
++                                      unsigned long adjustment,
++                                      unsigned char force)
++{
++    int rc;
++
++    if (channel->adjust_state == libssh2_NB_state_idle) {
++        if (!force
++            && (adjustment + channel->adjust_queue <
++                LIBSSH2_CHANNEL_MINADJUST)) {
++            _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
++                           "Queueing %lu bytes for receive window adjustment "
++                           "for channel %lu/%lu",
++                           adjustment, channel->local.id, channel->remote.id);
++            channel->adjust_queue += adjustment;
++            return channel->remote.window_size;
++        }
++
++        if (!adjustment && !channel->adjust_queue) {
++            return channel->remote.window_size;
++        }
++
++        adjustment += channel->adjust_queue;
++        channel->adjust_queue = 0;
++
++
++        /* Adjust the window based on the block we just freed */
++        channel->adjust_adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST;
++        libssh2_htonu32(channel->adjust_adjust + 1, channel->remote.id);
++        libssh2_htonu32(channel->adjust_adjust + 5, adjustment);
++        _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
++                       "Adjusting window %lu bytes for data flushed from "
++                       "channel %lu/%lu",
++                       adjustment, channel->local.id, channel->remote.id);
++
++        channel->adjust_state = libssh2_NB_state_created;
++    }
++
++    rc = libssh2_packet_write(channel->session, channel->adjust_adjust, 9);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    } else if (rc) {
++        libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND,
++                      "Unable to send transfer-window adjustment packet, "
++                      "deferring",
++                      0);
++        channel->adjust_queue = adjustment;
++        channel->adjust_state = libssh2_NB_state_idle;
++    } else {
++        channel->adjust_state = libssh2_NB_state_idle;
++        channel->remote.window_size += adjustment;
++    }
++
++    return channel->remote.window_size;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_handle_extended_data
++ *
++ * How should extended data look to the calling app?  Keep it in separate
++ * channels[_read() _read_stdder()]? (NORMAL) Merge the extended data to the
++ * standard data? [everything via _read()]? (MERGE) Ignore it entirely [toss
++ * out packets as they come in]? (IGNORE)
++ */
++LIBSSH2_API void
++libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL * channel,
++                                     int ignore_mode)
++{
++    while (libssh2_channel_handle_extended_data2(channel, ignore_mode) ==
++           PACKET_EAGAIN);
++}
++
++LIBSSH2_API int
++libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL * channel,
++                                      int ignore_mode)
++{
++    if (channel->extData2_state == libssh2_NB_state_idle) {
++        _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
++                       "Setting channel %lu/%lu handle_extended_data mode to %d",
++                       channel->local.id, channel->remote.id, ignore_mode);
++        channel->remote.extended_data_ignore_mode = ignore_mode;
++
++        channel->extData2_state = libssh2_NB_state_created;
++    }
++
++    if (channel->extData2_state == libssh2_NB_state_idle) {
++        if (ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) {
++            if (libssh2_channel_flush_ex
++                (channel,
++                 LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA) == PACKET_EAGAIN) {
++                return PACKET_EAGAIN;
++            }
++        }
++    }
++
++    channel->extData2_state = libssh2_NB_state_idle;
++    return 0;
++}
++
++/* }}} */
++
++/*
++ * {{{ libssh2_channel_read_ex
++ * Read data from a channel blocking or non-blocking depending on set state
++ *
++ * When this is done non-blocking, it is important to not return 0 until the
++ * currently read channel is complete. If we read stuff from the wire but it
++ * was no payload data to fill in the buffer with, we MUST make sure to return
++ * PACKET_EAGAIN.
++ */
++LIBSSH2_API ssize_t
++libssh2_channel_read_ex(LIBSSH2_CHANNEL * channel, int stream_id, char *buf,
++                        size_t buflen)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    libssh2pack_t rc = 0;
++
++    if (channel->read_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "Attempting to read %d bytes from channel %lu/%lu stream #%d",
++                       (int) buflen, channel->local.id, channel->remote.id,
++                       stream_id);
++
++        /* process all incoming packets */
++        do {
++            if (libssh2_waitsocket(session, 0) > 0) {
++                rc = libssh2_packet_read(session);
++            } else {
++                /* Set for PACKET_EAGAIN so we continue */
++                rc = PACKET_EAGAIN;
++            }
++        } while (rc > 0);
++
++        if ((rc < 0) && (rc != PACKET_EAGAIN)) {
++            return rc;
++        }
++        channel->read_bytes_read = 0;
++
++        channel->read_packet = session->packets.head;
++        channel->read_state = libssh2_NB_state_created;
++    }
++
++    /*
++     * =============================== NOTE ===============================
++     * I know this is very ugly and not a really good use of "goto", but
++     * this case statement would be even uglier to do it any other way
++     */
++    if (channel->read_state == libssh2_NB_state_jump1) {
++        goto channel_read_ex_point1;
++    }
++
++    rc = 0;
++    channel->read_block = 0;
++
++    do {
++        if (channel->read_block) {
++            /* in the second lap and onwards, do this...
++             * If we haven't yet filled our buffer, try to read more
++             * data.  */
++            if ( channel->read_bytes_read < (int) buflen) {
++                rc = libssh2_packet_read(session);
++
++                /* If we didn't find any more data to read */
++                if (rc < 0) {
++                    if ( channel->read_bytes_read > 0){
++                        break;  /* finish processing and return */
++                    }
++
++                    /* no packets available, no data read. */
++                    channel->read_state = libssh2_NB_state_idle;
++                    return rc;
++                }
++                /* We read more data, restart our processing at the beginning
++                 * of our packet list. */
++                channel->read_packet = session->packets.head;
++            }
++            else { /* The read buffer is full, finish processing and return */
++                break;
++            }
++        }
++
++        while (channel->read_packet
++               && (channel->read_bytes_read < (int) buflen)) {
++            /* In case packet gets destroyed during this iteration */
++            channel->read_next = channel->read_packet->next;
++
++            channel->read_local_id =
++                libssh2_ntohu32(channel->read_packet->data + 1);
++
++            /*
++             * Either we asked for a specific extended data stream
++             * (and data was available),
++             * or the standard stream (and data was available),
++             * or the standard stream with extended_data_merge
++             * enabled and data was available
++             */
++            if ((stream_id
++                 && (channel->read_packet->data[0] ==
++                     SSH_MSG_CHANNEL_EXTENDED_DATA)
++                 && (channel->local.id == channel->read_local_id)
++                 && (stream_id ==
++                     (int) libssh2_ntohu32(channel->read_packet->data + 5)))
++                || (!stream_id
++                    && (channel->read_packet->data[0] == SSH_MSG_CHANNEL_DATA)
++                    && (channel->local.id == channel->read_local_id))
++                || (!stream_id
++                    && (channel->read_packet->data[0] ==
++                        SSH_MSG_CHANNEL_EXTENDED_DATA)
++                    && (channel->local.id == channel->read_local_id)
++                    && (channel->remote.extended_data_ignore_mode ==
++                        LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) {
++
++                channel->read_want = buflen - channel->read_bytes_read;
++                channel->read_unlink_packet = 0;
++
++                if (channel->read_want >=
++                    (int) (channel->read_packet->data_len -
++                           channel->read_packet->data_head)) {
++                    channel->read_want =
++                        channel->read_packet->data_len -
++                        channel->read_packet->data_head;
++                    channel->read_unlink_packet = 1;
++                }
++
++                _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                               "Reading %d of buffered data from %lu/%lu/%d",
++                               channel->read_want, channel->local.id,
++                               channel->remote.id, stream_id);
++                memcpy(buf + channel->read_bytes_read,
++                       channel->read_packet->data +
++                       channel->read_packet->data_head, channel->read_want);
++                channel->read_packet->data_head += channel->read_want;
++                channel->read_bytes_read += channel->read_want;
++
++                if (channel->read_unlink_packet) {
++                    if (channel->read_packet->prev) {
++                        channel->read_packet->prev->next =
++                            channel->read_packet->next;
++                    } else {
++                        session->packets.head = channel->read_packet->next;
++                    }
++                    if (channel->read_packet->next) {
++                        channel->read_packet->next->prev =
++                            channel->read_packet->prev;
++                    } else {
++                        session->packets.tail = channel->read_packet->prev;
++                    }
++                    LIBSSH2_FREE(session, channel->read_packet->data);
++
++
++                    _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                                   "Unlinking empty packet buffer from "
++                                   "channel %lu/%lu",
++                                   channel->local.id, channel->remote.id);
++                  channel_read_ex_point1:
++                    channel->read_state = libssh2_NB_state_jump1;
++                    rc = libssh2_channel_receive_window_adjust(channel,
++                                                               channel->
++                                                               read_packet->
++                                                               data_len -
++                                                               (stream_id ? 13
++                                                                : 9), 0);
++                    if (rc == PACKET_EAGAIN) {
++                        return PACKET_EAGAIN;
++                    }
++                    channel->read_state = libssh2_NB_state_created;
++                    LIBSSH2_FREE(session, channel->read_packet);
++                    channel->read_packet = NULL;
++                }
++            }
++            channel->read_packet = channel->read_next;
++        }
++        channel->read_block = 1;
++    } while ((channel->read_bytes_read == 0) && !channel->remote.close);
++
++    channel->read_state = libssh2_NB_state_idle;
++    if (channel->read_bytes_read == 0) {
++        if (channel->session->socket_block) {
++            libssh2_error(session, LIBSSH2_ERROR_CHANNEL_CLOSED,
++                          "Remote end has closed this channel", 0);
++        } else {
++            /*
++             * when non-blocking, we must return PACKET_EAGAIN if we haven't
++             * completed reading the channel
++             */
++            if (!libssh2_channel_eof(channel)) {
++                return PACKET_EAGAIN;
++            }
++        }
++    }
++
++    channel->read_state = libssh2_NB_state_idle;
++    return channel->read_bytes_read;
++}
++
++/* }}} */
++
++/*
++ * {{{ libssh2_channel_packet_data_len
++ * Return the size of the data block of the current packet, or 0 if there
++ * isn't a packet.
++ */
++unsigned long
++libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    LIBSSH2_PACKET *read_packet;
++    uint32_t read_local_id;
++
++    if ((read_packet = session->packets.head) == NULL) {
++        return 0;
++    }
++
++    while (read_packet) {
++        read_local_id = libssh2_ntohu32(read_packet->data + 1);
++
++        /*
++         * Either we asked for a specific extended data stream
++         * (and data was available),
++         * or the standard stream (and data was available),
++         * or the standard stream with extended_data_merge
++         * enabled and data was available
++         */
++        if ((stream_id
++             && (read_packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)
++             && (channel->local.id == read_local_id)
++             && (stream_id == (int) libssh2_ntohu32(read_packet->data + 5)))
++            || (!stream_id && (read_packet->data[0] == SSH_MSG_CHANNEL_DATA)
++                && (channel->local.id == read_local_id)) ||
++            (!stream_id
++             && (read_packet->
++                 data[0] ==
++                 SSH_MSG_CHANNEL_EXTENDED_DATA)
++             && (channel->
++                 local.id ==
++                 read_local_id)
++             && (channel->
++                 remote.
++                 extended_data_ignore_mode
++                 ==
++                 LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE)))
++        {
++            return (read_packet->data_len - read_packet->data_head);
++        }
++        read_packet = read_packet->next;
++    }
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_write_ex
++ * Send data to a channel
++ */
++LIBSSH2_API ssize_t
++libssh2_channel_write_ex(LIBSSH2_CHANNEL * channel, int stream_id,
++                         const char *buf, size_t buflen)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    libssh2pack_t rc;
++
++    if (channel->write_state == libssh2_NB_state_idle) {
++        channel->write_bufwrote = 0;
++
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "Writing %d bytes on channel %lu/%lu, stream #%d",
++                       (int) buflen, channel->local.id, channel->remote.id,
++                       stream_id);
++
++        if (channel->local.close) {
++            libssh2_error(session, LIBSSH2_ERROR_CHANNEL_CLOSED,
++                          "We've already closed this channel", 0);
++            return -1;
++        }
++
++        if (channel->local.eof) {
++            libssh2_error(session, LIBSSH2_ERROR_CHANNEL_EOF_SENT,
++                          "EOF has already been sight, data might be ignored",
++                          0);
++        }
++
++        /* [13] 9 = packet_type(1) + channelno(4) [ + streamid(4) ] +
++           buflen(4) */
++        channel->write_packet_len = buflen + (stream_id ? 13 : 9);
++        channel->write_packet =
++            LIBSSH2_ALLOC(session, channel->write_packet_len);
++        if (!channel->write_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocte space for data transmission packet",
++                          0);
++            return -1;
++        }
++
++        channel->write_state = libssh2_NB_state_allocated;
++    }
++
++    while (buflen > 0) {
++        if (channel->write_state == libssh2_NB_state_allocated) {
++            channel->write_bufwrite = buflen;
++            channel->write_s = channel->write_packet;
++
++            *(channel->write_s++) =
++                stream_id ? SSH_MSG_CHANNEL_EXTENDED_DATA :
++                SSH_MSG_CHANNEL_DATA;
++            libssh2_htonu32(channel->write_s, channel->remote.id);
++            channel->write_s += 4;
++            if (stream_id) {
++                libssh2_htonu32(channel->write_s, stream_id);
++                channel->write_s += 4;
++            }
++
++            /* twiddle our thumbs until there's window space available */
++            while (channel->local.window_size <= 0) {
++                /* Don't worry -- This is never hit unless it's a
++                   blocking channel anyway */
++                rc = libssh2_packet_read(session);
++
++                if (rc < 0) {
++                    /* Error or EAGAIN occurred, disconnect? */
++                    if (rc != PACKET_EAGAIN) {
++                        channel->write_state = libssh2_NB_state_idle;
++                    }
++                    return rc;
++                }
++
++                if ((rc == 0) && (session->socket_block == 0)) {
++                    /*
++                     * if rc == 0 and in non-blocking, then fake EAGAIN
++                     * to prevent busyloops until data arriaves on the network
++                     * which seemed like a very bad idea
++                     */
++                    return PACKET_EAGAIN;
++                }
++            }
++
++            /* Don't exceed the remote end's limits */
++            /* REMEMBER local means local as the SOURCE of the data */
++            if (channel->write_bufwrite > channel->local.window_size) {
++                _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                               "Splitting write block due to %lu byte "
++                               "window_size on %lu/%lu/%d",
++                               channel->local.window_size, channel->local.id,
++                               channel->remote.id, stream_id);
++                channel->write_bufwrite = channel->local.window_size;
++            }
++            if (channel->write_bufwrite > channel->local.packet_size) {
++                _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                               "Splitting write block due to %lu byte "
++                               "packet_size on %lu/%lu/%d",
++                               channel->local.packet_size, channel->local.id,
++                               channel->remote.id, stream_id);
++                channel->write_bufwrite = channel->local.packet_size;
++            }
++            libssh2_htonu32(channel->write_s, channel->write_bufwrite);
++            channel->write_s += 4;
++            memcpy(channel->write_s, buf, channel->write_bufwrite);
++            channel->write_s += channel->write_bufwrite;
++
++            _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                           "Sending %d bytes on channel %lu/%lu, stream_id=%d",
++                           (int) channel->write_bufwrite, channel->local.id,
++                           channel->remote.id, stream_id);
++
++            channel->write_state = libssh2_NB_state_created;
++        }
++
++        if (channel->write_state == libssh2_NB_state_created) {
++            rc = libssh2_packet_write(session, channel->write_packet,
++                                      channel->write_s -
++                                      channel->write_packet);
++            if (rc == PACKET_EAGAIN) {
++                _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                               "libssh2_packet_write returned EAGAIN");
++                return PACKET_EAGAIN;
++            }
++            else if (rc) {
++                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                              "Unable to send channel data", 0);
++                LIBSSH2_FREE(session, channel->write_packet);
++                channel->write_packet = NULL;
++                channel->write_state = libssh2_NB_state_idle;
++                return -1;
++            }
++            /* Shrink local window size */
++            channel->local.window_size -= channel->write_bufwrite;
++
++            /* Adjust buf for next iteration */
++            buflen -= channel->write_bufwrite;
++            buf += channel->write_bufwrite;
++            channel->write_bufwrote += channel->write_bufwrite;
++
++            channel->write_state = libssh2_NB_state_allocated;
++
++            /*
++             * Not sure this is still wanted
++             if (!channel->session->socket_block) {
++             break;
++             }
++             */
++        }
++    }
++
++    LIBSSH2_FREE(session, channel->write_packet);
++    channel->write_packet = NULL;
++
++    channel->write_state = libssh2_NB_state_idle;
++
++    return channel->write_bufwrote;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_send_eof
++ * Send EOF on channel
++ */
++LIBSSH2_API int
++libssh2_channel_send_eof(LIBSSH2_CHANNEL * channel)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned char packet[5];    /* packet_type(1) + channelno(4) */
++    int rc;
++
++    _libssh2_debug(session, LIBSSH2_DBG_CONN, "Sending EOF on channel %lu/%lu",
++                   channel->local.id, channel->remote.id);
++    packet[0] = SSH_MSG_CHANNEL_EOF;
++    libssh2_htonu32(packet + 1, channel->remote.id);
++    rc = libssh2_packet_write(session, packet, 5);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    } else if (rc) {
++        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                      "Unable to send EOF on channel", 0);
++        return -1;
++    }
++    channel->local.eof = 1;
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_eof
++ * Read channel's eof status
++ */
++LIBSSH2_API int
++libssh2_channel_eof(LIBSSH2_CHANNEL * channel)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    LIBSSH2_PACKET *packet = session->packets.head;
++
++    while (packet) {
++        if (((packet->data[0] == SSH_MSG_CHANNEL_DATA)
++             || (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA))
++            && (channel->local.id == libssh2_ntohu32(packet->data + 1))) {
++            /* There's data waiting to be read yet, mask the EOF status */
++            return 0;
++        }
++        packet = packet->next;
++    }
++
++    return channel->remote.eof;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_wait_eof
++* Awaiting channel EOF
++*/
++LIBSSH2_API int
++libssh2_channel_wait_eof(LIBSSH2_CHANNEL * channel)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    int rc;
++
++    if (channel->wait_eof_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "Awaiting close of channel %lu/%lu", channel->local.id,
++                       channel->remote.id);
++
++        channel->wait_eof_state = libssh2_NB_state_created;
++    }
++
++    /*
++     * While channel is not eof, read more packets from the network.
++     * Either the EOF will be set or network timeout will occur.
++     */
++    do {
++        if (channel->remote.eof) {
++            break;
++        }
++        rc = libssh2_packet_read(session);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc < 0) {
++            channel->wait_eof_state = libssh2_NB_state_idle;
++            return -1;
++        }
++    } while (1);
++
++    channel->wait_eof_state = libssh2_NB_state_idle;
++
++    return 0;
++}
++
++/* }}} */
++
++
++/* {{{ libssh2_channel_close
++ * Close a channel
++ */
++LIBSSH2_API int
++libssh2_channel_close(LIBSSH2_CHANNEL * channel)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    int rc = 0;
++    int retcode;
++
++    if (channel->local.close) {
++        /* Already closed, act like we sent another close,
++         * even though we didn't... shhhhhh */
++        channel->close_state = libssh2_NB_state_idle;
++        return 0;
++    }
++
++    if (channel->close_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_CONN, "Closing channel %lu/%lu",
++                       channel->local.id, channel->remote.id);
++
++        if (channel->close_cb) {
++            LIBSSH2_CHANNEL_CLOSE(session, channel);
++        }
++        channel->local.close = 1;
++
++        channel->close_packet[0] = SSH_MSG_CHANNEL_CLOSE;
++        libssh2_htonu32(channel->close_packet + 1, channel->remote.id);
++
++        channel->close_state = libssh2_NB_state_created;
++    }
++
++    if (channel->close_state == libssh2_NB_state_created) {
++        retcode = libssh2_packet_write(session, channel->close_packet, 5);
++        if (retcode == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (retcode) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send close-channel request", 0);
++            channel->close_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        channel->close_state = libssh2_NB_state_sent;
++    }
++
++    if (channel->close_state == libssh2_NB_state_sent) {
++        /* We must wait for the remote SSH_MSG_CHANNEL_CLOSE message */
++        if (!channel->remote.close) {
++            libssh2pack_t ret;
++
++            do {
++                ret = libssh2_packet_read(session);
++                if (ret == PACKET_EAGAIN) {
++                    return PACKET_EAGAIN;
++                } else if (ret < 0) {
++                    rc = -1;
++                }
++            } while ((ret != SSH_MSG_CHANNEL_CLOSE) && (rc == 0));
++        }
++    }
++
++    channel->close_state = libssh2_NB_state_idle;
++
++    return rc;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_wait_closed
++ * Awaiting channel close after EOF
++ */
++LIBSSH2_API int
++libssh2_channel_wait_closed(LIBSSH2_CHANNEL * channel)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    int rc;
++
++    if (!libssh2_channel_eof(channel)) {
++        libssh2_error(session, LIBSSH2_ERROR_INVAL,
++                      "libssh2_channel_wait_closed() invoked when channel is "
++                      "not in EOF state",
++                      0);
++        return -1;
++    }
++
++    if (channel->wait_closed_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "Awaiting close of channel %lu/%lu", channel->local.id,
++                       channel->remote.id);
++
++        channel->wait_closed_state = libssh2_NB_state_created;
++    }
++
++    /*
++     * While channel is not closed, read more packets from the network.
++     * Either the channel will be closed or network timeout will occur.
++     */
++    do {
++        if (!channel->remote.close) {
++            break;
++        }
++        rc = libssh2_packet_read(session);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc <= 0) {
++            break;
++        }
++    } while (1);
++
++    channel->wait_closed_state = libssh2_NB_state_idle;
++
++    return 0;
++}
++
++/* }}} */
++
++
++/* {{{ libssh2_channel_free
++ * Make sure a channel is closed, then remove the channel from the session
++ * and free its resource(s)
++ *
++ * Returns 0 on success, -1 on failure
++ */
++LIBSSH2_API int
++libssh2_channel_free(LIBSSH2_CHANNEL * channel)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned char channel_id[4];
++    unsigned char *data;
++    unsigned long data_len;
++    int rc;
++
++    if (channel->free_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                       "Freeing channel %lu/%lu resources", channel->local.id,
++                       channel->remote.id);
++
++        channel->free_state = libssh2_NB_state_created;
++    }
++
++    /* Allow channel freeing even when the socket has lost its connection */
++    if (!channel->local.close
++        && (session->socket_state == LIBSSH2_SOCKET_CONNECTED)) {
++        while ((rc = libssh2_channel_close(channel)) == PACKET_EAGAIN);
++        if (rc) {
++            channel->free_state = libssh2_NB_state_idle;
++            return -1;
++        }
++    }
++
++    channel->free_state = libssh2_NB_state_idle;
++
++    /*
++     * channel->remote.close *might* not be set yet, Well...
++     * We've sent the close packet, what more do you want?
++     * Just let packet_add ignore it when it finally arrives
++     */
++
++    /* Clear out packets meant for this channel */
++    libssh2_htonu32(channel_id, channel->local.id);
++    while ((libssh2_packet_ask_ex
++            (session, SSH_MSG_CHANNEL_DATA, &data, &data_len, 1, channel_id, 4,
++             0) >= 0)
++           ||
++           (libssh2_packet_ask_ex
++            (session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, &data_len, 1,
++             channel_id, 4, 0) >= 0)) {
++        LIBSSH2_FREE(session, data);
++    }
++
++    /* free "channel_type" */
++    if (channel->channel_type) {
++        LIBSSH2_FREE(session, channel->channel_type);
++    }
++
++    /* Unlink from channel brigade */
++    if (channel->prev) {
++        channel->prev->next = channel->next;
++    } else {
++        session->channels.head = channel->next;
++    }
++    if (channel->next) {
++        channel->next->prev = channel->prev;
++    } else {
++        session->channels.tail = channel->prev;
++    }
++
++    /*
++     * Make sure all memory used in the state variables are free
++     */
++    if (channel->setenv_packet) {
++        LIBSSH2_FREE(session, channel->setenv_packet);
++    }
++    if (channel->reqPTY_packet) {
++        LIBSSH2_FREE(session, channel->reqPTY_packet);
++    }
++    if (channel->reqX11_packet) {
++        LIBSSH2_FREE(session, channel->reqX11_packet);
++    }
++    if (channel->process_packet) {
++        LIBSSH2_FREE(session, channel->process_packet);
++    }
++    if (channel->write_packet) {
++        LIBSSH2_FREE(session, channel->write_packet);
++    }
++
++    LIBSSH2_FREE(session, channel);
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_window_read_ex
++ *
++ * Check the status of the read window. Returns the number of bytes which the
++ * remote end may send without overflowing the window limit read_avail (if
++ * passed) will be populated with the number of bytes actually available to be
++ * read window_size_initial (if passed) will be populated with the
++ * window_size_initial as defined by the channel_open request
++ */
++LIBSSH2_API unsigned long
++libssh2_channel_window_read_ex(LIBSSH2_CHANNEL * channel,
++                               unsigned long *read_avail,
++                               unsigned long *window_size_initial)
++{
++    if (window_size_initial) {
++        *window_size_initial = channel->remote.window_size_initial;
++    }
++
++    if (read_avail) {
++        unsigned long bytes_queued = 0;
++        LIBSSH2_PACKET *packet = channel->session->packets.head;
++
++        while (packet) {
++            unsigned char packet_type = packet->data[0];
++
++            if (((packet_type == SSH_MSG_CHANNEL_DATA)
++                 || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
++                && (libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
++                bytes_queued += packet->data_len - packet->data_head;
++            }
++
++            packet = packet->next;
++        }
++
++        *read_avail = bytes_queued;
++    }
++
++    return channel->remote.window_size;
++}
++
++/* }}} */
++
++/* {{{ libssh2_channel_window_write_ex
++ *
++ * Check the status of the write window Returns the number of bytes which may
++ * be safely writen on the channel without blocking window_size_initial (if
++ * passed) will be populated with the size of the initial window as defined by
++ * the channel_open request
++ */
++LIBSSH2_API unsigned long
++libssh2_channel_window_write_ex(LIBSSH2_CHANNEL * channel,
++                                unsigned long *window_size_initial)
++{
++    if (window_size_initial) {
++        /* For locally initiated channels this is very often 0, so it's not
++         * *that* useful as information goes */
++        *window_size_initial = channel->local.window_size_initial;
++    }
++
++    return channel->local.window_size;
++}
++
++/* }}} */
+
+Property changes on: libssh2/src/channel.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.2
+Added: svn:eol-style
+   + native
+
+Index: libssh2/src/libssh2_priv.h
+===================================================================
+--- libssh2/src/libssh2_priv.h (.../tags/RELEASE_0_11_0)
++++ libssh2/src/libssh2_priv.h (.../trunk)
+@@ -0,0 +1,1211 @@
++/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
++ */
++
++#ifndef LIBSSH2_PRIV_H
++#define LIBSSH2_PRIV_H 1
++
++#define LIBSSH2_LIBRARY
++#include "libssh2_config.h"
++
++#ifdef HAVE_WINDOWS_H
++#include <windows.h>
++#endif
++
++#ifdef HAVE_WS2TCPIP_H
++#include <ws2tcpip.h>
++#endif
++
++#include <stdio.h>
++#include <time.h>
++
++/* The following CPP block should really only be in session.c and
++   packet.c.  However, AIX have #define's for 'events' and 'revents'
++   and we are using those names in libssh2.h, so we need to include
++   the AIX headers first, to make sure all code is compiled with
++   consistent names of these fields.  While arguable the best would to
++   change libssh2.h to use other names, that would break backwards
++   compatibility.  For more information, see:
++   http://www.mail-archive.com/libssh2-devel%40lists.sourceforge.net/msg00003.html
++   http://www.mail-archive.com/libssh2-devel%40lists.sourceforge.net/msg00224.html
++*/
++#ifdef HAVE_POLL
++# include <sys/poll.h>
++#else
++# if defined(HAVE_SELECT) && !defined(WIN32)
++# ifdef HAVE_SYS_SELECT_H
++# include <sys/select.h>
++# else
++# include <sys/time.h>
++# include <sys/types.h>
++# endif
++# endif
++#endif
++
++#include "libssh2.h"
++#include "libssh2_publickey.h"
++#include "libssh2_sftp.h"
++
++/* Provide iovec / writev on WIN32 platform. */
++#ifdef WIN32
++
++/* same as WSABUF */
++struct iovec {
++      u_long iov_len;
++      char *iov_base;
++};
++
++#define inline __inline
++
++static inline int writev(int sock, struct iovec *iov, int nvecs)
++{
++      DWORD ret;
++      if (WSASend(sock, (LPWSABUF)iov, nvecs, &ret, 0, NULL, NULL) == 0) {
++              return ret;
++      }
++      return -1;
++}
++
++#endif /* WIN32 */
++
++/* Needed for struct iovec on some platforms */
++#ifdef HAVE_SYS_UIO_H
++#include <sys/uio.h>
++#endif
++
++#ifdef HAVE_SYS_SOCKET_H
++# include <sys/socket.h>
++#endif
++#ifdef HAVE_SYS_IOCTL_H
++# include <sys/ioctl.h>
++#endif
++#ifdef HAVE_INTTYPES_H
++#include <inttypes.h>
++#endif
++
++#ifdef LIBSSH2_LIBGCRYPT
++#include "libgcrypt.h"
++#else
++#include "openssl.h"
++#endif
++
++#ifdef HAVE_WINSOCK2_H
++
++#include <winsock2.h>
++#include <mswsock.h>
++#include <ws2tcpip.h>
++
++#ifdef _MSC_VER
++/* "inline" keyword is valid only with C++ engine! */
++#define inline __inline
++#endif
++
++/* not really usleep, but safe for the way we use it in this lib */
++static inline int usleep(int udelay)
++{
++      Sleep(udelay / 1000);
++      return 0;
++}
++
++#endif
++
++/* RFC4253 section 6.1 Maximum Packet Length says:
++ *
++ * "All implementations MUST be able to process packets with
++ * uncompressed payload length of 32768 bytes or less and
++ * total packet size of 35000 bytes or less (including length,
++ * padding length, payload, padding, and MAC.)."
++ */
++#define MAX_SSH_PACKET_LEN 35000
++
++#define LIBSSH2_ALLOC(session, count)                               session->alloc((count), &(session)->abstract)
++#define LIBSSH2_REALLOC(session, ptr, count)                        ((ptr) ? session->realloc((ptr), (count), &(session)->abstract) : session->alloc((count), &(session)->abstract))
++#define LIBSSH2_FREE(session, ptr)                                  session->free((ptr), &(session)->abstract)
++
++#define LIBSSH2_IGNORE(session, data, datalen)                      session->ssh_msg_ignore((session), (data), (datalen), &(session)->abstract)
++#define LIBSSH2_DEBUG(session, always_display, message, message_len, language, language_len)    \
++                session->ssh_msg_disconnect((session), (always_display), (message), (message_len), (language), (language_len), &(session)->abstract)
++#define LIBSSH2_DISCONNECT(session, reason, message, message_len, language, language_len)   \
++                session->ssh_msg_disconnect((session), (reason), (message), (message_len), (language), (language_len), &(session)->abstract)
++
++#define LIBSSH2_MACERROR(session, data, datalen)                    session->macerror((session), (data), (datalen), &(session)->abstract)
++#define LIBSSH2_X11_OPEN(channel, shost, sport)                     channel->session->x11(((channel)->session), (channel), (shost), (sport), (&(channel)->session->abstract))
++
++#define LIBSSH2_CHANNEL_CLOSE(session, channel)                     channel->close_cb((session), &(session)->abstract, (channel), &(channel)->abstract)
++
++typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD;
++typedef struct _LIBSSH2_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD;
++typedef struct _LIBSSH2_MAC_METHOD LIBSSH2_MAC_METHOD;
++typedef struct _LIBSSH2_CRYPT_METHOD LIBSSH2_CRYPT_METHOD;
++typedef struct _LIBSSH2_COMP_METHOD LIBSSH2_COMP_METHOD;
++
++typedef struct _LIBSSH2_PACKET LIBSSH2_PACKET;
++typedef struct _LIBSSH2_PACKET_BRIGADE LIBSSH2_PACKET_BRIGADE;
++typedef struct _LIBSSH2_CHANNEL_BRIGADE LIBSSH2_CHANNEL_BRIGADE;
++
++typedef int libssh2pack_t;
++
++typedef enum
++{
++    libssh2_NB_state_idle = 0,
++    libssh2_NB_state_allocated,
++    libssh2_NB_state_created,
++    libssh2_NB_state_sent,
++    libssh2_NB_state_sent1,
++    libssh2_NB_state_sent2,
++    libssh2_NB_state_sent3,
++    libssh2_NB_state_sent4,
++    libssh2_NB_state_sent5,
++    libssh2_NB_state_sent6,
++    libssh2_NB_state_sent7,
++    libssh2_NB_state_jump1,
++    libssh2_NB_state_jump2,
++    libssh2_NB_state_jump3
++} libssh2_nonblocking_states;
++
++typedef struct packet_require_state_t
++{
++    libssh2_nonblocking_states state;
++    time_t start;
++} packet_require_state_t;
++
++typedef struct packet_requirev_state_t
++{
++    time_t start;
++} packet_requirev_state_t;
++
++typedef struct kmdhgGPsha1kex_state_t
++{
++    libssh2_nonblocking_states state;
++    unsigned char *e_packet;
++    unsigned char *s_packet;
++    unsigned char *tmp;
++    unsigned char h_sig_comp[SHA_DIGEST_LENGTH];
++    unsigned char c;
++    unsigned long e_packet_len;
++    unsigned long s_packet_len;
++    unsigned long tmp_len;
++    _libssh2_bn_ctx *ctx;
++    _libssh2_bn *x;
++    _libssh2_bn *e;
++    _libssh2_bn *f;
++    _libssh2_bn *k;
++    unsigned char *s;
++    unsigned char *f_value;
++    unsigned char *k_value;
++    unsigned char *h_sig;
++    unsigned long f_value_len;
++    unsigned long k_value_len;
++    unsigned long h_sig_len;
++    libssh2_sha1_ctx exchange_hash;
++    packet_require_state_t req_state;
++    libssh2_nonblocking_states burn_state;
++} kmdhgGPsha1kex_state_t;
++
++typedef struct key_exchange_state_low_t
++{
++    libssh2_nonblocking_states state;
++    packet_require_state_t req_state;
++    kmdhgGPsha1kex_state_t exchange_state;
++    _libssh2_bn *p;             /* SSH2 defined value (p_value) */
++    _libssh2_bn *g;             /* SSH2 defined value (2) */
++    unsigned char request[13];
++    unsigned char *data;
++    unsigned long request_len;
++    unsigned long data_len;
++} key_exchange_state_low_t;
++
++typedef struct key_exchange_state_t
++{
++    libssh2_nonblocking_states state;
++    packet_require_state_t req_state;
++    key_exchange_state_low_t key_state_low;
++    unsigned char *data;
++    unsigned long data_len;
++    unsigned char *oldlocal;
++    unsigned long oldlocal_len;
++} key_exchange_state_t;
++
++#define FwdNotReq "Forward not requested"
++
++typedef struct packet_queue_listener_state_t
++{
++    libssh2_nonblocking_states state;
++    unsigned char packet[17 + (sizeof(FwdNotReq) - 1)];
++    unsigned char *host;
++    unsigned char *shost;
++    uint32_t sender_channel;
++    uint32_t initial_window_size;
++    uint32_t packet_size;
++    uint32_t port;
++    uint32_t sport;
++    uint32_t host_len;
++    uint32_t shost_len;
++} packet_queue_listener_state_t;
++
++#define X11FwdUnAvil "X11 Forward Unavailable"
++
++typedef struct packet_x11_open_state_t
++{
++    libssh2_nonblocking_states state;
++    unsigned char packet[17 + (sizeof(X11FwdUnAvil) - 1)];
++    unsigned char *shost;
++    uint32_t sender_channel;
++    uint32_t initial_window_size;
++    uint32_t packet_size;
++    uint32_t sport;
++    uint32_t shost_len;
++} packet_x11_open_state_t;
++
++struct _LIBSSH2_PACKET
++{
++    unsigned char type;
++
++    /* Unencrypted Payload (no type byte, no padding, just the facts ma'am) */
++    unsigned char *data;
++    unsigned long data_len;
++
++    /* Where to start reading data from,
++     * used for channel data that's been partially consumed */
++    unsigned long data_head;
++
++    /* Can the message be confirmed? */
++    int mac;
++
++    LIBSSH2_PACKET_BRIGADE *brigade;
++
++    LIBSSH2_PACKET *next, *prev;
++};
++
++struct _LIBSSH2_PACKET_BRIGADE
++{
++    LIBSSH2_PACKET *head, *tail;
++};
++
++typedef struct _libssh2_channel_data
++{
++    /* Identifier */
++    unsigned long id;
++
++    /* Limits and restrictions */
++    unsigned long window_size_initial, window_size, packet_size;
++
++    /* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */
++    char close, eof, extended_data_ignore_mode;
++} libssh2_channel_data;
++
++struct _LIBSSH2_CHANNEL
++{
++    unsigned char *channel_type;
++    unsigned channel_type_len;
++
++    /* channel's program exit status */
++    int exit_status;
++
++    libssh2_channel_data local, remote;
++    /* Amount of bytes to be refunded to receive window (but not yet sent) */
++    unsigned long adjust_queue;
++
++    LIBSSH2_SESSION *session;
++
++    LIBSSH2_CHANNEL *next, *prev;
++
++    void *abstract;
++      LIBSSH2_CHANNEL_CLOSE_FUNC((*close_cb));
++
++    /* State variables used in libssh2_channel_setenv_ex() */
++    libssh2_nonblocking_states setenv_state;
++    unsigned char *setenv_packet;
++    unsigned long setenv_packet_len;
++    unsigned char setenv_local_channel[4];
++    packet_requirev_state_t setenv_packet_requirev_state;
++
++    /* State variables used in libssh2_channel_request_pty_ex() */
++    libssh2_nonblocking_states reqPTY_state;
++    unsigned char *reqPTY_packet;
++    unsigned long reqPTY_packet_len;
++    unsigned char reqPTY_local_channel[4];
++    packet_requirev_state_t reqPTY_packet_requirev_state;
++
++    /* State variables used in libssh2_channel_x11_req_ex() */
++    libssh2_nonblocking_states reqX11_state;
++    unsigned char *reqX11_packet;
++    unsigned long reqX11_packet_len;
++    unsigned char reqX11_local_channel[4];
++    packet_requirev_state_t reqX11_packet_requirev_state;
++
++    /* State variables used in libssh2_channel_process_startup() */
++    libssh2_nonblocking_states process_state;
++    unsigned char *process_packet;
++    unsigned long process_packet_len;
++    unsigned char process_local_channel[4];
++    packet_requirev_state_t process_packet_requirev_state;
++
++    /* State variables used in libssh2_channel_flush_ex() */
++    libssh2_nonblocking_states flush_state;
++    unsigned long flush_refund_bytes;
++    unsigned long flush_flush_bytes;
++
++    /* State variables used in libssh2_channel_receive_window_adjust() */
++    libssh2_nonblocking_states adjust_state;
++    unsigned char adjust_adjust[9];     /* packet_type(1) + channel(4) + adjustment(4) */
++
++    /* State variables used in libssh2_channel_read_ex() */
++    libssh2_nonblocking_states read_state;
++    LIBSSH2_PACKET *read_packet;
++    LIBSSH2_PACKET *read_next;
++    int read_block;
++    int read_bytes_read;
++    uint32_t read_local_id;
++    int read_want;
++    int read_unlink_packet;
++
++    /* State variables used in libssh2_channel_write_ex() */
++    libssh2_nonblocking_states write_state;
++    unsigned char *write_packet;
++    unsigned char *write_s;
++    unsigned long write_packet_len;
++    unsigned long write_bufwrote;
++    size_t write_bufwrite;
++
++    /* State variables used in libssh2_channel_close() */
++    libssh2_nonblocking_states close_state;
++    unsigned char close_packet[5];
++
++    /* State variables used in libssh2_channel_wait_closedeof() */
++    libssh2_nonblocking_states wait_eof_state;
++
++    /* State variables used in libssh2_channel_wait_closed() */
++    libssh2_nonblocking_states wait_closed_state;
++
++    /* State variables used in libssh2_channel_free() */
++    libssh2_nonblocking_states free_state;
++
++    /* State variables used in libssh2_channel_handle_extended_data2() */
++    libssh2_nonblocking_states extData2_state;
++};
++
++struct _LIBSSH2_CHANNEL_BRIGADE
++{
++    LIBSSH2_CHANNEL *head, *tail;
++};
++
++struct _LIBSSH2_LISTENER
++{
++    LIBSSH2_SESSION *session;
++
++    char *host;
++    int port;
++
++    LIBSSH2_CHANNEL *queue;
++    int queue_size;
++    int queue_maxsize;
++
++    LIBSSH2_LISTENER *prev, *next;
++
++    /* State variables used in libssh2_channel_forward_cancel() */
++    libssh2_nonblocking_states chanFwdCncl_state;
++    unsigned char *chanFwdCncl_data;
++    size_t chanFwdCncl_data_len;
++};
++
++typedef struct _libssh2_endpoint_data
++{
++    unsigned char *banner;
++
++    unsigned char *kexinit;
++    unsigned long kexinit_len;
++
++    const LIBSSH2_CRYPT_METHOD *crypt;
++    void *crypt_abstract;
++
++    const LIBSSH2_MAC_METHOD *mac;
++    unsigned long seqno;
++    void *mac_abstract;
++
++    const LIBSSH2_COMP_METHOD *comp;
++    void *comp_abstract;
++
++    /* Method Preferences -- NULL yields "load order" */
++    char *crypt_prefs;
++    char *mac_prefs;
++    char *comp_prefs;
++    char *lang_prefs;
++} libssh2_endpoint_data;
++
++#define PACKETBUFSIZE 4096
++
++struct transportpacket
++{
++    /* ------------- for incoming data --------------- */
++    unsigned char buf[PACKETBUFSIZE];
++    unsigned char init[5];      /* first 5 bytes of the incoming data stream,
++                                   still encrypted */
++    int writeidx;               /* at what array index we do the next write into
++                                   the buffer */
++    int readidx;                /* at what array index we do the next read from
++                                   the buffer */
++    int packet_length;          /* the most recent packet_length as read from the
++                                   network data */
++    int padding_length;         /* the most recent padding_length as read from the
++                                   network data */
++    int data_num;               /* How much of the total package that has been read
++                                   so far. */
++    int total_num;              /* How much a total package is supposed to be, in
++                                   number of bytes. A full package is
++                                   packet_length + padding_length + 4 +
++                                   mac_length. */
++    unsigned char *payload;     /* this is a pointer to a LIBSSH2_ALLOC()
++                                   area to which we write decrypted data */
++    unsigned char *wptr;        /* write pointer into the payload to where we
++                                   are currently writing decrypted data */
++
++    /* ------------- for outgoing data --------------- */
++    unsigned char *outbuf;      /* pointer to a LIBSSH2_ALLOC() area for the
++                                   outgoing data */
++    int ototal_num;             /* size of outbuf in number of bytes */
++    unsigned char *odata;       /* original pointer to the data we stored in
++                                   outbuf */
++    unsigned long olen;         /* original size of the data we stored in
++                                   outbuf */
++    unsigned long osent;        /* number of bytes already sent */
++};
++
++struct _LIBSSH2_PUBLICKEY
++{
++    LIBSSH2_CHANNEL *channel;
++    unsigned long version;
++
++    /* State variables used in libssh2_publickey_packet_receive() */
++    libssh2_nonblocking_states receive_state;
++    unsigned char *receive_packet;
++    unsigned long receive_packet_len;
++
++    /* State variables used in libssh2_publickey_add_ex() */
++    libssh2_nonblocking_states add_state;
++    unsigned char *add_packet;
++    unsigned char *add_s;
++
++    /* State variables used in libssh2_publickey_remove_ex() */
++    libssh2_nonblocking_states remove_state;
++    unsigned char *remove_packet;
++    unsigned char *remove_s;
++
++    /* State variables used in libssh2_publickey_list_fetch() */
++    libssh2_nonblocking_states listFetch_state;
++    unsigned char *listFetch_s;
++    unsigned char listFetch_buffer[12];
++    unsigned char *listFetch_data;
++    unsigned long listFetch_data_len;
++};
++
++#define SFTP_HANDLE_MAXLEN 256 /* according to spec! */
++
++struct _LIBSSH2_SFTP_HANDLE
++{
++    LIBSSH2_SFTP *sftp;
++    LIBSSH2_SFTP_HANDLE *prev, *next;
++
++    /* This is a pre-allocated buffer used for sending SFTP requests as the
++       whole thing might not get sent in one go. This buffer is used for read,
++       write, close and MUST thus be big enough to suit all these. */
++    unsigned char request_packet[SFTP_HANDLE_MAXLEN + 25];
++
++    char handle[SFTP_HANDLE_MAXLEN];
++    int handle_len;
++
++    char handle_type;
++
++    union _libssh2_sftp_handle_data
++    {
++        struct _libssh2_sftp_handle_file_data
++        {
++            libssh2_uint64_t offset;
++        } file;
++        struct _libssh2_sftp_handle_dir_data
++        {
++            unsigned long names_left;
++            void *names_packet;
++            char *next_name;
++        } dir;
++    } u;
++
++    /* State variables used in libssh2_sftp_close_handle() */
++    libssh2_nonblocking_states close_state;
++    unsigned long close_request_id;
++    unsigned char *close_packet;
++};
++
++struct _LIBSSH2_SFTP
++{
++    LIBSSH2_CHANNEL *channel;
++
++    unsigned long request_id, version;
++
++    LIBSSH2_PACKET_BRIGADE packets;
++
++    LIBSSH2_SFTP_HANDLE *handles;
++
++    unsigned long last_errno;
++
++    /* Holder for partial packet, use in libssh2_sftp_packet_read() */
++    unsigned char *partial_packet;      /* The data                */
++    unsigned long partial_len;  /* Desired number of bytes */
++    unsigned long partial_received;     /* Bytes received so far   */
++
++    /* Time that libssh2_sftp_packet_requirev() started reading */
++    time_t requirev_start;
++
++    /* State variables used in libssh2_sftp_open_ex() */
++    libssh2_nonblocking_states open_state;
++    unsigned char *open_packet;
++    ssize_t open_packet_len;
++    unsigned long open_request_id;
++
++    /* State variables used in libssh2_sftp_read() */
++    libssh2_nonblocking_states read_state;
++    unsigned char *read_packet;
++    unsigned long read_request_id;
++    size_t read_total_read;
++
++    /* State variables used in libssh2_sftp_readdir() */
++    libssh2_nonblocking_states readdir_state;
++    unsigned char *readdir_packet;
++    unsigned long readdir_request_id;
++
++    /* State variables used in libssh2_sftp_write() */
++    libssh2_nonblocking_states write_state;
++    unsigned char *write_packet;
++    unsigned long write_request_id;
++
++    /* State variables used in libssh2_sftp_fstat_ex() */
++    libssh2_nonblocking_states fstat_state;
++    unsigned char *fstat_packet;
++    unsigned long fstat_request_id;
++
++    /* State variables used in libssh2_sftp_unlink_ex() */
++    libssh2_nonblocking_states unlink_state;
++    unsigned char *unlink_packet;
++    unsigned long unlink_request_id;
++
++    /* State variables used in libssh2_sftp_rename_ex() */
++    libssh2_nonblocking_states rename_state;
++    unsigned char *rename_packet;
++    unsigned char *rename_s;
++    unsigned long rename_request_id;
++
++    /* State variables used in libssh2_sftp_mkdir() */
++    libssh2_nonblocking_states mkdir_state;
++    unsigned char *mkdir_packet;
++    unsigned long mkdir_request_id;
++
++    /* State variables used in libssh2_sftp_rmdir() */
++    libssh2_nonblocking_states rmdir_state;
++    unsigned char *rmdir_packet;
++    unsigned long rmdir_request_id;
++
++    /* State variables used in libssh2_sftp_stat() */
++    libssh2_nonblocking_states stat_state;
++    unsigned char *stat_packet;
++    unsigned long stat_request_id;
++
++    /* State variables used in libssh2_sftp_symlink() */
++    libssh2_nonblocking_states symlink_state;
++    unsigned char *symlink_packet;
++    unsigned long symlink_request_id;
++};
++
++#define LIBSSH2_SCP_RESPONSE_BUFLEN     256
++
++struct _LIBSSH2_SESSION
++{
++    /* Memory management callbacks */
++    void *abstract;
++      LIBSSH2_ALLOC_FUNC((*alloc));
++      LIBSSH2_REALLOC_FUNC((*realloc));
++      LIBSSH2_FREE_FUNC((*free));
++
++    /* Other callbacks */
++      LIBSSH2_IGNORE_FUNC((*ssh_msg_ignore));
++      LIBSSH2_DEBUG_FUNC((*ssh_msg_debug));
++      LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect));
++      LIBSSH2_MACERROR_FUNC((*macerror));
++      LIBSSH2_X11_OPEN_FUNC((*x11));
++
++    /* Method preferences -- NULL yields "load order" */
++    char *kex_prefs;
++    char *hostkey_prefs;
++
++    int state;
++    int flags;
++
++    /* Agreed Key Exchange Method */
++    const LIBSSH2_KEX_METHOD *kex;
++    int burn_optimistic_kexinit:1;
++
++    unsigned char *session_id;
++    unsigned long session_id_len;
++
++    /* Server's public key */
++    const LIBSSH2_HOSTKEY_METHOD *hostkey;
++    void *server_hostkey_abstract;
++
++    /* Either set with libssh2_session_hostkey() (for server mode)
++     * Or read from server in (eg) KEXDH_INIT (for client mode)
++     */
++    unsigned char *server_hostkey;
++    unsigned long server_hostkey_len;
++#if LIBSSH2_MD5
++    unsigned char server_hostkey_md5[MD5_DIGEST_LENGTH];
++#endif                          /* ! LIBSSH2_MD5 */
++    unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH];
++
++    /* (remote as source of data -- packet_read ) */
++    libssh2_endpoint_data remote;
++
++    /* (local as source of data -- packet_write ) */
++    libssh2_endpoint_data local;
++
++    /* Inbound Data buffer -- Sometimes the packet that comes in isn't the packet we're ready for */
++    LIBSSH2_PACKET_BRIGADE packets;
++
++    /* Active connection channels */
++    LIBSSH2_CHANNEL_BRIGADE channels;
++    unsigned long next_channel;
++
++    LIBSSH2_LISTENER *listeners;
++
++    /* Actual I/O socket */
++    int socket_fd;
++    int socket_block;
++    int socket_state;
++    int socket_block_directions;
++
++    /* Error tracking */
++    char *err_msg;
++    unsigned long err_msglen;
++    int err_should_free;
++    int err_code;
++
++    /* struct members for packet-level reading */
++    struct transportpacket packet;
++#ifdef LIBSSH2DEBUG
++    int showmask;               /* what debug/trace messages to display */
++#endif
++
++    /* State variables used in libssh2_banner_send() */
++    libssh2_nonblocking_states banner_TxRx_state;
++    char banner_TxRx_banner[256];
++    ssize_t banner_TxRx_total_send;
++
++    /* State variables used in libssh2_kexinit() */
++    libssh2_nonblocking_states kexinit_state;
++    unsigned char *kexinit_data;
++    size_t kexinit_data_len;
++
++    /* State variables used in libssh2_session_startup() */
++    libssh2_nonblocking_states startup_state;
++    unsigned char *startup_data;
++    unsigned long startup_data_len;
++    unsigned char startup_service[sizeof("ssh-userauth") + 5 - 1];
++    unsigned long startup_service_length;
++    packet_require_state_t startup_req_state;
++    key_exchange_state_t startup_key_state;
++
++    /* State variables used in libssh2_session_free() */
++    libssh2_nonblocking_states free_state;
++
++    /* State variables used in libssh2_session_disconnect_ex() */
++    libssh2_nonblocking_states disconnect_state;
++    unsigned char *disconnect_data;
++    unsigned long disconnect_data_len;
++
++    /* State variables used in libssh2_packet_read() */
++    libssh2_nonblocking_states readPack_state;
++    int readPack_encrypted;
++
++    /* State variables used in libssh2_userauth_list() */
++    libssh2_nonblocking_states userauth_list_state;
++    unsigned char *userauth_list_data;
++    unsigned long userauth_list_data_len;
++    packet_requirev_state_t userauth_list_packet_requirev_state;
++
++    /* State variables used in libssh2_userauth_password_ex() */
++    libssh2_nonblocking_states userauth_pswd_state;
++    unsigned char *userauth_pswd_data;
++    unsigned char userauth_pswd_data0;
++    unsigned long userauth_pswd_data_len;
++    char *userauth_pswd_newpw;
++    int userauth_pswd_newpw_len;
++    packet_requirev_state_t userauth_pswd_packet_requirev_state;
++
++    /* State variables used in libssh2_userauth_hostbased_fromfile_ex() */
++    libssh2_nonblocking_states userauth_host_state;
++    unsigned char *userauth_host_data;
++    unsigned long userauth_host_data_len;
++    unsigned char *userauth_host_packet;
++    unsigned long userauth_host_packet_len;
++    unsigned char *userauth_host_method;
++    unsigned long userauth_host_method_len;
++    unsigned char *userauth_host_s;
++    packet_requirev_state_t userauth_host_packet_requirev_state;
++
++    /* State variables used in libssh2_userauth_publickey_fromfile_ex() */
++    libssh2_nonblocking_states userauth_pblc_state;
++    unsigned char *userauth_pblc_data;
++    unsigned long userauth_pblc_data_len;
++    unsigned char *userauth_pblc_packet;
++    unsigned long userauth_pblc_packet_len;
++    unsigned char *userauth_pblc_method;
++    unsigned long userauth_pblc_method_len;
++    unsigned char *userauth_pblc_s;
++    unsigned char *userauth_pblc_b;
++    packet_requirev_state_t userauth_pblc_packet_requirev_state;
++
++    /* State variables used in llibssh2_userauth_keyboard_interactive_ex() */
++    libssh2_nonblocking_states userauth_kybd_state;
++    unsigned char *userauth_kybd_data;
++    unsigned long userauth_kybd_data_len;
++    unsigned char *userauth_kybd_packet;
++    unsigned long userauth_kybd_packet_len;
++    unsigned int userauth_kybd_auth_name_len;
++    char *userauth_kybd_auth_name;
++    unsigned userauth_kybd_auth_instruction_len;
++    char *userauth_kybd_auth_instruction;
++    unsigned int userauth_kybd_num_prompts;
++    int userauth_kybd_auth_failure;
++    LIBSSH2_USERAUTH_KBDINT_PROMPT *userauth_kybd_prompts;
++    LIBSSH2_USERAUTH_KBDINT_RESPONSE *userauth_kybd_responses;
++    packet_requirev_state_t userauth_kybd_packet_requirev_state;
++
++    /* State variables used in libssh2_channel_open_ex() */
++    libssh2_nonblocking_states open_state;
++    packet_requirev_state_t open_packet_requirev_state;
++    LIBSSH2_CHANNEL *open_channel;
++    unsigned char *open_packet;
++    unsigned long open_packet_len;
++    unsigned char *open_data;
++    unsigned long open_data_len;
++    unsigned long open_local_channel;
++
++    /* State variables used in libssh2_channel_direct_tcpip_ex() */
++    libssh2_nonblocking_states direct_state;
++    unsigned char *direct_message;
++    unsigned long direct_host_len;
++    unsigned long direct_shost_len;
++    unsigned long direct_message_len;
++
++    /* State variables used in libssh2_channel_forward_listen_ex() */
++    libssh2_nonblocking_states fwdLstn_state;
++    unsigned char *fwdLstn_packet;
++    unsigned long fwdLstn_host_len;
++    unsigned long fwdLstn_packet_len;
++    packet_requirev_state_t fwdLstn_packet_requirev_state;
++
++    /* State variables used in libssh2_publickey_init() */
++    libssh2_nonblocking_states pkeyInit_state;
++    LIBSSH2_PUBLICKEY *pkeyInit_pkey;
++    LIBSSH2_CHANNEL *pkeyInit_channel;
++    unsigned char *pkeyInit_data;
++    unsigned long pkeyInit_data_len;
++
++    /* State variables used in libssh2_packet_add() */
++    libssh2_nonblocking_states packAdd_state;
++    LIBSSH2_PACKET *packAdd_packet;
++    LIBSSH2_CHANNEL *packAdd_channel;
++    unsigned long packAdd_data_head;
++    key_exchange_state_t packAdd_key_state;
++    packet_queue_listener_state_t packAdd_Qlstn_state;
++    packet_x11_open_state_t packAdd_x11open_state;
++
++    /* State variables used in fullpacket() */
++    libssh2_nonblocking_states fullpacket_state;
++    int fullpacket_macstate;
++    int fullpacket_payload_len;
++    libssh2pack_t fullpacket_packet_type;
++
++    /* State variables used in libssh2_sftp_init() */
++    libssh2_nonblocking_states sftpInit_state;
++    LIBSSH2_SFTP *sftpInit_sftp;
++    LIBSSH2_CHANNEL *sftpInit_channel;
++    unsigned char sftpInit_buffer[9];   /* sftp_header(5){excludes request_id} + version_id(4) */
++
++    /* State variables used in libssh2_scp_recv() */
++    libssh2_nonblocking_states scpRecv_state;
++    unsigned char *scpRecv_command;
++    unsigned long scpRecv_command_len;
++    unsigned char scpRecv_response[LIBSSH2_SCP_RESPONSE_BUFLEN];
++    unsigned long scpRecv_response_len;
++    long scpRecv_mode;
++#if defined(HAVE_LONGLONG) && defined(strtoll)
++    /* we have the type and we can parse such numbers */
++    long long scpRecv_size;
++#define scpsize_strtol strtoll
++#else
++    long scpRecv_size;
++#define scpsize_strtol strtol
++#endif
++    long scpRecv_mtime;
++    long scpRecv_atime;
++    char *scpRecv_err_msg;
++    long scpRecv_err_len;
++    LIBSSH2_CHANNEL *scpRecv_channel;
++
++    /* State variables used in libssh2_scp_send_ex() */
++    libssh2_nonblocking_states scpSend_state;
++    unsigned char *scpSend_command;
++    unsigned long scpSend_command_len;
++    unsigned char scpSend_response[LIBSSH2_SCP_RESPONSE_BUFLEN];
++    unsigned long scpSend_response_len;
++    char *scpSend_err_msg;
++    long scpSend_err_len;
++    LIBSSH2_CHANNEL *scpSend_channel;
++};
++
++/* session.state bits */
++#define LIBSSH2_STATE_EXCHANGING_KEYS   0x00000001
++#define LIBSSH2_STATE_NEWKEYS           0x00000002
++#define LIBSSH2_STATE_AUTHENTICATED     0x00000004
++#define LIBSSH2_STATE_KEX_ACTIVE        0x00000008
++
++/* session.flag helpers */
++#ifdef MSG_NOSIGNAL
++#define LIBSSH2_SOCKET_SEND_FLAGS(session)      (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
++#define LIBSSH2_SOCKET_RECV_FLAGS(session)      (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
++#else
++/* If MSG_NOSIGNAL isn't defined we're SOL on blocking SIGPIPE */
++#define LIBSSH2_SOCKET_SEND_FLAGS(session)      0
++#define LIBSSH2_SOCKET_RECV_FLAGS(session)      0
++#endif
++
++/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional methods via .so/.dll */
++
++struct _LIBSSH2_KEX_METHOD
++{
++    const char *name;
++
++    /* Key exchange, populates session->* and returns 0 on success, non-0 on error */
++    int (*exchange_keys) (LIBSSH2_SESSION * session,
++                          key_exchange_state_low_t * key_state);
++
++    long flags;
++};
++
++struct _LIBSSH2_HOSTKEY_METHOD
++{
++    const char *name;
++    unsigned long hash_len;
++
++    int (*init) (LIBSSH2_SESSION * session, const unsigned char *hostkey_data,
++                 unsigned long hostkey_data_len, void **abstract);
++    int (*initPEM) (LIBSSH2_SESSION * session, const char *privkeyfile,
++                    unsigned const char *passphrase, void **abstract);
++    int (*sig_verify) (LIBSSH2_SESSION * session, const unsigned char *sig,
++                       unsigned long sig_len, const unsigned char *m,
++                       unsigned long m_len, void **abstract);
++    int (*signv) (LIBSSH2_SESSION * session, unsigned char **signature,
++                  unsigned long *signature_len, unsigned long veccount,
++                  const struct iovec datavec[], void **abstract);
++    int (*encrypt) (LIBSSH2_SESSION * session, unsigned char **dst,
++                    unsigned long *dst_len, const unsigned char *src,
++                    unsigned long src_len, void **abstract);
++    int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
++};
++
++struct _LIBSSH2_CRYPT_METHOD
++{
++    const char *name;
++
++    int blocksize;
++
++    /* iv and key sizes (-1 for variable length) */
++    int iv_len;
++    int secret_len;
++
++    long flags;
++
++    int (*init) (LIBSSH2_SESSION * session,
++                 const LIBSSH2_CRYPT_METHOD * method, unsigned char *iv,
++                 int *free_iv, unsigned char *secret, int *free_secret,
++                 int encrypt, void **abstract);
++    int (*crypt) (LIBSSH2_SESSION * session, unsigned char *block,
++                  void **abstract);
++    int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
++
++      _libssh2_cipher_type(algo);
++};
++
++struct _LIBSSH2_COMP_METHOD
++{
++    const char *name;
++
++    int (*init) (LIBSSH2_SESSION * session, int compress, void **abstract);
++    int (*comp) (LIBSSH2_SESSION * session, int compress, unsigned char **dest,
++                 unsigned long *dest_len, unsigned long payload_limit,
++                 int *free_dest, const unsigned char *src,
++                 unsigned long src_len, void **abstract);
++    int (*dtor) (LIBSSH2_SESSION * session, int compress, void **abstract);
++};
++
++struct _LIBSSH2_MAC_METHOD
++{
++    const char *name;
++
++    /* The length of a given MAC packet */
++    int mac_len;
++
++    /* integrity key length */
++    int key_len;
++
++    /* Message Authentication Code Hashing algo */
++    int (*init) (LIBSSH2_SESSION * session, unsigned char *key, int *free_key,
++                 void **abstract);
++    int (*hash) (LIBSSH2_SESSION * session, unsigned char *buf,
++                 unsigned long seqno, const unsigned char *packet,
++                 unsigned long packet_len, const unsigned char *addtl,
++                 unsigned long addtl_len, void **abstract);
++    int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
++};
++
++#define LIBSSH2_DBG_TRANS   1
++#define LIBSSH2_DBG_KEX     2
++#define LIBSSH2_DBG_AUTH    3
++#define LIBSSH2_DBG_CONN    4
++#define LIBSSH2_DBG_SCP     5
++#define LIBSSH2_DBG_SFTP    6
++#define LIBSSH2_DBG_ERROR   7
++#define LIBSSH2_DBG_PUBLICKEY   8
++#ifdef LIBSSH2DEBUG
++void _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format,
++                    ...);
++#else
++#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
++/* C99 style */
++#define _libssh2_debug(x,y,z, __VA_ARGS__) do {} while (0)
++#elif defined(__GNUC__)
++/* GNU style */
++#define _libssh2_debug(x,y,z,...) do {} while (0)
++#else
++/* no gcc and not C99, do static and hopefully inline */
++static inline void
++_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
++{
++}
++#endif
++#endif
++
++#ifdef LIBSSH2DEBUG
++#define libssh2_error(session, errcode, errmsg, should_free)    \
++{ \
++    if (session->err_msg && session->err_should_free) { \
++        LIBSSH2_FREE(session, session->err_msg); \
++    } \
++    session->err_msg = (char *)errmsg; \
++    session->err_msglen = strlen(errmsg); \
++    session->err_should_free = should_free; \
++    session->err_code = errcode; \
++    _libssh2_debug(session, LIBSSH2_DBG_ERROR, "%d - %s", session->err_code, session->err_msg); \
++}
++
++#else /* ! LIBSSH2DEBUG */
++
++#define libssh2_error(session, errcode, errmsg, should_free)    \
++{ \
++    if (session->err_msg && session->err_should_free) { \
++        LIBSSH2_FREE(session, session->err_msg); \
++    } \
++    session->err_msg = (char *)errmsg; \
++    session->err_msglen = strlen(errmsg); \
++    session->err_should_free = should_free; \
++    session->err_code = errcode; \
++}
++
++#endif /* ! LIBSSH2DEBUG */
++
++
++#define LIBSSH2_SOCKET_UNKNOWN                   1
++#define LIBSSH2_SOCKET_CONNECTED                 0
++#define LIBSSH2_SOCKET_DISCONNECTED             -1
++
++/* Initial packet state, prior to MAC check */
++#define LIBSSH2_MAC_UNCONFIRMED                  1
++/* When MAC type is "none" (proto initiation phase) all packets are deemed "confirmed" */
++#define LIBSSH2_MAC_CONFIRMED                    0
++/* Something very bad is going on */
++#define LIBSSH2_MAC_INVALID                     -1
++
++/* SSH Packet Types -- Defined by internet draft */
++/* Transport Layer */
++#define SSH_MSG_DISCONNECT                          1
++#define SSH_MSG_IGNORE                              2
++#define SSH_MSG_UNIMPLEMENTED                       3
++#define SSH_MSG_DEBUG                               4
++#define SSH_MSG_SERVICE_REQUEST                     5
++#define SSH_MSG_SERVICE_ACCEPT                      6
++
++#define SSH_MSG_KEXINIT                             20
++#define SSH_MSG_NEWKEYS                             21
++
++/* diffie-hellman-group1-sha1 */
++#define SSH_MSG_KEXDH_INIT                          30
++#define SSH_MSG_KEXDH_REPLY                         31
++
++/* diffie-hellman-group-exchange-sha1 */
++#define SSH_MSG_KEX_DH_GEX_REQUEST_OLD              30
++#define SSH_MSG_KEX_DH_GEX_REQUEST                  34
++#define SSH_MSG_KEX_DH_GEX_GROUP                    31
++#define SSH_MSG_KEX_DH_GEX_INIT                     32
++#define SSH_MSG_KEX_DH_GEX_REPLY                    33
++
++/* User Authentication */
++#define SSH_MSG_USERAUTH_REQUEST                    50
++#define SSH_MSG_USERAUTH_FAILURE                    51
++#define SSH_MSG_USERAUTH_SUCCESS                    52
++#define SSH_MSG_USERAUTH_BANNER                     53
++
++/* "public key" method */
++#define SSH_MSG_USERAUTH_PK_OK                      60
++/* "password" method */
++#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ           60
++/* "keyboard-interactive" method */
++#define SSH_MSG_USERAUTH_INFO_REQUEST               60
++#define SSH_MSG_USERAUTH_INFO_RESPONSE              61
++
++/* Channels */
++#define SSH_MSG_GLOBAL_REQUEST                      80
++#define SSH_MSG_REQUEST_SUCCESS                     81
++#define SSH_MSG_REQUEST_FAILURE                     82
++
++#define SSH_MSG_CHANNEL_OPEN                        90
++#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION           91
++#define SSH_MSG_CHANNEL_OPEN_FAILURE                92
++#define SSH_MSG_CHANNEL_WINDOW_ADJUST               93
++#define SSH_MSG_CHANNEL_DATA                        94
++#define SSH_MSG_CHANNEL_EXTENDED_DATA               95
++#define SSH_MSG_CHANNEL_EOF                         96
++#define SSH_MSG_CHANNEL_CLOSE                       97
++#define SSH_MSG_CHANNEL_REQUEST                     98
++#define SSH_MSG_CHANNEL_SUCCESS                     99
++#define SSH_MSG_CHANNEL_FAILURE                     100
++
++void libssh2_session_shutdown(LIBSSH2_SESSION * session);
++
++unsigned long libssh2_ntohu32(const unsigned char *buf);
++libssh2_uint64_t libssh2_ntohu64(const unsigned char *buf);
++void libssh2_htonu32(unsigned char *buf, unsigned long val);
++void libssh2_htonu64(unsigned char *buf, libssh2_uint64_t val);
++
++#define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when
++                                   waiting for more data to arrive */
++int libssh2_waitsocket(LIBSSH2_SESSION * session, long seconds);
++
++
++/* CAUTION: some of these error codes are returned in the public API and is
++   there known with other #defined names from the public header file. They
++   should not be changed. */
++
++#define PACKET_TIMEOUT  -7
++#define PACKET_BADUSE   -6
++#define PACKET_COMPRESS -5
++#define PACKET_TOOBIG   -4
++#define PACKET_ENOMEM   -3
++#define PACKET_EAGAIN   LIBSSH2_ERROR_EAGAIN
++#define PACKET_FAIL     -1
++#define PACKET_NONE      0
++
++libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION * session);
++
++int libssh2_packet_ask_ex(LIBSSH2_SESSION * session, unsigned char packet_type,
++                          unsigned char **data, unsigned long *data_len,
++                          unsigned long match_ofs,
++                          const unsigned char *match_buf,
++                          unsigned long match_len, int poll_socket);
++
++int libssh2_packet_askv_ex(LIBSSH2_SESSION * session,
++                           const unsigned char *packet_types,
++                           unsigned char **data, unsigned long *data_len,
++                           unsigned long match_ofs,
++                           const unsigned char *match_buf,
++                           unsigned long match_len, int poll_socket);
++int libssh2_packet_require_ex(LIBSSH2_SESSION * session,
++                              unsigned char packet_type, unsigned char **data,
++                              unsigned long *data_len, unsigned long match_ofs,
++                              const unsigned char *match_buf,
++                              unsigned long match_len,
++                              packet_require_state_t * state);
++int libssh2_packet_requirev_ex(LIBSSH2_SESSION * session,
++                               const unsigned char *packet_types,
++                               unsigned char **data, unsigned long *data_len,
++                               unsigned long match_ofs,
++                               const unsigned char *match_buf,
++                               unsigned long match_len,
++                               packet_requirev_state_t * state);
++int libssh2_packet_burn(LIBSSH2_SESSION * session,
++                        libssh2_nonblocking_states * state);
++int libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
++                         unsigned long data_len);
++int libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
++                       size_t datalen, int macstate);
++int libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
++                         key_exchange_state_t * state);
++unsigned long libssh2_channel_nextid(LIBSSH2_SESSION * session);
++LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION * session,
++                                        unsigned long channel_id);
++unsigned long libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel,
++                                              int stream_id);
++
++/* this is the lib-internal set blocking function */
++int _libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking);
++
++/* Let crypt.c/hostkey.c/comp.c/mac.c expose their method structs */
++const LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void);
++const LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void);
++const LIBSSH2_COMP_METHOD **libssh2_comp_methods(void);
++const LIBSSH2_MAC_METHOD **libssh2_mac_methods(void);
++
++/* Language API doesn't exist yet.  Just act like we've agreed on a language */
++#define libssh2_kex_agree_lang(session, endpoint, str, str_len) 0
++
++/* pem.c */
++int _libssh2_pem_parse(LIBSSH2_SESSION * session,
++                       const char *headerbegin,
++                       const char *headerend,
++                       FILE * fp, unsigned char **data, unsigned int *datalen);
++int _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen);
++int _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
++                                unsigned char **i, unsigned int *ilen);
++
++#endif /* LIBSSH2_H */
+
+Property changes on: libssh2/src/libssh2_priv.h
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.1
+Added: svn:eol-style
+   + native
+Added: svn:executable
+   + *
+
+Index: libssh2/src/sftp.c
+===================================================================
+--- libssh2/src/sftp.c (.../tags/RELEASE_0_11_0)
++++ libssh2/src/sftp.c (.../trunk)
+@@ -0,0 +1,2358 @@
++/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++#include "libssh2_sftp.h"
++
++/* Note: Version 6 was documented at the time of writing
++ * However it was marked as "DO NOT IMPLEMENT" due to pending changes
++ *
++ * This release of libssh2 implements Version 5 with automatic downgrade
++ * based on server's declaration
++ */
++
++/* SFTP packet types */
++#define SSH_FXP_INIT                            1
++#define SSH_FXP_VERSION                         2
++#define SSH_FXP_OPEN                            3
++#define SSH_FXP_CLOSE                           4
++#define SSH_FXP_READ                            5
++#define SSH_FXP_WRITE                           6
++#define SSH_FXP_LSTAT                           7
++#define SSH_FXP_FSTAT                           8
++#define SSH_FXP_SETSTAT                         9
++#define SSH_FXP_FSETSTAT                        10
++#define SSH_FXP_OPENDIR                         11
++#define SSH_FXP_READDIR                         12
++#define SSH_FXP_REMOVE                          13
++#define SSH_FXP_MKDIR                           14
++#define SSH_FXP_RMDIR                           15
++#define SSH_FXP_REALPATH                        16
++#define SSH_FXP_STAT                            17
++#define SSH_FXP_RENAME                          18
++#define SSH_FXP_READLINK                        19
++#define SSH_FXP_SYMLINK                         20
++#define SSH_FXP_STATUS                          101
++#define SSH_FXP_HANDLE                          102
++#define SSH_FXP_DATA                            103
++#define SSH_FXP_NAME                            104
++#define SSH_FXP_ATTRS                           105
++#define SSH_FXP_EXTENDED                        200
++#define SSH_FXP_EXTENDED_REPLY                  201
++
++#define LIBSSH2_SFTP_HANDLE_FILE        0
++#define LIBSSH2_SFTP_HANDLE_DIR         1
++
++/* S_IFREG */
++#define LIBSSH2_SFTP_ATTR_PFILETYPE_FILE        0100000
++/* S_IFDIR */
++#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR         0040000
++
++/* {{{ sftp_packet_add
++ * Add a packet to the SFTP packet brigade
++ */
++static int
++sftp_packet_add(LIBSSH2_SFTP * sftp, unsigned char *data,
++                unsigned long data_len)
++{
++    LIBSSH2_SESSION *session = sftp->channel->session;
++    LIBSSH2_PACKET *packet;
++
++    _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Received packet %d (len %d)",
++                   (int) data[0], data_len);
++    packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
++    if (!packet) {
++        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                      "Unable to allocate datablock for SFTP packet", 0);
++        return -1;
++    }
++    memset(packet, 0, sizeof(LIBSSH2_PACKET));
++
++    packet->data = data;
++    packet->data_len = data_len;
++    packet->data_head = 5;
++    packet->brigade = &sftp->packets;
++    packet->next = NULL;
++    packet->prev = sftp->packets.tail;
++    if (packet->prev) {
++        packet->prev->next = packet;
++    } else {
++        sftp->packets.head = packet;
++    }
++    sftp->packets.tail = packet;
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ sftp_packet_read
++ * Frame an SFTP packet off the channel
++ */
++static int
++sftp_packet_read(LIBSSH2_SFTP * sftp)
++{
++    LIBSSH2_CHANNEL *channel = sftp->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned char buffer[4];    /* To store the packet length */
++    unsigned char *packet;
++    unsigned long packet_len, packet_received;
++    ssize_t bytes_received;
++    int rc;
++
++    _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Waiting for packet");
++
++
++    /* If there was a previous partial, start using it */
++    if (sftp->partial_packet) {
++
++        packet = sftp->partial_packet;
++        packet_len = sftp->partial_len;
++        packet_received = sftp->partial_received;
++        sftp->partial_packet = NULL;
++
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
++                       "partial read cont, len: %lu", packet_len);
++    }
++    else {
++        rc = libssh2_channel_read_ex(channel, 0, (char *) buffer, 4);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        }
++        else if (4 != rc) {
++            /* TODO: this is stupid since we can in fact get 1-3 bytes in a
++               legitimate working case as well if the connection happens to be
++               super slow or something */
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                          "Timeout waiting for FXP packet", 0);
++            return -1;
++        }
++
++        packet_len = libssh2_ntohu32(buffer);
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
++                       "Data begin - Packet Length: %lu", packet_len);
++        if (packet_len > LIBSSH2_SFTP_PACKET_MAXLEN) {
++            libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
++                          "SFTP packet too large", 0);
++            return -1;
++        }
++
++        packet = LIBSSH2_ALLOC(session, packet_len);
++        if (!packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate SFTP packet", 0);
++            return -1;
++        }
++
++        packet_received = 0;
++    }
++
++    /* Read as much of the packet as we can */
++    while (packet_len > packet_received) {
++        bytes_received =
++            libssh2_channel_read_ex(channel, 0,
++                                    (char *) packet + packet_received,
++                                    packet_len - packet_received);
++
++        if (bytes_received == PACKET_EAGAIN) {
++            /*
++             * We received EAGAIN, save what we have and
++             * return to EAGAIN to the caller
++             */
++            sftp->partial_packet = packet;
++            sftp->partial_len = packet_len;
++            sftp->partial_received = packet_received;
++            packet = NULL;
++
++            return PACKET_EAGAIN;
++        }
++        else if (bytes_received < 0) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                          "Receive error waiting for SFTP packet", 0);
++            LIBSSH2_FREE(session, packet);
++            return -1;
++        }
++        packet_received += bytes_received;
++    }
++
++    if (sftp_packet_add(sftp, packet, packet_len)) {
++        LIBSSH2_FREE(session, packet);
++        return -1;
++    }
++
++    return packet[0];
++}
++
++/* }}} */
++
++/* {{{ sftp_packet_ask
++ * A la libssh2_packet_ask()
++ */
++static int
++sftp_packet_ask(LIBSSH2_SFTP * sftp, unsigned char packet_type,
++                unsigned long request_id, unsigned char **data,
++                unsigned long *data_len, int poll_channel)
++{
++    LIBSSH2_SESSION *session = sftp->channel->session;
++    LIBSSH2_PACKET *packet = sftp->packets.head;
++    unsigned char match_buf[5];
++    int match_len = 5;
++
++    _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Asking for %d packet",
++                   (int) packet_type);
++    if (poll_channel) {
++        int ret = sftp_packet_read(sftp);
++        if (ret == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (ret < 0) {
++            return -1;
++        }
++    }
++
++    match_buf[0] = packet_type;
++    if (packet_type == SSH_FXP_VERSION) {
++        /* Special consideration when matching VERSION packet */
++        match_len = 1;
++    } else {
++        libssh2_htonu32(match_buf + 1, request_id);
++    }
++
++    while (packet) {
++        if (strncmp((char *) packet->data, (char *) match_buf, match_len) == 0) {
++            *data = packet->data;
++            *data_len = packet->data_len;
++
++            if (packet->prev) {
++                packet->prev->next = packet->next;
++            } else {
++                sftp->packets.head = packet->next;
++            }
++
++            if (packet->next) {
++                packet->next->prev = packet->prev;
++            } else {
++                sftp->packets.tail = packet->prev;
++            }
++
++            LIBSSH2_FREE(session, packet);
++
++            return 0;
++        }
++        packet = packet->next;
++    }
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ sftp_packet_require
++ * A la libssh2_packet_require
++ */
++static int
++sftp_packet_require(LIBSSH2_SFTP * sftp, unsigned char packet_type,
++                    unsigned long request_id, unsigned char **data,
++                    unsigned long *data_len)
++{
++    LIBSSH2_SESSION *session = sftp->channel->session;
++    int ret;
++
++    _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Requiring %d packet",
++                   (int) packet_type);
++
++    if (sftp_packet_ask(sftp, packet_type, request_id, data,
++                        data_len, 0) == 0) {
++        /* The right packet was available in the packet brigade */
++        return 0;
++    }
++
++    while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
++        ret = sftp_packet_read(sftp);
++        if (ret == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (ret <= 0) {
++            return -1;
++        }
++
++        if (packet_type == ret) {
++            /* Be lazy, let packet_ask pull it out of the brigade */
++            return sftp_packet_ask(sftp, packet_type, request_id, data,
++                                   data_len, 0);
++        }
++    }
++
++    /* Only reached if the socket died */
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ sftp_packet_requirev
++ * Require one of N possible reponses
++ */
++static int
++sftp_packet_requirev(LIBSSH2_SFTP * sftp, int num_valid_responses,
++                     const unsigned char *valid_responses,
++                     unsigned long request_id, unsigned char **data,
++                     unsigned long *data_len)
++{
++    int i;
++    int ret;
++
++    /* If no timeout is active, start a new one */
++    if (sftp->requirev_start == 0) {
++        sftp->requirev_start = time(NULL);
++    }
++
++    while (sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
++        for(i = 0; i < num_valid_responses; i++) {
++            if (sftp_packet_ask(sftp, valid_responses[i], request_id,
++                                data, data_len, 0) == 0) {
++                /*
++                 * Set to zero before all returns to say
++                 * the timeout is not active
++                 */
++                sftp->requirev_start = 0;
++                return 0;
++            }
++        }
++
++        ret = sftp_packet_read(sftp);
++        if ((ret < 0) && (ret != PACKET_EAGAIN)) {
++            sftp->requirev_start = 0;
++            return -1;
++        } else if (ret <= 0) {
++            /* prevent busy-looping */
++            long left =
++                LIBSSH2_READ_TIMEOUT - (time(NULL) - sftp->requirev_start);
++
++            if (left <= 0) {
++                sftp->requirev_start = 0;
++                return PACKET_TIMEOUT;
++            } else if (sftp->channel->session->socket_block
++                       && (libssh2_waitsocket(sftp->channel->session, left) <=
++                           0)) {
++                sftp->requirev_start = 0;
++                return PACKET_TIMEOUT;
++            } else if (ret == PACKET_EAGAIN) {
++                return PACKET_EAGAIN;
++            }
++        }
++    }
++
++    sftp->requirev_start = 0;
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_attrsize
++ * Size that attr will occupy when turned into a bin struct
++ */
++static int
++libssh2_sftp_attrsize(const LIBSSH2_SFTP_ATTRIBUTES * attrs)
++{
++    int attrsize = 4;           /* flags(4) */
++
++    if (!attrs) {
++        return attrsize;
++    }
++
++    if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE)
++        attrsize += 8;
++    if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID)
++        attrsize += 8;
++    if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS)
++        attrsize += 4;
++    if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME)
++        attrsize += 8;          /* atime + mtime as u32 */
++
++    return attrsize;
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_attr2bin
++ * Populate attributes into an SFTP block
++ */
++static int
++libssh2_sftp_attr2bin(unsigned char *p, const LIBSSH2_SFTP_ATTRIBUTES * attrs)
++{
++    unsigned char *s = p;
++    unsigned long flag_mask =
++        LIBSSH2_SFTP_ATTR_SIZE | LIBSSH2_SFTP_ATTR_UIDGID |
++        LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME;
++
++    /* TODO: When we add SFTP4+ functionality flag_mask can get additional bits */
++
++    if (!attrs) {
++        libssh2_htonu32(s, 0);
++        return 4;
++    }
++
++    libssh2_htonu32(s, attrs->flags & flag_mask);
++    s += 4;
++
++    if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
++        libssh2_htonu64(s, attrs->filesize);
++        s += 8;
++    }
++
++    if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) {
++        libssh2_htonu32(s, attrs->uid);
++        s += 4;
++        libssh2_htonu32(s, attrs->gid);
++        s += 4;
++    }
++
++    if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
++        libssh2_htonu32(s, attrs->permissions);
++        s += 4;
++    }
++
++    if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
++        libssh2_htonu32(s, attrs->atime);
++        s += 4;
++        libssh2_htonu32(s, attrs->mtime);
++        s += 4;
++    }
++
++    return (s - p);
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_bin2attr
++ */
++static int
++libssh2_sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES * attrs, const unsigned char *p)
++{
++    const unsigned char *s = p;
++
++    memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
++    attrs->flags = libssh2_ntohu32(s);
++    s += 4;
++
++    if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
++        attrs->filesize = libssh2_ntohu64(s);
++        s += 8;
++    }
++
++    if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) {
++        attrs->uid = libssh2_ntohu32(s);
++        s += 4;
++        attrs->gid = libssh2_ntohu32(s);
++        s += 4;
++    }
++
++    if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
++        attrs->permissions = libssh2_ntohu32(s);
++        s += 4;
++    }
++
++    if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
++        attrs->atime = libssh2_ntohu32(s);
++        s += 4;
++        attrs->mtime = libssh2_ntohu32(s);
++        s += 4;
++    }
++
++    return (s - p);
++}
++
++/* }}} */
++
++/* ************
++   * SFTP API *
++   ************ */
++
++LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor);
++
++/* {{{ libssh2_sftp_dtor
++ * Shutdown an SFTP stream when the channel closes
++ */
++LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor)
++{
++    LIBSSH2_SFTP *sftp = (LIBSSH2_SFTP *) (*channel_abstract);
++
++    (void) session_abstract;
++    (void) channel;
++
++    /* Loop through handles closing them */
++    while (sftp->handles) {
++        libssh2_sftp_close_handle(sftp->handles);
++    }
++
++    /* Free the partial packet storage for sftp_packet_read */
++    if (sftp->partial_packet) {
++        LIBSSH2_FREE(session, sftp->partial_packet);
++    }
++
++    /* Free the packet storage for _libssh2_sftp_packet_readdir */
++    if (sftp->readdir_packet) {
++        LIBSSH2_FREE(session, sftp->readdir_packet);
++    }
++
++    LIBSSH2_FREE(session, sftp);
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_init
++ * Startup an SFTP session
++ *
++ * NOTE:  Will block in a busy loop on error.  This has to be done,
++ *        otherwise the blocking error code would erase the true
++ *        cause of the error.
++ */
++LIBSSH2_API LIBSSH2_SFTP *
++libssh2_sftp_init(LIBSSH2_SESSION * session)
++{
++    unsigned char *data, *s;
++    unsigned long data_len;
++    int rc;
++
++    if (session->sftpInit_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
++                       "Initializing SFTP subsystem");
++
++        session->sftpInit_sftp = NULL;
++
++        session->sftpInit_state = libssh2_NB_state_created;
++    }
++
++    if (session->sftpInit_state == libssh2_NB_state_created) {
++        session->sftpInit_channel =
++            libssh2_channel_open_ex(session, "session", sizeof("session") - 1,
++                                    LIBSSH2_CHANNEL_WINDOW_DEFAULT,
++                                    LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0);
++        if (!session->sftpInit_channel) {
++            if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
++                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                              "Would block starting up channel", 0);
++                return NULL;
++            } else if (libssh2_session_last_errno(session) !=
++                       LIBSSH2_ERROR_EAGAIN) {
++                libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
++                              "Unable to startup channel", 0);
++                session->sftpInit_state = libssh2_NB_state_idle;
++                return NULL;
++            }
++        }
++
++        session->sftpInit_state = libssh2_NB_state_sent;
++    }
++
++    if (session->sftpInit_state == libssh2_NB_state_sent) {
++        rc = libssh2_channel_process_startup(session->sftpInit_channel,
++                                             "subsystem",
++                                             sizeof("subsystem") - 1, "sftp",
++                                             strlen("sftp"));
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block to request SFTP subsystem", 0);
++            return NULL;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
++                          "Unable to request SFTP subsystem", 0);
++            goto sftp_init_error;
++        }
++
++        session->sftpInit_state = libssh2_NB_state_sent1;
++    }
++
++    if (session->sftpInit_state == libssh2_NB_state_sent1) {
++        rc = libssh2_channel_handle_extended_data2(session->sftpInit_channel,
++                                                   LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block requesting handle extended data", 0);
++            return NULL;
++        }
++
++        session->sftpInit_sftp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP));
++        if (!session->sftpInit_sftp) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate a new SFTP structure", 0);
++            goto sftp_init_error;
++        }
++        memset(session->sftpInit_sftp, 0, sizeof(LIBSSH2_SFTP));
++        session->sftpInit_sftp->channel = session->sftpInit_channel;
++        session->sftpInit_sftp->request_id = 0;
++
++        libssh2_htonu32(session->sftpInit_buffer, 5);
++        session->sftpInit_buffer[4] = SSH_FXP_INIT;
++        libssh2_htonu32(session->sftpInit_buffer + 5, LIBSSH2_SFTP_VERSION);
++
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
++                       "Sending FXP_INIT packet advertising version %d support",
++                       (int) LIBSSH2_SFTP_VERSION);
++
++        session->sftpInit_state = libssh2_NB_state_sent2;
++    }
++
++    if (session->sftpInit_state == libssh2_NB_state_sent2) {
++        rc = libssh2_channel_write_ex(session->sftpInit_channel, 0,
++                                      (char *) session->sftpInit_buffer, 9);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block sending SSH_FXP_INIT", 0);
++            return NULL;
++        } else if (9 != rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send SSH_FXP_INIT", 0);
++            goto sftp_init_error;
++        }
++
++        session->sftpInit_state = libssh2_NB_state_sent3;
++    }
++
++    /* For initiallization we are requiring blocking, probably reasonable */
++    rc = sftp_packet_require(session->sftpInit_sftp, SSH_FXP_VERSION,
++                             0, &data, &data_len);
++    if (rc == PACKET_EAGAIN) {
++        libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                      "Would block waiting for response from SFTP subsystem",
++                      0);
++        return NULL;
++    } else if (rc) {
++        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                      "Timeout waiting for response from SFTP subsystem", 0);
++        goto sftp_init_error;
++    }
++    if (data_len < 5) {
++        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                      "Invalid SSH_FXP_VERSION response", 0);
++        goto sftp_init_error;
++    }
++
++    s = data + 1;
++    session->sftpInit_sftp->version = libssh2_ntohu32(s);
++    s += 4;
++    if (session->sftpInit_sftp->version > LIBSSH2_SFTP_VERSION) {
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
++                       "Truncating remote SFTP version from %lu",
++                       session->sftpInit_sftp->version);
++        session->sftpInit_sftp->version = LIBSSH2_SFTP_VERSION;
++    }
++    _libssh2_debug(session, LIBSSH2_DBG_SFTP,
++                   "Enabling SFTP version %lu compatability",
++                   session->sftpInit_sftp->version);
++    while (s < (data + data_len)) {
++        unsigned char *extension_name, *extension_data;
++        unsigned long extname_len, extdata_len;
++
++        extname_len = libssh2_ntohu32(s);
++        s += 4;
++        extension_name = s;
++        s += extname_len;
++
++        extdata_len = libssh2_ntohu32(s);
++        s += 4;
++        extension_data = s;
++        s += extdata_len;
++
++        /* TODO: Actually process extensions */
++    }
++    LIBSSH2_FREE(session, data);
++
++    /* Make sure that when the channel gets closed, the SFTP service is shut down too */
++    session->sftpInit_sftp->channel->abstract = session->sftpInit_sftp;
++    session->sftpInit_sftp->channel->close_cb = libssh2_sftp_dtor;
++
++    session->sftpInit_state = libssh2_NB_state_idle;
++    return session->sftpInit_sftp;
++
++  sftp_init_error:
++    while (libssh2_channel_free(session->sftpInit_channel) == PACKET_EAGAIN);
++    session->sftpInit_channel = NULL;
++    if (session->sftpInit_sftp) {
++        LIBSSH2_FREE(session, session->sftpInit_sftp);
++        session->sftpInit_sftp = NULL;
++    }
++    session->sftpInit_state = libssh2_NB_state_idle;
++    return NULL;
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_shutdown
++ * Shutsdown the SFTP subsystem
++ */
++LIBSSH2_API int
++libssh2_sftp_shutdown(LIBSSH2_SFTP * sftp)
++{
++    /*
++     * Make sure all memory used in the state variables are free
++     */
++    if (sftp->partial_packet) {
++        LIBSSH2_FREE(sftp->channel->session, sftp->partial_packet);
++        sftp->partial_packet = NULL;
++    }
++    if (sftp->open_packet) {
++        LIBSSH2_FREE(sftp->channel->session, sftp->open_packet);
++        sftp->open_packet = NULL;
++    }
++    if (sftp->readdir_packet) {
++        LIBSSH2_FREE(sftp->channel->session, sftp->readdir_packet);
++        sftp->readdir_packet = NULL;
++    }
++    if (sftp->write_packet) {
++        LIBSSH2_FREE(sftp->channel->session, sftp->write_packet);
++        sftp->write_packet = NULL;
++    }
++    if (sftp->fstat_packet) {
++        LIBSSH2_FREE(sftp->channel->session, sftp->fstat_packet);
++        sftp->fstat_packet = NULL;
++    }
++    if (sftp->unlink_packet) {
++        LIBSSH2_FREE(sftp->channel->session, sftp->unlink_packet);
++        sftp->unlink_packet = NULL;
++    }
++    if (sftp->rename_packet) {
++        LIBSSH2_FREE(sftp->channel->session, sftp->rename_packet);
++        sftp->rename_packet = NULL;
++    }
++    if (sftp->mkdir_packet) {
++        LIBSSH2_FREE(sftp->channel->session, sftp->mkdir_packet);
++        sftp->mkdir_packet = NULL;
++    }
++    if (sftp->rmdir_packet) {
++        LIBSSH2_FREE(sftp->channel->session, sftp->rmdir_packet);
++        sftp->rmdir_packet = NULL;
++    }
++    if (sftp->stat_packet) {
++        LIBSSH2_FREE(sftp->channel->session, sftp->stat_packet);
++        sftp->stat_packet = NULL;
++    }
++    if (sftp->symlink_packet) {
++        LIBSSH2_FREE(sftp->channel->session, sftp->symlink_packet);
++        sftp->symlink_packet = NULL;
++    }
++
++    return libssh2_channel_free(sftp->channel);
++}
++
++/* }}} */
++
++/* *******************************
++   * SFTP File and Directory Ops *
++   ******************************* */
++
++/* {{{ libssh2_sftp_open_ex
++ */
++LIBSSH2_API LIBSSH2_SFTP_HANDLE *
++libssh2_sftp_open_ex(LIBSSH2_SFTP * sftp, const char *filename,
++                     unsigned int filename_len, unsigned long flags, long mode,
++                     int open_type)
++{
++    LIBSSH2_CHANNEL *channel = sftp->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    LIBSSH2_SFTP_HANDLE *fp;
++    LIBSSH2_SFTP_ATTRIBUTES attrs = {
++        LIBSSH2_SFTP_ATTR_PERMISSIONS, 0, 0, 0, 0, 0, 0
++    };
++    unsigned long data_len;
++    unsigned char *data, *s;
++    static const unsigned char fopen_responses[2] =
++        { SSH_FXP_HANDLE, SSH_FXP_STATUS };
++    int rc;
++
++    if (sftp->open_state == libssh2_NB_state_idle) {
++        /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) +
++           flags(4) */
++        sftp->open_packet_len = filename_len + 13 +
++            ((open_type ==
++              LIBSSH2_SFTP_OPENFILE) ? (4 +
++                                        libssh2_sftp_attrsize(&attrs)) : 0);
++
++        s = sftp->open_packet = LIBSSH2_ALLOC(session, sftp->open_packet_len);
++        if (!sftp->open_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for FXP_OPEN or "
++                          "FXP_OPENDIR packet",
++                          0);
++            return NULL;
++        }
++        /* Filetype in SFTP 3 and earlier */
++        attrs.permissions = mode |
++            ((open_type ==
++              LIBSSH2_SFTP_OPENFILE) ? LIBSSH2_SFTP_ATTR_PFILETYPE_FILE :
++             LIBSSH2_SFTP_ATTR_PFILETYPE_DIR);
++
++        libssh2_htonu32(s, sftp->open_packet_len - 4);
++        s += 4;
++        *(s++) =
++            (open_type ==
++             LIBSSH2_SFTP_OPENFILE) ? SSH_FXP_OPEN : SSH_FXP_OPENDIR;
++        sftp->open_request_id = sftp->request_id++;
++        libssh2_htonu32(s, sftp->open_request_id);
++        s += 4;
++        libssh2_htonu32(s, filename_len);
++        s += 4;
++        memcpy(s, filename, filename_len);
++        s += filename_len;
++        if (open_type == LIBSSH2_SFTP_OPENFILE) {
++            libssh2_htonu32(s, flags);
++            s += 4;
++            s += libssh2_sftp_attr2bin(s, &attrs);
++        }
++
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending %s open request",
++                       (open_type ==
++                        LIBSSH2_SFTP_OPENFILE) ? "file" : "directory");
++
++        sftp->open_state = libssh2_NB_state_created;
++    }
++
++    if (sftp->open_state == libssh2_NB_state_created) {
++        rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->open_packet,
++                                      sftp->open_packet_len);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block sending FXP_OPEN or FXP_OPENDIR command",
++                          0);
++            return NULL;
++        }
++        else if (sftp->open_packet_len != rc) {
++            /* TODO: partial writes should be fine too and is not a sign of
++               an error when in non-blocking mode! */
++
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send FXP_OPEN or FXP_OPENDIR command", 0);
++            LIBSSH2_FREE(session, sftp->open_packet);
++            sftp->open_packet = NULL;
++            sftp->open_state = libssh2_NB_state_idle;
++            return NULL;
++        }
++        LIBSSH2_FREE(session, sftp->open_packet);
++        sftp->open_packet = NULL;
++
++        sftp->open_state = libssh2_NB_state_sent;
++    }
++
++    if (sftp->open_state == libssh2_NB_state_sent) {
++        rc = sftp_packet_requirev(sftp, 2, fopen_responses,
++                                  sftp->open_request_id, &data,
++                                  &data_len);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block waiting for status message", 0);
++            return NULL;
++        }
++        else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                          "Timeout waiting for status message", 0);
++            sftp->open_state = libssh2_NB_state_idle;
++            return NULL;
++        }
++    }
++
++    sftp->open_state = libssh2_NB_state_idle;
++
++    /* OPEN can basically get STATUS or HANDLE back, where HANDLE implies a
++       fine response while STATUS means error. It seems though that at times
++       we get an SSH_FX_OK back in a STATUS, followed the "real" HANDLE so
++       we need to properly deal with that. */
++    if (data[0] == SSH_FXP_STATUS) {
++        int badness = 1;
++        sftp->last_errno = libssh2_ntohu32(data + 5);
++
++        if(LIBSSH2_FX_OK == sftp->last_errno) {
++            _libssh2_debug(session, LIBSSH2_DBG_SFTP, "got HANDLE FXOK!");
++
++            /* silly situation, but check for a HANDLE */
++            rc = sftp_packet_require(sftp, SSH_FXP_HANDLE,
++                                     sftp->open_request_id, &data, &data_len);
++            if(rc == PACKET_EAGAIN) {
++                /* go back to sent state and wait for something else */
++                sftp->open_state = libssh2_NB_state_sent;
++                return NULL;
++            }
++            else if(!rc)
++                /* we got the handle so this is not a bad situation */
++                badness = 0;
++        }
++
++        if(badness) {
++            libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                          "Failed opening remote file", 0);
++            _libssh2_debug(session, LIBSSH2_DBG_SFTP, "got FXP_STATUS %d",
++                           sftp->last_errno);
++            LIBSSH2_FREE(session, data);
++            return NULL;
++        }
++    }
++
++    fp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP_HANDLE));
++    if (!fp) {
++        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                      "Unable to allocate new SFTP handle structure", 0);
++        LIBSSH2_FREE(session, data);
++        return NULL;
++    }
++    memset(fp, 0, sizeof(LIBSSH2_SFTP_HANDLE));
++    fp->handle_type =
++        (open_type ==
++         LIBSSH2_SFTP_OPENFILE) ? LIBSSH2_SFTP_HANDLE_FILE :
++        LIBSSH2_SFTP_HANDLE_DIR;
++
++    fp->handle_len = libssh2_ntohu32(data + 5);
++    if (fp->handle_len > SFTP_HANDLE_MAXLEN) {
++        /* SFTP doesn't allow handles longer than 256 characters */
++        fp->handle_len = SFTP_HANDLE_MAXLEN;
++    }
++
++    memcpy(fp->handle, data + 9, fp->handle_len);
++    LIBSSH2_FREE(session, data);
++
++    /* Link the file and the sftp session together */
++    fp->next = sftp->handles;
++    if (fp->next) {
++        fp->next->prev = fp;
++    }
++    fp->sftp = sftp;
++
++    fp->u.file.offset = 0;
++
++    _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Open command successful");
++    return fp;
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_read
++ * Read from an SFTP file handle
++ */
++LIBSSH2_API ssize_t
++libssh2_sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
++                  size_t buffer_maxlen)
++{
++    LIBSSH2_SFTP *sftp = handle->sftp;
++    LIBSSH2_CHANNEL *channel = sftp->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned long data_len, request_id = 0;
++    /* 25 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) +
++       offset(8) + length(4) */
++    ssize_t packet_len = handle->handle_len + 25;
++    unsigned char *packet, *s, *data;
++    static const unsigned char read_responses[2] =
++        { SSH_FXP_DATA, SSH_FXP_STATUS };
++    size_t bytes_read = 0;
++    size_t bytes_requested = 0;
++    size_t total_read = 0;
++    int retcode;
++
++    if (sftp->read_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
++                       "Reading %lu bytes from SFTP handle",
++                       (unsigned long) buffer_maxlen);
++        packet = handle->request_packet;
++        sftp->read_state = libssh2_NB_state_allocated;
++    } else {
++        packet = sftp->read_packet;
++        request_id = sftp->read_request_id;
++        total_read = sftp->read_total_read;
++    }
++
++    while (total_read < buffer_maxlen) {
++        s = packet;
++        /*
++         * If buffer_maxlen bytes will be requested, server may return all
++         * with one packet.  But libssh2 have packet length limit.
++         * So we request data by pieces.
++         */
++        bytes_requested = buffer_maxlen - total_read;
++        /* 10 = packet_type(1) + request_id(4) + data_length(4) +
++           end_of_line_flag(1)
++
++           10 is changed to 13 below simple because it seems there's a
++           "GlobalScape" SFTP server that responds with a slightly too big
++           buffer at times and we can apparently compensate for that by doing
++           this trick.
++
++           Further details on this issue:
++
++           https://sourceforge.net/mailarchive/forum.php?thread_name=9c3275a90811261517v6c0b1da2u918cc1b8370abf83%40mail.gmail.com&forum_name=libssh2-devel
++
++           http://forums.globalscape.com/tm.aspx?m=15249
++
++        */
++        if (bytes_requested > LIBSSH2_SFTP_PACKET_MAXLEN - 13) {
++            bytes_requested = LIBSSH2_SFTP_PACKET_MAXLEN - 13;
++        }
++#ifdef LIBSSH2_DEBUG_SFTP
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
++                       "Requesting %lu bytes from SFTP handle",
++                       (unsigned long) bytes_requested);
++#endif
++
++        if (sftp->read_state == libssh2_NB_state_allocated) {
++            libssh2_htonu32(s, packet_len - 4);
++            s += 4;
++            *(s++) = SSH_FXP_READ;
++            request_id = sftp->request_id++;
++            libssh2_htonu32(s, request_id);
++            s += 4;
++            libssh2_htonu32(s, handle->handle_len);
++            s += 4;
++
++            memcpy(s, handle->handle, handle->handle_len);
++            s += handle->handle_len;
++
++            libssh2_htonu64(s, handle->u.file.offset);
++            s += 8;
++
++            libssh2_htonu32(s, bytes_requested);
++            s += 4;
++
++            sftp->read_state = libssh2_NB_state_created;
++        }
++
++        if (sftp->read_state == libssh2_NB_state_created) {
++            retcode =
++                libssh2_channel_write_ex(channel, 0, (char *) packet,
++                                         packet_len);
++            if (retcode == PACKET_EAGAIN) {
++                sftp->read_packet = packet;
++                sftp->read_request_id = request_id;
++                sftp->read_total_read = total_read;
++                return PACKET_EAGAIN;
++            } else if (packet_len != retcode) {
++                /* TODO: a partial write is not a critical error when in
++                   non-blocking mode! */
++                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                              "Unable to send FXP_READ command", 0);
++                sftp->read_packet = NULL;
++                sftp->read_state = libssh2_NB_state_idle;
++                return -1;
++            }
++            sftp->read_packet = packet;
++            sftp->read_request_id = request_id;
++            sftp->read_total_read = total_read;
++            sftp->read_state = libssh2_NB_state_sent;
++        }
++
++        if (sftp->read_state == libssh2_NB_state_sent) {
++            retcode =
++                sftp_packet_requirev(sftp, 2, read_responses,
++                                     request_id, &data, &data_len);
++            if (retcode == PACKET_EAGAIN) {
++                return PACKET_EAGAIN;
++            } else if (retcode) {
++                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                              "Timeout waiting for status message", 0);
++                sftp->read_packet = NULL;
++                sftp->read_state = libssh2_NB_state_idle;
++                return -1;
++            }
++
++            sftp->read_state = libssh2_NB_state_sent1;
++        }
++
++        switch (data[0]) {
++        case SSH_FXP_STATUS:
++            retcode = libssh2_ntohu32(data + 5);
++            LIBSSH2_FREE(session, data);
++            sftp->read_packet = NULL;
++            sftp->read_state = libssh2_NB_state_idle;
++
++            if (retcode == LIBSSH2_FX_EOF) {
++                return total_read;
++            } else {
++                sftp->last_errno = retcode;
++                libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                              "SFTP Protocol Error", 0);
++                return -1;
++            }
++
++        case SSH_FXP_DATA:
++            bytes_read = libssh2_ntohu32(data + 5);
++            if (bytes_read > (data_len - 9)) {
++                sftp->read_packet = NULL;
++                sftp->read_state = libssh2_NB_state_idle;
++                return -1;
++            }
++#ifdef LIBSSH2_DEBUG_SFTP
++            _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu bytes returned",
++                           (unsigned long) bytes_read);
++#endif
++            memcpy(buffer + total_read, data + 9, bytes_read);
++            handle->u.file.offset += bytes_read;
++            total_read += bytes_read;
++            LIBSSH2_FREE(session, data);
++            /*
++             * Set the state back to allocated, so a new one will be
++             * created to either request more data or get EOF
++             */
++            sftp->read_state = libssh2_NB_state_allocated;
++        }
++    }
++
++    sftp->read_packet = NULL;
++    sftp->read_state = libssh2_NB_state_idle;
++    return total_read;
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_readdir
++ * Read from an SFTP directory handle
++ */
++LIBSSH2_API int
++libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
++                        size_t buffer_maxlen, char *longentry,
++                        size_t longentry_maxlen,
++                        LIBSSH2_SFTP_ATTRIBUTES * attrs)
++{
++    LIBSSH2_SFTP *sftp = handle->sftp;
++    LIBSSH2_CHANNEL *channel = sftp->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    LIBSSH2_SFTP_ATTRIBUTES attrs_dummy;
++    unsigned long data_len, filename_len, longentry_len, num_names;
++    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
++    ssize_t packet_len = handle->handle_len + 13;
++    unsigned char *s, *data;
++    unsigned char read_responses[2] = { SSH_FXP_NAME, SSH_FXP_STATUS };
++    int retcode;
++
++    if (sftp->readdir_state == libssh2_NB_state_idle) {
++        if (handle->u.dir.names_left) {
++            /*
++             * A prior request returned more than one directory entry,
++             * feed it back from the buffer
++             */
++            unsigned char *s = (unsigned char *) handle->u.dir.next_name;
++            unsigned long real_filename_len = libssh2_ntohu32(s);
++
++            filename_len = real_filename_len;
++            s += 4;
++            if (filename_len > buffer_maxlen) {
++                filename_len = buffer_maxlen;
++            }
++            memcpy(buffer, s, filename_len);
++            s += real_filename_len;
++
++            /* The filename is not null terminated, make it so if possible */
++            if (filename_len < buffer_maxlen) {
++                buffer[filename_len] = '\0';
++            }
++
++            if ((longentry == NULL) || (longentry_maxlen == 0)) {
++                /* Skip longname */
++                s += 4 + libssh2_ntohu32(s);
++            } else {
++                unsigned long real_longentry_len = libssh2_ntohu32(s);
++
++                longentry_len = real_longentry_len;
++                s += 4;
++                if (longentry_len > longentry_maxlen) {
++                    longentry_len = longentry_maxlen;
++                }
++                memcpy(longentry, s, longentry_len);
++                s += real_longentry_len;
++
++                /* The longentry is not null terminated, make it so if possible */
++                if (longentry_len < longentry_maxlen) {
++                    longentry[longentry_len] = '\0';
++                }
++            }
++
++            if (attrs) {
++                memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
++            }
++            s += libssh2_sftp_bin2attr(attrs ? attrs : &attrs_dummy, s);
++
++            handle->u.dir.next_name = (char *) s;
++            if ((--handle->u.dir.names_left) == 0) {
++                LIBSSH2_FREE(session, handle->u.dir.names_packet);
++            }
++
++            _libssh2_debug(session, LIBSSH2_DBG_SFTP,
++                           "libssh2_sftp_readdir_ex() return %d",
++                           filename_len);
++            return filename_len;
++        }
++
++        /* Request another entry(entries?) */
++
++        s = sftp->readdir_packet = LIBSSH2_ALLOC(session, packet_len);
++        if (!sftp->readdir_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for FXP_READDIR packet",
++                          0);
++            return -1;
++        }
++
++        libssh2_htonu32(s, packet_len - 4);
++        s += 4;
++        *(s++) = SSH_FXP_READDIR;
++        sftp->readdir_request_id = sftp->request_id++;
++        libssh2_htonu32(s, sftp->readdir_request_id);
++        s += 4;
++        libssh2_htonu32(s, handle->handle_len);
++        s += 4;
++        memcpy(s, handle->handle, handle->handle_len);
++        s += handle->handle_len;
++
++        sftp->readdir_state = libssh2_NB_state_created;
++    }
++
++    if (sftp->readdir_state == libssh2_NB_state_created) {
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
++                       "Reading entries from directory handle");
++        if ((retcode =
++             libssh2_channel_write_ex(channel, 0,
++                                      (char *) sftp->readdir_packet,
++                                      packet_len)) == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (packet_len != retcode) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send FXP_READ command", 0);
++            LIBSSH2_FREE(session, sftp->readdir_packet);
++            sftp->readdir_packet = NULL;
++            sftp->readdir_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        LIBSSH2_FREE(session, sftp->readdir_packet);
++        sftp->readdir_packet = NULL;
++
++        sftp->readdir_state = libssh2_NB_state_sent;
++    }
++
++    retcode =
++        sftp_packet_requirev(sftp, 2, read_responses,
++                             sftp->readdir_request_id, &data,
++                             &data_len);
++    if (retcode == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    } else if (retcode) {
++        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                      "Timeout waiting for status message", 0);
++        sftp->readdir_state = libssh2_NB_state_idle;
++        return -1;
++    }
++
++    if (data[0] == SSH_FXP_STATUS) {
++        retcode = libssh2_ntohu32(data + 5);
++        LIBSSH2_FREE(session, data);
++        if (retcode == LIBSSH2_FX_EOF) {
++            sftp->readdir_state = libssh2_NB_state_idle;
++            return 0;
++        } else {
++            sftp->last_errno = retcode;
++            libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                          "SFTP Protocol Error", 0);
++            sftp->readdir_state = libssh2_NB_state_idle;
++            return -1;
++        }
++    }
++
++    num_names = libssh2_ntohu32(data + 5);
++    _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu entries returned",
++                   num_names);
++    if (num_names <= 0) {
++        LIBSSH2_FREE(session, data);
++        sftp->readdir_state = libssh2_NB_state_idle;
++        return (num_names == 0) ? 0 : -1;
++    }
++
++    if (num_names == 1) {
++        unsigned long real_filename_len = libssh2_ntohu32(data + 9);
++
++        filename_len = real_filename_len;
++        if (filename_len > buffer_maxlen) {
++            filename_len = buffer_maxlen;
++        }
++        memcpy(buffer, data + 13, filename_len);
++
++        /* The filename is not null terminated, make it so if possible */
++        if (filename_len < buffer_maxlen) {
++            buffer[filename_len] = '\0';
++        }
++
++        if (attrs) {
++            memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
++            libssh2_sftp_bin2attr(attrs, data + 13 + real_filename_len +
++                                  (4 +
++                                   libssh2_ntohu32(data + 13 +
++                                                   real_filename_len)));
++        }
++        LIBSSH2_FREE(session, data);
++
++        sftp->readdir_state = libssh2_NB_state_idle;
++        return filename_len;
++    }
++
++    handle->u.dir.names_left = num_names;
++    handle->u.dir.names_packet = data;
++    handle->u.dir.next_name = (char *) data + 9;
++
++    sftp->readdir_state = libssh2_NB_state_idle;
++
++    /* Be lazy, just use the name popping mechanism from the start of the function */
++    return libssh2_sftp_readdir_ex(handle, buffer, buffer_maxlen, longentry,
++                                   longentry_maxlen, attrs);
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_write
++ * Write data to a file handle
++ */
++LIBSSH2_API ssize_t
++libssh2_sftp_write(LIBSSH2_SFTP_HANDLE * handle, const char *buffer,
++                   size_t count)
++{
++    LIBSSH2_SFTP *sftp = handle->sftp;
++    LIBSSH2_CHANNEL *channel = sftp->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned long data_len, retcode;
++    /* 25 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) +
++       offset(8) + count(4) */
++    ssize_t packet_len = handle->handle_len + count + 25;
++    unsigned char *s, *data;
++    int rc;
++
++    if (sftp->write_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Writing %lu bytes",
++                       (unsigned long) count);
++        s = sftp->write_packet = LIBSSH2_ALLOC(session, packet_len);
++        if (!sftp->write_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for FXP_WRITE packet", 0);
++            return -1;
++        }
++
++        libssh2_htonu32(s, packet_len - 4);
++        s += 4;
++        *(s++) = SSH_FXP_WRITE;
++        sftp->write_request_id = sftp->request_id++;
++        libssh2_htonu32(s, sftp->write_request_id);
++        s += 4;
++        libssh2_htonu32(s, handle->handle_len);
++        s += 4;
++        memcpy(s, handle->handle, handle->handle_len);
++        s += handle->handle_len;
++        libssh2_htonu64(s, handle->u.file.offset);
++        s += 8;
++        libssh2_htonu32(s, count);
++        s += 4;
++        memcpy(s, buffer, count);
++        s += count;
++
++        sftp->write_state = libssh2_NB_state_created;
++    }
++
++    if (sftp->write_state == libssh2_NB_state_created) {
++        if ((rc =
++             libssh2_channel_write_ex(channel, 0, (char *) sftp->write_packet,
++                                      packet_len)) == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        }
++        if (packet_len != rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send FXP_READ command", 0);
++            LIBSSH2_FREE(session, sftp->write_packet);
++            sftp->write_packet = NULL;
++            sftp->write_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, sftp->write_packet);
++        sftp->write_packet = NULL;
++        sftp->write_state = libssh2_NB_state_sent;
++    }
++
++    rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
++                             sftp->write_request_id, &data, &data_len);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    } else if (rc) {
++        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                      "Timeout waiting for status message", 0);
++        sftp->write_state = libssh2_NB_state_idle;
++        return -1;
++    }
++
++    sftp->write_state = libssh2_NB_state_idle;
++
++    retcode = libssh2_ntohu32(data + 5);
++    LIBSSH2_FREE(session, data);
++
++    if (retcode == LIBSSH2_FX_OK) {
++        handle->u.file.offset += count;
++        return count;
++    }
++    libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error",
++                  0);
++    sftp->last_errno = retcode;
++
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_fstat_ex
++ * Get or Set stat on a file
++ */
++LIBSSH2_API int
++libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE * handle,
++                      LIBSSH2_SFTP_ATTRIBUTES * attrs, int setstat)
++{
++    LIBSSH2_SFTP *sftp = handle->sftp;
++    LIBSSH2_CHANNEL *channel = sftp->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned long data_len;
++    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
++    ssize_t packet_len =
++        handle->handle_len + 13 + (setstat ? libssh2_sftp_attrsize(attrs) : 0);
++    unsigned char *s, *data;
++    static const unsigned char fstat_responses[2] =
++        { SSH_FXP_ATTRS, SSH_FXP_STATUS };
++    int rc;
++
++    if (sftp->fstat_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Issuing %s command",
++                       setstat ? "set-stat" : "stat");
++        s = sftp->fstat_packet = LIBSSH2_ALLOC(session, packet_len);
++        if (!sftp->fstat_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for FSTAT/FSETSTAT packet",
++                          0);
++            return -1;
++        }
++
++        libssh2_htonu32(s, packet_len - 4);
++        s += 4;
++        *(s++) = setstat ? SSH_FXP_FSETSTAT : SSH_FXP_FSTAT;
++        sftp->fstat_request_id = sftp->request_id++;
++        libssh2_htonu32(s, sftp->fstat_request_id);
++        s += 4;
++        libssh2_htonu32(s, handle->handle_len);
++        s += 4;
++        memcpy(s, handle->handle, handle->handle_len);
++        s += handle->handle_len;
++        if (setstat) {
++            s += libssh2_sftp_attr2bin(s, attrs);
++        }
++
++        sftp->fstat_state = libssh2_NB_state_created;
++    }
++
++    if (sftp->fstat_state == libssh2_NB_state_created) {
++        rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->fstat_packet,
++                                      packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (packet_len != rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          (setstat ? "Unable to send FXP_FSETSTAT"
++                           : "Unable to send FXP_FSTAT command"), 0);
++            LIBSSH2_FREE(session, sftp->fstat_packet);
++            sftp->fstat_packet = NULL;
++            sftp->fstat_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, sftp->fstat_packet);
++        sftp->fstat_packet = NULL;
++
++        sftp->fstat_state = libssh2_NB_state_sent;
++    }
++
++    rc = sftp_packet_requirev(sftp, 2, fstat_responses,
++                              sftp->fstat_request_id, &data,
++                              &data_len);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    } else if (rc) {
++        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                      "Timeout waiting for status message", 0);
++        sftp->fstat_state = libssh2_NB_state_idle;
++        return -1;
++    }
++
++    sftp->fstat_state = libssh2_NB_state_idle;
++
++    if (data[0] == SSH_FXP_STATUS) {
++        int retcode;
++
++        retcode = libssh2_ntohu32(data + 5);
++        LIBSSH2_FREE(session, data);
++        if (retcode == LIBSSH2_FX_OK) {
++            return 0;
++        } else {
++            sftp->last_errno = retcode;
++            libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                          "SFTP Protocol Error", 0);
++            return -1;
++        }
++    }
++
++    libssh2_sftp_bin2attr(attrs, data + 5);
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_seek
++ * Set the read/write pointer to an arbitrary position within the file
++ */
++LIBSSH2_API void
++libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE * handle, size_t offset)
++{
++    handle->u.file.offset = offset;
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_seek64
++ * Set the read/write pointer to an arbitrary position within the file
++ */
++LIBSSH2_API void
++libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE * handle, libssh2_uint64_t offset)
++{
++    handle->u.file.offset = offset;
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_tell
++ * Return the current read/write pointer's offset
++ */
++LIBSSH2_API size_t
++libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE * handle)
++{
++    return handle->u.file.offset;
++}
++
++/* {{{ libssh2_sftp_tell64
++ * Return the current read/write pointer's offset
++ */
++LIBSSH2_API libssh2_uint64_t
++libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE * handle)
++{
++    return handle->u.file.offset;
++}
++
++/* }}} */
++
++
++/* {{{ libssh2_sftp_close_handle
++ * Close a file or directory handle
++ * Also frees handle resource and unlinks it from the SFTP structure
++ */
++LIBSSH2_API int
++libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE * handle)
++{
++    LIBSSH2_SFTP *sftp = handle->sftp;
++    LIBSSH2_CHANNEL *channel = sftp->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned long data_len, retcode;
++    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
++    ssize_t packet_len = handle->handle_len + 13;
++    unsigned char *s, *data;
++    int rc;
++
++    if (handle->close_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Closing handle");
++        s = handle->close_packet = LIBSSH2_ALLOC(session, packet_len);
++        if (!handle->close_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for FXP_CLOSE packet", 0);
++            return -1;
++        }
++
++        libssh2_htonu32(s, packet_len - 4);
++        s += 4;
++        *(s++) = SSH_FXP_CLOSE;
++        handle->close_request_id = sftp->request_id++;
++        libssh2_htonu32(s, handle->close_request_id);
++        s += 4;
++        libssh2_htonu32(s, handle->handle_len);
++        s += 4;
++        memcpy(s, handle->handle, handle->handle_len);
++        s += handle->handle_len;
++
++        handle->close_state = libssh2_NB_state_created;
++    }
++
++    if (handle->close_state == libssh2_NB_state_created) {
++        rc = libssh2_channel_write_ex(channel, 0,
++                                      (char *) handle->close_packet,
++                                      packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (packet_len != rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send FXP_CLOSE command", 0);
++            LIBSSH2_FREE(session, handle->close_packet);
++            handle->close_packet = NULL;
++            handle->close_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, handle->close_packet);
++        handle->close_packet = NULL;
++
++        handle->close_state = libssh2_NB_state_sent;
++    }
++
++    if (handle->close_state == libssh2_NB_state_sent) {
++        rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
++                                 handle->close_request_id, &data,
++                                 &data_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                          "Timeout waiting for status message", 0);
++            handle->close_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        handle->close_state = libssh2_NB_state_sent1;
++    }
++
++    retcode = libssh2_ntohu32(data + 5);
++    LIBSSH2_FREE(session, data);
++
++    if (retcode != LIBSSH2_FX_OK) {
++        sftp->last_errno = retcode;
++        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                      "SFTP Protocol Error", 0);
++        handle->close_state = libssh2_NB_state_idle;
++        return -1;
++    }
++
++    if (handle == sftp->handles) {
++        sftp->handles = handle->next;
++    }
++    if (handle->next) {
++        handle->next->prev = NULL;
++    }
++
++    if ((handle->handle_type == LIBSSH2_SFTP_HANDLE_DIR)
++        && handle->u.dir.names_left) {
++        LIBSSH2_FREE(session, handle->u.dir.names_packet);
++    }
++
++    handle->close_state = libssh2_NB_state_idle;
++
++    LIBSSH2_FREE(session, handle);
++
++    return 0;
++}
++
++/* }}} */
++
++/* **********************
++   * SFTP Miscellaneous *
++   ********************** */
++
++/* {{{ libssh2_sftp_unlink_ex
++ * Delete a file from the remote server
++ */
++/* libssh2_sftp_unlink_ex - NB-UNSAFE?? */
++LIBSSH2_API int
++libssh2_sftp_unlink_ex(LIBSSH2_SFTP * sftp, const char *filename,
++                       unsigned int filename_len)
++{
++    LIBSSH2_CHANNEL *channel = sftp->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned long data_len, retcode;
++    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */
++    ssize_t packet_len = filename_len + 13;
++    unsigned char *s, *data;
++    int rc;
++
++    if (sftp->unlink_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Unlinking %s", filename);
++        s = sftp->unlink_packet = LIBSSH2_ALLOC(session, packet_len);
++        if (!sftp->unlink_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for FXP_REMOVE packet",
++                          0);
++            return -1;
++        }
++
++        libssh2_htonu32(s, packet_len - 4);
++        s += 4;
++        *(s++) = SSH_FXP_REMOVE;
++        sftp->unlink_request_id = sftp->request_id++;
++        libssh2_htonu32(s, sftp->unlink_request_id);
++        s += 4;
++        libssh2_htonu32(s, filename_len);
++        s += 4;
++        memcpy(s, filename, filename_len);
++        s += filename_len;
++
++        sftp->unlink_state = libssh2_NB_state_created;
++    }
++
++    if (sftp->unlink_state == libssh2_NB_state_created) {
++        rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->unlink_packet,
++                                      packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (packet_len != rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send FXP_REMOVE command", 0);
++            LIBSSH2_FREE(session, sftp->unlink_packet);
++            sftp->unlink_packet = NULL;
++            sftp->unlink_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, sftp->unlink_packet);
++        sftp->unlink_packet = NULL;
++
++        sftp->unlink_state = libssh2_NB_state_sent;
++    }
++
++    rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
++                             sftp->unlink_request_id, &data,
++                             &data_len);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    }
++    else if (rc) {
++        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                      "Timeout waiting for status message", 0);
++        sftp->unlink_state = libssh2_NB_state_idle;
++        return -1;
++    }
++
++    sftp->unlink_state = libssh2_NB_state_idle;
++
++    retcode = libssh2_ntohu32(data + 5);
++    LIBSSH2_FREE(session, data);
++
++    if (retcode == LIBSSH2_FX_OK) {
++        return 0;
++    } else {
++        sftp->last_errno = retcode;
++        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                      "SFTP Protocol Error", 0);
++        return -1;
++    }
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_rename_ex
++ * Rename a file on the remote server
++ */
++LIBSSH2_API int
++libssh2_sftp_rename_ex(LIBSSH2_SFTP * sftp, const char *source_filename,
++                       unsigned int source_filename_len,
++                       const char *dest_filename,
++                       unsigned int dest_filename_len, long flags)
++{
++    LIBSSH2_CHANNEL *channel = sftp->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned long data_len, retcode;
++    ssize_t packet_len =
++        source_filename_len + dest_filename_len + 17 + (sftp->version >=
++                                                        5 ? 4 : 0);
++    /* packet_len(4) + packet_type(1) + request_id(4) +
++       source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */
++    unsigned char *data;
++    int rc;
++
++    if (sftp->version < 2) {
++        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                      "Server does not support RENAME", 0);
++        return -1;
++    }
++
++    if (sftp->rename_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Renaming %s to %s",
++                       source_filename, dest_filename);
++        sftp->rename_s = sftp->rename_packet =
++            LIBSSH2_ALLOC(session, packet_len);
++        if (!sftp->rename_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for FXP_RENAME packet",
++                          0);
++            return -1;
++        }
++
++        libssh2_htonu32(sftp->rename_s, packet_len - 4);
++        sftp->rename_s += 4;
++        *(sftp->rename_s++) = SSH_FXP_RENAME;
++        sftp->rename_request_id = sftp->request_id++;
++        libssh2_htonu32(sftp->rename_s, sftp->rename_request_id);
++        sftp->rename_s += 4;
++        libssh2_htonu32(sftp->rename_s, source_filename_len);
++        sftp->rename_s += 4;
++        memcpy(sftp->rename_s, source_filename, source_filename_len);
++        sftp->rename_s += source_filename_len;
++        libssh2_htonu32(sftp->rename_s, dest_filename_len);
++        sftp->rename_s += 4;
++        memcpy(sftp->rename_s, dest_filename, dest_filename_len);
++        sftp->rename_s += dest_filename_len;
++
++        if (sftp->version >= 5) {
++            libssh2_htonu32(sftp->rename_s, flags);
++            sftp->rename_s += 4;
++        }
++
++        sftp->rename_state = libssh2_NB_state_created;
++    }
++
++    if (sftp->rename_state == libssh2_NB_state_created) {
++        rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->rename_packet,
++                                      sftp->rename_s - sftp->rename_packet);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (packet_len != rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send FXP_RENAME command", 0);
++            LIBSSH2_FREE(session, sftp->rename_packet);
++            sftp->rename_packet = NULL;
++            sftp->rename_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, sftp->rename_packet);
++        sftp->rename_packet = NULL;
++
++        sftp->rename_state = libssh2_NB_state_sent;
++    }
++
++    rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
++                             sftp->rename_request_id, &data,
++                             &data_len);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    } else if (rc) {
++        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                      "Timeout waiting for status message", 0);
++        sftp->rename_state = libssh2_NB_state_idle;
++        return -1;
++    }
++
++    sftp->rename_state = libssh2_NB_state_idle;
++
++    retcode = libssh2_ntohu32(data + 5);
++    LIBSSH2_FREE(session, data);
++
++    switch (retcode) {
++    case LIBSSH2_FX_OK:
++        retcode = 0;
++        break;
++
++    case LIBSSH2_FX_FILE_ALREADY_EXISTS:
++        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                      "File already exists and SSH_FXP_RENAME_OVERWRITE not specified",
++                      0);
++        sftp->last_errno = retcode;
++        retcode = -1;
++        break;
++
++    case LIBSSH2_FX_OP_UNSUPPORTED:
++        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                      "Operation Not Supported", 0);
++        sftp->last_errno = retcode;
++        retcode = -1;
++        break;
++
++    default:
++        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                      "SFTP Protocol Error", 0);
++        sftp->last_errno = retcode;
++        retcode = -1;
++    }
++
++    return retcode;
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_mkdir_ex
++ * Create an SFTP directory
++ */
++LIBSSH2_API int
++libssh2_sftp_mkdir_ex(LIBSSH2_SFTP * sftp, const char *path,
++                      unsigned int path_len, long mode)
++{
++    LIBSSH2_CHANNEL *channel = sftp->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    LIBSSH2_SFTP_ATTRIBUTES attrs = {
++        LIBSSH2_SFTP_ATTR_PERMISSIONS, 0, 0, 0, 0, 0, 0
++    };
++    unsigned long data_len, retcode, request_id;
++    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
++    ssize_t packet_len = path_len + 13 + libssh2_sftp_attrsize(&attrs);
++    unsigned char *packet, *s, *data;
++    int rc;
++
++    if (sftp->mkdir_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
++                       "Creating directory %s with mode 0%lo", path, mode);
++        s = packet = LIBSSH2_ALLOC(session, packet_len);
++        if (!packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for FXP_MKDIR packet", 0);
++            return -1;
++        }
++        /* Filetype in SFTP 3 and earlier */
++        attrs.permissions = mode | LIBSSH2_SFTP_ATTR_PFILETYPE_DIR;
++
++        libssh2_htonu32(s, packet_len - 4);
++        s += 4;
++        *(s++) = SSH_FXP_MKDIR;
++        request_id = sftp->request_id++;
++        libssh2_htonu32(s, request_id);
++        s += 4;
++        libssh2_htonu32(s, path_len);
++        s += 4;
++        memcpy(s, path, path_len);
++        s += path_len;
++        s += libssh2_sftp_attr2bin(s, &attrs);
++
++        sftp->mkdir_state = libssh2_NB_state_created;
++    } else {
++        packet = sftp->mkdir_packet;
++        request_id = sftp->mkdir_request_id;
++    }
++
++    if (sftp->mkdir_state == libssh2_NB_state_created) {
++        rc = libssh2_channel_write_ex(channel, 0, (char *) packet, packet_len);
++        if (rc == PACKET_EAGAIN) {
++            sftp->mkdir_packet = packet;
++            sftp->mkdir_request_id = request_id;
++            return PACKET_EAGAIN;
++        }
++        if (packet_len != rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send FXP_READ command", 0);
++            LIBSSH2_FREE(session, packet);
++            sftp->mkdir_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, packet);
++        sftp->mkdir_state = libssh2_NB_state_sent;
++        sftp->mkdir_packet = NULL;
++    }
++
++    rc = sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data,
++                             &data_len);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    } else if (rc) {
++        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                      "Timeout waiting for status message", 0);
++        sftp->mkdir_state = libssh2_NB_state_idle;
++        return -1;
++    }
++
++    sftp->mkdir_state = libssh2_NB_state_idle;
++
++    retcode = libssh2_ntohu32(data + 5);
++    LIBSSH2_FREE(session, data);
++
++    if (retcode == LIBSSH2_FX_OK) {
++        return 0;
++    } else {
++        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                      "SFTP Protocol Error", 0);
++        sftp->last_errno = retcode;
++        return -1;
++    }
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_rmdir_ex
++ * Remove a directory
++ */
++/* libssh2_sftp_rmdir_ex - NB-UNSAFE?? */
++LIBSSH2_API int
++libssh2_sftp_rmdir_ex(LIBSSH2_SFTP * sftp, const char *path,
++                      unsigned int path_len)
++{
++    LIBSSH2_CHANNEL *channel = sftp->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned long data_len, retcode;
++    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
++    ssize_t packet_len = path_len + 13;
++    unsigned char *s, *data;
++    int rc;
++
++    if (sftp->rmdir_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Removing directory: %s",
++                       path);
++        s = sftp->rmdir_packet = LIBSSH2_ALLOC(session, packet_len);
++        if (!sftp->rmdir_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for FXP_MKDIR packet", 0);
++            return -1;
++        }
++
++        libssh2_htonu32(s, packet_len - 4);
++        s += 4;
++        *(s++) = SSH_FXP_RMDIR;
++        sftp->rmdir_request_id = sftp->request_id++;
++        libssh2_htonu32(s, sftp->rmdir_request_id);
++        s += 4;
++        libssh2_htonu32(s, path_len);
++        s += 4;
++        memcpy(s, path, path_len);
++        s += path_len;
++
++        sftp->rmdir_state = libssh2_NB_state_created;
++    }
++
++    if (sftp->rmdir_state == libssh2_NB_state_created) {
++        rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->rmdir_packet,
++                                      packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (packet_len != rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send FXP_MKDIR command", 0);
++            LIBSSH2_FREE(session, sftp->rmdir_packet);
++            sftp->rmdir_packet = NULL;
++            sftp->rmdir_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, sftp->rmdir_packet);
++        sftp->rmdir_packet = NULL;
++
++        sftp->rmdir_state = libssh2_NB_state_sent;
++    }
++
++    rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
++                             sftp->rmdir_request_id, &data, &data_len);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    } else if (rc) {
++        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                      "Timeout waiting for status message", 0);
++        sftp->rmdir_state = libssh2_NB_state_idle;
++        return -1;
++    }
++
++    sftp->rmdir_state = libssh2_NB_state_idle;
++
++    retcode = libssh2_ntohu32(data + 5);
++    LIBSSH2_FREE(session, data);
++
++    if (retcode == LIBSSH2_FX_OK) {
++        return 0;
++    } else {
++        sftp->last_errno = retcode;
++        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                      "SFTP Protocol Error", 0);
++        return -1;
++    }
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_stat_ex
++ * Stat a file or symbolic link
++ */
++/* libssh2_sftp_stat_ex - NB-UNSAFE?? */
++LIBSSH2_API int
++libssh2_sftp_stat_ex(LIBSSH2_SFTP * sftp, const char *path,
++                     unsigned int path_len, int stat_type,
++                     LIBSSH2_SFTP_ATTRIBUTES * attrs)
++{
++    LIBSSH2_CHANNEL *channel = sftp->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned long data_len;
++    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
++    ssize_t packet_len =
++        path_len + 13 +
++        ((stat_type ==
++          LIBSSH2_SFTP_SETSTAT) ? libssh2_sftp_attrsize(attrs) : 0);
++    unsigned char *s, *data;
++    static const unsigned char stat_responses[2] =
++        { SSH_FXP_ATTRS, SSH_FXP_STATUS };
++    int rc;
++
++    if (sftp->stat_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s",
++                       (stat_type == LIBSSH2_SFTP_SETSTAT) ? "Set-statting" :
++                       (stat_type ==
++                        LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path);
++        s = sftp->stat_packet = LIBSSH2_ALLOC(session, packet_len);
++        if (!sftp->stat_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for FXP_MKDIR packet", 0);
++            return -1;
++        }
++
++        libssh2_htonu32(s, packet_len - 4);
++        s += 4;
++        switch (stat_type) {
++        case LIBSSH2_SFTP_SETSTAT:
++            *(s++) = SSH_FXP_SETSTAT;
++            break;
++
++        case LIBSSH2_SFTP_LSTAT:
++            *(s++) = SSH_FXP_LSTAT;
++            break;
++
++        case LIBSSH2_SFTP_STAT:
++        default:
++            *(s++) = SSH_FXP_STAT;
++        }
++        sftp->stat_request_id = sftp->request_id++;
++        libssh2_htonu32(s, sftp->stat_request_id);
++        s += 4;
++        libssh2_htonu32(s, path_len);
++        s += 4;
++        memcpy(s, path, path_len);
++        s += path_len;
++        if (stat_type == LIBSSH2_SFTP_SETSTAT) {
++            s += libssh2_sftp_attr2bin(s, attrs);
++        }
++
++        sftp->stat_state = libssh2_NB_state_created;
++    }
++
++    if (sftp->stat_state == libssh2_NB_state_created) {
++        rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->stat_packet,
++                                      packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (packet_len != rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send STAT/LSTAT/SETSTAT command", 0);
++            LIBSSH2_FREE(session, sftp->stat_packet);
++            sftp->stat_packet = NULL;
++            sftp->stat_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, sftp->stat_packet);
++        sftp->stat_packet = NULL;
++
++        sftp->stat_state = libssh2_NB_state_sent;
++    }
++
++    rc = sftp_packet_requirev(sftp, 2, stat_responses,
++                              sftp->stat_request_id, &data, &data_len);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    } else if (rc) {
++        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                      "Timeout waiting for status message", 0);
++        sftp->stat_state = libssh2_NB_state_idle;
++        return -1;
++    }
++
++    sftp->stat_state = libssh2_NB_state_idle;
++
++    if (data[0] == SSH_FXP_STATUS) {
++        int retcode;
++
++        retcode = libssh2_ntohu32(data + 5);
++        LIBSSH2_FREE(session, data);
++        if (retcode == LIBSSH2_FX_OK) {
++            return 0;
++        } else {
++            sftp->last_errno = retcode;
++            libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                          "SFTP Protocol Error", 0);
++            return -1;
++        }
++    }
++
++    memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
++    libssh2_sftp_bin2attr(attrs, data + 5);
++    LIBSSH2_FREE(session, data);
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_symlink_ex
++ * Read or set a symlink
++ */
++LIBSSH2_API int
++libssh2_sftp_symlink_ex(LIBSSH2_SFTP * sftp, const char *path,
++                        unsigned int path_len, char *target,
++                        unsigned int target_len, int link_type)
++{
++    LIBSSH2_CHANNEL *channel = sftp->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned long data_len, link_len;
++    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
++    ssize_t packet_len =
++        path_len + 13 +
++        ((link_type == LIBSSH2_SFTP_SYMLINK) ? (4 + target_len) : 0);
++    unsigned char *s, *data;
++    static const unsigned char link_responses[2] =
++        { SSH_FXP_NAME, SSH_FXP_STATUS };
++    int rc;
++
++    if ((sftp->version < 3) && (link_type != LIBSSH2_SFTP_REALPATH)) {
++        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                      "Server does not support SYMLINK or READLINK", 0);
++        return -1;
++    }
++
++    if (sftp->symlink_state == libssh2_NB_state_idle) {
++        s = sftp->symlink_packet = LIBSSH2_ALLOC(session, packet_len);
++        if (!sftp->symlink_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for SYMLINK/READLINK"
++                          "/REALPATH packet", 0);
++            return -1;
++        }
++
++        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s on %s",
++                       (link_type ==
++                        LIBSSH2_SFTP_SYMLINK) ? "Creating" : "Reading",
++                       (link_type ==
++                        LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", path);
++
++        libssh2_htonu32(s, packet_len - 4);
++        s += 4;
++        switch (link_type) {
++        case LIBSSH2_SFTP_REALPATH:
++            *(s++) = SSH_FXP_REALPATH;
++            break;
++
++        case LIBSSH2_SFTP_SYMLINK:
++            *(s++) = SSH_FXP_SYMLINK;
++            break;
++
++        case LIBSSH2_SFTP_READLINK:
++        default:
++            *(s++) = SSH_FXP_READLINK;
++        }
++        sftp->symlink_request_id = sftp->request_id++;
++        libssh2_htonu32(s, sftp->symlink_request_id);
++        s += 4;
++        libssh2_htonu32(s, path_len);
++        s += 4;
++        memcpy(s, path, path_len);
++        s += path_len;
++        if (link_type == LIBSSH2_SFTP_SYMLINK) {
++            libssh2_htonu32(s, target_len);
++            s += 4;
++            memcpy(s, target, target_len);
++            s += target_len;
++        }
++
++        sftp->symlink_state = libssh2_NB_state_created;
++    }
++
++    if (sftp->symlink_state == libssh2_NB_state_created) {
++        rc = libssh2_channel_write_ex(channel, 0,
++                                      (char *) sftp->symlink_packet,
++                                      packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (packet_len != rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send SYMLINK/READLINK command", 0);
++            LIBSSH2_FREE(session, sftp->symlink_packet);
++            sftp->symlink_packet = NULL;
++            sftp->symlink_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, sftp->symlink_packet);
++        sftp->symlink_packet = NULL;
++
++        sftp->symlink_state = libssh2_NB_state_sent;
++    }
++
++    rc = sftp_packet_requirev(sftp, 2, link_responses,
++                              sftp->symlink_request_id, &data,
++                              &data_len);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    }
++    else if (rc) {
++        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                      "Timeout waiting for status message", 0);
++        sftp->symlink_state = libssh2_NB_state_idle;
++        return -1;
++    }
++
++    sftp->symlink_state = libssh2_NB_state_idle;
++
++    if (data[0] == SSH_FXP_STATUS) {
++        int retcode;
++
++        retcode = libssh2_ntohu32(data + 5);
++        LIBSSH2_FREE(session, data);
++        if (retcode == LIBSSH2_FX_OK) {
++            return 0;
++        } else {
++            sftp->last_errno = retcode;
++            libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                          "SFTP Protocol Error", 0);
++            return -1;
++        }
++    }
++
++    if (libssh2_ntohu32(data + 5) < 1) {
++        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                      "Invalid READLINK/REALPATH response, no name entries",
++                      0);
++        LIBSSH2_FREE(session, data);
++        return -1;
++    }
++
++    link_len = libssh2_ntohu32(data + 9);
++    if (link_len >= target_len) {
++        link_len = target_len - 1;
++    }
++    memcpy(target, data + 13, link_len);
++    target[link_len] = 0;
++    LIBSSH2_FREE(session, data);
++
++    return link_len;
++}
++
++/* }}} */
++
++/* {{{ libssh2_sftp_last_error
++ * Returns the last error code reported by SFTP
++ */
++LIBSSH2_API unsigned long
++libssh2_sftp_last_error(LIBSSH2_SFTP * sftp)
++{
++    return sftp->last_errno;
++}
++
++/* }}} */
+
+Property changes on: libssh2/src/sftp.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.2
+Added: svn:eol-style
+   + native
+
+Index: libssh2/src/libssh2_config.h.in.w32
+===================================================================
+--- libssh2/src/libssh2_config.h.in.w32        (.../tags/RELEASE_0_11_0)
++++ libssh2/src/libssh2_config.h.in.w32        (.../trunk)
+@@ -0,0 +1,44 @@
++#ifndef LIBSSH2_CONFIG_H
++#define LIBSSH2_CONFIG_H
++
++#ifndef WIN32
++#define WIN32
++#endif
++#include <winsock2.h>
++#include <mswsock.h>
++#include <ws2tcpip.h>
++
++#ifdef __MINGW32__
++#define HAVE_UNISTD_H
++#define HAVE_INTTYPES_H
++#define HAVE_SYS_TIME_H
++#endif
++
++#define HAVE_WINSOCK2_H
++#define HAVE_IOCTLSOCKET
++#define HAVE_SELECT
++
++#ifdef _MSC_VER
++#define snprintf _snprintf
++#if _MSC_VER < 1500
++#define vsnprintf _vsnprintf
++#else
++#define ssize_t SSIZE_T
++#define uint32_t UINT32
++#endif
++#define strncasecmp _strnicmp
++#define strcasecmp _stricmp
++#else
++#define strncasecmp strnicmp
++#define strcasecmp stricmp
++#endif /* _MSC_VER */
++
++/* Compile in zlib support */
++#define LIBSSH2_HAVE_ZLIB 1
++
++/* Enable newer diffie-hellman-group-exchange-sha1 syntax */
++#define LIBSSH2_DH_GEX_NEW 1
++
++#endif /* LIBSSH2_CONFIG_H */
++
++
+
+Property changes on: libssh2/src/libssh2_config.h.in.w32
+___________________________________________________________________
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.1
+Added: svn:eol-style
+   + native
+Added: svn:executable
+   + *
+
+Index: libssh2/src/pem.c
+===================================================================
+--- libssh2/src/pem.c  (.../tags/RELEASE_0_11_0)
++++ libssh2/src/pem.c  (.../trunk)
+@@ -0,0 +1,209 @@
++/* Copyright (C) 2007 The Written Word, Inc.
++ * Copyright (C) 2008, Simon Josefsson
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++
++static int
++readline(char *line, int line_size, FILE * fp)
++{
++    if (!fgets(line, line_size, fp)) {
++        return -1;
++    }
++    if (*line && line[strlen(line) - 1] == '\n') {
++        line[strlen(line) - 1] = '\0';
++    }
++    if (*line && line[strlen(line) - 1] == '\r') {
++        line[strlen(line) - 1] = '\0';
++    }
++    return 0;
++}
++
++#define LINE_SIZE 128
++
++int
++_libssh2_pem_parse(LIBSSH2_SESSION * session,
++                   const char *headerbegin,
++                   const char *headerend,
++                   FILE * fp, unsigned char **data, unsigned int *datalen)
++{
++    char line[LINE_SIZE];
++    char *b64data = NULL;
++    unsigned int b64datalen = 0;
++    int ret;
++
++    do {
++        if (readline(line, LINE_SIZE, fp)) {
++            return -1;
++        }
++    }
++    while (strcmp(line, headerbegin) != 0);
++
++    *line = '\0';
++
++    do {
++        if (*line) {
++            char *tmp;
++            size_t linelen;
++
++            linelen = strlen(line);
++            tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
++            if (!tmp) {
++                ret = -1;
++                goto out;
++            }
++            memcpy(tmp + b64datalen, line, linelen);
++            b64data = tmp;
++            b64datalen += linelen;
++        }
++
++        if (readline(line, LINE_SIZE, fp)) {
++            ret = -1;
++            goto out;
++        }
++    } while (strcmp(line, headerend) != 0);
++
++    if (libssh2_base64_decode(session, (char**) data, datalen,
++                              b64data, b64datalen)) {
++        ret = -1;
++        goto out;
++    }
++
++    ret = 0;
++  out:
++    if (b64data) {
++        LIBSSH2_FREE(session, b64data);
++    }
++    return ret;
++}
++
++static int
++read_asn1_length(const unsigned char *data,
++                 unsigned int datalen, unsigned int *len)
++{
++    unsigned int lenlen;
++    int nextpos;
++
++    if (datalen < 1) {
++        return -1;
++    }
++    *len = data[0];
++
++    if (*len >= 0x80) {
++        lenlen = *len & 0x7F;
++        *len = data[1];
++        if (1 + lenlen > datalen) {
++            return -1;
++        }
++        if (lenlen > 1) {
++            *len <<= 8;
++            *len |= data[2];
++        }
++    } else {
++        lenlen = 0;
++    }
++
++    nextpos = 1 + lenlen;
++    if (lenlen > 2 || 1 + lenlen + *len > datalen) {
++        return -1;
++    }
++
++    return nextpos;
++}
++
++int
++_libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen)
++{
++    unsigned int len;
++    int lenlen;
++
++    if (*datalen < 1) {
++        return -1;
++    }
++
++    if ((*data)[0] != '\x30') {
++        return -1;
++    }
++
++    (*data)++;
++    (*datalen)--;
++
++    lenlen = read_asn1_length(*data, *datalen, &len);
++    if (lenlen < 0 || lenlen + len != *datalen) {
++        return -1;
++    }
++
++    *data += lenlen;
++    *datalen -= lenlen;
++
++    return 0;
++}
++
++int
++_libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
++                            unsigned char **i, unsigned int *ilen)
++{
++    unsigned int len;
++    int lenlen;
++
++    if (*datalen < 1) {
++        return -1;
++    }
++
++    if ((*data)[0] != '\x02') {
++        return -1;
++    }
++
++    (*data)++;
++    (*datalen)--;
++
++    lenlen = read_asn1_length(*data, *datalen, &len);
++    if (lenlen < 0 || lenlen + len > *datalen) {
++        return -1;
++    }
++
++    *data += lenlen;
++    *datalen -= lenlen;
++
++    *i = *data;
++    *ilen = len;
++
++    *data += len;
++    *datalen -= len;
++
++    return 0;
++}
+
+Property changes on: libssh2/src/pem.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.1
+Added: svn:eol-style
+   + native
+Added: svn:executable
+   + *
+
+Index: libssh2/src/session.c
+===================================================================
+--- libssh2/src/session.c      (.../tags/RELEASE_0_11_0)
++++ libssh2/src/session.c      (.../trunk)
+@@ -0,0 +1,1554 @@
++/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++#include <errno.h>
++#ifdef HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#include <stdlib.h>
++#include <fcntl.h>
++
++#ifdef HAVE_GETTIMEOFDAY
++#include <sys/time.h>
++#endif
++#ifdef HAVE_ALLOCA_H
++#include <alloca.h>
++#endif
++
++/* {{{ libssh2_default_alloc
++ */
++static
++LIBSSH2_ALLOC_FUNC(libssh2_default_alloc)
++{
++    (void) abstract;
++    return malloc(count);
++}
++
++/* }}} */
++
++/* {{{ libssh2_default_free
++ */
++static
++LIBSSH2_FREE_FUNC(libssh2_default_free)
++{
++    (void) abstract;
++    free(ptr);
++}
++
++/* }}} */
++
++/* {{{ libssh2_default_realloc
++ */
++static
++LIBSSH2_REALLOC_FUNC(libssh2_default_realloc)
++{
++    (void) abstract;
++    return realloc(ptr, count);
++}
++
++/* }}} */
++
++/* {{{ libssh2_banner_receive
++ * Wait for a hello from the remote host
++ * Allocate a buffer and store the banner in session->remote.banner
++ * Returns: 0 on success, PACKET_EAGAIN if read would block, 1 on failure
++ */
++static int
++libssh2_banner_receive(LIBSSH2_SESSION * session)
++{
++    int ret;
++    int banner_len;
++
++    if (session->banner_TxRx_state == libssh2_NB_state_idle) {
++        banner_len = 0;
++
++        session->banner_TxRx_state = libssh2_NB_state_created;
++    } else {
++        banner_len = session->banner_TxRx_total_send;
++    }
++
++    while ((banner_len < (int) sizeof(session->banner_TxRx_banner)) &&
++           ((banner_len == 0)
++            || (session->banner_TxRx_banner[banner_len - 1] != '\n'))) {
++        char c = '\0';
++
++        ret =
++            recv(session->socket_fd, &c, 1,
++                 LIBSSH2_SOCKET_RECV_FLAGS(session));
++
++        if (ret < 0) {
++#ifdef WIN32
++            switch (WSAGetLastError()) {
++            case WSAEWOULDBLOCK:
++                errno = EAGAIN;
++                break;
++
++            case WSAENOTSOCK:
++                errno = EBADF;
++                break;
++
++            case WSAENOTCONN:
++            case WSAECONNABORTED:
++                errno = WSAENOTCONN;
++                break;
++
++            case WSAEINTR:
++                errno = EINTR;
++                break;
++            }
++#endif /* WIN32 */
++            if (errno == EAGAIN) {
++                session->socket_block_directions =
++                    LIBSSH2_SESSION_BLOCK_INBOUND;
++                session->banner_TxRx_total_send = banner_len;
++                return PACKET_EAGAIN;
++            }
++
++            /* Some kinda error */
++            session->banner_TxRx_state = libssh2_NB_state_idle;
++            session->banner_TxRx_total_send = 0;
++            return 1;
++        }
++
++        if (ret == 0) {
++            session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
++            return PACKET_FAIL;
++        }
++
++        if (c == '\0') {
++            /* NULLs are not allowed in SSH banners */
++            session->banner_TxRx_state = libssh2_NB_state_idle;
++            session->banner_TxRx_total_send = 0;
++            return 1;
++        }
++
++        session->banner_TxRx_banner[banner_len++] = c;
++    }
++
++    while (banner_len &&
++           ((session->banner_TxRx_banner[banner_len - 1] == '\n') ||
++            (session->banner_TxRx_banner[banner_len - 1] == '\r'))) {
++        banner_len--;
++    }
++
++    /* From this point on, we are done here */
++    session->banner_TxRx_state = libssh2_NB_state_idle;
++    session->banner_TxRx_total_send = 0;
++
++    if (!banner_len)
++        return 1;
++
++    session->remote.banner = LIBSSH2_ALLOC(session, banner_len + 1);
++    if (!session->remote.banner) {
++        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                      "Error allocating space for remote banner", 0);
++        return 1;
++    }
++    memcpy(session->remote.banner, session->banner_TxRx_banner, banner_len);
++    session->remote.banner[banner_len] = '\0';
++    _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Received Banner: %s",
++                   session->remote.banner);
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_banner_send
++ * Send the default banner, or the one set via libssh2_setopt_string
++ *
++ * Returns PACKET_EAGAIN if it would block - and if it does so, you should
++ * call this function again as soon as it is likely that more data can be
++ * sent, and this function should then be called with the same argument set
++ * (same data pointer and same data_len) until zero or failure is returned.
++ */
++static int
++libssh2_banner_send(LIBSSH2_SESSION * session)
++{
++    char *banner = (char *) LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF;
++    int banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1;
++    ssize_t ret;
++#ifdef LIBSSH2DEBUG
++    char banner_dup[256];
++#endif
++
++    if (session->banner_TxRx_state == libssh2_NB_state_idle) {
++        if (session->local.banner) {
++            /* setopt_string will have given us our \r\n characters */
++            banner_len = strlen((char *) session->local.banner);
++            banner = (char *) session->local.banner;
++        }
++#ifdef LIBSSH2DEBUG
++        /* Hack and slash to avoid sending CRLF in debug output */
++        if (banner_len < 256) {
++            memcpy(banner_dup, banner, banner_len - 2);
++            banner_dup[banner_len - 2] = '\0';
++        } else {
++            memcpy(banner_dup, banner, 255);
++            banner[255] = '\0';
++        }
++
++        _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending Banner: %s",
++                       banner_dup);
++#endif
++
++        session->banner_TxRx_state = libssh2_NB_state_created;
++    }
++
++    ret =
++        send(session->socket_fd, banner + session->banner_TxRx_total_send,
++             banner_len - session->banner_TxRx_total_send,
++             LIBSSH2_SOCKET_SEND_FLAGS(session));
++
++    if (ret != (banner_len - session->banner_TxRx_total_send)) {
++        if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
++            /* the whole packet could not be sent, save the what was */
++            session->socket_block_directions =
++                LIBSSH2_SESSION_BLOCK_OUTBOUND;
++            session->banner_TxRx_total_send += ret;
++            return PACKET_EAGAIN;
++        }
++        session->banner_TxRx_state = libssh2_NB_state_idle;
++        session->banner_TxRx_total_send = 0;
++        return PACKET_FAIL;
++    }
++
++    /* Set the state back to idle */
++    session->banner_TxRx_state = libssh2_NB_state_idle;
++    session->banner_TxRx_total_send = 0;
++
++    return 0;
++}
++
++/* }}} */
++
++/*
++ * _libssh2_nonblock() sets the given socket to either blocking or
++ * non-blocking mode based on the 'nonblock' boolean argument. This function
++ * is copied from the libcurl sources with permission.
++ */
++static int
++_libssh2_nonblock(int sockfd,   /* operate on this */
++                  int nonblock /* TRUE or FALSE */ )
++{
++#undef SETBLOCK
++#define SETBLOCK 0
++#ifdef HAVE_O_NONBLOCK
++    /* most recent unix versions */
++    int flags;
++
++    flags = fcntl(sockfd, F_GETFL, 0);
++    if (nonblock)
++        return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
++    else
++        return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
++#undef SETBLOCK
++#define SETBLOCK 1
++#endif
++
++#if defined(HAVE_FIONBIO) && (SETBLOCK == 0)
++    /* older unix versions */
++    int flags;
++
++    flags = nonblock;
++    return ioctl(sockfd, FIONBIO, &flags);
++#undef SETBLOCK
++#define SETBLOCK 2
++#endif
++
++#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0)
++    /* Windows? */
++    unsigned long flags;
++    flags = nonblock;
++
++    return ioctlsocket(sockfd, FIONBIO, &flags);
++#undef SETBLOCK
++#define SETBLOCK 3
++#endif
++
++#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0)
++    /* presumably for Amiga */
++    return IoctlSocket(sockfd, FIONBIO, (long) nonblock);
++#undef SETBLOCK
++#define SETBLOCK 4
++#endif
++
++#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0)
++    /* BeOS */
++    long b = nonblock ? 1 : 0;
++    return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
++#undef SETBLOCK
++#define SETBLOCK 5
++#endif
++
++#ifdef HAVE_DISABLED_NONBLOCKING
++    return 0;                   /* returns success */
++#undef SETBLOCK
++#define SETBLOCK 6
++#endif
++
++#if (SETBLOCK == 0)
++#error "no non-blocking method was found/used/set"
++#endif
++}
++
++/*
++ * _libssh2_get_socket_nonblocking() gets the given blocking or non-blocking
++ * state of the socket.
++ */
++static int
++_libssh2_get_socket_nonblocking(int sockfd)
++{                               /* operate on this */
++#undef GETBLOCK
++#define GETBLOCK 0
++#ifdef HAVE_O_NONBLOCK
++    /* most recent unix versions */
++    int flags;
++
++    if ((flags = fcntl(sockfd, F_GETFL, 0)) == -1) {
++        /* Assume blocking on error */
++        return 1;
++    }
++    return (flags & O_NONBLOCK);
++#undef GETBLOCK
++#define GETBLOCK 1
++#endif
++
++#if defined(WSAEWOULDBLOCK) && (GETBLOCK == 0)
++    /* Windows? */
++    unsigned int option_value;
++    socklen_t option_len = sizeof(option_value);
++
++    if (getsockopt
++        (sockfd, SOL_SOCKET, SO_ERROR, (void *) &option_value, &option_len)) {
++        /* Assume blocking on error */
++        return 1;
++    }
++    return (int) option_value;
++#undef GETBLOCK
++#define GETBLOCK 2
++#endif
++
++#if defined(HAVE_SO_NONBLOCK) && (GETBLOCK == 0)
++    /* BeOS */
++    long b;
++    if (getsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b))) {
++        /* Assume blocking on error */
++        return 1;
++    }
++    return (int) b;
++#undef GETBLOCK
++#define GETBLOCK 5
++#endif
++
++#ifdef HAVE_DISABLED_NONBLOCKING
++    return 1;                   /* returns blocking */
++#undef GETBLOCK
++#define GETBLOCK 6
++#endif
++
++#if (GETBLOCK == 0)
++#error "no non-blocking method was found/used/get"
++#endif
++}
++
++/* {{{ libssh2_banner_set
++ * Set the local banner
++ */
++LIBSSH2_API int
++libssh2_banner_set(LIBSSH2_SESSION * session, const char *banner)
++{
++    int banner_len = banner ? strlen(banner) : 0;
++
++    if (session->local.banner) {
++        LIBSSH2_FREE(session, session->local.banner);
++        session->local.banner = NULL;
++    }
++
++    if (!banner_len) {
++        return 0;
++    }
++
++    session->local.banner = LIBSSH2_ALLOC(session, banner_len + 3);
++    if (!session->local.banner) {
++        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                      "Unable to allocate memory for local banner", 0);
++        return -1;
++    }
++
++    memcpy(session->local.banner, banner, banner_len);
++    session->local.banner[banner_len] = '\0';
++    _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting local Banner: %s",
++                   session->local.banner);
++    session->local.banner[banner_len++] = '\r';
++    session->local.banner[banner_len++] = '\n';
++    session->local.banner[banner_len++] = '\0';
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ proto libssh2_session_init
++ * Allocate and initialize a libssh2 session structure
++ * Allows for malloc callbacks in case the calling program has its own memory manager
++ * It's allowable (but unadvisable) to define some but not all of the malloc callbacks
++ * An additional pointer value may be optionally passed to be sent to the callbacks (so they know who's asking)
++ */
++LIBSSH2_API LIBSSH2_SESSION *
++libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)),
++                        LIBSSH2_FREE_FUNC((*my_free)),
++                        LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract)
++{
++    LIBSSH2_ALLOC_FUNC((*local_alloc)) = libssh2_default_alloc;
++    LIBSSH2_FREE_FUNC((*local_free)) = libssh2_default_free;
++    LIBSSH2_REALLOC_FUNC((*local_realloc)) = libssh2_default_realloc;
++    LIBSSH2_SESSION *session;
++
++    if (my_alloc) {
++        local_alloc = my_alloc;
++    }
++    if (my_free) {
++        local_free = my_free;
++    }
++    if (my_realloc) {
++        local_realloc = my_realloc;
++    }
++
++    session = local_alloc(sizeof(LIBSSH2_SESSION), abstract);
++    if (session) {
++        memset(session, 0, sizeof(LIBSSH2_SESSION));
++        session->alloc = local_alloc;
++        session->free = local_free;
++        session->realloc = local_realloc;
++        session->abstract = abstract;
++        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
++                       "New session resource allocated");
++        libssh2_crypto_init();
++    }
++    return session;
++}
++
++/* }}} */
++
++/* {{{ libssh2_session_callback_set
++ * Set (or reset) a callback function
++ * Returns the prior address
++ *
++ * FIXME: this function relies on that we can typecast function pointers
++ * to void pointers, which isn't allowed in ISO C!
++ */
++LIBSSH2_API void *
++libssh2_session_callback_set(LIBSSH2_SESSION * session,
++                             int cbtype, void *callback)
++{
++    void *oldcb;
++
++    switch (cbtype) {
++    case LIBSSH2_CALLBACK_IGNORE:
++        oldcb = session->ssh_msg_ignore;
++        session->ssh_msg_ignore = callback;
++        return oldcb;
++
++    case LIBSSH2_CALLBACK_DEBUG:
++        oldcb = session->ssh_msg_debug;
++        session->ssh_msg_debug = callback;
++        return oldcb;
++
++    case LIBSSH2_CALLBACK_DISCONNECT:
++        oldcb = session->ssh_msg_disconnect;
++        session->ssh_msg_disconnect = callback;
++        return oldcb;
++
++    case LIBSSH2_CALLBACK_MACERROR:
++        oldcb = session->macerror;
++        session->macerror = callback;
++        return oldcb;
++
++    case LIBSSH2_CALLBACK_X11:
++        oldcb = session->x11;
++        session->x11 = callback;
++        return oldcb;
++
++    }
++    _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting Callback %d", cbtype);
++
++    return NULL;
++}
++
++/* }}} */
++
++/* {{{ proto libssh2_session_startup
++ * session: LIBSSH2_SESSION struct allocated and owned by the calling program
++ * Returns: 0 on success, or non-zero on failure
++ * Any memory allocated by libssh2 will use alloc/realloc/free
++ * callbacks in session
++ * socket *must* be populated with an opened and connected socket.
++ */
++LIBSSH2_API int
++libssh2_session_startup(LIBSSH2_SESSION * session, int sock)
++{
++    int rc;
++
++    if (session->startup_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
++                       "session_startup for socket %d", sock);
++        /* FIXME: on some platforms (like win32) sockets are unsigned */
++        if (sock < 0) {
++            /* Did we forget something? */
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE,
++                          "Bad socket provided", 0);
++            return LIBSSH2_ERROR_SOCKET_NONE;
++        }
++        session->socket_fd = sock;
++
++        session->socket_block =
++            !_libssh2_get_socket_nonblocking(session->socket_fd);
++        if (session->socket_block) {
++            /*
++             * Since we can't be sure that we are in blocking or there
++             * was an error detecting the state, so set to blocking to
++             * be sure
++             */
++            _libssh2_nonblock(session->socket_fd, 0);
++        }
++
++        session->startup_state = libssh2_NB_state_created;
++    }
++
++    /* TODO: Liveness check */
++
++    if (session->startup_state == libssh2_NB_state_created) {
++        rc = libssh2_banner_send(session);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block sending banner to remote host", 0);
++            return LIBSSH2_ERROR_EAGAIN;
++        } else if (rc) {
++            /* Unable to send banner? */
++            libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND,
++                          "Error sending banner to remote host", 0);
++            return LIBSSH2_ERROR_BANNER_SEND;
++        }
++
++        session->startup_state = libssh2_NB_state_sent;
++    }
++
++    if (session->startup_state == libssh2_NB_state_sent) {
++        rc = libssh2_banner_receive(session);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block waiting for banner", 0);
++            return LIBSSH2_ERROR_EAGAIN;
++        } else if (rc) {
++            /* Unable to receive banner from remote */
++            libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE,
++                          "Timeout waiting for banner", 0);
++            return LIBSSH2_ERROR_BANNER_NONE;
++        }
++
++        session->startup_state = libssh2_NB_state_sent1;
++    }
++
++    if (session->startup_state == libssh2_NB_state_sent1) {
++        rc = libssh2_kex_exchange(session, 0, &session->startup_key_state);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block exchanging encryption keys", 0);
++            return LIBSSH2_ERROR_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
++                          "Unable to exchange encryption keys", 0);
++            return LIBSSH2_ERROR_KEX_FAILURE;
++        }
++
++        session->startup_state = libssh2_NB_state_sent2;
++    }
++
++    if (session->startup_state == libssh2_NB_state_sent2) {
++        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
++                       "Requesting userauth service");
++
++        /* Request the userauth service */
++        session->startup_service[0] = SSH_MSG_SERVICE_REQUEST;
++        libssh2_htonu32(session->startup_service + 1,
++                        sizeof("ssh-userauth") - 1);
++        memcpy(session->startup_service + 5, "ssh-userauth",
++               sizeof("ssh-userauth") - 1);
++
++        session->startup_state = libssh2_NB_state_sent3;
++    }
++
++    if (session->startup_state == libssh2_NB_state_sent3) {
++        rc = libssh2_packet_write(session, session->startup_service,
++                                  sizeof("ssh-userauth") + 5 - 1);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block asking for ssh-userauth service", 0);
++            return LIBSSH2_ERROR_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to ask for ssh-userauth service", 0);
++            return LIBSSH2_ERROR_SOCKET_SEND;
++        }
++
++        session->startup_state = libssh2_NB_state_sent4;
++    }
++
++    if (session->startup_state == libssh2_NB_state_sent4) {
++        rc = libssh2_packet_require_ex(session, SSH_MSG_SERVICE_ACCEPT,
++                                       &session->startup_data,
++                                       &session->startup_data_len, 0, NULL, 0,
++                                       &session->startup_req_state);
++        if (rc == PACKET_EAGAIN) {
++            return LIBSSH2_ERROR_EAGAIN;
++        } else if (rc) {
++            return LIBSSH2_ERROR_SOCKET_DISCONNECT;
++        }
++        session->startup_service_length =
++            libssh2_ntohu32(session->startup_data + 1);
++
++        if ((session->startup_service_length != (sizeof("ssh-userauth") - 1))
++            || strncmp("ssh-userauth", (char *) session->startup_data + 5,
++                       session->startup_service_length)) {
++            LIBSSH2_FREE(session, session->startup_data);
++            session->startup_data = NULL;
++            libssh2_error(session, LIBSSH2_ERROR_PROTO,
++                          "Invalid response received from server", 0);
++            return LIBSSH2_ERROR_PROTO;
++        }
++        LIBSSH2_FREE(session, session->startup_data);
++        session->startup_data = NULL;
++
++        session->startup_state = libssh2_NB_state_idle;
++
++        return 0;
++    }
++
++    /* just for safety return some error */
++    return LIBSSH2_ERROR_INVAL;
++}
++
++/* }}} */
++
++/* {{{ proto libssh2_session_free
++ * Frees the memory allocated to the session
++ * Also closes and frees any channels attached to this session
++ */
++LIBSSH2_API int
++libssh2_session_free(LIBSSH2_SESSION * session)
++{
++    int rc;
++
++    if (session->free_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Freeing session resource",
++                       session->remote.banner);
++
++        session->state = libssh2_NB_state_created;
++    }
++
++    if (session->free_state == libssh2_NB_state_created) {
++        while (session->channels.head) {
++            LIBSSH2_CHANNEL *tmp = session->channels.head;
++
++            rc = libssh2_channel_free(session->channels.head);
++            if (rc == PACKET_EAGAIN) {
++                return PACKET_EAGAIN;
++            }
++            if (tmp == session->channels.head) {
++                /* channel_free couldn't do it's job, perform a messy cleanup */
++                tmp = session->channels.head;
++
++                /* unlink */
++                session->channels.head = tmp->next;
++
++                /* free */
++                LIBSSH2_FREE(session, tmp);
++
++                /* reverse linking isn't important here, we're killing the structure */
++            }
++        }
++
++        session->state = libssh2_NB_state_sent;
++    }
++
++    if (session->state == libssh2_NB_state_sent) {
++        while (session->listeners) {
++            rc = libssh2_channel_forward_cancel(session->listeners);
++            if (rc == PACKET_EAGAIN) {
++                return PACKET_EAGAIN;
++            }
++        }
++
++        session->state = libssh2_NB_state_sent1;
++    }
++
++    if (session->state & LIBSSH2_STATE_NEWKEYS) {
++        /* hostkey */
++        if (session->hostkey && session->hostkey->dtor) {
++            session->hostkey->dtor(session, &session->server_hostkey_abstract);
++        }
++
++        /* Client to Server */
++        /* crypt */
++        if (session->local.crypt && session->local.crypt->dtor) {
++            session->local.crypt->dtor(session,
++                                       &session->local.crypt_abstract);
++        }
++        /* comp */
++        if (session->local.comp && session->local.comp->dtor) {
++            session->local.comp->dtor(session, 1,
++                                      &session->local.comp_abstract);
++        }
++        /* mac */
++        if (session->local.mac && session->local.mac->dtor) {
++            session->local.mac->dtor(session, &session->local.mac_abstract);
++        }
++
++        /* Server to Client */
++        /* crypt */
++        if (session->remote.crypt && session->remote.crypt->dtor) {
++            session->remote.crypt->dtor(session,
++                                        &session->remote.crypt_abstract);
++        }
++        /* comp */
++        if (session->remote.comp && session->remote.comp->dtor) {
++            session->remote.comp->dtor(session, 0,
++                                       &session->remote.comp_abstract);
++        }
++        /* mac */
++        if (session->remote.mac && session->remote.mac->dtor) {
++            session->remote.mac->dtor(session, &session->remote.mac_abstract);
++        }
++
++        /* session_id */
++        if (session->session_id) {
++            LIBSSH2_FREE(session, session->session_id);
++        }
++    }
++
++    /* Free banner(s) */
++    if (session->remote.banner) {
++        LIBSSH2_FREE(session, session->remote.banner);
++    }
++    if (session->local.banner) {
++        LIBSSH2_FREE(session, session->local.banner);
++    }
++
++    /* Free preference(s) */
++    if (session->kex_prefs) {
++        LIBSSH2_FREE(session, session->kex_prefs);
++    }
++    if (session->hostkey_prefs) {
++        LIBSSH2_FREE(session, session->hostkey_prefs);
++    }
++
++    if (session->local.crypt_prefs) {
++        LIBSSH2_FREE(session, session->local.crypt_prefs);
++    }
++    if (session->local.mac_prefs) {
++        LIBSSH2_FREE(session, session->local.mac_prefs);
++    }
++    if (session->local.comp_prefs) {
++        LIBSSH2_FREE(session, session->local.comp_prefs);
++    }
++    if (session->local.lang_prefs) {
++        LIBSSH2_FREE(session, session->local.lang_prefs);
++    }
++
++    if (session->remote.crypt_prefs) {
++        LIBSSH2_FREE(session, session->remote.crypt_prefs);
++    }
++    if (session->remote.mac_prefs) {
++        LIBSSH2_FREE(session, session->remote.mac_prefs);
++    }
++    if (session->remote.comp_prefs) {
++        LIBSSH2_FREE(session, session->remote.comp_prefs);
++    }
++    if (session->remote.lang_prefs) {
++        LIBSSH2_FREE(session, session->remote.lang_prefs);
++    }
++
++    /*
++     * Make sure all memory used in the state variables are free
++     */
++    if (session->startup_data) {
++        LIBSSH2_FREE(session, session->startup_data);
++    }
++    if (session->disconnect_data) {
++        LIBSSH2_FREE(session, session->disconnect_data);
++    }
++    if (session->userauth_list_data) {
++        LIBSSH2_FREE(session, session->userauth_list_data);
++    }
++    if (session->userauth_pswd_data) {
++        LIBSSH2_FREE(session, session->userauth_pswd_data);
++    }
++    if (session->userauth_pswd_newpw) {
++        LIBSSH2_FREE(session, session->userauth_pswd_newpw);
++    }
++    if (session->userauth_host_packet) {
++        LIBSSH2_FREE(session, session->userauth_host_packet);
++    }
++    if (session->userauth_host_method) {
++        LIBSSH2_FREE(session, session->userauth_host_method);
++    }
++    if (session->userauth_host_data) {
++        LIBSSH2_FREE(session, session->userauth_host_data);
++    }
++    if (session->userauth_pblc_data) {
++        LIBSSH2_FREE(session, session->userauth_pblc_data);
++    }
++    if (session->userauth_pblc_packet) {
++        LIBSSH2_FREE(session, session->userauth_pblc_packet);
++    }
++    if (session->userauth_pblc_method) {
++        LIBSSH2_FREE(session, session->userauth_pblc_method);
++    }
++    if (session->userauth_kybd_data) {
++        LIBSSH2_FREE(session, session->userauth_kybd_data);
++    }
++    if (session->userauth_kybd_packet) {
++        LIBSSH2_FREE(session, session->userauth_kybd_packet);
++    }
++    if (session->userauth_kybd_auth_instruction) {
++        LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction);
++    }
++    if (session->open_packet) {
++        LIBSSH2_FREE(session, session->open_packet);
++    }
++    if (session->open_data) {
++        LIBSSH2_FREE(session, session->open_data);
++    }
++    if (session->direct_message) {
++        LIBSSH2_FREE(session, session->direct_message);
++    }
++    if (session->fwdLstn_packet) {
++        LIBSSH2_FREE(session, session->fwdLstn_packet);
++    }
++    if (session->pkeyInit_data) {
++        LIBSSH2_FREE(session, session->pkeyInit_data);
++    }
++    if (session->scpRecv_command) {
++        LIBSSH2_FREE(session, session->scpRecv_command);
++    }
++    if (session->scpSend_command) {
++        LIBSSH2_FREE(session, session->scpSend_command);
++    }
++    if (session->scpRecv_err_msg) {
++        LIBSSH2_FREE(session, session->scpRecv_err_msg);
++    }
++    if (session->scpSend_err_msg) {
++        LIBSSH2_FREE(session, session->scpSend_err_msg);
++    }
++
++    /* Free the error message, if we ar supposed to */
++    if (session->err_msg && session->err_should_free) {
++        LIBSSH2_FREE(session, session->err_msg);
++    }
++
++    /* Cleanup any remaining packets */
++    while (session->packets.head) {
++        LIBSSH2_PACKET *tmp = session->packets.head;
++
++        /* unlink */
++        session->packets.head = tmp->next;
++
++        /* free */
++        LIBSSH2_FREE(session, tmp->data);
++        LIBSSH2_FREE(session, tmp);
++    }
++
++    LIBSSH2_FREE(session, session);
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_session_disconnect_ex
++ */
++LIBSSH2_API int
++libssh2_session_disconnect_ex(LIBSSH2_SESSION * session, int reason,
++                              const char *description, const char *lang)
++{
++    unsigned char *s;
++    unsigned long descr_len = 0, lang_len = 0;
++    int rc;
++
++    if (session->disconnect_state == libssh2_NB_state_idle) {
++        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
++                       "Disconnecting: reason=%d, desc=%s, lang=%s", reason,
++                       description, lang);
++        if (description) {
++            descr_len = strlen(description);
++        }
++        if (lang) {
++            lang_len = strlen(lang);
++        }
++        /* 13 = packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */
++        session->disconnect_data_len = descr_len + lang_len + 13;
++
++        s = session->disconnect_data =
++            LIBSSH2_ALLOC(session, session->disconnect_data_len);
++        if (!session->disconnect_data) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for disconnect packet",
++                          0);
++            session->disconnect_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        *(s++) = SSH_MSG_DISCONNECT;
++        libssh2_htonu32(s, reason);
++        s += 4;
++
++        libssh2_htonu32(s, descr_len);
++        s += 4;
++        if (description) {
++            memcpy(s, description, descr_len);
++            s += descr_len;
++        }
++
++        libssh2_htonu32(s, lang_len);
++        s += 4;
++        if (lang) {
++            memcpy(s, lang, lang_len);
++            s += lang_len;
++        }
++
++        session->disconnect_state = libssh2_NB_state_created;
++    }
++
++    rc = libssh2_packet_write(session, session->disconnect_data,
++                              session->disconnect_data_len);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    }
++
++    LIBSSH2_FREE(session, session->disconnect_data);
++    session->disconnect_data = NULL;
++    session->disconnect_state = libssh2_NB_state_idle;
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_session_methods
++ * Return the currently active methods for method_type
++ * NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string regardless of actual negotiation
++ * Strings should NOT be freed
++ */
++LIBSSH2_API const char *
++libssh2_session_methods(LIBSSH2_SESSION * session, int method_type)
++{
++    /* All methods have char *name as their first element */
++    const LIBSSH2_KEX_METHOD *method = NULL;
++
++    switch (method_type) {
++    case LIBSSH2_METHOD_KEX:
++        method = session->kex;
++        break;
++
++    case LIBSSH2_METHOD_HOSTKEY:
++        method = (LIBSSH2_KEX_METHOD *) session->hostkey;
++        break;
++
++    case LIBSSH2_METHOD_CRYPT_CS:
++        method = (LIBSSH2_KEX_METHOD *) session->local.crypt;
++        break;
++
++    case LIBSSH2_METHOD_CRYPT_SC:
++        method = (LIBSSH2_KEX_METHOD *) session->remote.crypt;
++        break;
++
++    case LIBSSH2_METHOD_MAC_CS:
++        method = (LIBSSH2_KEX_METHOD *) session->local.mac;
++        break;
++
++    case LIBSSH2_METHOD_MAC_SC:
++        method = (LIBSSH2_KEX_METHOD *) session->remote.mac;
++        break;
++
++    case LIBSSH2_METHOD_COMP_CS:
++        method = (LIBSSH2_KEX_METHOD *) session->local.comp;
++        break;
++
++    case LIBSSH2_METHOD_COMP_SC:
++        method = (LIBSSH2_KEX_METHOD *) session->remote.comp;
++        break;
++
++    case LIBSSH2_METHOD_LANG_CS:
++        return "";
++        break;
++
++    case LIBSSH2_METHOD_LANG_SC:
++        return "";
++        break;
++
++    default:
++        libssh2_error(session, LIBSSH2_ERROR_INVAL,
++                      "Invalid parameter specified for method_type", 0);
++        return NULL;
++        break;
++    }
++
++    if (!method) {
++        libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
++                      "No method negotiated", 0);
++        return NULL;
++    }
++
++    return method->name;
++}
++
++/* }}} */
++
++/* {{{ libssh2_session_abstract
++ * Retrieve a pointer to the abstract property
++ */
++LIBSSH2_API void **
++libssh2_session_abstract(LIBSSH2_SESSION * session)
++{
++    return &session->abstract;
++}
++
++/* }}} */
++
++/* {{{ libssh2_session_last_error
++ * Returns error code and populates an error string into errmsg
++ * If want_buf is non-zero then the string placed into errmsg must be freed by the calling program
++ * Otherwise it is assumed to be owned by libssh2
++ */
++LIBSSH2_API int
++libssh2_session_last_error(LIBSSH2_SESSION * session, char **errmsg,
++                           int *errmsg_len, int want_buf)
++{
++    /* No error to report */
++    if (!session->err_code) {
++        if (errmsg) {
++            if (want_buf) {
++                *errmsg = LIBSSH2_ALLOC(session, 1);
++                if (*errmsg) {
++                    **errmsg = 0;
++                }
++            } else {
++                *errmsg = (char *) "";
++            }
++        }
++        if (errmsg_len) {
++            *errmsg_len = 0;
++        }
++        return 0;
++    }
++
++    if (errmsg) {
++        char *serrmsg = session->err_msg ? session->err_msg : (char *) "";
++        int ownbuf = session->err_msg ? session->err_should_free : 0;
++
++        if (want_buf) {
++            if (ownbuf) {
++                /* Just give the calling program the buffer */
++                *errmsg = serrmsg;
++                session->err_should_free = 0;
++            } else {
++                /* Make a copy so the calling program can own it */
++                *errmsg = LIBSSH2_ALLOC(session, session->err_msglen + 1);
++                if (*errmsg) {
++                    memcpy(*errmsg, session->err_msg, session->err_msglen);
++                    (*errmsg)[session->err_msglen] = 0;
++                }
++            }
++        } else {
++            *errmsg = serrmsg;
++        }
++    }
++
++    if (errmsg_len) {
++        *errmsg_len = session->err_msglen;
++    }
++
++    return session->err_code;
++}
++
++/* }}} */
++
++/* {{{ libssh2_session_last_error
++* Returns error code
++*/
++LIBSSH2_API int
++libssh2_session_last_errno(LIBSSH2_SESSION * session)
++{
++    return session->err_code;
++}
++
++/* }}} */
++
++/* {{{ libssh2_session_flag
++ * Set/Get session flags
++ * Passing flag==0 will avoid changing session->flags while still returning its current value
++ */
++LIBSSH2_API int
++libssh2_session_flag(LIBSSH2_SESSION * session, int flag, int value)
++{
++    if (value) {
++        session->flags |= flag;
++    } else {
++        session->flags &= ~flag;
++    }
++
++    return session->flags;
++}
++
++/* }}} */
++
++/* {{{ _libssh2_session_set_blocking
++ * Set a session's blocking mode on or off, return the previous status
++ * when this function is called.
++ */
++int
++_libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking)
++{
++    int bl = session->socket_block;
++    _libssh2_debug(session, LIBSSH2_DBG_CONN,
++                   "Setting blocking mode on session %d", blocking);
++    if (blocking == session->socket_block) {
++        /* avoid if already correct */
++        return bl;
++    }
++    session->socket_block = blocking;
++
++    _libssh2_nonblock(session->socket_fd, !blocking);
++
++    return bl;
++}
++
++/* }}} */
++
++/* {{{ libssh2_session_set_blocking
++ * Set a channel's blocking mode on or off, similar to a socket's
++ * fcntl(fd, F_SETFL, O_NONBLOCK); type command
++ */
++LIBSSH2_API void
++libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking)
++{
++    (void) _libssh2_session_set_blocking(session, blocking);
++}
++
++/* }}} */
++
++/* {{{ libssh2_session_get_blocking
++* Returns a session's blocking mode on or off
++*/
++LIBSSH2_API int
++libssh2_session_get_blocking(LIBSSH2_SESSION * session)
++{
++    return session->socket_block;
++}
++
++/* }}} */
++
++/* {{{ libssh2_poll_channel_read
++ * Returns 0 if no data is waiting on channel,
++ * non-0 if data is available
++ */
++LIBSSH2_API int
++libssh2_poll_channel_read(LIBSSH2_CHANNEL * channel, int extended)
++{
++    LIBSSH2_SESSION *session = channel->session;
++    LIBSSH2_PACKET *packet = session->packets.head;
++
++    while (packet) 
++      {
++              if ( channel->local.id == libssh2_ntohu32(packet->data + 1)) {
++                      if ( extended == 1 &&
++                              (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA 
++                              || packet->data[0] == SSH_MSG_CHANNEL_DATA )) {
++                              return 1;
++                      } else if ( extended == 0 && 
++                              packet->data[0] == SSH_MSG_CHANNEL_DATA) {
++                              return 1;
++                      }
++                      /* else - no data of any type is ready to be read */
++        }
++        packet = packet->next;
++    }
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_poll_channel_write
++ * Returns 0 if writing to channel would block,
++ * non-0 if data can be written without blocking
++ */
++static inline int
++libssh2_poll_channel_write(LIBSSH2_CHANNEL * channel)
++{
++    return channel->local.window_size ? 1 : 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_poll_listener_queued
++ * Returns 0 if no connections are waiting to be accepted
++ * non-0 if one or more connections are available
++ */
++static inline int
++libssh2_poll_listener_queued(LIBSSH2_LISTENER * listener)
++{
++    return listener->queue ? 1 : 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_poll
++ * Poll sockets, channels, and listeners for activity
++ */
++LIBSSH2_API int
++libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
++{
++    long timeout_remaining;
++    unsigned int i, active_fds;
++#ifdef HAVE_POLL
++    LIBSSH2_SESSION *session = NULL;
++#ifdef HAVE_ALLOCA
++    struct pollfd *sockets = alloca(sizeof(struct pollfd) * nfds);
++#else
++    struct pollfd sockets[256];
++
++    if (nfds > 256)
++        /* systems without alloca use a fixed-size array, this can be fixed
++           if we really want to, at least if the compiler is a C99 capable one */
++        return -1;
++#endif
++    /* Setup sockets for polling */
++    for(i = 0; i < nfds; i++) {
++        fds[i].revents = 0;
++        switch (fds[i].type) {
++        case LIBSSH2_POLLFD_SOCKET:
++            sockets[i].fd = fds[i].fd.socket;
++            sockets[i].events = fds[i].events;
++            sockets[i].revents = 0;
++            break;
++
++        case LIBSSH2_POLLFD_CHANNEL:
++            sockets[i].fd = fds[i].fd.channel->session->socket_fd;
++            sockets[i].events = POLLIN;
++            sockets[i].revents = 0;
++            if (!session)
++                session = fds[i].fd.channel->session;
++            break;
++
++        case LIBSSH2_POLLFD_LISTENER:
++            sockets[i].fd = fds[i].fd.listener->session->socket_fd;
++            sockets[i].events = POLLIN;
++            sockets[i].revents = 0;
++            if (!session)
++                session = fds[i].fd.listener->session;
++            break;
++
++        default:
++            if (session)
++                libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
++                              "Invalid descriptor passed to libssh2_poll()",
++                              0);
++            return -1;
++        }
++    }
++#elif defined(HAVE_SELECT)
++    LIBSSH2_SESSION *session = NULL;
++    int maxfd = 0;
++    fd_set rfds, wfds;
++    struct timeval tv;
++
++    FD_ZERO(&rfds);
++    FD_ZERO(&wfds);
++    for(i = 0; i < nfds; i++) {
++        fds[i].revents = 0;
++        switch (fds[i].type) {
++        case LIBSSH2_POLLFD_SOCKET:
++            if (fds[i].events & LIBSSH2_POLLFD_POLLIN) {
++                FD_SET(fds[i].fd.socket, &rfds);
++                if (fds[i].fd.socket > maxfd)
++                    maxfd = fds[i].fd.socket;
++            }
++            if (fds[i].events & LIBSSH2_POLLFD_POLLOUT) {
++                FD_SET(fds[i].fd.socket, &wfds);
++                if (fds[i].fd.socket > maxfd)
++                    maxfd = fds[i].fd.socket;
++            }
++            break;
++
++        case LIBSSH2_POLLFD_CHANNEL:
++            FD_SET(fds[i].fd.channel->session->socket_fd, &rfds);
++            if (fds[i].fd.channel->session->socket_fd > maxfd)
++                maxfd = fds[i].fd.channel->session->socket_fd;
++            if (!session)
++                session = fds[i].fd.channel->session;
++            break;
++
++        case LIBSSH2_POLLFD_LISTENER:
++            FD_SET(fds[i].fd.listener->session->socket_fd, &rfds);
++            if (fds[i].fd.listener->session->socket_fd > maxfd)
++                maxfd = fds[i].fd.listener->session->socket_fd;
++            if (!session)
++                session = fds[i].fd.listener->session;
++            break;
++
++        default:
++            if (session)
++                libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
++                              "Invalid descriptor passed to libssh2_poll()",
++                              0);
++            return -1;
++        }
++    }
++#else
++    /* No select() or poll()
++     * no sockets sturcture to setup
++     */
++
++    timeout = 0;
++#endif /* HAVE_POLL or HAVE_SELECT */
++
++    timeout_remaining = timeout;
++    do {
++#if defined(HAVE_POLL) || defined(HAVE_SELECT)
++        int sysret;
++#endif
++
++        active_fds = 0;
++
++        for(i = 0; i < nfds; i++) {
++            if (fds[i].events != fds[i].revents) {
++                switch (fds[i].type) {
++                case LIBSSH2_POLLFD_CHANNEL:
++                    if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) &&      /* Want to be ready for read */
++                        ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) {      /* Not yet known to be ready for read */
++                        fds[i].revents |=
++                            libssh2_poll_channel_read(fds[i].fd.channel,
++                                                      0) ?
++                            LIBSSH2_POLLFD_POLLIN : 0;
++                    }
++                    if ((fds[i].events & LIBSSH2_POLLFD_POLLEXT) &&     /* Want to be ready for extended read */
++                        ((fds[i].revents & LIBSSH2_POLLFD_POLLEXT) == 0)) {     /* Not yet known to be ready for extended read */
++                        fds[i].revents |=
++                            libssh2_poll_channel_read(fds[i].fd.channel,
++                                                      1) ?
++                            LIBSSH2_POLLFD_POLLEXT : 0;
++                    }
++                    if ((fds[i].events & LIBSSH2_POLLFD_POLLOUT) &&     /* Want to be ready for write */
++                        ((fds[i].revents & LIBSSH2_POLLFD_POLLOUT) == 0)) {     /* Not yet known to be ready for write */
++                        fds[i].revents |=
++                            libssh2_poll_channel_write(fds[i].fd.
++                                                       channel) ?
++                            LIBSSH2_POLLFD_POLLOUT : 0;
++                    }
++                    if (fds[i].fd.channel->remote.close
++                        || fds[i].fd.channel->local.close) {
++                        fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED;
++                    }
++                    if (fds[i].fd.channel->session->socket_state ==
++                        LIBSSH2_SOCKET_DISCONNECTED) {
++                        fds[i].revents |=
++                            LIBSSH2_POLLFD_CHANNEL_CLOSED |
++                            LIBSSH2_POLLFD_SESSION_CLOSED;
++                    }
++                    break;
++
++                case LIBSSH2_POLLFD_LISTENER:
++                    if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) &&      /* Want a connection */
++                        ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) {      /* No connections known of yet */
++                        fds[i].revents |=
++                            libssh2_poll_listener_queued(fds[i].fd.
++                                                         listener) ?
++                            LIBSSH2_POLLFD_POLLIN : 0;
++                    }
++                    if (fds[i].fd.listener->session->socket_state ==
++                        LIBSSH2_SOCKET_DISCONNECTED) {
++                        fds[i].revents |=
++                            LIBSSH2_POLLFD_LISTENER_CLOSED |
++                            LIBSSH2_POLLFD_SESSION_CLOSED;
++                    }
++                    break;
++                }
++            }
++            if (fds[i].revents) {
++                active_fds++;
++            }
++        }
++
++        if (active_fds) {
++            /* Don't block on the sockets if we have channels/listeners which are ready */
++            timeout_remaining = 0;
++        }
++#ifdef HAVE_POLL
++
++#ifdef HAVE_GETTIMEOFDAY
++        {
++            struct timeval tv_begin, tv_end;
++
++            gettimeofday((struct timeval *) &tv_begin, NULL);
++            sysret = poll(sockets, nfds, timeout_remaining);
++            gettimeofday((struct timeval *) &tv_end, NULL);
++            timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
++            timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
++        }
++#else
++        /* If the platform doesn't support gettimeofday,
++         * then just make the call non-blocking and walk away
++         */
++        sysret = poll(sockets, nfds, timeout_remaining);
++        timeout_remaining = 0;
++#endif /* HAVE_GETTIMEOFDAY */
++
++        if (sysret > 0) {
++            for(i = 0; i < nfds; i++) {
++                switch (fds[i].type) {
++                case LIBSSH2_POLLFD_SOCKET:
++                    fds[i].revents = sockets[i].revents;
++                    sockets[i].revents = 0;     /* In case we loop again, be nice */
++                    if (fds[i].revents) {
++                        active_fds++;
++                    }
++                    break;
++                case LIBSSH2_POLLFD_CHANNEL:
++                    if (sockets[i].events & POLLIN) {
++                        /* Spin session until no data available */
++                        while (libssh2_packet_read(fds[i].fd.channel->session)
++                               > 0);
++                    }
++                    if (sockets[i].revents & POLLHUP) {
++                        fds[i].revents |=
++                            LIBSSH2_POLLFD_CHANNEL_CLOSED |
++                            LIBSSH2_POLLFD_SESSION_CLOSED;
++                    }
++                    sockets[i].revents = 0;
++                    break;
++                case LIBSSH2_POLLFD_LISTENER:
++                    if (sockets[i].events & POLLIN) {
++                        /* Spin session until no data available */
++                        while (libssh2_packet_read(fds[i].fd.listener->session)
++                               > 0);
++                    }
++                    if (sockets[i].revents & POLLHUP) {
++                        fds[i].revents |=
++                            LIBSSH2_POLLFD_LISTENER_CLOSED |
++                            LIBSSH2_POLLFD_SESSION_CLOSED;
++                    }
++                    sockets[i].revents = 0;
++                    break;
++                }
++            }
++        }
++#elif defined(HAVE_SELECT)
++        tv.tv_sec = timeout_remaining / 1000;
++        tv.tv_usec = (timeout_remaining % 1000) * 1000;
++#ifdef HAVE_GETTIMEOFDAY
++        {
++            struct timeval tv_begin, tv_end;
++
++            gettimeofday((struct timeval *) &tv_begin, NULL);
++            sysret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
++            gettimeofday((struct timeval *) &tv_end, NULL);
++
++            timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
++            timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
++        }
++#else
++        /* If the platform doesn't support gettimeofday,
++         * then just make the call non-blocking and walk away
++         */
++        sysret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
++        timeout_remaining = 0;
++#endif
++
++        if (sysret > 0) {
++            for(i = 0; i < nfds; i++) {
++                switch (fds[i].type) {
++                case LIBSSH2_POLLFD_SOCKET:
++                    if (FD_ISSET(fds[i].fd.socket, &rfds)) {
++                        fds[i].revents |= LIBSSH2_POLLFD_POLLIN;
++                    }
++                    if (FD_ISSET(fds[i].fd.socket, &wfds)) {
++                        fds[i].revents |= LIBSSH2_POLLFD_POLLOUT;
++                    }
++                    if (fds[i].revents) {
++                        active_fds++;
++                    }
++                    break;
++
++                case LIBSSH2_POLLFD_CHANNEL:
++                    if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) {
++                        /* Spin session until no data available */
++                        while (libssh2_packet_read(fds[i].fd.channel->session)
++                               > 0);
++                    }
++                    break;
++
++                case LIBSSH2_POLLFD_LISTENER:
++                    if (FD_ISSET
++                        (fds[i].fd.listener->session->socket_fd, &rfds)) {
++                        /* Spin session until no data available */
++                        while (libssh2_packet_read(fds[i].fd.listener->session)
++                               > 0);
++                    }
++                    break;
++                }
++            }
++        }
++#endif /* else no select() or poll() -- timeout (and by extension timeout_remaining) will be equal to 0 */
++    } while ((timeout_remaining > 0) && !active_fds);
++
++    return active_fds;
++}
++
++/* {{{ libssh2_session_block_direction
++ * Get blocked direction when a function returns LIBSSH2_ERROR_EAGAIN
++ * Returns LIBSSH2_SOCKET_BLOCK_INBOUND if recv() blocked
++ * or LIBSSH2_SOCKET_BLOCK_OUTBOUND if send() blocked
++ */
++LIBSSH2_API int
++libssh2_session_block_directions(LIBSSH2_SESSION *session)
++{
++    return session->socket_block_directions;
++}
++
++/* }}} */
+
+Property changes on: libssh2/src/session.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.3
+Added: svn:eol-style
+   + native
+
+Index: libssh2/src/openssl.c
+===================================================================
+--- libssh2/src/openssl.c      (.../tags/RELEASE_0_11_0)
++++ libssh2/src/openssl.c      (.../trunk)
+@@ -0,0 +1,316 @@
++/* Copyright (C) 2006, 2007 The Written Word, Inc.  All rights reserved.
++ * Author: Simon Josefsson
++ * Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++#include <string.h>
++
++#ifndef EVP_MAX_BLOCK_LENGTH
++#define EVP_MAX_BLOCK_LENGTH 32
++#endif
++
++int
++_libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
++                 const unsigned char *edata,
++                 unsigned long elen,
++                 const unsigned char *ndata,
++                 unsigned long nlen,
++                 const unsigned char *ddata,
++                 unsigned long dlen,
++                 const unsigned char *pdata,
++                 unsigned long plen,
++                 const unsigned char *qdata,
++                 unsigned long qlen,
++                 const unsigned char *e1data,
++                 unsigned long e1len,
++                 const unsigned char *e2data,
++                 unsigned long e2len,
++                 const unsigned char *coeffdata, unsigned long coefflen)
++{
++    *rsa = RSA_new();
++
++    (*rsa)->e = BN_new();
++    BN_bin2bn(edata, elen, (*rsa)->e);
++
++    (*rsa)->n = BN_new();
++    BN_bin2bn(ndata, nlen, (*rsa)->n);
++
++    if (ddata) {
++        (*rsa)->d = BN_new();
++        BN_bin2bn(ddata, dlen, (*rsa)->d);
++
++        (*rsa)->p = BN_new();
++        BN_bin2bn(pdata, plen, (*rsa)->p);
++
++        (*rsa)->q = BN_new();
++        BN_bin2bn(qdata, qlen, (*rsa)->q);
++
++        (*rsa)->dmp1 = BN_new();
++        BN_bin2bn(e1data, e1len, (*rsa)->dmp1);
++
++        (*rsa)->dmq1 = BN_new();
++        BN_bin2bn(e2data, e2len, (*rsa)->dmq1);
++
++        (*rsa)->iqmp = BN_new();
++        BN_bin2bn(coeffdata, coefflen, (*rsa)->iqmp);
++    }
++    return 0;
++}
++
++int
++_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx,
++                         const unsigned char *sig,
++                         unsigned long sig_len,
++                         const unsigned char *m, unsigned long m_len)
++{
++    unsigned char hash[SHA_DIGEST_LENGTH];
++    int ret;
++
++    SHA1(m, m_len, hash);
++    ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
++                     (unsigned char *) sig, sig_len, rsactx);
++    return (ret == 1) ? 0 : -1;
++}
++
++int
++_libssh2_dsa_new(libssh2_dsa_ctx ** dsactx,
++                 const unsigned char *p,
++                 unsigned long p_len,
++                 const unsigned char *q,
++                 unsigned long q_len,
++                 const unsigned char *g,
++                 unsigned long g_len,
++                 const unsigned char *y,
++                 unsigned long y_len,
++                 const unsigned char *x, unsigned long x_len)
++{
++    *dsactx = DSA_new();
++
++    (*dsactx)->p = BN_new();
++    BN_bin2bn(p, p_len, (*dsactx)->p);
++
++    (*dsactx)->q = BN_new();
++    BN_bin2bn(q, q_len, (*dsactx)->q);
++
++    (*dsactx)->g = BN_new();
++    BN_bin2bn(g, g_len, (*dsactx)->g);
++
++    (*dsactx)->pub_key = BN_new();
++    BN_bin2bn(y, y_len, (*dsactx)->pub_key);
++
++    if (x_len) {
++        (*dsactx)->priv_key = BN_new();
++        BN_bin2bn(x, x_len, (*dsactx)->priv_key);
++    }
++
++    return 0;
++}
++
++int
++_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
++                         const unsigned char *sig,
++                         const unsigned char *m, unsigned long m_len)
++{
++    unsigned char hash[SHA_DIGEST_LENGTH];
++    DSA_SIG dsasig;
++    int ret;
++
++    dsasig.r = BN_new();
++    BN_bin2bn(sig, 20, dsasig.r);
++    dsasig.s = BN_new();
++    BN_bin2bn(sig + 20, 20, dsasig.s);
++
++    libssh2_sha1(m, m_len, hash);
++    ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, &dsasig, dsactx);
++    BN_clear_free(dsasig.s);
++    BN_clear_free(dsasig.r);
++
++    return (ret == 1) ? 0 : -1;
++}
++
++int
++_libssh2_cipher_init(_libssh2_cipher_ctx * h,
++                     _libssh2_cipher_type(algo),
++                     unsigned char *iv, unsigned char *secret, int encrypt)
++{
++    EVP_CIPHER_CTX_init(h);
++    EVP_CipherInit(h, algo(), secret, iv, encrypt);
++    return 0;
++}
++
++int
++_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
++                      _libssh2_cipher_type(algo),
++                      int encrypt, unsigned char *block)
++{
++    int blocksize = ctx->cipher->block_size;
++    unsigned char buf[EVP_MAX_BLOCK_LENGTH];
++    int ret;
++    (void) algo;
++    (void) encrypt;
++
++    if (blocksize == 1) {
++/* Hack for arcfour. */
++        blocksize = 8;
++    }
++    ret = EVP_Cipher(ctx, buf, block, blocksize);
++    if (ret == 1) {
++        memcpy(block, buf, blocksize);
++    }
++    return ret == 1 ? 0 : 1;
++}
++
++/* TODO: Optionally call a passphrase callback specified by the
++ * calling program
++ */
++static int
++passphrase_cb(char *buf, int size, int rwflag, char *passphrase)
++{
++    int passphrase_len = strlen(passphrase);
++    (void) rwflag;
++
++    if (passphrase_len > (size - 1)) {
++        passphrase_len = size - 1;
++    }
++    memcpy(buf, passphrase, passphrase_len);
++    buf[passphrase_len] = '\0';
++
++    return passphrase_len;
++}
++
++int
++_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
++                         LIBSSH2_SESSION * session,
++                         FILE * fp, unsigned const char *passphrase)
++{
++    (void) session;
++    if (!EVP_get_cipherbyname("des")) {
++/* If this cipher isn't loaded it's a pretty good indication that none are.
++ * I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
++ * Someone buy me an OpenSSL manual and I'll read up on it.
++ */
++        OpenSSL_add_all_ciphers();
++    }
++    *rsa = PEM_read_RSAPrivateKey(fp, NULL, (void *) passphrase_cb,
++                                  (void *) passphrase);
++    if (!*rsa) {
++        return -1;
++    }
++    return 0;
++}
++
++int
++_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
++                         LIBSSH2_SESSION * session,
++                         FILE * fp, unsigned const char *passphrase)
++{
++    (void) session;
++    if (!EVP_get_cipherbyname("des")) {
++/* If this cipher isn't loaded it's a pretty good indication that none are.
++ * I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
++ * Someone buy me an OpenSSL manual and I'll read up on it.
++ */
++        OpenSSL_add_all_ciphers();
++    }
++    *dsa = PEM_read_DSAPrivateKey(fp, NULL, (void *) passphrase_cb,
++                                  (void *) passphrase);
++    if (!*dsa) {
++        return -1;
++    }
++    return 0;
++}
++
++int
++_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
++                       libssh2_rsa_ctx * rsactx,
++                       const unsigned char *hash,
++                       unsigned long hash_len,
++                       unsigned char **signature, unsigned long *signature_len)
++{
++    int ret;
++    unsigned char *sig;
++    unsigned int sig_len;
++
++    sig_len = RSA_size(rsactx);
++    sig = LIBSSH2_ALLOC(session, sig_len);
++
++    if (!sig) {
++        return -1;
++    }
++
++    ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx);
++
++    if (!ret) {
++        LIBSSH2_FREE(session, sig);
++        return -1;
++    }
++
++    *signature = sig;
++    *signature_len = sig_len;
++
++    return 0;
++}
++
++int
++_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
++                       const unsigned char *hash,
++                       unsigned long hash_len, unsigned char *signature)
++{
++    DSA_SIG *sig;
++    int r_len, s_len, rs_pad;
++    (void) hash_len;
++
++    sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
++    if (!sig) {
++        return -1;
++    }
++
++    r_len = BN_num_bytes(sig->r);
++    s_len = BN_num_bytes(sig->s);
++    rs_pad = (2 * SHA_DIGEST_LENGTH) - (r_len + s_len);
++    if (rs_pad < 0) {
++        DSA_SIG_free(sig);
++        return -1;
++    }
++
++    BN_bn2bin(sig->r, signature + rs_pad);
++    BN_bn2bin(sig->s, signature + rs_pad + r_len);
++
++    DSA_SIG_free(sig);
++
++    return 0;
++}
+
+Property changes on: libssh2/src/openssl.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.1
+Added: svn:eol-style
+   + native
+Added: svn:executable
+   + *
+
+Index: libssh2/src/scp.c
+===================================================================
+--- libssh2/src/scp.c  (.../tags/RELEASE_0_11_0)
++++ libssh2/src/scp.c  (.../trunk)
+@@ -0,0 +1,811 @@
++/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++#include <errno.h>
++#include <stdlib.h>
++
++/* {{{ libssh2_scp_recv
++ * Open a channel and request a remote file via SCP
++ *
++ * NOTE:  Will block in a busy loop on error.  This has to be done,
++ *        otherwise the blocking error code would erase the true
++ *        cause of the error.
++ */
++LIBSSH2_API LIBSSH2_CHANNEL *
++libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
++{
++    int path_len = strlen(path);
++    int rc;
++
++    if (session->scpRecv_state == libssh2_NB_state_idle) {
++        session->scpRecv_mode = 0;
++        session->scpRecv_size = 0;
++        session->scpRecv_mtime = 0;
++        session->scpRecv_atime = 0;
++
++        session->scpRecv_command_len = path_len + sizeof("scp -f ");
++
++        if (sb) {
++            session->scpRecv_command_len++;
++        }
++
++        session->scpRecv_command =
++            LIBSSH2_ALLOC(session, session->scpRecv_command_len);
++        if (!session->scpRecv_command) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate a command buffer for SCP session",
++                          0);
++            return NULL;
++        }
++        if (sb) {
++            memcpy(session->scpRecv_command, "scp -pf ",
++                   sizeof("scp -pf ") - 1);
++            memcpy(session->scpRecv_command + sizeof("scp -pf ") - 1, path,
++                   path_len);
++        } else {
++            memcpy(session->scpRecv_command, "scp -f ", sizeof("scp -f ") - 1);
++            memcpy(session->scpRecv_command + sizeof("scp -f ") - 1, path,
++                   path_len);
++        }
++        session->scpRecv_command[session->scpRecv_command_len - 1] = '\0';
++
++        _libssh2_debug(session, LIBSSH2_DBG_SCP,
++                       "Opening channel for SCP receive");
++
++        session->scpRecv_state = libssh2_NB_state_created;
++    }
++
++    if (session->scpRecv_state == libssh2_NB_state_created) {
++        /* Allocate a channel */
++        do {
++            session->scpRecv_channel =
++                libssh2_channel_open_ex(session, "session",
++                                        sizeof("session") - 1,
++                                        LIBSSH2_CHANNEL_WINDOW_DEFAULT,
++                                        LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL,
++                                        0);
++            if (!session->scpRecv_channel) {
++                if (libssh2_session_last_errno(session) !=
++                    LIBSSH2_ERROR_EAGAIN) {
++                    LIBSSH2_FREE(session, session->scpRecv_command);
++                    session->scpRecv_command = NULL;
++                    session->scpRecv_state = libssh2_NB_state_idle;
++                    return NULL;
++                } else if (libssh2_session_last_errno(session) ==
++                           LIBSSH2_ERROR_EAGAIN) {
++                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                                  "Would block starting up channel", 0);
++                    return NULL;
++                }
++            }
++        } while (!session->scpRecv_channel);
++
++        session->scpRecv_state = libssh2_NB_state_sent;
++    }
++
++    if (session->scpRecv_state == libssh2_NB_state_sent) {
++        /* Request SCP for the desired file */
++        rc = libssh2_channel_process_startup(session->scpRecv_channel, "exec",
++                                             sizeof("exec") - 1,
++                                             (char *) session->scpRecv_command,
++                                             session->scpRecv_command_len);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block requesting SCP startup", 0);
++            return NULL;
++        } else if (rc) {
++            LIBSSH2_FREE(session, session->scpRecv_command);
++            session->scpRecv_command = NULL;
++            goto scp_recv_error;
++        }
++        LIBSSH2_FREE(session, session->scpRecv_command);
++        session->scpRecv_command = NULL;
++
++        _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup");
++        /* SCP ACK */
++        session->scpRecv_response[0] = '\0';
++
++        session->scpRecv_state = libssh2_NB_state_sent1;
++    }
++
++    if (session->scpRecv_state == libssh2_NB_state_sent1) {
++        rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
++                                      (char *) session->scpRecv_response, 1);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block sending initial wakeup", 0);
++            return NULL;
++        } else if (rc != 1) {
++            goto scp_recv_error;
++        }
++
++        /* Parse SCP response */
++        session->scpRecv_response_len = 0;
++
++        session->scpRecv_state = libssh2_NB_state_sent2;
++    }
++
++    if ((session->scpRecv_state == libssh2_NB_state_sent2)
++        || (session->scpRecv_state == libssh2_NB_state_sent3)) {
++        while (sb
++               && (session->scpRecv_response_len <
++                   LIBSSH2_SCP_RESPONSE_BUFLEN)) {
++            unsigned char *s, *p;
++
++            if (session->scpRecv_state == libssh2_NB_state_sent2) {
++                rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
++                                             (char *) session->
++                                             scpRecv_response +
++                                             session->scpRecv_response_len, 1);
++                if (rc == PACKET_EAGAIN) {
++                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                                  "Would block waiting for SCP response", 0);
++                    return NULL;
++                } else if (rc <= 0) {
++                    /* Timeout, give up */
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Timed out waiting for SCP response", 0);
++                    goto scp_recv_error;
++                }
++                session->scpRecv_response_len++;
++
++                if (session->scpRecv_response[0] != 'T') {
++                    /*
++                     * Set this as the default error for here, if
++                     * we are successful it will be replaced
++                     */
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid data in SCP response, missing Time data",
++                                  0);
++
++                    session->scpRecv_err_len =
++                        libssh2_channel_packet_data_len(session->
++                                                        scpRecv_channel, 0);
++                    session->scpRecv_err_msg =
++                        LIBSSH2_ALLOC(session, session->scpRecv_err_len + 1);
++                    if (!session->scpRecv_err_msg) {
++                        goto scp_recv_error;
++                    }
++                    memset(session->scpRecv_err_msg, 0,
++                           session->scpRecv_err_len + 1);
++
++                    /* Read the remote error message */
++                    rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
++                                                 session->scpRecv_err_msg,
++                                                 session->scpRecv_err_len);
++                    if (rc <= 0) {
++                        /*
++                         * Since we have alread started reading this packet, it is
++                         * already in the systems so it can't return PACKET_EAGAIN
++                         */
++                        LIBSSH2_FREE(session, session->scpRecv_err_msg);
++                        session->scpRecv_err_msg = NULL;
++                        libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                      "Unknown error while getting error string",
++                                      0);
++                        goto scp_recv_error;
++                    }
++
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  session->scpRecv_err_msg, 1);
++                    session->scpRecv_err_msg = NULL;
++                    goto scp_recv_error;
++                }
++
++                if ((session->scpRecv_response_len > 1) &&
++                    ((session->
++                      scpRecv_response[session->scpRecv_response_len - 1] <
++                      '0')
++                     || (session->
++                         scpRecv_response[session->scpRecv_response_len - 1] >
++                         '9'))
++                    && (session->
++                        scpRecv_response[session->scpRecv_response_len - 1] !=
++                        ' ')
++                    && (session->
++                        scpRecv_response[session->scpRecv_response_len - 1] !=
++                        '\r')
++                    && (session->
++                        scpRecv_response[session->scpRecv_response_len - 1] !=
++                        '\n')) {
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid data in SCP response", 0);
++                    goto scp_recv_error;
++                }
++
++                if ((session->scpRecv_response_len < 9)
++                    || (session->
++                        scpRecv_response[session->scpRecv_response_len - 1] !=
++                        '\n')) {
++                    if (session->scpRecv_response_len ==
++                        LIBSSH2_SCP_RESPONSE_BUFLEN) {
++                        /* You had your chance */
++                        libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                      "Unterminated response from SCP server",
++                                      0);
++                        goto scp_recv_error;
++                    }
++                    /* Way too short to be an SCP response,  or not done yet, short circuit */
++                    continue;
++                }
++
++                /* We're guaranteed not to go under response_len == 0 by the logic above */
++                while ((session->
++                        scpRecv_response[session->scpRecv_response_len - 1] ==
++                        '\r')
++                       || (session->
++                           scpRecv_response[session->scpRecv_response_len -
++                                            1] == '\n'))
++                    session->scpRecv_response_len--;
++                session->scpRecv_response[session->scpRecv_response_len] =
++                    '\0';
++
++                if (session->scpRecv_response_len < 8) {
++                    /* EOL came too soon */
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid response from SCP server, too short",
++                                  0);
++                    goto scp_recv_error;
++                }
++
++                s = session->scpRecv_response + 1;
++
++                p = (unsigned char *) strchr((char *) s, ' ');
++                if (!p || ((p - s) <= 0)) {
++                    /* No spaces or space in the wrong spot */
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid response from SCP server, malformed mtime",
++                                  0);
++                    goto scp_recv_error;
++                }
++
++                *(p++) = '\0';
++                /* Make sure we don't get fooled by leftover values */
++                errno = 0;
++                session->scpRecv_mtime = strtol((char *) s, NULL, 10);
++                if (errno) {
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid response from SCP server, invalid mtime",
++                                  0);
++                    goto scp_recv_error;
++                }
++                s = (unsigned char *) strchr((char *) p, ' ');
++                if (!s || ((s - p) <= 0)) {
++                    /* No spaces or space in the wrong spot */
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid response from SCP server, malformed mtime.usec",
++                                  0);
++                    goto scp_recv_error;
++                }
++
++                /* Ignore mtime.usec */
++                s++;
++                p = (unsigned char *) strchr((char *) s, ' ');
++                if (!p || ((p - s) <= 0)) {
++                    /* No spaces or space in the wrong spot */
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid response from SCP server, too short or malformed",
++                                  0);
++                    goto scp_recv_error;
++                }
++
++                *(p++) = '\0';
++                /* Make sure we don't get fooled by leftover values */
++                errno = 0;
++                session->scpRecv_atime = strtol((char *) s, NULL, 10);
++                if (errno) {
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid response from SCP server, invalid atime",
++                                  0);
++                    goto scp_recv_error;
++                }
++
++                /* SCP ACK */
++                session->scpRecv_response[0] = '\0';
++
++                session->scpRecv_state = libssh2_NB_state_sent3;
++            }
++
++            if (session->scpRecv_state == libssh2_NB_state_sent3) {
++                rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
++                                              (char *) session->
++                                              scpRecv_response, 1);
++                if (rc == PACKET_EAGAIN) {
++                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                                  "Would block waiting to send SCP ACK", 0);
++                    return NULL;
++                } else if (rc != 1) {
++                    goto scp_recv_error;
++                }
++
++                _libssh2_debug(session, LIBSSH2_DBG_SCP,
++                               "mtime = %ld, atime = %ld",
++                               session->scpRecv_mtime, session->scpRecv_atime);
++
++                /* We *should* check that atime.usec is valid, but why let that stop use? */
++                break;
++            }
++        }
++
++        session->scpRecv_state = libssh2_NB_state_sent4;
++    }
++
++    if (session->scpRecv_state == libssh2_NB_state_sent4) {
++        session->scpRecv_response_len = 0;
++
++        session->scpRecv_state = libssh2_NB_state_sent5;
++    }
++
++    if ((session->scpRecv_state == libssh2_NB_state_sent5)
++        || (session->scpRecv_state == libssh2_NB_state_sent6)) {
++        while (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) {
++            char *s, *p, *e = NULL;
++
++            if (session->scpRecv_state == libssh2_NB_state_sent5) {
++                rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
++                                             (char *) session->
++                                             scpRecv_response +
++                                             session->scpRecv_response_len, 1);
++                if (rc == PACKET_EAGAIN) {
++                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                                  "Would block waiting for SCP response", 0);
++                    return NULL;
++                } else if (rc <= 0) {
++                    /* Timeout, give up */
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Timed out waiting for SCP response", 0);
++                    goto scp_recv_error;
++                }
++                session->scpRecv_response_len++;
++
++                if (session->scpRecv_response[0] != 'C') {
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid response from SCP server", 0);
++                    goto scp_recv_error;
++                }
++
++                if ((session->scpRecv_response_len > 1) &&
++                    (session->
++                     scpRecv_response[session->scpRecv_response_len - 1] !=
++                     '\r')
++                    && (session->
++                        scpRecv_response[session->scpRecv_response_len - 1] !=
++                        '\n')
++                    &&
++                    ((session->
++                      scpRecv_response[session->scpRecv_response_len - 1] < 32)
++                     || (session->
++                         scpRecv_response[session->scpRecv_response_len - 1] >
++                         126))) {
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid data in SCP response", 0);
++                    goto scp_recv_error;
++                }
++
++                if ((session->scpRecv_response_len < 7)
++                    || (session->
++                        scpRecv_response[session->scpRecv_response_len - 1] !=
++                        '\n')) {
++                    if (session->scpRecv_response_len ==
++                        LIBSSH2_SCP_RESPONSE_BUFLEN) {
++                        /* You had your chance */
++                        libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                      "Unterminated response from SCP server",
++                                      0);
++                        goto scp_recv_error;
++                    }
++                    /* Way too short to be an SCP response,  or not done yet, short circuit */
++                    continue;
++                }
++
++                /* We're guaranteed not to go under response_len == 0 by the logic above */
++                while ((session->
++                        scpRecv_response[session->scpRecv_response_len - 1] ==
++                        '\r')
++                       || (session->
++                           scpRecv_response[session->scpRecv_response_len -
++                                            1] == '\n')) {
++                    session->scpRecv_response_len--;
++                }
++                session->scpRecv_response[session->scpRecv_response_len] =
++                    '\0';
++
++                if (session->scpRecv_response_len < 6) {
++                    /* EOL came too soon */
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid response from SCP server, too short",
++                                  0);
++                    goto scp_recv_error;
++                }
++
++                s = (char *) session->scpRecv_response + 1;
++
++                p = strchr(s, ' ');
++                if (!p || ((p - s) <= 0)) {
++                    /* No spaces or space in the wrong spot */
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid response from SCP server, malformed mode",
++                                  0);
++                    goto scp_recv_error;
++                }
++
++                *(p++) = '\0';
++                /* Make sure we don't get fooled by leftover values */
++                errno = 0;
++                session->scpRecv_mode = strtol(s, &e, 8);
++                if ((e && *e) || errno) {
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid response from SCP server, invalid mode",
++                                  0);
++                    goto scp_recv_error;
++                }
++
++                s = strchr(p, ' ');
++                if (!s || ((s - p) <= 0)) {
++                    /* No spaces or space in the wrong spot */
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid response from SCP server, too short or malformed",
++                                  0);
++                    goto scp_recv_error;
++                }
++
++                *(s++) = '\0';
++                /* Make sure we don't get fooled by leftover values */
++                errno = 0;
++                session->scpRecv_size = scpsize_strtol(p, &e, 10);
++                if ((e && *e) || errno) {
++                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                                  "Invalid response from SCP server, invalid size",
++                                  0);
++                    goto scp_recv_error;
++                }
++
++                /* SCP ACK */
++                session->scpRecv_response[0] = '\0';
++
++                session->scpRecv_state = libssh2_NB_state_sent6;
++            }
++
++            if (session->scpRecv_state == libssh2_NB_state_sent6) {
++                rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
++                                              (char *) session->
++                                              scpRecv_response, 1);
++                if (rc == PACKET_EAGAIN) {
++                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                                  "Would block sending SCP ACK", 0);
++                    return NULL;
++                } else if (rc != 1) {
++                    goto scp_recv_error;
++                }
++                _libssh2_debug(session, LIBSSH2_DBG_SCP,
++                               "mode = 0%lo size = %ld", session->scpRecv_mode,
++                               session->scpRecv_size);
++
++                /* We *should* check that basename is valid, but why let that stop us? */
++                break;
++            }
++        }
++
++        session->scpRecv_state = libssh2_NB_state_sent7;
++    }
++
++    if (sb) {
++        memset(sb, 0, sizeof(struct stat));
++
++        sb->st_mtime = session->scpRecv_mtime;
++        sb->st_atime = session->scpRecv_atime;
++        sb->st_size = session->scpRecv_size;
++        sb->st_mode = session->scpRecv_mode;
++    }
++
++    session->scpRecv_state = libssh2_NB_state_idle;
++    return session->scpRecv_channel;
++
++  scp_recv_error:
++    while (libssh2_channel_free(session->scpRecv_channel) == PACKET_EAGAIN);
++    session->scpRecv_channel = NULL;
++    session->scpRecv_state = libssh2_NB_state_idle;
++    return NULL;
++}
++
++/* }}} */
++
++/* {{{ libssh2_scp_send_ex
++ * Send a file using SCP
++ *
++ * NOTE:  Will block in a busy loop on error.  This has to be done,
++ *        otherwise the blocking error code would erase the true
++ *        cause of the error.
++ */
++LIBSSH2_API LIBSSH2_CHANNEL *
++libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
++                    size_t size, long mtime, long atime)
++{
++    int path_len = strlen(path);
++    unsigned const char *base;
++    int rc;
++
++    if (session->scpSend_state == libssh2_NB_state_idle) {
++        session->scpSend_command_len = path_len + sizeof("scp -t ");
++
++        if (mtime || atime) {
++            session->scpSend_command_len++;
++        }
++
++        session->scpSend_command =
++            LIBSSH2_ALLOC(session, session->scpSend_command_len);
++        if (!session->scpSend_command) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate a command buffer for scp session",
++                          0);
++            return NULL;
++        }
++
++        if (mtime || atime) {
++            memcpy(session->scpSend_command, "scp -pt ",
++                   sizeof("scp -pt ") - 1);
++            memcpy(session->scpSend_command + sizeof("scp -pt ") - 1, path,
++                   path_len);
++        } else {
++            memcpy(session->scpSend_command, "scp -t ", sizeof("scp -t ") - 1);
++            memcpy(session->scpSend_command + sizeof("scp -t ") - 1, path,
++                   path_len);
++        }
++        session->scpSend_command[session->scpSend_command_len - 1] = '\0';
++
++        _libssh2_debug(session, LIBSSH2_DBG_SCP,
++                       "Opening channel for SCP send");
++        /* Allocate a channel */
++
++        session->scpSend_state = libssh2_NB_state_created;
++    }
++
++    if (session->scpSend_state == libssh2_NB_state_created) {
++        session->scpSend_channel =
++            libssh2_channel_open_ex(session, "session", sizeof("session") - 1,
++                                    LIBSSH2_CHANNEL_WINDOW_DEFAULT,
++                                    LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0);
++        if (!session->scpSend_channel) {
++            if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
++                /* previous call set libssh2_session_last_error(), pass it through */
++                LIBSSH2_FREE(session, session->scpSend_command);
++                session->scpSend_command = NULL;
++                session->scpSend_state = libssh2_NB_state_idle;
++                return NULL;
++            } else if (libssh2_session_last_errno(session) ==
++                       LIBSSH2_ERROR_EAGAIN) {
++                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                              "Would block starting up channel", 0);
++                return NULL;
++            }
++        }
++
++        session->scpSend_state = libssh2_NB_state_sent;
++    }
++
++    if (session->scpSend_state == libssh2_NB_state_sent) {
++        /* Request SCP for the desired file */
++        rc = libssh2_channel_process_startup(session->scpSend_channel, "exec",
++                                             sizeof("exec") - 1,
++                                             (char *) session->scpSend_command,
++                                             session->scpSend_command_len);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block requesting SCP startup", 0);
++            return NULL;
++        } else if (rc) {
++            /* previous call set libssh2_session_last_error(), pass it through */
++            LIBSSH2_FREE(session, session->scpSend_command);
++            session->scpSend_command = NULL;
++            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                          "Unknown error while getting error string", 0);
++            goto scp_send_error;
++        }
++        LIBSSH2_FREE(session, session->scpSend_command);
++        session->scpSend_command = NULL;
++
++        session->scpSend_state = libssh2_NB_state_sent1;
++    }
++
++    if (session->scpSend_state == libssh2_NB_state_sent1) {
++        /* Wait for ACK */
++        rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
++                                     (char *) session->scpSend_response, 1);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block waiting for response from remote", 0);
++            return NULL;
++        } else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
++            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                          "Invalid ACK response from remote", 0);
++            goto scp_send_error;
++        }
++
++        if (mtime || atime) {
++            /* Send mtime and atime to be used for file */
++            session->scpSend_response_len =
++                snprintf((char *) session->scpSend_response,
++                         LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", mtime,
++                         atime);
++            _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
++                           session->scpSend_response);
++        }
++
++        session->scpSend_state = libssh2_NB_state_sent2;
++    }
++
++    /* Send mtime and atime to be used for file */
++    if (mtime || atime) {
++        if (session->scpSend_state == libssh2_NB_state_sent2) {
++            rc = libssh2_channel_write_ex(session->scpSend_channel, 0,
++                                          (char *) session->scpSend_response,
++                                          session->scpSend_response_len);
++            if (rc == PACKET_EAGAIN) {
++                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                              "Would block sending time data for SCP file", 0);
++                return NULL;
++            } else if (rc != session->scpSend_response_len) {
++                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                              "Unable to send time data for SCP file", 0);
++                goto scp_send_error;
++            }
++
++            session->scpSend_state = libssh2_NB_state_sent3;
++        }
++
++        if (session->scpSend_state == libssh2_NB_state_sent3) {
++            /* Wait for ACK */
++            rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
++                                         (char *) session->scpSend_response,
++                                         1);
++            if (rc == PACKET_EAGAIN) {
++                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                              "Would block waiting for response", 0);
++                return NULL;
++            } else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
++                libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                              "Invalid ACK response from remote", 0);
++                goto scp_send_error;
++            }
++
++            session->scpSend_state = libssh2_NB_state_sent4;
++        }
++    } else {
++        if (session->scpSend_state == libssh2_NB_state_sent2) {
++            session->scpSend_state = libssh2_NB_state_sent4;
++        }
++    }
++
++    if (session->scpSend_state == libssh2_NB_state_sent4) {
++        /* Send mode, size, and basename */
++        base = (unsigned char *) strrchr(path, '/');
++        if (base) {
++            base++;
++        } else {
++            base = (unsigned char *) path;
++        }
++
++        session->scpSend_response_len =
++            snprintf((char *) session->scpSend_response,
++                     LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %lu %s\n", mode,
++                     (unsigned long) size, base);
++        _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
++                       session->scpSend_response);
++
++        session->scpSend_state = libssh2_NB_state_sent5;
++    }
++
++    if (session->scpSend_state == libssh2_NB_state_sent5) {
++        rc = libssh2_channel_write_ex(session->scpSend_channel, 0,
++                                      (char *) session->scpSend_response,
++                                      session->scpSend_response_len);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block send core file data for SCP file", 0);
++            return NULL;
++        } else if (rc != session->scpSend_response_len) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send core file data for SCP file", 0);
++            goto scp_send_error;
++        }
++
++        session->scpSend_state = libssh2_NB_state_sent6;
++    }
++
++    if (session->scpSend_state == libssh2_NB_state_sent6) {
++        /* Wait for ACK */
++        rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
++                                     (char *) session->scpSend_response, 1);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block waiting for response", 0);
++            return NULL;
++        } else if (rc <= 0) {
++            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                          "Invalid ACK response from remote", 0);
++            goto scp_send_error;
++        } else if (session->scpSend_response[0] != 0) {
++            /*
++             * Set this as the default error for here, if
++             * we are successful it will be replaced
++             */
++            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                          "Invalid ACK response from remote", 0);
++
++            session->scpSend_err_len =
++                libssh2_channel_packet_data_len(session->scpSend_channel, 0);
++            session->scpSend_err_msg =
++                LIBSSH2_ALLOC(session, session->scpSend_err_len + 1);
++            if (!session->scpSend_err_msg) {
++                goto scp_send_error;
++            }
++            memset(session->scpSend_err_msg, 0, session->scpSend_err_len + 1);
++
++            /* Read the remote error message */
++            rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
++                                         session->scpSend_err_msg,
++                                         session->scpSend_err_len);
++            if (rc <= 0) {
++                /*
++                 * Since we have alread started reading this packet, it is
++                 * already in the systems so it can't return PACKET_EAGAIN
++                 */
++                LIBSSH2_FREE(session, session->scpSend_err_msg);
++                session->scpSend_err_msg = NULL;
++                goto scp_send_error;
++            }
++
++            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
++                          session->scpSend_err_msg, 1);
++            session->scpSend_err_msg = NULL;
++            goto scp_send_error;
++        }
++    }
++
++    session->scpSend_state = libssh2_NB_state_idle;
++
++    return session->scpSend_channel;
++
++  scp_send_error:
++    while (libssh2_channel_free(session->scpSend_channel) == PACKET_EAGAIN);
++    session->scpSend_channel = NULL;
++    session->scpSend_state = libssh2_NB_state_idle;
++    return NULL;
++}
++
++/* }}} */
+
+Property changes on: libssh2/src/scp.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.2
+Added: svn:eol-style
+   + native
+
+Index: libssh2/src/hostkey.c
+===================================================================
+--- libssh2/src/hostkey.c      (.../tags/RELEASE_0_11_0)
++++ libssh2/src/hostkey.c      (.../trunk)
+@@ -0,0 +1,455 @@
++/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++
++/* Needed for struct iovec on some platforms */
++#ifdef HAVE_SYS_UIO_H
++#include <sys/uio.h>
++#endif
++
++#if LIBSSH2_RSA
++/* ***********
++   * ssh-rsa *
++   *********** */
++
++static int libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session,
++                                               void **abstract);
++
++/* {{{ libssh2_hostkey_method_ssh_rsa_init
++ * Initialize the server hostkey working area with e/n pair
++ */
++static int
++libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session,
++                                    const unsigned char *hostkey_data,
++                                    unsigned long hostkey_data_len,
++                                    void **abstract)
++{
++    libssh2_rsa_ctx *rsactx;
++    const unsigned char *s, *e, *n;
++    unsigned long len, e_len, n_len;
++
++    (void) hostkey_data_len;
++
++    if (*abstract) {
++        libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
++        *abstract = NULL;
++    }
++
++    s = hostkey_data;
++    len = libssh2_ntohu32(s);
++    s += 4;
++
++    if (len != 7 || strncmp((char *) s, "ssh-rsa", 7) != 0) {
++        return -1;
++    }
++    s += 7;
++
++    e_len = libssh2_ntohu32(s);
++    s += 4;
++
++    e = s;
++    s += e_len;
++    n_len = libssh2_ntohu32(s);
++    s += 4;
++    n = s;
++    s += n_len;
++
++    if (_libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0,
++                         NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0))
++        return -1;
++
++    *abstract = rsactx;
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_hostkey_method_ssh_rsa_initPEM
++ * Load a Private Key from a PEM file
++ */
++static int
++libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session,
++                                       const char *privkeyfile,
++                                       unsigned const char *passphrase,
++                                       void **abstract)
++{
++    libssh2_rsa_ctx *rsactx;
++    FILE *fp;
++    int ret;
++
++    if (*abstract) {
++        libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
++        *abstract = NULL;
++    }
++
++    fp = fopen(privkeyfile, "r");
++    if (!fp) {
++        return -1;
++    }
++
++    ret = _libssh2_rsa_new_private(&rsactx, session, fp, passphrase);
++    fclose(fp);
++    if (ret) {
++        return -1;
++    }
++
++    *abstract = rsactx;
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_hostkey_method_ssh_rsa_sign
++ * Verify signature created by remote
++ */
++static int
++libssh2_hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session,
++                                          const unsigned char *sig,
++                                          unsigned long sig_len,
++                                          const unsigned char *m,
++                                          unsigned long m_len, void **abstract)
++{
++    libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
++    (void) session;
++
++    /* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */
++    sig += 15;
++    sig_len -= 15;
++    return _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len);
++}
++
++/* }}} */
++
++/* {{{ libssh2_hostkey_method_ssh_rsa_signv
++ * Construct a signature from an array of vectors
++ */
++static int
++libssh2_hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session,
++                                     unsigned char **signature,
++                                     unsigned long *signature_len,
++                                     unsigned long veccount,
++                                     const struct iovec datavec[],
++                                     void **abstract)
++{
++    libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
++    int ret;
++    unsigned int i;
++    unsigned char hash[SHA_DIGEST_LENGTH];
++    libssh2_sha1_ctx ctx;
++
++    libssh2_sha1_init(&ctx);
++    for(i = 0; i < veccount; i++) {
++        libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
++    }
++    libssh2_sha1_final(ctx, hash);
++
++    ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH,
++                                 signature, signature_len);
++    if (ret) {
++        return -1;
++    }
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_hostkey_method_ssh_rsa_dtor
++ * Shutdown the hostkey
++ */
++static int
++libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, void **abstract)
++{
++    libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
++    (void) session;
++
++    _libssh2_rsa_free(rsactx);
++
++    *abstract = NULL;
++
++    return 0;
++}
++
++/* }}} */
++
++static const LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_rsa = {
++    "ssh-rsa",
++    MD5_DIGEST_LENGTH,
++    libssh2_hostkey_method_ssh_rsa_init,
++    libssh2_hostkey_method_ssh_rsa_initPEM,
++    libssh2_hostkey_method_ssh_rsa_sig_verify,
++    libssh2_hostkey_method_ssh_rsa_signv,
++    NULL,                       /* encrypt */
++    libssh2_hostkey_method_ssh_rsa_dtor,
++};
++#endif /* LIBSSH2_RSA */
++
++#if LIBSSH2_DSA
++/* ***********
++   * ssh-dss *
++   *********** */
++
++static int libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session,
++                                               void **abstract);
++
++/* {{{ libssh2_hostkey_method_ssh_dss_init
++ * Initialize the server hostkey working area with p/q/g/y set
++ */
++static int
++libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session,
++                                    const unsigned char *hostkey_data,
++                                    unsigned long hostkey_data_len,
++                                    void **abstract)
++{
++    libssh2_dsa_ctx *dsactx;
++    const unsigned char *p, *q, *g, *y, *s;
++    unsigned long p_len, q_len, g_len, y_len, len;
++    (void) hostkey_data_len;
++
++    if (*abstract) {
++        libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
++        *abstract = NULL;
++    }
++
++    s = hostkey_data;
++    len = libssh2_ntohu32(s);
++    s += 4;
++    if (len != 7 || strncmp((char *) s, "ssh-dss", 7) != 0) {
++        return -1;
++    }
++    s += 7;
++
++    p_len = libssh2_ntohu32(s);
++    s += 4;
++    p = s;
++    s += p_len;
++    q_len = libssh2_ntohu32(s);
++    s += 4;
++    q = s;
++    s += q_len;
++    g_len = libssh2_ntohu32(s);
++    s += 4;
++    g = s;
++    s += g_len;
++    y_len = libssh2_ntohu32(s);
++    s += 4;
++    y = s;
++    s += y_len;
++
++    _libssh2_dsa_new(&dsactx, p, p_len, q, q_len, g, g_len, y, y_len, NULL, 0);
++
++    *abstract = dsactx;
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_hostkey_method_ssh_dss_initPEM
++ * Load a Private Key from a PEM file
++ */
++static int
++libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session,
++                                       const char *privkeyfile,
++                                       unsigned const char *passphrase,
++                                       void **abstract)
++{
++    libssh2_dsa_ctx *dsactx;
++    FILE *fp;
++    int ret;
++
++    if (*abstract) {
++        libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
++        *abstract = NULL;
++    }
++
++    fp = fopen(privkeyfile, "r");
++    if (!fp) {
++        return -1;
++    }
++
++    ret = _libssh2_dsa_new_private(&dsactx, session, fp, passphrase);
++    fclose(fp);
++    if (ret) {
++        return -1;
++    }
++
++    *abstract = dsactx;
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_hostkey_method_ssh_dss_sign
++ * Verify signature created by remote
++ */
++static int
++libssh2_hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION * session,
++                                          const unsigned char *sig,
++                                          unsigned long sig_len,
++                                          const unsigned char *m,
++                                          unsigned long m_len, void **abstract)
++{
++    libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
++
++    /* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
++    sig += 15;
++    sig_len -= 15;
++    if (sig_len != 40) {
++        libssh2_error(session, LIBSSH2_ERROR_PROTO,
++                      "Invalid DSS signature length", 0);
++        return -1;
++    }
++    return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len);
++}
++
++/* }}} */
++
++/* {{{ libssh2_hostkey_method_ssh_dss_signv
++ * Construct a signature from an array of vectors
++ */
++static int
++libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session,
++                                     unsigned char **signature,
++                                     unsigned long *signature_len,
++                                     unsigned long veccount,
++                                     const struct iovec datavec[],
++                                     void **abstract)
++{
++    libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
++    unsigned char hash[SHA_DIGEST_LENGTH];
++    libssh2_sha1_ctx ctx;
++    unsigned int i;
++
++    *signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
++    if (!*signature) {
++        return -1;
++    }
++
++    *signature_len = 2 * SHA_DIGEST_LENGTH;
++    memset(*signature, 0, 2 * SHA_DIGEST_LENGTH);
++
++    libssh2_sha1_init(&ctx);
++    for(i = 0; i < veccount; i++) {
++        libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
++    }
++    libssh2_sha1_final(ctx, hash);
++
++    if (_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) {
++        LIBSSH2_FREE(session, *signature);
++        return -1;
++    }
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_hostkey_method_ssh_dss_dtor
++ * Shutdown the hostkey method
++ */
++static int
++libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, void **abstract)
++{
++    libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
++    (void) session;
++
++    _libssh2_dsa_free(dsactx);
++
++    *abstract = NULL;
++
++    return 0;
++}
++
++/* }}} */
++
++static const LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_dss = {
++    "ssh-dss",
++    MD5_DIGEST_LENGTH,
++    libssh2_hostkey_method_ssh_dss_init,
++    libssh2_hostkey_method_ssh_dss_initPEM,
++    libssh2_hostkey_method_ssh_dss_sig_verify,
++    libssh2_hostkey_method_ssh_dss_signv,
++    NULL,                       /* encrypt */
++    libssh2_hostkey_method_ssh_dss_dtor,
++};
++#endif /* LIBSSH2_DSA */
++
++static const LIBSSH2_HOSTKEY_METHOD *_libssh2_hostkey_methods[] = {
++#if LIBSSH2_RSA
++    &libssh2_hostkey_method_ssh_rsa,
++#endif /* LIBSSH2_RSA */
++#if LIBSSH2_DSA
++    &libssh2_hostkey_method_ssh_dss,
++#endif /* LIBSSH2_DSA */
++    NULL
++};
++
++const LIBSSH2_HOSTKEY_METHOD **
++libssh2_hostkey_methods(void)
++{
++    return _libssh2_hostkey_methods;
++}
++
++/* {{{ libssh2_hostkey_hash
++ * Returns hash signature
++ * Returned buffer should NOT be freed
++ * Length of buffer is determined by hash type
++ * i.e. MD5 == 16, SHA1 == 20
++ */
++LIBSSH2_API const char *
++libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type)
++{
++    switch (hash_type) {
++#if LIBSSH2_MD5
++    case LIBSSH2_HOSTKEY_HASH_MD5:
++        return (char *) session->server_hostkey_md5;
++        break;
++#endif /* LIBSSH2_MD5 */
++    case LIBSSH2_HOSTKEY_HASH_SHA1:
++        return (char *) session->server_hostkey_sha1;
++        break;
++    default:
++        return NULL;
++    }
++}
++
++/* }}} */
+
+Property changes on: libssh2/src/hostkey.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.2
+Added: svn:eol-style
+   + native
+
+Index: libssh2/src/publickey.c
+===================================================================
+--- libssh2/src/publickey.c    (.../tags/RELEASE_0_11_0)
++++ libssh2/src/publickey.c    (.../trunk)
+@@ -0,0 +1,1094 @@
++/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++#include "libssh2_publickey.h"
++
++#define LIBSSH2_PUBLICKEY_VERSION               2
++
++/* Numericised response codes -- Not IETF standard, just a local representation */
++#define LIBSSH2_PUBLICKEY_RESPONSE_STATUS       0
++#define LIBSSH2_PUBLICKEY_RESPONSE_VERSION      1
++#define LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY    2
++
++typedef struct _LIBSSH2_PUBLICKEY_CODE_LIST
++{
++    int code;
++    const char *name;
++    int name_len;
++} LIBSSH2_PUBLICKEY_CODE_LIST;
++
++static const LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_response_codes[] = {
++    {LIBSSH2_PUBLICKEY_RESPONSE_STATUS, "status", sizeof("status") - 1}
++    ,
++    {LIBSSH2_PUBLICKEY_RESPONSE_VERSION, "version", sizeof("version") - 1}
++    ,
++    {LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY, "publickey", sizeof("publickey") - 1}
++    ,
++    {0, NULL, 0}
++};
++
++/* PUBLICKEY status codes -- IETF defined */
++#define LIBSSH2_PUBLICKEY_SUCCESS               0
++#define LIBSSH2_PUBLICKEY_ACCESS_DENIED         1
++#define LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED      2
++#define LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED 3
++#define LIBSSH2_PUBLICKEY_KEY_NOT_FOUND         4
++#define LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED     5
++#define LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT   6
++#define LIBSSH2_PUBLICKEY_GENERAL_FAILURE       7
++#define LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED 8
++
++#define LIBSSH2_PUBLICKEY_STATUS_CODE_MAX       8
++
++static const LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_status_codes[] = {
++    {LIBSSH2_PUBLICKEY_SUCCESS, "success", sizeof("success") - 1}
++    ,
++    {LIBSSH2_PUBLICKEY_ACCESS_DENIED, "access denied",
++     sizeof("access denied") - 1}
++    ,
++    {LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED, "storage exceeded",
++     sizeof("storage exceeded") - 1}
++    ,
++    {LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED, "version not supported",
++     sizeof("version not supported") - 1}
++    ,
++    {LIBSSH2_PUBLICKEY_KEY_NOT_FOUND, "key not found",
++     sizeof("key not found") - 1}
++    ,
++    {LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED, "key not supported",
++     sizeof("key not supported") - 1}
++    ,
++    {LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT, "key already present",
++     sizeof("key already present") - 1}
++    ,
++    {LIBSSH2_PUBLICKEY_GENERAL_FAILURE, "general failure",
++     sizeof("general failure") - 1}
++    ,
++    {LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED, "request not supported",
++     sizeof("request not supported") - 1}
++    ,
++    {0, NULL, 0}
++};
++
++/* {{{ libssh2_publickey_status_error
++ * Format an error message from a status code
++ */
++#define LIBSSH2_PUBLICKEY_STATUS_TEXT_START     "Publickey Subsystem Error: \""
++#define LIBSSH2_PUBLICKEY_STATUS_TEXT_MID       "\" Server Reports: \""
++#define LIBSSH2_PUBLICKEY_STATUS_TEXT_END       "\""
++static void
++libssh2_publickey_status_error(const LIBSSH2_PUBLICKEY * pkey,
++                               LIBSSH2_SESSION * session, int status,
++                               const unsigned char *message, int message_len)
++{
++    const char *status_text;
++    int status_text_len;
++    char *m, *s;
++    int m_len;
++
++    /* GENERAL_FAILURE got remapped between version 1 and 2 */
++    if (status == 6 && pkey && pkey->version == 1) {
++        status = 7;
++    }
++
++    if (status < 0 || status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) {
++        status_text = "unknown";
++        status_text_len = sizeof("unknown") - 1;
++    } else {
++        status_text = libssh2_publickey_status_codes[status].name;
++        status_text_len = libssh2_publickey_status_codes[status].name_len;
++    }
++
++    m_len =
++        (sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1) + status_text_len +
++        (sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1) + message_len +
++        (sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
++    m = LIBSSH2_ALLOC(session, m_len + 1);
++    if (!m) {
++        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                      "Unable to allocate memory for status message", 0);
++        return;
++    }
++    s = m;
++    memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_START,
++           sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1);
++    s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1;
++    memcpy(s, status_text, status_text_len);
++    s += status_text_len;
++    memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_MID,
++           sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1);
++    s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1;
++    memcpy(s, message, message_len);
++    s += message_len;
++    memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_END,
++           sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
++    s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END);
++    libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, m, 1);
++}
++
++/* }}} */
++
++/* {{{ libssh2_publickey_packet_receive
++ * Read a packet from the subsystem
++ */
++static int
++libssh2_publickey_packet_receive(LIBSSH2_PUBLICKEY * pkey,
++                                 unsigned char **data, unsigned long *data_len)
++{
++    LIBSSH2_CHANNEL *channel = pkey->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    unsigned char buffer[4];
++    int rc;
++
++    if (pkey->receive_state == libssh2_NB_state_idle) {
++        rc = libssh2_channel_read_ex(channel, 0, (char *) buffer, 4);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc != 4) {
++            libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
++                          "Invalid response from publickey subsystem", 0);
++            return -1;
++        }
++
++        pkey->receive_packet_len = libssh2_ntohu32(buffer);
++        pkey->receive_packet =
++            LIBSSH2_ALLOC(session, pkey->receive_packet_len);
++        if (!pkey->receive_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate publickey response buffer", 0);
++            return -1;
++        }
++
++        pkey->receive_state = libssh2_NB_state_sent;
++    }
++
++    if (pkey->receive_state == libssh2_NB_state_sent) {
++        rc = libssh2_channel_read_ex(channel, 0, (char *) pkey->receive_packet,
++                                     pkey->receive_packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc != (int)pkey->receive_packet_len) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                          "Timeout waiting for publickey subsystem response packet",
++                          0);
++            LIBSSH2_FREE(session, pkey->receive_packet);
++            pkey->receive_packet = NULL;
++            pkey->receive_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        *data = pkey->receive_packet;
++        *data_len = pkey->receive_packet_len;
++    }
++
++    pkey->receive_state = libssh2_NB_state_idle;
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_publickey_response_id
++ * Translate a string response name to a numeric code
++ * Data will be incremented by 4 + response_len on success only
++ */
++static int
++libssh2_publickey_response_id(unsigned char **pdata, int data_len)
++{
++    unsigned long response_len;
++    unsigned char *data = *pdata;
++    const LIBSSH2_PUBLICKEY_CODE_LIST *codes =
++        libssh2_publickey_response_codes;
++
++    if (data_len < 4) {
++        /* Malformed response */
++        return -1;
++    }
++    response_len = libssh2_ntohu32(data);
++    data += 4;
++    data_len -= 4;
++    if (data_len < (int)response_len) {
++        /* Malformed response */
++        return -1;
++    }
++
++    while (codes->name) {
++        if ((unsigned long)codes->name_len == response_len &&
++            strncmp(codes->name, (char *) data, response_len) == 0) {
++            *pdata = data + response_len;
++            return codes->code;
++        }
++        codes++;
++    }
++
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_publickey_response_success
++ * Generic helper routine to wait for success response and nothing else
++ */
++static int
++libssh2_publickey_response_success(LIBSSH2_PUBLICKEY * pkey)
++{
++    LIBSSH2_SESSION *session = pkey->channel->session;
++    unsigned char *data, *s;
++    unsigned long data_len;
++    int response;
++    int rc;
++
++    while (1) {
++        rc = libssh2_publickey_packet_receive(pkey, &data, &data_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                          "Timeout waiting for response from publickey subsystem",
++                          0);
++            return -1;
++        }
++
++        s = data;
++        if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
++            libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
++                          "Invalid publickey subsystem response code", 0);
++            LIBSSH2_FREE(session, data);
++            return -1;
++        }
++
++        switch (response) {
++        case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
++            /* Error, or processing complete */
++            {
++                unsigned long status, descr_len, lang_len;
++                unsigned char *descr, *lang;
++
++                status = libssh2_ntohu32(s);
++                s += 4;
++                descr_len = libssh2_ntohu32(s);
++                s += 4;
++                descr = s;
++                s += descr_len;
++                lang_len = libssh2_ntohu32(s);
++                s += 4;
++                lang = s;
++                s += lang_len;
++
++                if (s > data + data_len) {
++                    libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
++                                  "Malformed publickey subsystem packet", 0);
++                    LIBSSH2_FREE(session, data);
++                    return -1;
++                }
++
++                if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
++                    LIBSSH2_FREE(session, data);
++                    return 0;
++                }
++
++                libssh2_publickey_status_error(pkey, session, status, descr,
++                                               descr_len);
++                LIBSSH2_FREE(session, data);
++                return -1;
++            }
++        default:
++            /* Unknown/Unexpected */
++            libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
++                          "Unexpected publickey subsystem response, ignoring",
++                          0);
++            LIBSSH2_FREE(session, data);
++            data = NULL;
++        }
++    }
++    /* never reached, but include `return` to silence compiler warnings */
++    return -1;
++}
++
++/* }}} */
++
++
++/* *****************
++   * Publickey API *
++   ***************** */
++
++/* {{{ libssh2_publickey_init
++ * Startup the publickey subsystem
++ */
++LIBSSH2_API LIBSSH2_PUBLICKEY *
++libssh2_publickey_init(LIBSSH2_SESSION * session)
++{
++    /* 19 = packet_len(4) + version_len(4) + "version"(7) + version_num(4) */
++    unsigned char buffer[19];
++    unsigned char *s;
++    int response;
++    int rc;
++
++    if (session->pkeyInit_state == libssh2_NB_state_idle) {
++        session->pkeyInit_data = NULL;
++        session->pkeyInit_pkey = NULL;
++        session->pkeyInit_channel = NULL;
++
++        _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
++                       "Initializing publickey subsystem");
++
++        session->pkeyInit_state = libssh2_NB_state_allocated;
++    }
++
++    if (session->pkeyInit_state == libssh2_NB_state_allocated) {
++        do {
++            session->pkeyInit_channel =
++                libssh2_channel_open_ex(session, "session",
++                                        sizeof("session") - 1,
++                                        LIBSSH2_CHANNEL_WINDOW_DEFAULT,
++                                        LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL,
++                                        0);
++            if (!session->pkeyInit_channel
++                && (libssh2_session_last_errno(session) ==
++                    LIBSSH2_ERROR_EAGAIN)) {
++                /* The error state is already set, so leave it */
++                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                              "Would block to startup channel", 0);
++                return NULL;
++            } else if (!session->pkeyInit_channel
++                       && (libssh2_session_last_errno(session) !=
++                           LIBSSH2_ERROR_EAGAIN)) {
++                libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
++                              "Unable to startup channel", 0);
++                goto err_exit;
++            }
++        } while (!session->pkeyInit_channel);
++
++        session->pkeyInit_state = libssh2_NB_state_sent;
++    }
++
++    if (session->pkeyInit_state == libssh2_NB_state_sent) {
++        rc = libssh2_channel_process_startup(session->pkeyInit_channel,
++                                             "subsystem",
++                                             sizeof("subsystem") - 1,
++                                             "publickey", strlen("publickey"));
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block starting publickey subsystem", 0);
++            return NULL;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
++                          "Unable to request publickey subsystem", 0);
++            goto err_exit;
++        }
++
++        session->pkeyInit_state = libssh2_NB_state_sent1;
++    }
++
++    if (session->pkeyInit_state == libssh2_NB_state_sent1) {
++        rc = libssh2_channel_handle_extended_data2(session->pkeyInit_channel,
++                                                   LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block starting publickey subsystem", 0);
++            return NULL;
++        }
++
++        session->pkeyInit_pkey =
++            LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PUBLICKEY));
++        if (!session->pkeyInit_pkey) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate a new publickey structure", 0);
++            goto err_exit;
++        }
++        memset(session->pkeyInit_pkey, 0, sizeof(LIBSSH2_PUBLICKEY));
++        session->pkeyInit_pkey->channel = session->pkeyInit_channel;
++        session->pkeyInit_pkey->version = 0;
++
++        s = buffer;
++        libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4);
++        s += 4;
++        libssh2_htonu32(s, sizeof("version") - 1);
++        s += 4;
++        memcpy(s, "version", sizeof("version") - 1);
++        s += sizeof("version") - 1;
++        libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION);
++        s += 4;
++
++        _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
++                       "Sending publickey version packet advertising version %d support",
++                       (int) LIBSSH2_PUBLICKEY_VERSION);
++
++        session->pkeyInit_state = libssh2_NB_state_sent2;
++    }
++
++    if (session->pkeyInit_state == libssh2_NB_state_sent2) {
++        rc = libssh2_channel_write_ex(session->pkeyInit_channel, 0,
++                                      (char *) buffer, (s - buffer));
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block sending publickey version packet", 0);
++            return NULL;
++        } else if ((s - buffer) != rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send publickey version packet", 0);
++            goto err_exit;
++        }
++
++        session->pkeyInit_state = libssh2_NB_state_sent3;
++    }
++
++    if (session->pkeyInit_state == libssh2_NB_state_sent3) {
++        while (1) {
++            rc = libssh2_publickey_packet_receive(session->pkeyInit_pkey,
++                                                  &session->pkeyInit_data,
++                                                  &session->pkeyInit_data_len);
++            if (rc == PACKET_EAGAIN) {
++                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                              "Would block waiting for response from publickey subsystem",
++                              0);
++                return NULL;
++            } else if (rc) {
++                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                              "Timeout waiting for response from publickey subsystem",
++                              0);
++                goto err_exit;
++            }
++
++            s = session->pkeyInit_data;
++            if ((response =
++                 libssh2_publickey_response_id(&s,
++                                               session->pkeyInit_data_len)) <
++                0) {
++                libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
++                              "Invalid publickey subsystem response code", 0);
++                goto err_exit;
++            }
++
++            switch (response) {
++            case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
++                /* Error */
++                {
++                    unsigned long status, descr_len, lang_len;
++                    unsigned char *descr, *lang;
++
++                    status = libssh2_ntohu32(s);
++                    s += 4;
++                    descr_len = libssh2_ntohu32(s);
++                    s += 4;
++                    descr = s;
++                    s += descr_len;
++                    lang_len = libssh2_ntohu32(s);
++                    s += 4;
++                    lang = s;
++                    s += lang_len;
++
++                    if (s >
++                        session->pkeyInit_data + session->pkeyInit_data_len) {
++                        libssh2_error(session,
++                                      LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
++                                      "Malformed publickey subsystem packet",
++                                      0);
++                        goto err_exit;
++                    }
++
++                    libssh2_publickey_status_error(NULL, session, status,
++                                                   descr, descr_len);
++                    goto err_exit;
++                }
++
++            case LIBSSH2_PUBLICKEY_RESPONSE_VERSION:
++                /* What we want */
++                session->pkeyInit_pkey->version = libssh2_ntohu32(s);
++                if (session->pkeyInit_pkey->version >
++                    LIBSSH2_PUBLICKEY_VERSION) {
++                    _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
++                                   "Truncating remote publickey version from %lu",
++                                   session->pkeyInit_pkey->version);
++                    session->pkeyInit_pkey->version =
++                        LIBSSH2_PUBLICKEY_VERSION;
++                }
++                _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
++                               "Enabling publickey subsystem version %lu",
++                               session->pkeyInit_pkey->version);
++                LIBSSH2_FREE(session, session->pkeyInit_data);
++                session->pkeyInit_data = NULL;
++                session->pkeyInit_state = libssh2_NB_state_idle;
++                return session->pkeyInit_pkey;
++
++            default:
++                /* Unknown/Unexpected */
++                libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
++                              "Unexpected publickey subsystem response, ignoring",
++                              0);
++                LIBSSH2_FREE(session, session->pkeyInit_data);
++                session->pkeyInit_data = NULL;
++            }
++        }
++    }
++
++    /* Never reached except by direct goto */
++  err_exit:
++    session->pkeyInit_state = libssh2_NB_state_sent4;
++    if (session->pkeyInit_channel) {
++        rc = libssh2_channel_close(session->pkeyInit_channel);
++        if (rc == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                          "Would block closing channel", 0);
++            return NULL;
++        }
++    }
++    if (session->pkeyInit_pkey) {
++        LIBSSH2_FREE(session, session->pkeyInit_pkey);
++        session->pkeyInit_pkey = NULL;
++    }
++    if (session->pkeyInit_data) {
++        LIBSSH2_FREE(session, session->pkeyInit_data);
++        session->pkeyInit_data = NULL;
++    }
++    session->pkeyInit_state = libssh2_NB_state_idle;
++    return NULL;
++}
++
++/* }}} */
++
++/* {{{ libssh2_publickey_add_ex
++ * Add a new public key entry
++ */
++LIBSSH2_API int
++libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY * pkey, const unsigned char *name,
++                         unsigned long name_len, const unsigned char *blob,
++                         unsigned long blob_len, char overwrite,
++                         unsigned long num_attrs,
++                         const libssh2_publickey_attribute attrs[])
++{
++    LIBSSH2_CHANNEL *channel = pkey->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    /*  19 = packet_len(4) + add_len(4) + "add"(3) + name_len(4) + {name} blob_len(4) + {blob} */
++    unsigned long i, packet_len = 19 + name_len + blob_len;
++    unsigned char *comment = NULL;
++    unsigned long comment_len = 0;
++    int rc;
++
++    if (pkey->add_state == libssh2_NB_state_idle) {
++        pkey->add_packet = NULL;
++
++        _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Adding %s publickey",
++                       name);
++
++        if (pkey->version == 1) {
++            for(i = 0; i < num_attrs; i++) {
++                /* Search for a comment attribute */
++                if (attrs[i].name_len == (sizeof("comment") - 1) &&
++                    strncmp(attrs[i].name, "comment",
++                            sizeof("comment") - 1) == 0) {
++                    comment = (unsigned char *) attrs[i].value;
++                    comment_len = attrs[i].value_len;
++                    break;
++                }
++            }
++            packet_len += 4 + comment_len;
++        } else {
++            packet_len += 5;    /* overwrite(1) + attribute_count(4) */
++            for(i = 0; i < num_attrs; i++) {
++                packet_len += 9 + attrs[i].name_len + attrs[i].value_len;
++                /* name_len(4) + value_len(4) + mandatory(1) */
++            }
++        }
++
++        pkey->add_packet = LIBSSH2_ALLOC(session, packet_len);
++        if (!pkey->add_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for publickey \"add\" packet",
++                          0);
++            return -1;
++        }
++
++        pkey->add_s = pkey->add_packet;
++        libssh2_htonu32(pkey->add_s, packet_len - 4);
++        pkey->add_s += 4;
++        libssh2_htonu32(pkey->add_s, sizeof("add") - 1);
++        pkey->add_s += 4;
++        memcpy(pkey->add_s, "add", sizeof("add") - 1);
++        pkey->add_s += sizeof("add") - 1;
++        if (pkey->version == 1) {
++            libssh2_htonu32(pkey->add_s, comment_len);
++            pkey->add_s += 4;
++            if (comment) {
++                memcpy(pkey->add_s, comment, comment_len);
++                pkey->add_s += comment_len;
++            }
++
++            libssh2_htonu32(pkey->add_s, name_len);
++            pkey->add_s += 4;
++            memcpy(pkey->add_s, name, name_len);
++            pkey->add_s += name_len;
++            libssh2_htonu32(pkey->add_s, blob_len);
++            pkey->add_s += 4;
++            memcpy(pkey->add_s, blob, blob_len);
++            pkey->add_s += blob_len;
++        } else {
++            /* Version == 2 */
++
++            libssh2_htonu32(pkey->add_s, name_len);
++            pkey->add_s += 4;
++            memcpy(pkey->add_s, name, name_len);
++            pkey->add_s += name_len;
++            libssh2_htonu32(pkey->add_s, blob_len);
++            pkey->add_s += 4;
++            memcpy(pkey->add_s, blob, blob_len);
++            pkey->add_s += blob_len;
++            *(pkey->add_s++) = overwrite ? 0x01 : 0;
++            libssh2_htonu32(pkey->add_s, num_attrs);
++            pkey->add_s += 4;
++            for(i = 0; i < num_attrs; i++) {
++                libssh2_htonu32(pkey->add_s, attrs[i].name_len);
++                pkey->add_s += 4;
++                memcpy(pkey->add_s, attrs[i].name, attrs[i].name_len);
++                pkey->add_s += attrs[i].name_len;
++                libssh2_htonu32(pkey->add_s, attrs[i].value_len);
++                pkey->add_s += 4;
++                memcpy(pkey->add_s, attrs[i].value, attrs[i].value_len);
++                pkey->add_s += attrs[i].value_len;
++                *(pkey->add_s++) = attrs[i].mandatory ? 0x01 : 0;
++            }
++        }
++
++        _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
++                       "Sending publickey \"add\" packet: type=%s blob_len=%ld num_attrs=%ld",
++                       name, blob_len, num_attrs);
++
++        pkey->add_state = libssh2_NB_state_created;
++    }
++
++    if (pkey->add_state == libssh2_NB_state_created) {
++        rc = libssh2_channel_write_ex(channel, 0, (char *) pkey->add_packet,
++                                      (pkey->add_s - pkey->add_packet));
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if ((pkey->add_s - pkey->add_packet) != rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send publickey add packet", 0);
++            LIBSSH2_FREE(session, pkey->add_packet);
++            pkey->add_packet = NULL;
++            return -1;
++        }
++        LIBSSH2_FREE(session, pkey->add_packet);
++        pkey->add_packet = NULL;
++
++        pkey->add_state = libssh2_NB_state_sent;
++    }
++
++    rc = libssh2_publickey_response_success(pkey);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    }
++
++    pkey->add_state = libssh2_NB_state_idle;
++
++    return rc;
++}
++
++/* }}} */
++
++/* {{{ libssh2_publickey_remove_ex
++ * Remove an existing publickey so that authentication can no longer be performed using it
++ */
++LIBSSH2_API int
++libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY * pkey,
++                            const unsigned char *name, unsigned long name_len,
++                            const unsigned char *blob, unsigned long blob_len)
++{
++    LIBSSH2_CHANNEL *channel = pkey->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    /* 22 = packet_len(4) + remove_len(4) + "remove"(6) + name_len(4) + {name} + blob_len(4) + {blob} */
++    unsigned long packet_len = 22 + name_len + blob_len;
++    int rc;
++
++    if (pkey->remove_state == libssh2_NB_state_idle) {
++        pkey->remove_packet = NULL;
++
++        pkey->remove_packet = LIBSSH2_ALLOC(session, packet_len);
++        if (!pkey->remove_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for publickey \"remove\" packet",
++                          0);
++            return -1;
++        }
++
++        pkey->remove_s = pkey->remove_packet;
++        libssh2_htonu32(pkey->remove_s, packet_len - 4);
++        pkey->remove_s += 4;
++        libssh2_htonu32(pkey->remove_s, sizeof("remove") - 1);
++        pkey->remove_s += 4;
++        memcpy(pkey->remove_s, "remove", sizeof("remove") - 1);
++        pkey->remove_s += sizeof("remove") - 1;
++        libssh2_htonu32(pkey->remove_s, name_len);
++        pkey->remove_s += 4;
++        memcpy(pkey->remove_s, name, name_len);
++        pkey->remove_s += name_len;
++        libssh2_htonu32(pkey->remove_s, blob_len);
++        pkey->remove_s += 4;
++        memcpy(pkey->remove_s, blob, blob_len);
++        pkey->remove_s += blob_len;
++
++        _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
++                       "Sending publickey \"remove\" packet: type=%s blob_len=%ld",
++                       name, blob_len);
++
++        pkey->remove_state = libssh2_NB_state_created;
++    }
++
++    if (pkey->remove_state == libssh2_NB_state_created) {
++        rc = libssh2_channel_write_ex(channel, 0, (char *) pkey->remove_packet,
++                                      (pkey->remove_s - pkey->remove_packet));
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if ((pkey->remove_s - pkey->remove_packet) != rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send publickey remove packet", 0);
++            LIBSSH2_FREE(session, pkey->remove_packet);
++            pkey->remove_packet = NULL;
++            pkey->remove_state = libssh2_NB_state_idle;
++            return -1;
++        }
++        LIBSSH2_FREE(session, pkey->remove_packet);
++        pkey->remove_packet = NULL;
++
++        pkey->remove_state = libssh2_NB_state_sent;
++    }
++
++    rc = libssh2_publickey_response_success(pkey);
++    if (rc == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    }
++
++    pkey->remove_state = libssh2_NB_state_idle;
++
++    return rc;
++}
++
++/* }}} */
++
++/* {{{ libssh2_publickey_list_fetch
++ * Fetch a list of supported public key from a server
++ */
++LIBSSH2_API int
++libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys,
++                             libssh2_publickey_list ** pkey_list)
++{
++    LIBSSH2_CHANNEL *channel = pkey->channel;
++    LIBSSH2_SESSION *session = channel->session;
++    libssh2_publickey_list *list = NULL;
++    unsigned long buffer_len = 12, keys = 0, max_keys = 0, i;
++    /* 12 = packet_len(4) + list_len(4) + "list"(4) */
++    int response;
++    int rc;
++
++    if (pkey->listFetch_state == libssh2_NB_state_idle) {
++        pkey->listFetch_data = NULL;
++
++        pkey->listFetch_s = pkey->listFetch_buffer;
++        libssh2_htonu32(pkey->listFetch_s, buffer_len - 4);
++        pkey->listFetch_s += 4;
++        libssh2_htonu32(pkey->listFetch_s, sizeof("list") - 1);
++        pkey->listFetch_s += 4;
++        memcpy(pkey->listFetch_s, "list", sizeof("list") - 1);
++        pkey->listFetch_s += sizeof("list") - 1;
++
++        _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
++                       "Sending publickey \"list\" packet");
++
++        pkey->listFetch_state = libssh2_NB_state_created;
++    }
++
++    if (pkey->listFetch_state == libssh2_NB_state_created) {
++        rc = libssh2_channel_write_ex(channel, 0,
++                                      (char *) pkey->listFetch_buffer,
++                                      (pkey->listFetch_s -
++                                       pkey->listFetch_buffer));
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if ((pkey->listFetch_s - pkey->listFetch_buffer) != rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send publickey list packet", 0);
++            pkey->listFetch_state = libssh2_NB_state_idle;
++            return -1;
++        }
++
++        pkey->listFetch_state = libssh2_NB_state_sent;
++    }
++
++    while (1) {
++        rc = libssh2_publickey_packet_receive(pkey, &pkey->listFetch_data,
++                                              &pkey->listFetch_data_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
++                          "Timeout waiting for response from publickey subsystem",
++                          0);
++            goto err_exit;
++        }
++
++        pkey->listFetch_s = pkey->listFetch_data;
++        if ((response =
++             libssh2_publickey_response_id(&pkey->listFetch_s,
++                                           pkey->listFetch_data_len)) < 0) {
++            libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
++                          "Invalid publickey subsystem response code", 0);
++            goto err_exit;
++        }
++
++        switch (response) {
++        case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
++            /* Error, or processing complete */
++            {
++                unsigned long status, descr_len, lang_len;
++                unsigned char *descr, *lang;
++
++                status = libssh2_ntohu32(pkey->listFetch_s);
++                pkey->listFetch_s += 4;
++                descr_len = libssh2_ntohu32(pkey->listFetch_s);
++                pkey->listFetch_s += 4;
++                descr = pkey->listFetch_s;
++                pkey->listFetch_s += descr_len;
++                lang_len = libssh2_ntohu32(pkey->listFetch_s);
++                pkey->listFetch_s += 4;
++                lang = pkey->listFetch_s;
++                pkey->listFetch_s += lang_len;
++
++                if (pkey->listFetch_s >
++                    pkey->listFetch_data + pkey->listFetch_data_len) {
++                    libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
++                                  "Malformed publickey subsystem packet", 0);
++                    goto err_exit;
++                }
++
++                if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
++                    LIBSSH2_FREE(session, pkey->listFetch_data);
++                    pkey->listFetch_data = NULL;
++                    *pkey_list = list;
++                    *num_keys = keys;
++                    pkey->listFetch_state = libssh2_NB_state_idle;
++                    return 0;
++                }
++
++                libssh2_publickey_status_error(pkey, session, status, descr,
++                                               descr_len);
++                goto err_exit;
++            }
++        case LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY:
++            /* What we want */
++            if (keys >= max_keys) {
++                libssh2_publickey_list *newlist;
++                /* Grow the key list if necessary */
++                max_keys += 8;
++                newlist =
++                    LIBSSH2_REALLOC(session, list,
++                                    (max_keys +
++                                     1) * sizeof(libssh2_publickey_list));
++                if (!newlist) {
++                    libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                                  "Unable to allocate memory for publickey list",
++                                  0);
++                    goto err_exit;
++                }
++                list = newlist;
++            }
++            if (pkey->version == 1) {
++                unsigned long comment_len;
++
++                comment_len = libssh2_ntohu32(pkey->listFetch_s);
++                pkey->listFetch_s += 4;
++                if (comment_len) {
++                    list[keys].num_attrs = 1;
++                    list[keys].attrs =
++                        LIBSSH2_ALLOC(session,
++                                      sizeof(libssh2_publickey_attribute));
++                    if (!list[keys].attrs) {
++                        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                                      "Unable to allocate memory for publickey attributes",
++                                      0);
++                        goto err_exit;
++                    }
++                    list[keys].attrs[0].name = "comment";
++                    list[keys].attrs[0].name_len = sizeof("comment") - 1;
++                    list[keys].attrs[0].value = (char *) pkey->listFetch_s;
++                    list[keys].attrs[0].value_len = comment_len;
++                    list[keys].attrs[0].mandatory = 0;
++
++                    pkey->listFetch_s += comment_len;
++                } else {
++                    list[keys].num_attrs = 0;
++                    list[keys].attrs = NULL;
++                }
++                list[keys].name_len = libssh2_ntohu32(pkey->listFetch_s);
++                pkey->listFetch_s += 4;
++                list[keys].name = pkey->listFetch_s;
++                pkey->listFetch_s += list[keys].name_len;
++                list[keys].blob_len = libssh2_ntohu32(pkey->listFetch_s);
++                pkey->listFetch_s += 4;
++                list[keys].blob = pkey->listFetch_s;
++                pkey->listFetch_s += list[keys].blob_len;
++            } else {
++                /* Version == 2 */
++                list[keys].name_len = libssh2_ntohu32(pkey->listFetch_s);
++                pkey->listFetch_s += 4;
++                list[keys].name = pkey->listFetch_s;
++                pkey->listFetch_s += list[keys].name_len;
++                list[keys].blob_len = libssh2_ntohu32(pkey->listFetch_s);
++                pkey->listFetch_s += 4;
++                list[keys].blob = pkey->listFetch_s;
++                pkey->listFetch_s += list[keys].blob_len;
++                list[keys].num_attrs = libssh2_ntohu32(pkey->listFetch_s);
++                pkey->listFetch_s += 4;
++                if (list[keys].num_attrs) {
++                    list[keys].attrs =
++                        LIBSSH2_ALLOC(session,
++                                      list[keys].num_attrs *
++                                      sizeof(libssh2_publickey_attribute));
++                    if (!list[keys].attrs) {
++                        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                                      "Unable to allocate memory for publickey attributes",
++                                      0);
++                        goto err_exit;
++                    }
++                    for(i = 0; i < list[keys].num_attrs; i++) {
++                        list[keys].attrs[i].name_len =
++                            libssh2_ntohu32(pkey->listFetch_s);
++                        pkey->listFetch_s += 4;
++                        list[keys].attrs[i].name = (char *) pkey->listFetch_s;
++                        pkey->listFetch_s += list[keys].attrs[i].name_len;
++                        list[keys].attrs[i].value_len =
++                            libssh2_ntohu32(pkey->listFetch_s);
++                        pkey->listFetch_s += 4;
++                        list[keys].attrs[i].value = (char *) pkey->listFetch_s;
++                        pkey->listFetch_s += list[keys].attrs[i].value_len;
++                        list[keys].attrs[i].mandatory = 0;      /* actually an ignored value */
++                    }
++                } else {
++                    list[keys].attrs = NULL;
++                }
++            }
++            list[keys].packet = pkey->listFetch_data;   /* To be FREEd in libssh2_publickey_list_free() */
++            keys++;
++
++            list[keys].packet = NULL;   /* Terminate the list */
++            pkey->listFetch_data = NULL;
++            break;
++        default:
++            /* Unknown/Unexpected */
++            libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
++                          "Unexpected publickey subsystem response, ignoring",
++                          0);
++            LIBSSH2_FREE(session, pkey->listFetch_data);
++            pkey->listFetch_data = NULL;
++        }
++    }
++
++    /* Only reached via explicit goto */
++  err_exit:
++    if (pkey->listFetch_data) {
++        LIBSSH2_FREE(session, pkey->listFetch_data);
++        pkey->listFetch_data = NULL;
++    }
++    if (list) {
++        libssh2_publickey_list_free(pkey, list);
++    }
++    pkey->listFetch_state = libssh2_NB_state_idle;
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_publickey_list_free
++ * Free a previously fetched list of public keys
++ */
++LIBSSH2_API void
++libssh2_publickey_list_free(LIBSSH2_PUBLICKEY * pkey,
++                            libssh2_publickey_list * pkey_list)
++{
++    LIBSSH2_SESSION *session = pkey->channel->session;
++    libssh2_publickey_list *p = pkey_list;
++
++    while (p->packet) {
++        if (p->attrs) {
++            LIBSSH2_FREE(session, p->attrs);
++        }
++        LIBSSH2_FREE(session, p->packet);
++        p++;
++    }
++
++    LIBSSH2_FREE(session, pkey_list);
++}
++
++/* }}} */
++
++/* {{{ libssh2_publickey_shutdown
++ * Shutdown the publickey subsystem
++ */
++LIBSSH2_API int
++libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY * pkey)
++{
++    LIBSSH2_SESSION *session = pkey->channel->session;
++
++    /*
++     * Make sure all memory used in the state variables are free
++     */
++    if (pkey->receive_packet) {
++        LIBSSH2_FREE(session, pkey->receive_packet);
++        pkey->receive_packet = NULL;
++    }
++    if (pkey->add_packet) {
++        LIBSSH2_FREE(session, pkey->add_packet);
++        pkey->add_packet = NULL;
++    }
++    if (pkey->remove_packet) {
++        LIBSSH2_FREE(session, pkey->remove_packet);
++        pkey->remove_packet = NULL;
++    }
++    if (pkey->listFetch_data) {
++        LIBSSH2_FREE(session, pkey->listFetch_data);
++        pkey->listFetch_data = NULL;
++    }
++
++    if (libssh2_channel_free(pkey->channel) == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    }
++
++    LIBSSH2_FREE(session, pkey);
++    return 0;
++}
++
++/* }}} */
+
+Property changes on: libssh2/src/publickey.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.4
+Added: svn:eol-style
+   + native
+
+Index: libssh2/src/kex.c
+===================================================================
+--- libssh2/src/kex.c  (.../tags/RELEASE_0_11_0)
++++ libssh2/src/kex.c  (.../trunk)
+@@ -0,0 +1,1916 @@
++/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++
++/* TODO: Switch this to an inline and handle alloc() failures */
++/* Helper macro called from libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange */
++#define LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(value, reqlen, version) \
++{                                                                           \
++    libssh2_sha1_ctx hash;                                                  \
++    unsigned long len = 0;                                                  \
++    if (!(value)) {                                                         \
++        value = LIBSSH2_ALLOC(session, reqlen + SHA_DIGEST_LENGTH);         \
++    }                                                                       \
++    if (value)                                                              \
++        while (len < (unsigned long)reqlen) {                               \
++            libssh2_sha1_init(&hash);                                       \
++            libssh2_sha1_update(hash, exchange_state->k_value,              \
++                                exchange_state->k_value_len);               \
++            libssh2_sha1_update(hash, exchange_state->h_sig_comp,           \
++                                SHA_DIGEST_LENGTH);                         \
++            if (len > 0) {                                                  \
++                libssh2_sha1_update(hash, value, len);                      \
++            }    else {                                                     \
++                libssh2_sha1_update(hash, (version), 1);                    \
++                libssh2_sha1_update(hash, session->session_id,              \
++                                    session->session_id_len);               \
++            }                                                               \
++            libssh2_sha1_final(hash, (value) + len);                        \
++            len += SHA_DIGEST_LENGTH;                                       \
++        }                                                                   \
++}
++
++/* {{{ libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange
++ * Diffie Hellman Key Exchange, Group Agnostic
++ */
++static int
++libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *
++                                                            session,
++                                                            _libssh2_bn * g,
++                                                            _libssh2_bn * p,
++                                                            int group_order,
++                                                            unsigned char
++                                                            packet_type_init,
++                                                            unsigned char
++                                                            packet_type_reply,
++                                                            unsigned char
++                                                            *midhash,
++                                                            unsigned long
++                                                            midhash_len,
++                                                            kmdhgGPsha1kex_state_t
++                                                            * exchange_state)
++{
++    int ret = 0;
++    int rc;
++
++    if (exchange_state->state == libssh2_NB_state_idle) {
++        /* Setup initial values */
++        exchange_state->e_packet = NULL;
++        exchange_state->s_packet = NULL;
++        exchange_state->k_value = NULL;
++        exchange_state->ctx = _libssh2_bn_ctx_new();
++        exchange_state->x = _libssh2_bn_init(); /* Random from client */
++        exchange_state->e = _libssh2_bn_init(); /* g^x mod p */
++        exchange_state->f = _libssh2_bn_init(); /* g^(Random from server) mod p */
++        exchange_state->k = _libssh2_bn_init(); /* The shared secret: f^x mod p */
++
++        /* Zero the whole thing out */
++        memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t));
++
++        /* Generate x and e */
++        _libssh2_bn_rand(exchange_state->x, group_order, 0, -1);
++        _libssh2_bn_mod_exp(exchange_state->e, g, exchange_state->x, p,
++                            exchange_state->ctx);
++
++        /* Send KEX init */
++        /* packet_type(1) + String Length(4) + leading 0(1) */
++        exchange_state->e_packet_len =
++            _libssh2_bn_bytes(exchange_state->e) + 6;
++        if (_libssh2_bn_bits(exchange_state->e) % 8) {
++            /* Leading 00 not needed */
++            exchange_state->e_packet_len--;
++        }
++
++        exchange_state->e_packet =
++            LIBSSH2_ALLOC(session, exchange_state->e_packet_len);
++        if (!exchange_state->e_packet) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Out of memory error",
++                          0);
++            ret = -1;
++            goto clean_exit;
++        }
++        exchange_state->e_packet[0] = packet_type_init;
++        libssh2_htonu32(exchange_state->e_packet + 1,
++                        exchange_state->e_packet_len - 5);
++        if (_libssh2_bn_bits(exchange_state->e) % 8) {
++            _libssh2_bn_to_bin(exchange_state->e,
++                               exchange_state->e_packet + 5);
++        } else {
++            exchange_state->e_packet[5] = 0;
++            _libssh2_bn_to_bin(exchange_state->e,
++                               exchange_state->e_packet + 6);
++        }
++
++        _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending KEX packet %d",
++                       (int) packet_type_init);
++        exchange_state->state = libssh2_NB_state_created;
++    }
++
++    if (exchange_state->state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, exchange_state->e_packet,
++                                  exchange_state->e_packet_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send KEX init message", 0);
++            ret = -1;
++            goto clean_exit;
++        }
++        exchange_state->state = libssh2_NB_state_sent;
++    }
++
++    if (exchange_state->state == libssh2_NB_state_sent) {
++        if (session->burn_optimistic_kexinit) {
++            /* The first KEX packet to come along will be the guess initially 
++             * sent by the server.  That guess turned out to be wrong so we
++             * need to silently ignore it */
++            int burn_type;
++
++            _libssh2_debug(session, LIBSSH2_DBG_KEX,
++                           "Waiting for badly guessed KEX packet (to be ignored)");
++            burn_type =
++                libssh2_packet_burn(session, &exchange_state->burn_state);
++            if (burn_type == PACKET_EAGAIN) {
++                return PACKET_EAGAIN;
++            } else if (burn_type <= 0) {
++                /* Failed to receive a packet */
++                ret = -1;
++                goto clean_exit;
++            }
++            session->burn_optimistic_kexinit = 0;
++
++            _libssh2_debug(session, LIBSSH2_DBG_KEX,
++                           "Burnt packet of type: %02x",
++                           (unsigned int) burn_type);
++        }
++
++        exchange_state->state = libssh2_NB_state_sent1;
++    }
++
++    if (exchange_state->state == libssh2_NB_state_sent1) {
++        /* Wait for KEX reply */
++        rc = libssh2_packet_require_ex(session, packet_type_reply,
++                                       &exchange_state->s_packet,
++                                       &exchange_state->s_packet_len, 0, NULL,
++                                       0, &exchange_state->req_state);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        }
++        if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
++                          "Timed out waiting for KEX reply", 0);
++            ret = -1;
++            goto clean_exit;
++        }
++
++        /* Parse KEXDH_REPLY */
++        exchange_state->s = exchange_state->s_packet + 1;
++
++        session->server_hostkey_len = libssh2_ntohu32(exchange_state->s);
++        exchange_state->s += 4;
++        session->server_hostkey =
++            LIBSSH2_ALLOC(session, session->server_hostkey_len);
++        if (!session->server_hostkey) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory for a copy of the host key",
++                          0);
++            ret = -1;
++            goto clean_exit;
++        }
++        memcpy(session->server_hostkey, exchange_state->s,
++               session->server_hostkey_len);
++        exchange_state->s += session->server_hostkey_len;
++
++#if LIBSSH2_MD5
++        {
++            libssh2_md5_ctx fingerprint_ctx;
++
++            libssh2_md5_init(&fingerprint_ctx);
++            libssh2_md5_update(fingerprint_ctx, session->server_hostkey,
++                               session->server_hostkey_len);
++            libssh2_md5_final(fingerprint_ctx, session->server_hostkey_md5);
++        }
++#ifdef LIBSSH2DEBUG
++        {
++            char fingerprint[50], *fprint = fingerprint;
++            int i;
++            for(i = 0; i < 16; i++, fprint += 3) {
++                snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]);
++            }
++            *(--fprint) = '\0';
++            _libssh2_debug(session, LIBSSH2_DBG_KEX,
++                           "Server's MD5 Fingerprint: %s", fingerprint);
++        }
++#endif /* LIBSSH2DEBUG */
++#endif /* ! LIBSSH2_MD5 */
++
++        {
++            libssh2_sha1_ctx fingerprint_ctx;
++
++            libssh2_sha1_init(&fingerprint_ctx);
++            libssh2_sha1_update(fingerprint_ctx, session->server_hostkey,
++                                session->server_hostkey_len);
++            libssh2_sha1_final(fingerprint_ctx, session->server_hostkey_sha1);
++        }
++#ifdef LIBSSH2DEBUG
++        {
++            char fingerprint[64], *fprint = fingerprint;
++            int i;
++
++            for(i = 0; i < 20; i++, fprint += 3) {
++                snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]);
++            }
++            *(--fprint) = '\0';
++            _libssh2_debug(session, LIBSSH2_DBG_KEX,
++                           "Server's SHA1 Fingerprint: %s", fingerprint);
++        }
++#endif /* LIBSSH2DEBUG */
++
++        if (session->hostkey->
++            init(session, session->server_hostkey, session->server_hostkey_len,
++                 &session->server_hostkey_abstract)) {
++            libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT,
++                          "Unable to initialize hostkey importer", 0);
++            ret = -1;
++            goto clean_exit;
++        }
++
++        exchange_state->f_value_len = libssh2_ntohu32(exchange_state->s);
++        exchange_state->s += 4;
++        exchange_state->f_value = exchange_state->s;
++        exchange_state->s += exchange_state->f_value_len;
++        _libssh2_bn_from_bin(exchange_state->f, exchange_state->f_value_len,
++                             exchange_state->f_value);
++
++        exchange_state->h_sig_len = libssh2_ntohu32(exchange_state->s);
++        exchange_state->s += 4;
++        exchange_state->h_sig = exchange_state->s;
++
++        /* Compute the shared secret */
++        _libssh2_bn_mod_exp(exchange_state->k, exchange_state->f,
++                            exchange_state->x, p, exchange_state->ctx);
++        exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5;
++        if (_libssh2_bn_bits(exchange_state->k) % 8) {
++            /* don't need leading 00 */
++            exchange_state->k_value_len--;
++        }
++        exchange_state->k_value =
++            LIBSSH2_ALLOC(session, exchange_state->k_value_len);
++        if (!exchange_state->k_value) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate buffer for K", 0);
++            ret = -1;
++            goto clean_exit;
++        }
++        libssh2_htonu32(exchange_state->k_value,
++                        exchange_state->k_value_len - 4);
++        if (_libssh2_bn_bits(exchange_state->k) % 8) {
++            _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4);
++        } else {
++            exchange_state->k_value[4] = 0;
++            _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5);
++        }
++
++        libssh2_sha1_init(&exchange_state->exchange_hash);
++        if (session->local.banner) {
++            libssh2_htonu32(exchange_state->h_sig_comp,
++                            strlen((char *) session->local.banner) - 2);
++            libssh2_sha1_update(exchange_state->exchange_hash,
++                                exchange_state->h_sig_comp, 4);
++            libssh2_sha1_update(exchange_state->exchange_hash,
++                                (char *) session->local.banner,
++                                strlen((char *) session->local.banner) - 2);
++        } else {
++            libssh2_htonu32(exchange_state->h_sig_comp,
++                            sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
++            libssh2_sha1_update(exchange_state->exchange_hash,
++                                exchange_state->h_sig_comp, 4);
++            libssh2_sha1_update(exchange_state->exchange_hash,
++                                LIBSSH2_SSH_DEFAULT_BANNER,
++                                sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
++        }
++
++        libssh2_htonu32(exchange_state->h_sig_comp,
++                        strlen((char *) session->remote.banner));
++        libssh2_sha1_update(exchange_state->exchange_hash,
++                            exchange_state->h_sig_comp, 4);
++        libssh2_sha1_update(exchange_state->exchange_hash,
++                            session->remote.banner,
++                            strlen((char *) session->remote.banner));
++
++        libssh2_htonu32(exchange_state->h_sig_comp,
++                        session->local.kexinit_len);
++        libssh2_sha1_update(exchange_state->exchange_hash,
++                            exchange_state->h_sig_comp, 4);
++        libssh2_sha1_update(exchange_state->exchange_hash,
++                            session->local.kexinit,
++                            session->local.kexinit_len);
++
++        libssh2_htonu32(exchange_state->h_sig_comp,
++                        session->remote.kexinit_len);
++        libssh2_sha1_update(exchange_state->exchange_hash,
++                            exchange_state->h_sig_comp, 4);
++        libssh2_sha1_update(exchange_state->exchange_hash,
++                            session->remote.kexinit,
++                            session->remote.kexinit_len);
++
++        libssh2_htonu32(exchange_state->h_sig_comp,
++                        session->server_hostkey_len);
++        libssh2_sha1_update(exchange_state->exchange_hash,
++                            exchange_state->h_sig_comp, 4);
++        libssh2_sha1_update(exchange_state->exchange_hash,
++                            session->server_hostkey,
++                            session->server_hostkey_len);
++
++        if (packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) {
++            /* diffie-hellman-group-exchange hashes additional fields */
++#ifdef LIBSSH2_DH_GEX_NEW
++            libssh2_htonu32(exchange_state->h_sig_comp,
++                            LIBSSH2_DH_GEX_MINGROUP);
++            libssh2_htonu32(exchange_state->h_sig_comp + 4,
++                            LIBSSH2_DH_GEX_OPTGROUP);
++            libssh2_htonu32(exchange_state->h_sig_comp + 8,
++                            LIBSSH2_DH_GEX_MAXGROUP);
++            libssh2_sha1_update(exchange_state->exchange_hash,
++                                exchange_state->h_sig_comp, 12);
++#else
++            libssh2_htonu32(exchange_state->h_sig_comp,
++                            LIBSSH2_DH_GEX_OPTGROUP);
++            libssh2_sha1_update(exchange_state->exchange_hash,
++                                exchange_state->h_sig_comp, 4);
++#endif
++        }
++
++        if (midhash) {
++            libssh2_sha1_update(exchange_state->exchange_hash, midhash,
++                                midhash_len);
++        }
++
++        libssh2_sha1_update(exchange_state->exchange_hash,
++                            exchange_state->e_packet + 1,
++                            exchange_state->e_packet_len - 1);
++
++        libssh2_htonu32(exchange_state->h_sig_comp,
++                        exchange_state->f_value_len);
++        libssh2_sha1_update(exchange_state->exchange_hash,
++                            exchange_state->h_sig_comp, 4);
++        libssh2_sha1_update(exchange_state->exchange_hash,
++                            exchange_state->f_value,
++                            exchange_state->f_value_len);
++
++        libssh2_sha1_update(exchange_state->exchange_hash,
++                            exchange_state->k_value,
++                            exchange_state->k_value_len);
++
++        libssh2_sha1_final(exchange_state->exchange_hash,
++                           exchange_state->h_sig_comp);
++
++        if (session->hostkey->
++            sig_verify(session, exchange_state->h_sig,
++                       exchange_state->h_sig_len, exchange_state->h_sig_comp,
++                       20, &session->server_hostkey_abstract)) {
++            libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN,
++                          "Unable to verify hostkey signature", 0);
++            ret = -1;
++            goto clean_exit;
++        }
++
++        _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending NEWKEYS message");
++        exchange_state->c = SSH_MSG_NEWKEYS;
++
++        exchange_state->state = libssh2_NB_state_sent2;
++    }
++
++    if (exchange_state->state == libssh2_NB_state_sent2) {
++        rc = libssh2_packet_write(session, &exchange_state->c, 1);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send NEWKEYS message", 0);
++            ret = -1;
++            goto clean_exit;
++        }
++
++        exchange_state->state = libssh2_NB_state_sent3;
++    }
++
++    if (exchange_state->state == libssh2_NB_state_sent3) {
++        rc = libssh2_packet_require_ex(session, SSH_MSG_NEWKEYS,
++                                       &exchange_state->tmp,
++                                       &exchange_state->tmp_len, 0, NULL, 0,
++                                       &exchange_state->req_state);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
++                          "Timed out waiting for NEWKEYS", 0);
++            ret = -1;
++            goto clean_exit;
++        }
++        /* The first key exchange has been performed, 
++           switch to active crypt/comp/mac mode */
++        session->state |= LIBSSH2_STATE_NEWKEYS;
++        _libssh2_debug(session, LIBSSH2_DBG_KEX, "Received NEWKEYS message");
++
++        /* This will actually end up being just packet_type(1) 
++           for this packet type anyway */
++        LIBSSH2_FREE(session, exchange_state->tmp);
++
++        if (!session->session_id) {
++            session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH);
++            if (!session->session_id) {
++                ret = -1;
++                goto clean_exit;
++            }
++            memcpy(session->session_id, exchange_state->h_sig_comp,
++                   SHA_DIGEST_LENGTH);
++            session->session_id_len = SHA_DIGEST_LENGTH;
++            _libssh2_debug(session, LIBSSH2_DBG_KEX, "session_id calculated");
++        }
++
++        /* Cleanup any existing cipher */
++        if (session->local.crypt->dtor) {
++            session->local.crypt->dtor(session,
++                                       &session->local.crypt_abstract);
++        }
++
++        /* Calculate IV/Secret/Key for each direction */
++        if (session->local.crypt->init) {
++            unsigned char *iv = NULL, *secret = NULL;
++            int free_iv = 0, free_secret = 0;
++
++            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv,
++                                                        session->local.crypt->
++                                                        iv_len, "A");
++            if (!iv) {
++                ret = -1;
++                goto clean_exit;
++            }
++            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret,
++                                                        session->local.crypt->
++                                                        secret_len, "C");
++            if (!secret) {
++                LIBSSH2_FREE(session, iv);
++                ret = -1;
++                goto clean_exit;
++            }
++            if (session->local.crypt->
++                init(session, session->local.crypt, iv, &free_iv, secret,
++                     &free_secret, 1, &session->local.crypt_abstract)) {
++                LIBSSH2_FREE(session, iv);
++                LIBSSH2_FREE(session, secret);
++                ret = -1;
++                goto clean_exit;
++            }
++
++            if (free_iv) {
++                memset(iv, 0, session->local.crypt->iv_len);
++                LIBSSH2_FREE(session, iv);
++            }
++
++            if (free_secret) {
++                memset(secret, 0, session->local.crypt->secret_len);
++                LIBSSH2_FREE(session, secret);
++            }
++        }
++        _libssh2_debug(session, LIBSSH2_DBG_KEX,
++                       "Client to Server IV and Key calculated");
++
++        if (session->remote.crypt->dtor) {
++            /* Cleanup any existing cipher */
++            session->remote.crypt->dtor(session,
++                                        &session->remote.crypt_abstract);
++        }
++
++        if (session->remote.crypt->init) {
++            unsigned char *iv = NULL, *secret = NULL;
++            int free_iv = 0, free_secret = 0;
++
++            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv,
++                                                        session->remote.crypt->
++                                                        iv_len, "B");
++            if (!iv) {
++                ret = -1;
++                goto clean_exit;
++            }
++            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret,
++                                                        session->remote.crypt->
++                                                        secret_len, "D");
++            if (!secret) {
++                LIBSSH2_FREE(session, iv);
++                ret = -1;
++                goto clean_exit;
++            }
++            if (session->remote.crypt->
++                init(session, session->remote.crypt, iv, &free_iv, secret,
++                     &free_secret, 0, &session->remote.crypt_abstract)) {
++                LIBSSH2_FREE(session, iv);
++                LIBSSH2_FREE(session, secret);
++                ret = -1;
++                goto clean_exit;
++            }
++
++            if (free_iv) {
++                memset(iv, 0, session->remote.crypt->iv_len);
++                LIBSSH2_FREE(session, iv);
++            }
++
++            if (free_secret) {
++                memset(secret, 0, session->remote.crypt->secret_len);
++                LIBSSH2_FREE(session, secret);
++            }
++        }
++        _libssh2_debug(session, LIBSSH2_DBG_KEX,
++                       "Server to Client IV and Key calculated");
++
++        if (session->local.mac->dtor) {
++            session->local.mac->dtor(session, &session->local.mac_abstract);
++        }
++
++        if (session->local.mac->init) {
++            unsigned char *key = NULL;
++            int free_key = 0;
++
++            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key,
++                                                        session->local.mac->
++                                                        key_len, "E");
++            if (!key) {
++                ret = -1;
++                goto clean_exit;
++            }
++            session->local.mac->init(session, key, &free_key,
++                                     &session->local.mac_abstract);
++
++            if (free_key) {
++                memset(key, 0, session->local.mac->key_len);
++                LIBSSH2_FREE(session, key);
++            }
++        }
++        _libssh2_debug(session, LIBSSH2_DBG_KEX,
++                       "Client to Server HMAC Key calculated");
++
++        if (session->remote.mac->dtor) {
++            session->remote.mac->dtor(session, &session->remote.mac_abstract);
++        }
++
++        if (session->remote.mac->init) {
++            unsigned char *key = NULL;
++            int free_key = 0;
++
++            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key,
++                                                        session->remote.mac->
++                                                        key_len, "F");
++            if (!key) {
++                ret = -1;
++                goto clean_exit;
++            }
++            session->remote.mac->init(session, key, &free_key,
++                                      &session->remote.mac_abstract);
++
++            if (free_key) {
++                memset(key, 0, session->remote.mac->key_len);
++                LIBSSH2_FREE(session, key);
++            }
++        }
++        _libssh2_debug(session, LIBSSH2_DBG_KEX,
++                       "Server to Client HMAC Key calculated");
++    }
++
++  clean_exit:
++    _libssh2_bn_free(exchange_state->x);
++    exchange_state->x = NULL;
++    _libssh2_bn_free(exchange_state->e);
++    exchange_state->e = NULL;
++    _libssh2_bn_free(exchange_state->f);
++    exchange_state->f = NULL;
++    _libssh2_bn_free(exchange_state->k);
++    exchange_state->k = NULL;
++    _libssh2_bn_ctx_free(exchange_state->ctx);
++    exchange_state->ctx = NULL;
++
++    if (exchange_state->e_packet) {
++        LIBSSH2_FREE(session, exchange_state->e_packet);
++        exchange_state->e_packet = NULL;
++    }
++
++    if (exchange_state->s_packet) {
++        LIBSSH2_FREE(session, exchange_state->s_packet);
++        exchange_state->s_packet = NULL;
++    }
++
++    if (exchange_state->k_value) {
++        LIBSSH2_FREE(session, exchange_state->k_value);
++        exchange_state->k_value = NULL;
++    }
++
++    if (session->server_hostkey) {
++        LIBSSH2_FREE(session, session->server_hostkey);
++        session->server_hostkey = NULL;
++    }
++
++    exchange_state->state = libssh2_NB_state_idle;
++
++    return ret;
++}
++
++/* }}} */
++
++/* {{{ libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange
++ * Diffie-Hellman Group1 (Actually Group2) Key Exchange using SHA1
++ */
++static int
++libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *
++                                                           session,
++                                                           key_exchange_state_low_t
++                                                           * key_state)
++{
++    static const unsigned char p_value[128] = {
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
++        0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
++        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
++        0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
++        0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
++        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++        0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
++        0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
++        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
++        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
++        0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
++        0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
++        0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
++        0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
++    };
++
++    int ret;
++
++    if (key_state->state == libssh2_NB_state_idle) {
++        /* g == 2 */
++        key_state->p = _libssh2_bn_init();      /* SSH2 defined value (p_value) */
++        key_state->g = _libssh2_bn_init();      /* SSH2 defined value (2) */
++
++        /* Initialize P and G */
++        _libssh2_bn_set_word(key_state->g, 2);
++        _libssh2_bn_from_bin(key_state->p, 128, p_value);
++
++        _libssh2_debug(session, LIBSSH2_DBG_KEX,
++                       "Initiating Diffie-Hellman Group1 Key Exchange");
++
++        key_state->state = libssh2_NB_state_created;
++    }
++
++    ret =
++        libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session,
++                                                                    key_state->
++                                                                    g,
++                                                                    key_state->
++                                                                    p, 128,
++                                                                    SSH_MSG_KEXDH_INIT,
++                                                                    SSH_MSG_KEXDH_REPLY,
++                                                                    NULL, 0,
++                                                                    &key_state->
++                                                                    exchange_state);
++    if (ret == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    }
++
++    _libssh2_bn_free(key_state->p);
++    key_state->p = NULL;
++    _libssh2_bn_free(key_state->g);
++    key_state->g = NULL;
++    key_state->state = libssh2_NB_state_idle;
++
++    return ret;
++}
++
++/* }}} */
++
++/* {{{ libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange
++ * Diffie-Hellman Group14 Key Exchange using SHA1
++ */
++static int
++libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *
++                                                            session,
++                                                            key_exchange_state_low_t
++                                                            * key_state)
++{
++    static const unsigned char p_value[256] = {
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
++        0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
++        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
++        0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
++        0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
++        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
++        0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
++        0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
++        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
++        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
++        0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
++        0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
++        0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
++        0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
++        0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
++        0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
++        0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
++        0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
++        0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
++        0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
++        0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
++        0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
++        0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
++        0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
++        0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
++        0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
++        0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
++        0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
++        0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
++        0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
++    };
++    int ret;
++
++    if (key_state->state == libssh2_NB_state_idle) {
++        key_state->p = _libssh2_bn_init();      /* SSH2 defined value (p_value) */
++        key_state->g = _libssh2_bn_init();      /* SSH2 defined value (2) */
++
++        /* g == 2 */
++        /* Initialize P and G */
++        _libssh2_bn_set_word(key_state->g, 2);
++        _libssh2_bn_from_bin(key_state->p, 256, p_value);
++
++        _libssh2_debug(session, LIBSSH2_DBG_KEX,
++                       "Initiating Diffie-Hellman Group14 Key Exchange");
++
++        key_state->state = libssh2_NB_state_created;
++    }
++    ret =
++        libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session,
++                                                                    key_state->
++                                                                    g,
++                                                                    key_state->
++                                                                    p, 256,
++                                                                    SSH_MSG_KEXDH_INIT,
++                                                                    SSH_MSG_KEXDH_REPLY,
++                                                                    NULL, 0,
++                                                                    &key_state->
++                                                                    exchange_state);
++    if (ret == PACKET_EAGAIN) {
++        return PACKET_EAGAIN;
++    }
++
++    key_state->state = libssh2_NB_state_idle;
++    _libssh2_bn_free(key_state->p);
++    key_state->p = NULL;
++    _libssh2_bn_free(key_state->g);
++    key_state->g = NULL;
++
++    return ret;
++}
++
++/* }}} */
++
++/* {{{ libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange
++ * Diffie-Hellman Group Exchange Key Exchange using SHA1
++ * Negotiates random(ish) group for secret derivation
++ */
++static int
++    libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange
++    (LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state)
++{
++    unsigned char *s;
++    unsigned long p_len, g_len;
++    int ret = 0;
++    int rc;
++
++    if (key_state->state == libssh2_NB_state_idle) {
++        key_state->p = _libssh2_bn_init();
++        key_state->g = _libssh2_bn_init();
++        /* Ask for a P and G pair */
++#ifdef LIBSSH2_DH_GEX_NEW
++        key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST;
++        libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_MINGROUP);
++        libssh2_htonu32(key_state->request + 5, LIBSSH2_DH_GEX_OPTGROUP);
++        libssh2_htonu32(key_state->request + 9, LIBSSH2_DH_GEX_MAXGROUP);
++        key_state->request_len = 13;
++        _libssh2_debug(session, LIBSSH2_DBG_KEX,
++                       "Initiating Diffie-Hellman Group-Exchange (New Method)");
++#else
++        key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD;
++        libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_OPTGROUP);
++        key_state->request_len = 5;
++        _libssh2_debug(session, LIBSSH2_DBG_KEX,
++                       "Initiating Diffie-Hellman Group-Exchange (Old Method)");
++#endif
++
++        key_state->state = libssh2_NB_state_created;
++    }
++
++    if (key_state->state == libssh2_NB_state_created) {
++        rc = libssh2_packet_write(session, key_state->request,
++                                  key_state->request_len);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                          "Unable to send Group Exchange Request", 0);
++            ret = -1;
++            goto dh_gex_clean_exit;
++        }
++
++        key_state->state = libssh2_NB_state_sent;
++    }
++
++    if (key_state->state == libssh2_NB_state_sent) {
++        rc = libssh2_packet_require_ex(session, SSH_MSG_KEX_DH_GEX_GROUP,
++                                       &key_state->data, &key_state->data_len,
++                                       0, NULL, 0, &key_state->req_state);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc) {
++            libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
++                          "Timeout waiting for GEX_GROUP reply", 0);
++            ret = -1;
++            goto dh_gex_clean_exit;
++        }
++
++        key_state->state = libssh2_NB_state_sent1;
++    }
++
++    if (key_state->state == libssh2_NB_state_sent1) {
++        s = key_state->data + 1;
++        p_len = libssh2_ntohu32(s);
++        s += 4;
++        _libssh2_bn_from_bin(key_state->p, p_len, s);
++        s += p_len;
++
++        g_len = libssh2_ntohu32(s);
++        s += 4;
++        _libssh2_bn_from_bin(key_state->g, g_len, s);
++        s += g_len;
++
++        ret =
++            libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange
++            (session, key_state->g, key_state->p, p_len,
++             SSH_MSG_KEX_DH_GEX_INIT, SSH_MSG_KEX_DH_GEX_REPLY,
++             key_state->data + 1, key_state->data_len - 1,
++             &key_state->exchange_state);
++        if (ret == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        }
++
++        LIBSSH2_FREE(session, key_state->data);
++    }
++
++  dh_gex_clean_exit:
++    key_state->state = libssh2_NB_state_idle;
++    _libssh2_bn_free(key_state->g);
++    key_state->g = NULL;
++    _libssh2_bn_free(key_state->p);
++    key_state->p = NULL;
++
++    return ret;
++}
++
++/* }}} */
++
++#define LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY     0x0001
++#define LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY    0x0002
++
++static const LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group1_sha1 = {
++    "diffie-hellman-group1-sha1",
++    libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange,
++    LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
++};
++
++static const LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group14_sha1 = {
++    "diffie-hellman-group14-sha1",
++    libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange,
++    LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
++};
++
++static const LIBSSH2_KEX_METHOD
++    libssh2_kex_method_diffie_helman_group_exchange_sha1 = {
++    "diffie-hellman-group-exchange-sha1",
++    libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange,
++    LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
++};
++
++static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = {
++    &libssh2_kex_method_diffie_helman_group14_sha1,
++    &libssh2_kex_method_diffie_helman_group_exchange_sha1,
++    &libssh2_kex_method_diffie_helman_group1_sha1,
++    NULL
++};
++
++typedef struct _LIBSSH2_COMMON_METHOD
++{
++    const char *name;
++} LIBSSH2_COMMON_METHOD;
++
++/* {{{ libssh2_kex_method_strlen
++ * Calculate the length of a particular method list's resulting string
++ * Includes SUM(strlen() of each individual method plus 1 (for coma)) - 1 (because the last coma isn't used)
++ * Another sign of bad coding practices gone mad.  Pretend you don't see this.
++ */
++static size_t
++libssh2_kex_method_strlen(LIBSSH2_COMMON_METHOD ** method)
++{
++    size_t len = 0;
++
++    if (!method || !*method) {
++        return 0;
++    }
++
++    while (*method && (*method)->name) {
++        len += strlen((*method)->name) + 1;
++        method++;
++    }
++
++    return len - 1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_kex_method_list
++ * Generate formatted preference list in buf
++ */
++static size_t
++libssh2_kex_method_list(unsigned char *buf, size_t list_strlen,
++                        LIBSSH2_COMMON_METHOD ** method)
++{
++    libssh2_htonu32(buf, list_strlen);
++    buf += 4;
++
++    if (!method || !*method) {
++        return 4;
++    }
++
++    while (*method && (*method)->name) {
++        int mlen = strlen((*method)->name);
++        memcpy(buf, (*method)->name, mlen);
++        buf += mlen;
++        *(buf++) = ',';
++        method++;
++    }
++
++    return list_strlen + 4;
++}
++
++/* }}} */
++
++#define LIBSSH2_METHOD_PREFS_LEN(prefvar, defaultvar)   ((prefvar) ? strlen(prefvar) : libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar)))
++#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar)                              \
++    if (prefvar) {                                                                                  \
++        libssh2_htonu32((buf), (prefvarlen));                                                       \
++        buf += 4;                                                                                   \
++        memcpy((buf), (prefvar), (prefvarlen));                                                     \
++        buf += (prefvarlen);                                                                        \
++    } else {                                                                                        \
++        buf += libssh2_kex_method_list((buf), (prefvarlen), (LIBSSH2_COMMON_METHOD**)(defaultvar)); \
++    }
++
++/* {{{ libssh2_kexinit
++ * Send SSH_MSG_KEXINIT packet
++ */
++static int
++libssh2_kexinit(LIBSSH2_SESSION * session)
++{
++    /* 62 = packet_type(1) + cookie(16) + first_packet_follows(1) + 
++       reserved(4) + length longs(40) */
++    size_t data_len = 62;
++    size_t kex_len, hostkey_len = 0;
++    size_t crypt_cs_len, crypt_sc_len;
++    size_t comp_cs_len, comp_sc_len;
++    size_t mac_cs_len, mac_sc_len;
++    size_t lang_cs_len, lang_sc_len;
++    unsigned char *data, *s;
++    int rc;
++
++    if (session->kexinit_state == libssh2_NB_state_idle) {
++        kex_len =
++            LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods);
++        hostkey_len =
++            LIBSSH2_METHOD_PREFS_LEN(session->hostkey_prefs,
++                                     libssh2_hostkey_methods());
++        crypt_cs_len =
++            LIBSSH2_METHOD_PREFS_LEN(session->local.crypt_prefs,
++                                     libssh2_crypt_methods());
++        crypt_sc_len =
++            LIBSSH2_METHOD_PREFS_LEN(session->remote.crypt_prefs,
++                                     libssh2_crypt_methods());
++        mac_cs_len =
++            LIBSSH2_METHOD_PREFS_LEN(session->local.mac_prefs,
++                                     libssh2_mac_methods());
++        mac_sc_len =
++            LIBSSH2_METHOD_PREFS_LEN(session->remote.mac_prefs,
++                                     libssh2_mac_methods());
++        comp_cs_len =
++            LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs,
++                                     libssh2_comp_methods());
++        comp_sc_len =
++            LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs,
++                                     libssh2_comp_methods());
++        lang_cs_len =
++            LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL);
++        lang_sc_len =
++            LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL);
++
++        data_len += kex_len + hostkey_len + crypt_cs_len + crypt_sc_len +
++            comp_cs_len + comp_sc_len + mac_cs_len + mac_sc_len +
++            lang_cs_len + lang_sc_len;
++
++        s = data = LIBSSH2_ALLOC(session, data_len);
++        if (!data) {
++            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                          "Unable to allocate memory", 0);
++            return -1;
++        }
++
++        *(s++) = SSH_MSG_KEXINIT;
++
++        libssh2_random(s, 16);
++        s += 16;
++
++        /* Ennumerating through these lists twice is probably (certainly?) 
++           inefficient from a CPU standpoint, but it saves multiple 
++           malloc/realloc calls */
++        LIBSSH2_METHOD_PREFS_STR(s, kex_len, session->kex_prefs,
++                                 libssh2_kex_methods);
++        LIBSSH2_METHOD_PREFS_STR(s, hostkey_len, session->hostkey_prefs,
++                                 libssh2_hostkey_methods());
++        LIBSSH2_METHOD_PREFS_STR(s, crypt_cs_len, session->local.crypt_prefs,
++                                 libssh2_crypt_methods());
++        LIBSSH2_METHOD_PREFS_STR(s, crypt_sc_len, session->remote.crypt_prefs,
++                                 libssh2_crypt_methods());
++        LIBSSH2_METHOD_PREFS_STR(s, mac_cs_len, session->local.mac_prefs,
++                                 libssh2_mac_methods());
++        LIBSSH2_METHOD_PREFS_STR(s, mac_sc_len, session->remote.mac_prefs,
++                                 libssh2_mac_methods());
++        LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len, session->local.comp_prefs,
++                                 libssh2_comp_methods());
++        LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len, session->remote.comp_prefs,
++                                 libssh2_comp_methods());
++        LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len, session->local.lang_prefs,
++                                 NULL);
++        LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs,
++                                 NULL);
++
++        /* No optimistic KEX packet follows */
++        /* Deal with optimistic packets
++         * session->flags |= KEXINIT_OPTIMISTIC
++         * session->flags |= KEXINIT_METHODSMATCH
++         */
++        *(s++) = 0;
++
++        /* Reserved == 0 */
++        *(s++) = 0;
++        *(s++) = 0;
++        *(s++) = 0;
++        *(s++) = 0;
++
++#ifdef LIBSSH2DEBUG
++        {
++            /* Funnily enough, they'll all "appear" to be '\0' terminated */
++            unsigned char *p = data + 21;       /* type(1) + cookie(16) + len(4) */
++
++            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent KEX: %s", p);
++            p += kex_len + 4;
++            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent HOSTKEY: %s", p);
++            p += hostkey_len + 4;
++            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_CS: %s", p);
++            p += crypt_cs_len + 4;
++            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_SC: %s", p);
++            p += crypt_sc_len + 4;
++            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_CS: %s", p);
++            p += mac_cs_len + 4;
++            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_SC: %s", p);
++            p += mac_sc_len + 4;
++            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_CS: %s", p);
++            p += comp_cs_len + 4;
++            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_SC: %s", p);
++            p += comp_sc_len + 4;
++            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_CS: %s", p);
++            p += lang_cs_len + 4;
++            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_SC: %s", p);
++            p += lang_sc_len + 4;
++        }
++#endif /* LIBSSH2DEBUG */
++
++        session->kexinit_state = libssh2_NB_state_created;
++    } else {
++        data = session->kexinit_data;
++        data_len = session->kexinit_data_len;
++    }
++
++    if ((rc = libssh2_packet_write(session, data, data_len)) == PACKET_EAGAIN) {
++        session->kexinit_data = data;
++        session->kexinit_data_len = data_len;
++        return PACKET_EAGAIN;
++    } else if (rc) {
++        LIBSSH2_FREE(session, data);
++        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
++                      "Unable to send KEXINIT packet to remote host", 0);
++        session->kexinit_state = libssh2_NB_state_idle;
++        return -1;
++    }
++
++    if (session->local.kexinit) {
++        LIBSSH2_FREE(session, session->local.kexinit);
++    }
++
++    session->local.kexinit = data;
++    session->local.kexinit_len = data_len;
++
++    session->kexinit_state = libssh2_NB_state_idle;
++
++    return 0;
++}
++
++/* }}}  */
++
++/* {{{ libssh2_kex_agree_instr
++ * Kex specific variant of strstr()
++ * Needle must be preceed by BOL or ',', and followed by ',' or EOL
++ */
++static unsigned char *
++libssh2_kex_agree_instr(unsigned char *haystack, unsigned long haystack_len,
++                        const unsigned char *needle, unsigned long needle_len)
++{
++    unsigned char *s;
++
++    /* Haystack too short to bother trying */
++    if (haystack_len < needle_len) {
++        return NULL;
++    }
++
++    /* Needle at start of haystack */
++    if ((strncmp((char *) haystack, (char *) needle, needle_len) == 0) &&
++        (needle_len == haystack_len || haystack[needle_len] == ',')) {
++        return haystack;
++    }
++
++    s = haystack;
++    /* Search until we run out of comas or we run out of haystack,
++       whichever comes first */
++    while ((s = (unsigned char *) strchr((char *) s, ','))
++           && ((haystack_len - (s - haystack)) > needle_len)) {
++        s++;
++        /* Needle at X position */
++        if ((strncmp((char *) s, (char *) needle, needle_len) == 0) &&
++            (((s - haystack) + needle_len) == haystack_len
++             || s[needle_len] == ',')) {
++            return s;
++        }
++    }
++
++    return NULL;
++}
++
++/* }}} */
++
++/* {{{ libssh2_get_method_by_name
++ */
++static const LIBSSH2_COMMON_METHOD *
++libssh2_get_method_by_name(const char *name, int name_len,
++                           const LIBSSH2_COMMON_METHOD ** methodlist)
++{
++    while (*methodlist) {
++        if ((strlen((*methodlist)->name) == name_len) &&
++            (strncmp((*methodlist)->name, name, name_len) == 0)) {
++            return *methodlist;
++        }
++        methodlist++;
++    }
++    return NULL;
++}
++
++/* }}} */
++
++/* {{{ libssh2_kex_agree_hostkey
++ * Agree on a Hostkey which works with this kex
++ */
++static int
++libssh2_kex_agree_hostkey(LIBSSH2_SESSION * session, unsigned long kex_flags,
++                          unsigned char *hostkey, unsigned long hostkey_len)
++{
++    const LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods();
++    unsigned char *s;
++
++    if (session->hostkey_prefs) {
++        s = (unsigned char *) session->hostkey_prefs;
++
++        while (s && *s) {
++            unsigned char *p = (unsigned char *) strchr((char *) s, ',');
++            int method_len = (p ? (p - s) : strlen((char *) s));
++            if (libssh2_kex_agree_instr(hostkey, hostkey_len, s, method_len)) {
++                const LIBSSH2_HOSTKEY_METHOD *method =
++                    (const LIBSSH2_HOSTKEY_METHOD *)
++                    libssh2_get_method_by_name((char *) s, method_len,
++                                               (const LIBSSH2_COMMON_METHOD **)
++                                               hostkeyp);
++
++                if (!method) {
++                    /* Invalid method -- Should never be reached */
++                    return -1;
++                }
++
++                /* So far so good, but does it suit our purposes? (Encrypting vs Signing) */
++                if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) ==
++                     0) || (method->encrypt)) {
++                    /* Either this hostkey can do encryption or this kex just doesn't require it */
++                    if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY)
++                         == 0) || (method->sig_verify)) {
++                        /* Either this hostkey can do signing or this kex just doesn't require it */
++                        session->hostkey = method;
++                        return 0;
++                    }
++                }
++            }
++
++            s = p ? p + 1 : NULL;
++        }
++        return -1;
++    }
++
++    while (hostkeyp && (*hostkeyp)->name) {
++        s = libssh2_kex_agree_instr(hostkey, hostkey_len,
++                                    (unsigned char *) (*hostkeyp)->name,
++                                    strlen((*hostkeyp)->name));
++        if (s) {
++            /* So far so good, but does it suit our purposes? (Encrypting vs Signing) */
++            if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) == 0) ||
++                ((*hostkeyp)->encrypt)) {
++                /* Either this hostkey can do encryption or this kex just doesn't require it */
++                if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY) ==
++                     0) || ((*hostkeyp)->sig_verify)) {
++                    /* Either this hostkey can do signing or this kex just doesn't require it */
++                    session->hostkey = *hostkeyp;
++                    return 0;
++                }
++            }
++        }
++        hostkeyp++;
++    }
++
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_kex_agree_kex_hostkey
++ * Agree on a Key Exchange method and a hostkey encoding type
++ */
++static int
++libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
++                              unsigned long kex_len, unsigned char *hostkey,
++                              unsigned long hostkey_len)
++{
++    const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods;
++    unsigned char *s;
++
++    if (session->kex_prefs) {
++        s = (unsigned char *) session->kex_prefs;
++
++        while (s && *s) {
++            unsigned char *q, *p = (unsigned char *) strchr((char *) s, ',');
++            int method_len = (p ? (p - s) : strlen((char *) s));
++            if ((q = libssh2_kex_agree_instr(kex, kex_len, s, method_len))) {
++                const LIBSSH2_KEX_METHOD *method = (const LIBSSH2_KEX_METHOD *)
++                    libssh2_get_method_by_name((char *) s, method_len,
++                                               (const LIBSSH2_COMMON_METHOD **)
++                                               kexp);
++
++                if (!method) {
++                    /* Invalid method -- Should never be reached */
++                    return -1;
++                }
++
++                /* We've agreed on a key exchange method,
++                 * Can we agree on a hostkey that works with this kex?
++                 */
++                if (libssh2_kex_agree_hostkey
++                    (session, method->flags, hostkey, hostkey_len) == 0) {
++                    session->kex = method;
++                    if (session->burn_optimistic_kexinit && (kex == q)) {
++                        /* Server sent an optimistic packet,
++                         * and client agrees with preference
++                         * cancel burning the first KEX_INIT packet that comes in */
++                        session->burn_optimistic_kexinit = 0;
++                    }
++                    return 0;
++                }
++            }
++
++            s = p ? p + 1 : NULL;
++        }
++        return -1;
++    }
++
++    while (*kexp && (*kexp)->name) {
++        s = libssh2_kex_agree_instr(kex, kex_len,
++                                    (unsigned char *) (*kexp)->name,
++                                    strlen((*kexp)->name));
++        if (s) {
++            /* We've agreed on a key exchange method,
++             * Can we agree on a hostkey that works with this kex?
++             */
++            if (libssh2_kex_agree_hostkey
++                (session, (*kexp)->flags, hostkey, hostkey_len) == 0) {
++                session->kex = *kexp;
++                if (session->burn_optimistic_kexinit && (kex == s)) {
++                    /* Server sent an optimistic packet,
++                     * and client agrees with preference
++                     * cancel burning the first KEX_INIT packet that comes in */
++                    session->burn_optimistic_kexinit = 0;
++                }
++                return 0;
++            }
++        }
++        kexp++;
++    }
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_kex_agree_crypt
++ * Agree on a cipher algo
++ */
++static int
++libssh2_kex_agree_crypt(LIBSSH2_SESSION * session,
++                        libssh2_endpoint_data * endpoint, unsigned char *crypt,
++                        unsigned long crypt_len)
++{
++    const LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods();
++    unsigned char *s;
++
++    (void) session;
++
++    if (endpoint->crypt_prefs) {
++        s = (unsigned char *) endpoint->crypt_prefs;
++
++        while (s && *s) {
++            unsigned char *p = (unsigned char *) strchr((char *) s, ',');
++            int method_len = (p ? (p - s) : strlen((char *) s));
++
++            if (libssh2_kex_agree_instr(crypt, crypt_len, s, method_len)) {
++                const LIBSSH2_CRYPT_METHOD *method =
++                    (const LIBSSH2_CRYPT_METHOD *)
++                    libssh2_get_method_by_name((char *) s, method_len,
++                                               (const LIBSSH2_COMMON_METHOD **)
++                                               cryptp);
++
++                if (!method) {
++                    /* Invalid method -- Should never be reached */
++                    return -1;
++                }
++
++                endpoint->crypt = method;
++                return 0;
++            }
++
++            s = p ? p + 1 : NULL;
++        }
++        return -1;
++    }
++
++    while (*cryptp && (*cryptp)->name) {
++        s = libssh2_kex_agree_instr(crypt, crypt_len,
++                                    (unsigned char *) (*cryptp)->name,
++                                    strlen((*cryptp)->name));
++        if (s) {
++            endpoint->crypt = *cryptp;
++            return 0;
++        }
++        cryptp++;
++    }
++
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_kex_agree_mac
++ * Agree on a message authentication hash
++ */
++static int
++libssh2_kex_agree_mac(LIBSSH2_SESSION * session,
++                      libssh2_endpoint_data * endpoint, unsigned char *mac,
++                      unsigned long mac_len)
++{
++    const LIBSSH2_MAC_METHOD **macp = libssh2_mac_methods();
++    unsigned char *s;
++    (void) session;
++
++    if (endpoint->mac_prefs) {
++        s = (unsigned char *) endpoint->mac_prefs;
++
++        while (s && *s) {
++            unsigned char *p = (unsigned char *) strchr((char *) s, ',');
++            int method_len = (p ? (p - s) : strlen((char *) s));
++
++            if (libssh2_kex_agree_instr(mac, mac_len, s, method_len)) {
++                const LIBSSH2_MAC_METHOD *method = (const LIBSSH2_MAC_METHOD *)
++                    libssh2_get_method_by_name((char *) s, method_len,
++                                               (const LIBSSH2_COMMON_METHOD **)
++                                               macp);
++
++                if (!method) {
++                    /* Invalid method -- Should never be reached */
++                    return -1;
++                }
++
++                endpoint->mac = method;
++                return 0;
++            }
++
++            s = p ? p + 1 : NULL;
++        }
++        return -1;
++    }
++
++    while (*macp && (*macp)->name) {
++        s = libssh2_kex_agree_instr(mac, mac_len,
++                                    (unsigned char *) (*macp)->name,
++                                    strlen((*macp)->name));
++        if (s) {
++            endpoint->mac = *macp;
++            return 0;
++        }
++        macp++;
++    }
++
++    return -1;
++}
++
++/* }}} */
++
++/* {{{ libssh2_kex_agree_comp
++ * Agree on a compression scheme
++ */
++static int
++libssh2_kex_agree_comp(LIBSSH2_SESSION * session,
++                       libssh2_endpoint_data * endpoint, unsigned char *comp,
++                       unsigned long comp_len)
++{
++    const LIBSSH2_COMP_METHOD **compp = libssh2_comp_methods();
++    unsigned char *s;
++    (void) session;
++
++    if (endpoint->comp_prefs) {
++        s = (unsigned char *) endpoint->comp_prefs;
++
++        while (s && *s) {
++            unsigned char *p = (unsigned char *) strchr((char *) s, ',');
++            int method_len = (p ? (p - s) : strlen((char *) s));
++
++            if (libssh2_kex_agree_instr(comp, comp_len, s, method_len)) {
++                const LIBSSH2_COMP_METHOD *method =
++                    (const LIBSSH2_COMP_METHOD *)
++                    libssh2_get_method_by_name((char *) s, method_len,
++                                               (const LIBSSH2_COMMON_METHOD **)
++                                               compp);
++
++                if (!method) {
++                    /* Invalid method -- Should never be reached */
++                    return -1;
++                }
++
++                endpoint->comp = method;
++                return 0;
++            }
++
++            s = p ? p + 1 : NULL;
++        }
++        return -1;
++    }
++
++    while (*compp && (*compp)->name) {
++        s = libssh2_kex_agree_instr(comp, comp_len,
++                                    (unsigned char *) (*compp)->name,
++                                    strlen((*compp)->name));
++        if (s) {
++            endpoint->comp = *compp;
++            return 0;
++        }
++        compp++;
++    }
++
++    return -1;
++}
++
++/* }}} */
++
++/* TODO: When in server mode we need to turn this logic on its head
++ * The Client gets to make the final call on "agreed methods"
++ */
++
++/* {{{ libssh2_kex_agree_methods
++ * Decide which specific method to use of the methods offered by each party
++ */
++static int
++libssh2_kex_agree_methods(LIBSSH2_SESSION * session, unsigned char *data,
++                          unsigned data_len)
++{
++    unsigned char *kex, *hostkey, *crypt_cs, *crypt_sc, *comp_cs, *comp_sc,
++        *mac_cs, *mac_sc, *lang_cs, *lang_sc;
++    size_t kex_len, hostkey_len, crypt_cs_len, crypt_sc_len, comp_cs_len;
++    size_t comp_sc_len, mac_cs_len, mac_sc_len, lang_cs_len, lang_sc_len;
++    unsigned char *s = data;
++
++    /* Skip packet_type, we know it already */
++    s++;
++
++    /* Skip cookie, don't worry, it's preserved in the kexinit field */
++    s += 16;
++
++    /* Locate each string */
++    kex_len = libssh2_ntohu32(s);
++    kex = s + 4;
++    s += 4 + kex_len;
++    hostkey_len = libssh2_ntohu32(s);
++    hostkey = s + 4;
++    s += 4 + hostkey_len;
++    crypt_cs_len = libssh2_ntohu32(s);
++    crypt_cs = s + 4;
++    s += 4 + crypt_cs_len;
++    crypt_sc_len = libssh2_ntohu32(s);
++    crypt_sc = s + 4;
++    s += 4 + crypt_sc_len;
++    mac_cs_len = libssh2_ntohu32(s);
++    mac_cs = s + 4;
++    s += 4 + mac_cs_len;
++    mac_sc_len = libssh2_ntohu32(s);
++    mac_sc = s + 4;
++    s += 4 + mac_sc_len;
++    comp_cs_len = libssh2_ntohu32(s);
++    comp_cs = s + 4;
++    s += 4 + comp_cs_len;
++    comp_sc_len = libssh2_ntohu32(s);
++    comp_sc = s + 4;
++    s += 4 + comp_sc_len;
++    lang_cs_len = libssh2_ntohu32(s);
++    lang_cs = s + 4;
++    s += 4 + lang_cs_len;
++    lang_sc_len = libssh2_ntohu32(s);
++    lang_sc = s + 4;
++    s += 4 + lang_sc_len;
++
++    /* If the server sent an optimistic packet, assume that it guessed wrong.
++     * If the guess is determined to be right (by libssh2_kex_agree_kex_hostkey)
++     * This flag will be reset to zero so that it's not ignored */
++    session->burn_optimistic_kexinit = *(s++);
++    /* Next uint32 in packet is all zeros (reserved) */
++
++    if (data_len < (unsigned) (s - data))
++        return -1;              /* short packet */
++
++    if (libssh2_kex_agree_kex_hostkey
++        (session, kex, kex_len, hostkey, hostkey_len)) {
++        return -1;
++    }
++
++    if (libssh2_kex_agree_crypt
++        (session, &session->local, crypt_cs, crypt_cs_len)
++        || libssh2_kex_agree_crypt(session, &session->remote, crypt_sc,
++                                   crypt_sc_len)) {
++        return -1;
++    }
++
++    if (libssh2_kex_agree_mac(session, &session->local, mac_cs, mac_cs_len) ||
++        libssh2_kex_agree_mac(session, &session->remote, mac_sc, mac_sc_len)) {
++        return -1;
++    }
++
++    if (libssh2_kex_agree_comp(session, &session->local, comp_cs, comp_cs_len)
++        || libssh2_kex_agree_comp(session, &session->remote, comp_sc,
++                                  comp_sc_len)) {
++        return -1;
++    }
++
++    if (libssh2_kex_agree_lang(session, &session->local, lang_cs, lang_cs_len)
++        || libssh2_kex_agree_lang(session, &session->remote, lang_sc,
++                                  lang_sc_len)) {
++        return -1;
++    }
++
++    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on KEX method: %s",
++                   session->kex->name);
++    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on HOSTKEY method: %s",
++                   session->hostkey->name);
++    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_CS method: %s",
++                   session->local.crypt->name);
++    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_SC method: %s",
++                   session->remote.crypt->name);
++    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_CS method: %s",
++                   session->local.mac->name);
++    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_SC method: %s",
++                   session->remote.mac->name);
++    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_CS method: %s",
++                   session->local.comp->name);
++    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_SC method: %s",
++                   session->remote.comp->name);
++    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_CS method:");      /* None yet */
++    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_SC method:");      /* None yet */
++
++    /* Initialize compression layer */
++    if (session->local.comp && session->local.comp->init &&
++        session->local.comp->init(session, 1, &session->local.comp_abstract)) {
++        return -1;
++    }
++
++    if (session->remote.comp && session->remote.comp->init &&
++        session->remote.comp->init(session, 0,
++                                   &session->remote.comp_abstract)) {
++        return -1;
++    }
++
++    return 0;
++}
++
++/* }}} */
++
++/* {{{ libssh2_kex_exchange
++ * Exchange keys
++ * Returns 0 on success, non-zero on failure
++ */
++int
++libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
++                     key_exchange_state_t * key_state)
++{
++    int rc = 0;
++    int retcode;
++
++    session->state |= LIBSSH2_STATE_KEX_ACTIVE;
++
++    if (key_state->state == libssh2_NB_state_idle) {
++        /* Prevent loop in packet_add() */
++        session->state |= LIBSSH2_STATE_EXCHANGING_KEYS;
++
++        if (reexchange) {
++            session->kex = NULL;
++
++            if (session->hostkey && session->hostkey->dtor) {
++                session->hostkey->dtor(session,
++                                       &session->server_hostkey_abstract);
++            }
++            session->hostkey = NULL;
++        }
++
++        key_state->state = libssh2_NB_state_created;
++    }
++
++    if (!session->kex || !session->hostkey) {
++        if (key_state->state == libssh2_NB_state_created) {
++            /* Preserve in case of failure */
++            key_state->oldlocal = session->local.kexinit;
++            key_state->oldlocal_len = session->local.kexinit_len;
++
++            session->local.kexinit = NULL;
++
++            key_state->state = libssh2_NB_state_sent;
++        }
++
++        if (key_state->state == libssh2_NB_state_sent) {
++            retcode = libssh2_kexinit(session);
++            if (retcode == PACKET_EAGAIN) {
++                session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
++                return PACKET_EAGAIN;
++            } else if (retcode) {
++                session->local.kexinit = key_state->oldlocal;
++                session->local.kexinit_len = key_state->oldlocal_len;
++                key_state->state = libssh2_NB_state_idle;
++                session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
++                session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
++                return -1;
++            }
++
++            key_state->state = libssh2_NB_state_sent1;
++        }
++
++        if (key_state->state == libssh2_NB_state_sent1) {
++            retcode =
++                libssh2_packet_require_ex(session, SSH_MSG_KEXINIT,
++                                          &key_state->data,
++                                          &key_state->data_len, 0, NULL, 0,
++                                          &key_state->req_state);
++            if (retcode == PACKET_EAGAIN) {
++                session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
++                return PACKET_EAGAIN;
++            } else if (retcode) {
++                if (session->local.kexinit) {
++                    LIBSSH2_FREE(session, session->local.kexinit);
++                }
++                session->local.kexinit = key_state->oldlocal;
++                session->local.kexinit_len = key_state->oldlocal_len;
++                key_state->state = libssh2_NB_state_idle;
++                session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
++                session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
++                return -1;
++            }
++
++            if (session->remote.kexinit) {
++                LIBSSH2_FREE(session, session->remote.kexinit);
++            }
++            session->remote.kexinit = key_state->data;
++            session->remote.kexinit_len = key_state->data_len;
++
++            if (libssh2_kex_agree_methods
++                (session, key_state->data, key_state->data_len)) {
++                rc = -1;
++            }
++
++            key_state->state = libssh2_NB_state_sent2;
++        }
++    } else {
++        key_state->state = libssh2_NB_state_sent2;
++    }
++
++    if (rc == 0) {
++        if (key_state->state == libssh2_NB_state_sent2) {
++            retcode =
++                session->kex->exchange_keys(session,
++                                            &key_state->key_state_low);
++            if (retcode == PACKET_EAGAIN) {
++                session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
++                return PACKET_EAGAIN;
++            } else if (retcode) {
++                libssh2_error(session, LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE,
++                              "Unrecoverable error exchanging keys", 0);
++                rc = -1;
++            }
++        }
++    }
++
++    /* Done with kexinit buffers */
++    if (session->local.kexinit) {
++        LIBSSH2_FREE(session, session->local.kexinit);
++        session->local.kexinit = NULL;
++    }
++    if (session->remote.kexinit) {
++        LIBSSH2_FREE(session, session->remote.kexinit);
++        session->remote.kexinit = NULL;
++    }
++
++    session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
++    session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
++
++    key_state->state = libssh2_NB_state_idle;
++
++    return rc;
++}
++
++/* }}} */
++
++/* {{{ libssh2_session_method_pref
++ * Set preferred method
++ */
++LIBSSH2_API int
++libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type,
++                            const char *prefs)
++{
++    char **prefvar, *s, *newprefs;
++    int prefs_len = strlen(prefs);
++    const LIBSSH2_COMMON_METHOD **mlist;
++
++    switch (method_type) {
++    case LIBSSH2_METHOD_KEX:
++        prefvar = &session->kex_prefs;
++        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods;
++        break;
++
++    case LIBSSH2_METHOD_HOSTKEY:
++        prefvar = &session->hostkey_prefs;
++        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods();
++        break;
++
++    case LIBSSH2_METHOD_CRYPT_CS:
++        prefvar = &session->local.crypt_prefs;
++        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods();
++        break;
++
++    case LIBSSH2_METHOD_CRYPT_SC:
++        prefvar = &session->remote.crypt_prefs;
++        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods();
++        break;
++
++    case LIBSSH2_METHOD_MAC_CS:
++        prefvar = &session->local.mac_prefs;
++        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_mac_methods();
++        break;
++
++    case LIBSSH2_METHOD_MAC_SC:
++        prefvar = &session->remote.mac_prefs;
++        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_mac_methods();
++        break;
++
++    case LIBSSH2_METHOD_COMP_CS:
++        prefvar = &session->local.comp_prefs;
++        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_comp_methods();
++        break;
++
++    case LIBSSH2_METHOD_COMP_SC:
++        prefvar = &session->remote.comp_prefs;
++        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_comp_methods();
++        break;
++
++    case LIBSSH2_METHOD_LANG_CS:
++        prefvar = &session->local.lang_prefs;
++        mlist = NULL;
++        break;
++
++    case LIBSSH2_METHOD_LANG_SC:
++        prefvar = &session->remote.lang_prefs;
++        mlist = NULL;
++        break;
++
++    default:
++        libssh2_error(session, LIBSSH2_ERROR_INVAL,
++                      "Invalid parameter specified for method_type", 0);
++        return -1;
++    }
++
++    s = newprefs = LIBSSH2_ALLOC(session, prefs_len + 1);
++    if (!newprefs) {
++        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
++                      "Error allocated space for method preferences", 0);
++        return -1;
++    }
++    memcpy(s, prefs, prefs_len + 1);
++
++    while (s && *s) {
++        char *p = strchr(s, ',');
++        int method_len = p ? (p - s) : (int) strlen(s);
++
++        if (!libssh2_get_method_by_name(s, method_len, mlist)) {
++            /* Strip out unsupported method */
++            if (p) {
++                memcpy(s, p + 1, strlen(s) - method_len);
++            } else {
++                if (s > newprefs) {
++                    *(--s) = '\0';
++                } else {
++                    *s = '\0';
++                }
++            }
++        }
++
++        s = p ? (p + 1) : NULL;
++    }
++
++    if (strlen(newprefs) == 0) {
++        libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
++                      "The requested method(s) are not currently supported",
++                      0);
++        LIBSSH2_FREE(session, newprefs);
++        return -1;
++    }
++
++    if (*prefvar) {
++        LIBSSH2_FREE(session, *prefvar);
++    }
++    *prefvar = newprefs;
++
++    return 0;
++}
++
++/* }}} */
+
+Property changes on: libssh2/src/kex.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.3
+Added: svn:eol-style
+   + native
+
+Index: libssh2/src/openssl.h
+===================================================================
+--- libssh2/src/openssl.h      (.../tags/RELEASE_0_11_0)
++++ libssh2/src/openssl.h      (.../trunk)
+@@ -0,0 +1,224 @@
++/* Copyright (C) 2006, 2007 The Written Word, Inc.  All rights reserved.
++ * Author: Simon Josefsson
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 <openssl/opensslconf.h>
++#include <openssl/sha.h>
++#ifndef OPENSSL_NO_MD5
++#include <openssl/md5.h>
++#endif
++#include <openssl/evp.h>
++#include <openssl/hmac.h>
++#include <openssl/bn.h>
++#include <openssl/pem.h>
++#include <openssl/rand.h>
++
++#ifdef OPENSSL_NO_RSA
++# define LIBSSH2_RSA 0
++#else
++# define LIBSSH2_RSA 1
++#endif
++
++#ifdef OPENSSL_NO_DSA
++# define LIBSSH2_DSA 0
++#else
++# define LIBSSH2_DSA 1
++#endif
++
++#ifdef OPENSSL_NO_MD5
++# define LIBSSH2_MD5 0
++#else
++# define LIBSSH2_MD5 1
++#endif
++
++#ifdef OPENSSL_NO_RIPEMD
++# define LIBSSH2_HMAC_RIPEMD 0
++#else
++# define LIBSSH2_HMAC_RIPEMD 1
++#endif
++
++#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)
++# define LIBSSH2_AES 1
++#else
++# define LIBSSH2_AES 0
++#endif
++
++#ifdef OPENSSL_NO_BLOWFISH
++# define LIBSSH2_BLOWFISH 0
++#else
++# define LIBSSH2_BLOWFISH 1
++#endif
++
++#ifdef OPENSSL_NO_RC4
++# define LIBSSH2_RC4 0
++#else
++# define LIBSSH2_RC4 1
++#endif
++
++#ifdef OPENSSL_NO_CAST
++# define LIBSSH2_CAST 0
++#else
++# define LIBSSH2_CAST 1
++#endif
++
++#ifdef OPENSSL_NO_DES
++# define LIBSSH2_3DES 0
++#else
++# define LIBSSH2_3DES 1
++#endif
++
++#define libssh2_random(buf, len)        \
++  RAND_bytes ((buf), (len))
++
++#define libssh2_sha1_ctx SHA_CTX
++#define libssh2_sha1_init(ctx) SHA1_Init(ctx)
++#define libssh2_sha1_update(ctx, data, len) SHA1_Update(&(ctx), data, len)
++#define libssh2_sha1_final(ctx, out) SHA1_Final(out, &(ctx))
++#define libssh2_sha1(message, len, out) SHA1(message, len, out)
++
++#define libssh2_md5_ctx MD5_CTX
++#define libssh2_md5_init(ctx) MD5_Init(ctx)
++#define libssh2_md5_update(ctx, data, len) MD5_Update(&(ctx), data, len)
++#define libssh2_md5_final(ctx, out) MD5_Final(out, &(ctx))
++#define libssh2_md5(message, len, out) MD5(message, len, out)
++
++#define libssh2_hmac_ctx HMAC_CTX
++#define libssh2_hmac_sha1_init(ctx, key, keylen) \
++  HMAC_Init(ctx, key, keylen, EVP_sha1())
++#define libssh2_hmac_md5_init(ctx, key, keylen) \
++  HMAC_Init(ctx, key, keylen, EVP_md5())
++#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
++  HMAC_Init(ctx, key, keylen, EVP_ripemd160())
++#define libssh2_hmac_update(ctx, data, datalen) \
++  HMAC_Update(&(ctx), data, datalen)
++#define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL)
++#define libssh2_hmac_cleanup(ctx) HMAC_cleanup(ctx)
++
++#define libssh2_crypto_init()
++
++#define libssh2_rsa_ctx RSA
++
++int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
++                     const unsigned char *edata,
++                     unsigned long elen,
++                     const unsigned char *ndata,
++                     unsigned long nlen,
++                     const unsigned char *ddata,
++                     unsigned long dlen,
++                     const unsigned char *pdata,
++                     unsigned long plen,
++                     const unsigned char *qdata,
++                     unsigned long qlen,
++                     const unsigned char *e1data,
++                     unsigned long e1len,
++                     const unsigned char *e2data,
++                     unsigned long e2len,
++                     const unsigned char *coeffdata, unsigned long coefflen);
++int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
++                             LIBSSH2_SESSION * session,
++                             FILE * fp, unsigned const char *passphrase);
++int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
++                             const unsigned char *sig,
++                             unsigned long sig_len,
++                             const unsigned char *m, unsigned long m_len);
++int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
++                           libssh2_rsa_ctx * rsactx,
++                           const unsigned char *hash,
++                           unsigned long hash_len,
++                           unsigned char **signature,
++                           unsigned long *signature_len);
++
++#define _libssh2_rsa_free(rsactx) RSA_free(rsactx)
++
++#define libssh2_dsa_ctx DSA
++
++int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
++                     const unsigned char *pdata,
++                     unsigned long plen,
++                     const unsigned char *qdata,
++                     unsigned long qlen,
++                     const unsigned char *gdata,
++                     unsigned long glen,
++                     const unsigned char *ydata,
++                     unsigned long ylen,
++                     const unsigned char *x, unsigned long x_len);
++int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
++                             LIBSSH2_SESSION * session,
++                             FILE * fp, unsigned const char *passphrase);
++int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
++                             const unsigned char *sig,
++                             const unsigned char *m, unsigned long m_len);
++int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
++                           const unsigned char *hash,
++                           unsigned long hash_len, unsigned char *sig);
++
++#define _libssh2_dsa_free(dsactx) DSA_free(dsactx)
++
++#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void)
++#define _libssh2_cipher_ctx EVP_CIPHER_CTX
++
++#define _libssh2_cipher_aes256 EVP_aes_256_cbc
++#define _libssh2_cipher_aes192 EVP_aes_192_cbc
++#define _libssh2_cipher_aes128 EVP_aes_128_cbc
++#define _libssh2_cipher_blowfish EVP_bf_cbc
++#define _libssh2_cipher_arcfour EVP_rc4
++#define _libssh2_cipher_cast5 EVP_cast5_cbc
++#define _libssh2_cipher_3des EVP_des_ede3_cbc
++
++int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
++                         _libssh2_cipher_type(algo),
++                         unsigned char *iv,
++                         unsigned char *secret, int encrypt);
++
++int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
++                          _libssh2_cipher_type(algo),
++                          int encrypt, unsigned char *block);
++
++#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_cleanup(ctx)
++
++#define _libssh2_bn BIGNUM
++#define _libssh2_bn_ctx BN_CTX
++#define _libssh2_bn_ctx_new() BN_CTX_new()
++#define _libssh2_bn_ctx_free(bnctx) BN_CTX_free(bnctx)
++#define _libssh2_bn_init() BN_new()
++#define _libssh2_bn_rand(bn, bits, top, bottom) BN_rand(bn, bits, top, bottom)
++#define _libssh2_bn_mod_exp(r, a, p, m, ctx) BN_mod_exp(r, a, p, m, ctx)
++#define _libssh2_bn_set_word(bn, val) BN_set_word(bn, val)
++#define _libssh2_bn_from_bin(bn, len, val) BN_bin2bn(val, len, bn)
++#define _libssh2_bn_to_bin(bn, val) BN_bn2bin(bn, val)
++#define _libssh2_bn_bytes(bn) BN_num_bytes(bn)
++#define _libssh2_bn_bits(bn) BN_num_bits(bn)
++#define _libssh2_bn_free(bn) BN_clear_free(bn)
+
+Property changes on: libssh2/src/openssl.h
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.1
+Added: svn:eol-style
+   + native
+Added: svn:executable
+   + *
+
+Index: libssh2/src/misc.c
+===================================================================
+--- libssh2/src/misc.c (.../tags/RELEASE_0_11_0)
++++ libssh2/src/misc.c (.../trunk)
+@@ -0,0 +1,240 @@
++/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 "libssh2_priv.h"
++#ifdef HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++
++/* {{{ libssh2_ntohu32
++ */
++unsigned long
++libssh2_ntohu32(const unsigned char *buf)
++{
++    return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
++}
++
++/* }}} */
++
++/* {{{ libssh2_ntohu64
++ *
++ */
++libssh2_uint64_t
++libssh2_ntohu64(const unsigned char *buf)
++{
++    unsigned long msl, lsl;
++
++    msl = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
++    lsl = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
++
++    return ((libssh2_uint64_t)msl <<32) | lsl;
++}
++
++/* }}} */
++
++/* {{{ libssh2_htonu32
++ */
++void
++libssh2_htonu32(unsigned char *buf, unsigned long value)
++{
++    buf[0] = (value >> 24) & 0xFF;
++    buf[1] = (value >> 16) & 0xFF;
++    buf[2] = (value >> 8) & 0xFF;
++    buf[3] = value & 0xFF;
++}
++
++/* }}} */
++
++/* {{{ libssh2_htonu64
++ */
++void
++libssh2_htonu64(unsigned char *buf, libssh2_uint64_t value)
++{
++    unsigned long msl = ((libssh2_uint64_t)value >> 32);
++
++    buf[0] = (msl >> 24) & 0xFF;
++    buf[1] = (msl >> 16) & 0xFF;
++    buf[2] = (msl >> 8) & 0xFF;
++    buf[3] = msl & 0xFF;
++
++    buf[4] = (value >> 24) & 0xFF;
++    buf[5] = (value >> 16) & 0xFF;
++    buf[6] = (value >> 8) & 0xFF;
++    buf[7] = value & 0xFF;
++}
++
++/* }}} */
++
++/* Base64 Conversion */
++
++/* {{{ */
++static const char libssh2_base64_table[] =
++    { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
++    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
++    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
++    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
++    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
++};
++
++static const char libssh2_base64_pad = '=';
++
++static const short libssh2_base64_reverse_table[256] = {
++    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
++    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
++    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
++    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
++    -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
++    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
++    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
++    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
++    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
++    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
++    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
++    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
++    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
++    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
++    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
++    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
++};
++
++/* }}} */
++
++
++/* {{{ libssh2_base64_decode
++ * Decode a base64 chunk and store it into a newly alloc'd buffer
++ */
++LIBSSH2_API int
++libssh2_base64_decode(LIBSSH2_SESSION * session, char **data,
++                      unsigned int *datalen, const char *src,
++                      unsigned int src_len)
++{
++    unsigned char *s, *d;
++    short v;
++    int i = 0, len = 0;
++
++    *data = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1);
++    d = (unsigned char *) *data;
++    if (!d) {
++        return -1;
++    }
++
++    for(s = (unsigned char *) src; ((char *) s) < (src + src_len); s++) {
++        if ((v = libssh2_base64_reverse_table[*s]) < 0)
++            continue;
++        switch (i % 4) {
++        case 0:
++            d[len] = v << 2;
++            break;
++        case 1:
++            d[len++] |= v >> 4;
++            d[len] = v << 4;
++            break;
++        case 2:
++            d[len++] |= v >> 2;
++            d[len] = v << 6;
++            break;
++        case 3:
++            d[len++] |= v;
++            break;
++        }
++        i++;
++    }
++    if ((i % 4) == 1) {
++        /* Invalid -- We have a byte which belongs exclusively to a partial octet */
++        LIBSSH2_FREE(session, *data);
++        return -1;
++    }
++
++    *datalen = len;
++    return 0;
++}
++
++/* }}} */
++
++#ifdef LIBSSH2DEBUG
++LIBSSH2_API int
++libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
++{
++    session->showmask = bitmask;
++    return 0;
++}
++
++void
++_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
++{
++    char buffer[1536];
++    int len;
++    va_list vargs;
++    static const char *const contexts[9] = {
++        "Unknown",
++        "Transport",
++        "Key Exchange",
++        "Userauth",
++        "Connection",
++        "scp",
++        "SFTP Subsystem",
++        "Failure Event",
++        "Publickey Subsystem",
++    };
++
++    if (context < 1 || context > 8) {
++        context = 0;
++    }
++    if (!(session->showmask & (1 << context))) {
++        /* no such output asked for */
++        return;
++    }
++
++    len = snprintf(buffer, 1535, "[libssh2] %s: ", contexts[context]);
++
++    va_start(vargs, format);
++    len += vsnprintf(buffer + len, 1535 - len, format, vargs);
++    buffer[len] = '\n';
++    va_end(vargs);
++    write(2, buffer, len + 1);
++
++}
++
++#else
++LIBSSH2_API int
++libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
++{
++    (void) session;
++    (void) bitmask;
++    return 0;
++}
++#endif
+
+Property changes on: libssh2/src/misc.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.3
+Added: svn:eol-style
+   + native
+
+Index: libssh2/src/transport.c
+===================================================================
+--- libssh2/src/transport.c    (.../tags/RELEASE_0_11_0)
++++ libssh2/src/transport.c    (.../trunk)
+@@ -0,0 +1,815 @@
++/* Copyright (C) 2007 The Written Word, Inc.  All rights reserved.
++ * Author: Daniel Stenberg <daniel@haxx.se>
++ *
++ * Redistribution and use in source and binary forms,
++ * with or without modification, are permitted provided
++ * that the following conditions are met:
++ *
++ *   Redistributions of source code must retain the above
++ *   copyright notice, this list of conditions and the
++ *   following disclaimer.
++ *
++ *   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.
++ *
++ *   Neither the name of the copyright holder nor the names
++ *   of any other contributors may be used to endorse or
++ *   promote products derived from this software without
++ *   specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
++ *
++ * This file handles reading and writing to the SECSH transport layer. RFC4253.
++ */
++
++#include "libssh2_priv.h"
++#include <errno.h>
++#include <fcntl.h>
++
++#include <assert.h>
++
++#define MAX_BLOCKSIZE 32        /* MUST fit biggest crypto block size we use/get */
++#define MAX_MACSIZE 20          /* MUST fit biggest MAC length we support */
++
++#ifdef LIBSSH2DEBUG
++#define UNPRINTABLE_CHAR '.'
++static void
++debugdump(LIBSSH2_SESSION * session,
++          const char *desc, unsigned char *ptr, unsigned long size)
++{
++    size_t i;
++    size_t c;
++    FILE *stream = stdout;
++    unsigned int width = 0x10;
++
++    if (!(session->showmask & (1 << LIBSSH2_DBG_TRANS))) {
++        /* not asked for, bail out */
++        return;
++    }
++
++    fprintf(stream, "=> %s (%d bytes)\n", desc, (int) size);
++
++    for(i = 0; i < size; i += width) {
++
++        fprintf(stream, "%04lx: ", (long)i);
++
++        /* 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++) {
++            fprintf(stream, "%c",
++                    (ptr[i + c] >= 0x20) &&
++                    (ptr[i + c] < 0x80) ? ptr[i + c] : UNPRINTABLE_CHAR);
++        }
++        fputc('\n', stream);    /* newline */
++    }
++    fflush(stream);
++}
++#else
++#define debugdump(a,x,y,z)
++#endif
++
++
++/* decrypt() decrypts 'len' bytes from 'source' to 'dest'.
++ *
++ * returns PACKET_NONE on success and PACKET_FAIL on failure
++ */
++
++static libssh2pack_t
++decrypt(LIBSSH2_SESSION * session, unsigned char *source,
++        unsigned char *dest, int len)
++{
++    struct transportpacket *p = &session->packet;
++    int blocksize = session->remote.crypt->blocksize;
++
++    /* if we get called with a len that isn't an even number of blocksizes
++       we risk losing those extra bytes */
++    assert((len % blocksize) == 0);
++
++    while (len >= blocksize) {
++        if (session->remote.crypt->crypt(session, source,
++                                         &session->remote.crypt_abstract)) {
++            libssh2_error(session, LIBSSH2_ERROR_DECRYPT,
++                          (char *) "Error decrypting packet", 0);
++            LIBSSH2_FREE(session, p->payload);
++            return PACKET_FAIL;
++        }
++
++        /* if the crypt() function would write to a given address it
++           wouldn't have to memcpy() and we could avoid this memcpy()
++           too */
++        memcpy(dest, source, blocksize);
++
++        len -= blocksize;       /* less bytes left */
++        dest += blocksize;      /* advance write pointer */
++        source += blocksize;    /* advance read pointer */
++    }
++    return PACKET_NONE;         /* all is fine */
++}
++
++/*
++ * fullpacket() gets called when a full packet has been received and properly
++ * collected.
++ */
++static libssh2pack_t
++fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
++{
++    unsigned char macbuf[MAX_MACSIZE];
++    struct transportpacket *p = &session->packet;
++    int rc;
++
++    if (session->fullpacket_state == libssh2_NB_state_idle) {
++        session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED;
++        session->fullpacket_payload_len = p->packet_length - 1;
++
++        if (encrypted) {
++
++            /* Calculate MAC hash */
++            session->remote.mac->hash(session, macbuf,  /* store hash here */
++                                      session->remote.seqno,
++                                      p->init, 5,
++                                      p->payload,
++                                      session->fullpacket_payload_len,
++                                      &session->remote.mac_abstract);
++
++            /* Compare the calculated hash with the MAC we just read from
++             * the network. The read one is at the very end of the payload
++             * buffer. Note that 'payload_len' here is the packet_length
++             * field which includes the padding but not the MAC.
++             */
++            if (memcmp(macbuf, p->payload + session->fullpacket_payload_len,
++                       session->remote.mac->mac_len)) {
++                session->fullpacket_macstate = LIBSSH2_MAC_INVALID;
++            }
++        }
++
++        session->remote.seqno++;
++
++        /* ignore the padding */
++        session->fullpacket_payload_len -= p->padding_length;
++
++        /* Check for and deal with decompression */
++        if (session->remote.comp && strcmp(session->remote.comp->name, "none")) {
++            unsigned char *data;
++            unsigned long data_len;
++            int free_payload = 1;
++
++            if (session->remote.comp->comp(session, 0,
++                                           &data, &data_len,
++                                           LIBSSH2_PACKET_MAXDECOMP,
++                                           &free_payload,
++                                           p->payload,
++                                           session->fullpacket_payload_len,
++                                           &session->remote.comp_abstract)) {
++                LIBSSH2_FREE(session, p->payload);
++                return PACKET_FAIL;
++            }
++
++            if (free_payload) {
++                LIBSSH2_FREE(session, p->payload);
++                p->payload = data;
++                session->fullpacket_payload_len = data_len;
++            } else {
++                if (data == p->payload) {
++                    /* It's not to be freed, because the
++                     * compression layer reused payload, So let's
++                     * do the same!
++                     */
++                    session->fullpacket_payload_len = data_len;
++                } else {
++                    /* No comp_method actually lets this happen,
++                     * but let's prepare for the future */
++
++                    LIBSSH2_FREE(session, p->payload);
++
++                    /* We need a freeable struct otherwise the
++                     * brigade won't know what to do with it */
++                    p->payload = LIBSSH2_ALLOC(session, data_len);
++                    if (!p->payload) {
++                        libssh2_error(session, LIBSSH2_ERROR_ALLOC, (char *)
++                                      "Unable to allocate memory for copy of uncompressed data",
++                                      0);
++                        return PACKET_ENOMEM;
++                    }
++                    memcpy(p->payload, data, data_len);
++                    session->fullpacket_payload_len = data_len;
++                }
++            }
++        }
++
++        session->fullpacket_packet_type = p->payload[0];
++
++        debugdump(session, "libssh2_packet_read() plain",
++                  p->payload, session->fullpacket_payload_len);
++
++        session->fullpacket_state = libssh2_NB_state_created;
++    }
++
++    if (session->fullpacket_state == libssh2_NB_state_created) {
++        rc = libssh2_packet_add(session, p->payload,
++                                session->fullpacket_payload_len,
++                                session->fullpacket_macstate);
++        if (rc == PACKET_EAGAIN) {
++            return PACKET_EAGAIN;
++        } else if (rc < 0) {
++            return PACKET_FAIL;
++        }
++    }
++
++    session->fullpacket_state = libssh2_NB_state_idle;
++
++    return session->fullpacket_packet_type;
++}
++
++
++/* {{{ libssh2_packet_read
++ * Collect a packet into the input brigade
++ * block only controls whether or not to wait for a packet to start,
++ * Once a packet starts, libssh2 will block until it is complete
++ *
++ * Returns packet type added to input brigade (PACKET_NONE if nothing added),
++ * or PACKET_FAIL on failure and PACKET_EAGAIN if it couldn't process a full
++ * packet.
++ */
++
++/*
++ * This function reads the binary stream as specified in chapter 6 of RFC4253
++ * "The Secure Shell (SSH) Transport Layer Protocol"
++ */
++libssh2pack_t
++libssh2_packet_read(LIBSSH2_SESSION * session)
++{
++    libssh2pack_t rc;
++    struct transportpacket *p = &session->packet;
++    int remainbuf;
++    int remainpack;
++    int numbytes;
++    int numdecrypt;
++    unsigned char block[MAX_BLOCKSIZE];
++    int blocksize;
++    int encrypted = 1;
++
++    int status;
++
++    /*
++     * All channels, systems, subsystems, etc eventually make it down here
++     * when looking for more incoming data. If a key exchange is going on
++     * (LIBSSH2_STATE_EXCHANGING_KEYS bit is set) then the remote end
++     * will ONLY send key exchange related traffic. In non-blocking mode,
++     * there is a chance to break out of the kex_exchange function with an
++     * EAGAIN status, and never come back to it. If LIBSSH2_STATE_EXCHANGING_KEYS
++     * is active, then we must redirect to the key exchange. However,
++     * if kex_exchange is active (as in it is the one that calls this execution
++     * of packet_read, then don't redirect, as that would be an infinite loop!
++     */
++
++    if (session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
++        !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) {
++
++        /* Whoever wants a packet won't get anything until the key re-exchange
++         * is done!
++         */
++        _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Redirecting into the"
++            " key re-exchange");
++        status = libssh2_kex_exchange(session, 1, &session->startup_key_state);
++        if (status == PACKET_EAGAIN) {
++            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
++                "Would block exchanging encryption keys", 0);
++            return PACKET_EAGAIN;
++      } else if (status) {
++          libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
++                      "Unable to exchange encryption keys",0);
++          return LIBSSH2_ERROR_KEX_FAILURE;
++      }
++    }
++
++    /*
++     * =============================== NOTE ===============================
++     * I know this is very ugly and not a really good use of "goto", but
++     * this case statement would be even uglier to do it any other way
++     */
++    if (session->readPack_state == libssh2_NB_state_jump1) {
++        session->readPack_state = libssh2_NB_state_idle;
++        encrypted = session->readPack_encrypted;
++        goto libssh2_packet_read_point1;
++    }
++
++    do {
++        if (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
++            return PACKET_NONE;
++        }
++
++        if (session->state & LIBSSH2_STATE_NEWKEYS) {
++            blocksize = session->remote.crypt->blocksize;
++        } else {
++            encrypted = 0;      /* not encrypted */
++            blocksize = 5;      /* not strictly true, but we can use 5 here to
++                                   make the checks below work fine still */
++        }
++
++        /* read/use a whole big chunk into a temporary area stored in
++           the LIBSSH2_SESSION struct. We will decrypt data from that
++           buffer into the packet buffer so this temp one doesn't have
++           to be able to keep a whole SSH packet, just be large enough
++           so that we can read big chunks from the network layer. */
++
++        /* how much data there is remaining in the buffer to deal with
++           before we should read more from the network */
++        remainbuf = p->writeidx - p->readidx;
++
++        /* if remainbuf turns negative we have a bad internal error */
++        assert(remainbuf >= 0);
++
++        if (remainbuf < blocksize) {
++            /* If we have less than a blocksize left, it is too
++               little data to deal with, read more */
++            ssize_t nread;
++
++            /* move any remainder to the start of the buffer so
++               that we can do a full refill */
++            if (remainbuf) {
++                memmove(p->buf, &p->buf[p->readidx], remainbuf);
++                p->readidx = 0;
++                p->writeidx = remainbuf;
++            } else {
++                /* nothing to move, just zero the indexes */
++                p->readidx = p->writeidx = 0;
++            }
++
++            /* now read a big chunk from the network into the temp buffer */
++            nread =
++                recv(session->socket_fd, &p->buf[remainbuf],
++                     PACKETBUFSIZE - remainbuf,
++                     LIBSSH2_SOCKET_RECV_FLAGS(session));
++            if (nread <= 0) {
++                /* check if this is due to EAGAIN and return the special
++                   return code if so, error out normally otherwise */
++#ifdef WIN32
++                switch (WSAGetLastError()) {
++                case WSAEWOULDBLOCK:
++                    errno = EAGAIN;
++                    break;
++
++                case WSAENOTSOCK:
++                    errno = EBADF;
++                    break;
++
++                case WSAENOTCONN:
++                case WSAECONNABORTED:
++                    errno = WSAENOTCONN;
++                    break;
++
++                case WSAEINTR:
++                    errno = EINTR;
++                    break;
++                }
++#endif /* WIN32 */
++                if ((nread < 0) && (errno == EAGAIN)) {
++                    session->socket_block_directions =
++                        LIBSSH2_SESSION_BLOCK_INBOUND;
++                    return PACKET_EAGAIN;
++                }
++                return PACKET_FAIL;
++            }
++            debugdump(session, "libssh2_packet_read() raw",
++                      &p->buf[remainbuf], nread);
++            /* advance write pointer */
++            p->writeidx += nread;
++
++            /* update remainbuf counter */
++            remainbuf = p->writeidx - p->readidx;
++        }
++
++        /* how much data to deal with from the buffer */
++        numbytes = remainbuf;
++
++        if (!p->total_num) {
++            /* No payload package area allocated yet. To know the
++               size of this payload, we need to decrypt the first
++               blocksize data. */
++
++            if (numbytes < blocksize) {
++                /* we can't act on anything less than blocksize, but this
++                   check is only done for the initial block since once we have
++                   got the start of a block we can in fact deal with fractions
++                */
++                return PACKET_EAGAIN;
++            }
++
++            if (encrypted) {
++                rc = decrypt(session, &p->buf[p->readidx], block, blocksize);
++                if (rc != PACKET_NONE) {
++                    return rc;
++                }
++                /* save the first 5 bytes of the decrypted package, to be
++                   used in the hash calculation later down. */
++                memcpy(p->init, &p->buf[p->readidx], 5);
++            } else {
++                /* the data is plain, just copy it verbatim to
++                   the working block buffer */
++                memcpy(block, &p->buf[p->readidx], blocksize);
++            }
++
++            /* advance the read pointer */
++            p->readidx += blocksize;
++
++            /* we now have the initial blocksize bytes decrypted,
++             * and we can extract packet and padding length from it
++             */
++            p->packet_length = libssh2_ntohu32(block);
++            p->padding_length = block[4];
++
++            /* total_num is the number of bytes following the initial
++               (5 bytes) packet length and padding length fields */
++            p->total_num =
++                p->packet_length - 1 +
++                (encrypted ? session->remote.mac->mac_len : 0);
++
++            /* RFC4253 section 6.1 Maximum Packet Length says:
++             *
++             * "All implementations MUST be able to process
++             * packets with uncompressed payload length of 32768
++             * bytes or less and total packet size of 35000 bytes
++             * or less (including length, padding length, payload,
++             * padding, and MAC.)."
++             */
++            if (p->total_num > LIBSSH2_PACKET_MAXPAYLOAD) {
++                return PACKET_TOOBIG;
++            }
++
++            /* Get a packet handle put data into. We get one to
++               hold all data, including padding and MAC. */
++            p->payload = LIBSSH2_ALLOC(session, p->total_num);
++            if (!p->payload) {
++                return PACKET_ENOMEM;
++            }
++            /* init write pointer to start of payload buffer */
++            p->wptr = p->payload;
++
++            if (blocksize > 5) {
++                /* copy the data from index 5 to the end of
++                   the blocksize from the temporary buffer to
++                   the start of the decrypted buffer */
++                memcpy(p->wptr, &block[5], blocksize - 5);
++                p->wptr += blocksize - 5;       /* advance write pointer */
++            }
++
++            /* init the data_num field to the number of bytes of
++               the package read so far */
++            p->data_num = p->wptr - p->payload;
++
++            /* we already dealt with a blocksize worth of data */
++            numbytes -= blocksize;
++        }
++
++        /* how much there is left to add to the current payload
++           package */
++        remainpack = p->total_num - p->data_num;
++
++        if (numbytes > remainpack) {
++            /* if we have more data in the buffer than what is going into this
++               particular packet, we limit this round to this packet only */
++            numbytes = remainpack;
++        }
++
++        if (encrypted) {
++            /* At the end of the incoming stream, there is a MAC,
++               and we don't want to decrypt that since we need it
++               "raw". We MUST however decrypt the padding data
++               since it is used for the hash later on. */
++            int skip = session->remote.mac->mac_len;
++
++            /* if what we have plus numbytes is bigger than the
++               total minus the skip margin, we should lower the
++               amount to decrypt even more */
++            if ((p->data_num + numbytes) > (p->total_num - skip)) {
++                numdecrypt = (p->total_num - skip) - p->data_num;
++            } else {
++                int frac;
++                numdecrypt = numbytes;
++                frac = numdecrypt % blocksize;
++                if (frac) {
++                    /* not an aligned amount of blocks,
++                       align it */
++                    numdecrypt -= frac;
++                    /* and make it no unencrypted data
++                       after it */
++                    numbytes = 0;
++                }
++            }
++        } else {
++            /* unencrypted data should not be decrypted at all */
++            numdecrypt = 0;
++        }
++
++        /* if there are bytes to decrypt, do that */
++        if (numdecrypt > 0) {
++            /* now decrypt the lot */
++            rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt);
++            if (rc != PACKET_NONE) {
++                return rc;
++            }
++
++            /* advance the read pointer */
++            p->readidx += numdecrypt;
++            /* advance write pointer */
++            p->wptr += numdecrypt;
++            /* increse data_num */
++            p->data_num += numdecrypt;
++
++            /* bytes left to take care of without decryption */
++            numbytes -= numdecrypt;
++        }
++
++        /* if there are bytes to copy that aren't decrypted, simply
++           copy them as-is to the target buffer */
++        if (numbytes > 0) {
++            memcpy(p->wptr, &p->buf[p->readidx], numbytes);
++
++            /* advance the read pointer */
++            p->readidx += numbytes;
++            /* advance write pointer */
++            p->wptr += numbytes;
++            /* increse data_num */
++            p->data_num += numbytes;
++        }
++
++        /* now check how much data there's left to read to finish the
++           current packet */
++        remainpack = p->total_num - p->data_num;
++
++        if (!remainpack) {
++            /* we have a full packet */
++          libssh2_packet_read_point1:
++            rc = fullpacket(session, encrypted);
++            if (rc == PACKET_EAGAIN) {
++
++                if (session->packAdd_state != libssh2_NB_state_idle)
++                {
++                    /* fullpacket only returns PACKET_EAGAIN if
++                     * libssh2_packet_add returns PACKET_EAGAIN. If that
++                     * returns PACKET_EAGAIN but the packAdd_state is idle,
++                     * then the packet has been added to the brigade, but some
++                     * immediate action that was taken based on the packet
++                     * type (such as key re-exchange) is not yet complete.
++                     * Clear the way for a new packet to be read in.
++                     */
++                    session->readPack_encrypted = encrypted;
++                    session->readPack_state = libssh2_NB_state_jump1;
++                }
++
++                return PACKET_EAGAIN;
++            }
++
++            p->total_num = 0;   /* no packet buffer available */
++
++            return rc;
++        }
++    } while (1);                /* loop */
++
++    return PACKET_FAIL;         /* we never reach this point */
++}
++
++/* }}} */
++
++static libssh2pack_t
++send_existing(LIBSSH2_SESSION * session, unsigned char *data,
++              unsigned long data_len, ssize_t * ret)
++{
++    ssize_t rc;
++    ssize_t length;
++    struct transportpacket *p = &session->packet;
++
++    if (!p->outbuf) {
++        *ret = 0;
++        return PACKET_NONE;
++    }
++
++    /* send as much as possible of the existing packet */
++    if ((data != p->odata) || (data_len != p->olen)) {
++        /* When we are about to complete the sending of a packet, it is vital
++           that the caller doesn't try to send a new/different packet since
++           we don't add this one up until the previous one has been sent. To
++           make the caller really notice his/hers flaw, we return error for
++           this case */
++        return PACKET_BADUSE;
++    }
++
++    *ret = 1;                   /* set to make our parent return */
++
++    /* number of bytes left to send */
++    length = p->ototal_num - p->osent;
++
++    rc = send(session->socket_fd, &p->outbuf[p->osent], length,
++              LIBSSH2_SOCKET_SEND_FLAGS(session));
++
++    if (rc == length) {
++        /* the remainder of the package was sent */
++        LIBSSH2_FREE(session, p->outbuf);
++        p->outbuf = NULL;
++        p->ototal_num = 0;
++    } else if (rc < 0) {
++        /* nothing was sent */
++        if (errno != EAGAIN) {
++            /* send failure! */
++            return PACKET_FAIL;
++        }
++        session->socket_block_directions = LIBSSH2_SESSION_BLOCK_OUTBOUND;
++        return PACKET_EAGAIN;
++    }
++
++    debugdump(session, "libssh2_packet_write send()", &p->outbuf[p->osent],
++              length);
++    p->osent += length;         /* we sent away this much data */
++
++    return PACKET_NONE;
++}
++
++/* {{{ libssh2_packet_write
++ * Send a packet, encrypting it and adding a MAC code if necessary
++ * Returns 0 on success, non-zero on failure.
++ *
++ * Returns PACKET_EAGAIN if it would block - and if it does so, you should
++ * call this function again as soon as it is likely that more data can be
++ * sent, and this function should then be called with the same argument set
++ * (same data pointer and same data_len) until zero or failure is returned.
++ *
++ * NOTE: this function does not verify that 'data_len' is less than ~35000
++ * which is what all implementations should support at least as packet size.
++ * (RFC4253 section 6.1)
++ */
++int
++libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
++                     unsigned long data_len)
++{
++    int blocksize =
++        (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->
++        blocksize : 8;
++    int padding_length;
++    int packet_length;
++    int total_length;
++    int free_data = 0;
++#ifdef RANDOM_PADDING
++    int rand_max;
++    int seed = data[0];         /* FIXME: make this random */
++#endif
++    struct transportpacket *p = &session->packet;
++    int encrypted;
++    int i;
++    ssize_t ret;
++    libssh2pack_t rc;
++    unsigned char *orgdata = data;
++    unsigned long orgdata_len = data_len;
++
++    debugdump(session, "libssh2_packet_write plain", data, data_len);
++
++    /* FIRST, check if we have a pending write to complete */
++    rc = send_existing(session, data, data_len, &ret);
++    if (rc || ret) {
++        return rc;
++    }
++
++    encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0;
++
++    /* check if we should compress */
++    if (encrypted && strcmp(session->local.comp->name, "none")) {
++        if (session->local.comp->comp(session, 1, &data, &data_len,
++                                      LIBSSH2_PACKET_MAXCOMP,
++                                      &free_data, data, data_len,
++                                      &session->local.comp_abstract)) {
++            return PACKET_COMPRESS;     /* compression failure */
++        }
++    }
++
++    /* RFC4253 says: Note that the length of the concatenation of
++       'packet_length', 'padding_length', 'payload', and 'random padding'
++       MUST be a multiple of the cipher block size or 8, whichever is
++       larger. */
++
++    /* Plain math: (4 + 1 + packet_length + padding_length) % blocksize == 0 */
++
++    packet_length = data_len + 1 + 4;   /* 1 is for padding_length field
++                                           4 for the packet_length field */
++
++    /* at this point we have it all except the padding */
++
++    /* first figure out our minimum padding amount to make it an even
++       block size */
++    padding_length = blocksize - (packet_length % blocksize);
++
++    /* if the padding becomes too small we add another blocksize worth
++       of it (taken from the original libssh2 where it didn't have any
++       real explanation) */
++    if (padding_length < 4) {
++        padding_length += blocksize;
++    }
++#ifdef RANDOM_PADDING
++    /* FIXME: we can add padding here, but that also makes the packets
++       bigger etc */
++
++    /* now we can add 'blocksize' to the padding_length N number of times
++       (to "help thwart traffic analysis") but it must be less than 255 in
++       total */
++    rand_max = (255 - padding_length) / blocksize + 1;
++    padding_length += blocksize * (seed % rand_max);
++#endif
++
++    packet_length += padding_length;
++
++    /* append the MAC length to the total_length size */
++    total_length =
++        packet_length + (encrypted ? session->local.mac->mac_len : 0);
++
++    /* allocate memory to store the outgoing packet in, in case we can't
++       send the whole one and thus need to keep it after this function
++       returns. */
++    p->outbuf = LIBSSH2_ALLOC(session, total_length);
++    if (!p->outbuf) {
++        return PACKET_ENOMEM;
++    }
++
++    /* store packet_length, which is the size of the whole packet except
++       the MAC and the packet_length field itself */
++    libssh2_htonu32(p->outbuf, packet_length - 4);
++    /* store padding_length */
++    p->outbuf[4] = padding_length;
++    /* copy the payload data */
++    memcpy(p->outbuf + 5, data, data_len);
++    /* fill the padding area with random junk */
++    libssh2_random(p->outbuf + 5 + data_len, padding_length);
++    if (free_data) {
++        LIBSSH2_FREE(session, data);
++    }
++
++    if (encrypted) {
++        /* Calculate MAC hash. Put the output at index packet_length,
++           since that size includes the whole packet. The MAC is
++           calculated on the entire unencrypted packet, including all
++           fields except the MAC field itself. */
++        session->local.mac->hash(session, p->outbuf + packet_length,
++                                 session->local.seqno, p->outbuf,
++                                 packet_length, NULL, 0,
++                                 &session->local.mac_abstract);
++
++        /* Encrypt the whole packet data, one block size at a time.
++           The MAC field is not encrypted. */
++        for(i = 0; i < packet_length; i += session->local.crypt->blocksize) {
++            unsigned char *ptr = &p->outbuf[i];
++            if (session->local.crypt->crypt(session, ptr,
++                                            &session->local.crypt_abstract))
++                return PACKET_FAIL;     /* encryption failure */
++        }
++    }
++
++    session->local.seqno++;
++
++    ret = send(session->socket_fd, p->outbuf, total_length,
++               LIBSSH2_SOCKET_SEND_FLAGS(session));
++
++    if (ret != -1) {
++        debugdump(session, "libssh2_packet_write send()", p->outbuf, ret);
++    }
++    if (ret != total_length) {
++        if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
++            /* the whole packet could not be sent, save the rest */
++            session->socket_block_directions = LIBSSH2_SESSION_BLOCK_OUTBOUND;
++            p->odata = orgdata;
++            p->olen = orgdata_len;
++            p->osent = (ret == -1) ? 0 : ret;
++            p->ototal_num = total_length;
++            return PACKET_EAGAIN;
++        }
++        return PACKET_FAIL;
++    }
++
++    /* the whole thing got sent away */
++    p->odata = NULL;
++    p->olen = 0;
++    LIBSSH2_FREE(session, p->outbuf);
++    p->outbuf = NULL;
++
++    return PACKET_NONE;         /* all is good */
++}
++
++/* }}} */
++
+
+Property changes on: libssh2/src/transport.c
+___________________________________________________________________
+Added: svn:mime-type
+   + text/x-c
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.1
+Added: svn:eol-style
+   + native
+Added: svn:executable
+   + *
+
+
+Property changes on: libssh2/src
+___________________________________________________________________
+Added: svn:ignore
+   + libssh2_config.h
+
+
+Index: package.xml
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/xml
+
+Property changes on: package.xml
+___________________________________________________________________
+Deleted: svn:mime-type
+   - application/xml
+
+Index: ssh2_fopen_wrappers.c
+===================================================================
+--- ssh2_fopen_wrappers.c      (.../tags/RELEASE_0_11_0)
++++ ssh2_fopen_wrappers.c      (.../trunk)
+@@ -46,7 +46,7 @@
+       libssh2_channel_set_blocking(abstract->channel, abstract->is_blocking);
+               
+       readstate = libssh2_channel_read_ex(abstract->channel, abstract->streamid, buf, count);
+-      return (readstate == LIBSSH2_ERROR_EAGAIN ? 0 : readstate);
++      return (readstate < 0 ? 0 : readstate);
+ }
+ static int php_ssh2_channel_stream_close(php_stream *stream, int close_handle TSRMLS_DC)
+
+Property changes on: ssh2_fopen_wrappers.c
+___________________________________________________________________
+Modified: cvs2svn:cvs-rev
+   - 1.15
+   + 1.16
+
+Index: php_ssh2.h
+===================================================================
+--- php_ssh2.h (.../tags/RELEASE_0_11_0)
++++ php_ssh2.h (.../trunk)
+@@ -101,6 +101,10 @@
+ } php_ssh2_pkey_subsys_data;
+ #endif
++#ifndef PHP_WIN32
++#define closesocket(s)        close(s)
++#endif
++
+ #ifdef ZTS
+ #define SSH2_TSRMLS_SET(datap)                ((php_ssh2_session_data*)(datap))->tsrm_ls = TSRMLS_C
+ #define SSH2_TSRMLS_FETCH(datap)      TSRMLS_D = ((php_ssh2_session_data*)(datap))->tsrm_ls
+@@ -109,6 +113,12 @@
+ #define SSH2_TSRMLS_FETCH(datap)
+ #endif
++#if (PHP_MAJOR_VERSION == 5) && (PHP_MINOR_VERSION >= 3)
++#define ZEND_IS_CALLABLE_TSRMLS_CC            TSRMLS_CC
++#else
++#define ZEND_IS_CALLABLE_TSRMLS_CC
++#endif
++
+ /* < 5.3 compatibility */
+ #ifndef Z_REFCOUNT_P
+ #define Z_REFCOUNT_P(pz)              (pz)->refcount
+
+Property changes on: php_ssh2.h
+___________________________________________________________________
+Modified: cvs2svn:cvs-rev
+   - 1.12
+   + 1.14
+
+Index: EXPERIMENTAL
+===================================================================
+
+Property changes on: EXPERIMENTAL
+___________________________________________________________________
+Added: svn:eol-style
+   + native
+Added: svn:keywords
+   + Id Rev Revision Date LastChangedDate LastChangedRevision Author LastChangedBy HeadURL URL
+Added: cvs2svn:cvs-rev
+   + 1.1
+
+
+Property changes on: .
+___________________________________________________________________
+Added: svn:ignore
+   + #*#
+*.dsw
+*.la
+*.lo
+*.ncb
+*.opt
+*.plg
+*.tgz
+*~
+.#*
+.deps
+.libs
+Debug
+Debug_TS
+Makefile
+Makefile.fragments
+Makefile.global
+Makefile.objects
+Release
+Release_TS
+Release_TSDbg
+Release_TS_inline
+Release_inline
+acinclude.m4
+aclocal.m4
+autom4te.cache
+build
+config.cache
+config.guess
+config.h
+config.h.in
+config.log
+config.nice
+config.status
+config.sub
+configure
+configure.in
+conftest
+conftest.c
+include
+install-sh
+libs.mk
+libtool
+ltmain.sh
+missing
+mkinstalldirs
+modules
+scan_makefile_in.awk
+*.gcda
+*.gcno
+run-tests.php
+
+
diff --git a/branch.sh b/branch.sh
new file mode 100644 (file)
index 0000000..fbb16a9
--- /dev/null
+++ b/branch.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+set -e
+pecl=ssh2
+svn=http://svn.php.net/repository/pecl/$pecl
+tag=RELEASE_0_11_0
+out=branch.diff
+
+d=$-
+filter() {
+       set -$d
+       # remove revno's for smaller diffs
+       sed -e 's,^\([-+]\{3\} .*\)\t(revision [0-9]\+)$,\1,'
+}
+
+old=$svn/tags/$tag
+new=$svn/trunk
+echo >&2 "Running diff: $old -> $new"
+LC_ALL=C svn diff --old=$old --new=$new | filter > $out.tmp
+
+if cmp -s $out{,.tmp}; then
+       echo >&2 "No new diffs..."
+       rm -f $out.tmp
+       exit 0
+fi
+mv -f $out{.tmp,}
index e2046ef0c6d6ff8103f7a468fafeb378b3952623..7753cdca491ca9472ac7fd07b4769cd9ae641afa 100644 (file)
@@ -1,15 +1,16 @@
 %define                modname ssh2
-%define                status          beta
+%define                status  beta
 Summary:       %{modname} - bindings for the libssh2 library
 Summary(pl.UTF-8):     %{modname} - dowiązania do biblioteki libssh2
 Name:          php-pecl-%{modname}
 Version:       0.11.0
-Release:       2
+Release:       3
 License:       PHP
 Group:         Development/Languages/PHP
 Source0:       http://pecl.php.net/get/%{modname}-%{version}.tgz
 # Source0-md5: 9f5dcd5b92299458389038f7318cbc46
 Patch0:                php-pecl-ssh2-libssh2.patch
+Patch1:                branch.diff
 URL:           http://pecl.php.net/package/ssh2/
 BuildRequires: libssh2-devel >= 0.16
 BuildRequires: openssl-devel >= 0.9.7d
@@ -34,6 +35,7 @@ To rozszerzenie ma w PECL status: %{status}.
 %setup -qc
 mv %{modname}-%{version}/* .
 %patch0 -p0
+%patch1 -p0
 
 %build
 phpize
This page took 0.977771 seconds and 4 git commands to generate.