diff --git a/Makefile.am b/Makefile.am
index 3060578..b13f5b9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,19 +1,10 @@
 AUTOMAKE_OPTIONS = foreign nostdinc
 
-SUBDIRS = src tests
+SUBDIRS = src example tests
 
 include_HEADERS = include/libssh2.h include/libssh2_publickey.h	\
  include/libssh2_sftp.h
 
-# and a sample tool
-noinst_PROGRAMS = ssh2_sample
-
-INCLUDES = -I$(top_srcdir)/include
-
-ssh2_sample_SOURCES = ssh2_sample.c
-
-ssh2_sample_LDADD = src/libssh2.la
-
 EXTRA_DIST = LICENSE win32
 
 ACLOCAL_AMFLAGS = -I m4
diff --git a/configure.in b/configure.in
index b7d3ba2..bcea2ab 100644
--- a/configure.in
+++ b/configure.in
@@ -224,7 +224,7 @@ AC_ARG_ENABLE(debug-errors,
 	AC_HELP_STRING([--enable-debug-errors],[Output failure events to stderr]),
 	[AC_DEFINE(LIBSSH2_DEBUG_ERRORS, 1, [Output failure events to stderr])])
 AC_ARG_ENABLE(debug-all,
-	AC_HELP_STRING([--enable-debug-all],[Output debugging info for all layers to stderr]),
+	AC_HELP_STRING([--enable-debug],[Enable debug]),
 	[
 		AC_DEFINE(LIBSSH2_DEBUG_TRANSPORT, 1, [Output transport layer debugging info to stderr])
 		AC_DEFINE(LIBSSH2_DEBUG_KEX, 1, [Output Key Exchange debugging info to stderr])
@@ -273,5 +273,7 @@ AC_C_INLINE
 
 AC_CONFIG_FILES([Makefile
                  src/Makefile
-                 tests/Makefile])
+                 tests/Makefile
+                 example/Makefile
+                 example/simple/Makefile])
 AC_OUTPUT
diff --git a/example/Makefile.am b/example/Makefile.am
new file mode 100644
index 0000000..3f2227e
--- /dev/null
+++ b/example/Makefile.am
@@ -0,0 +1,2 @@
+AUTOMAKE_OPTIONS = foreign nostdinc
+SUBDIRS = simple
diff --git a/example/simple/Makefile.am b/example/simple/Makefile.am
new file mode 100644
index 0000000..b66ab69
--- /dev/null
+++ b/example/simple/Makefile.am
@@ -0,0 +1,17 @@
+AUTOMAKE_OPTIONS = foreign nostdinc
+
+# samples
+noinst_PROGRAMS = ssh2 scp_nonblock sftp_nonblock sftp scp
+
+INCLUDES = -I$(top_srcdir)/include
+LDADD = $(top_builddir)/src/libssh2.la
+
+ssh2_SOURCES = ssh2.c
+
+sftp_SOURCES = sftp.c
+
+scp_nonblock_SOURCES = scp_nonblock.c
+
+sftp_nonblock_SOURCES = sftp_nonblock.c
+
+scp_SOURCES = scp.c
diff --git a/example/simple/scp_nonblock.c b/example/simple/scp_nonblock.c
new file mode 100644
index 0000000..d4a20b8
--- /dev/null
+++ b/example/simple/scp_nonblock.c
@@ -0,0 +1,193 @@
+/*
+ * $Id: scp_nonblock.c,v 1.1 2007/02/02 16:21:20 bagder Exp $
+ *
+ * Sample showing how to do SCP transfers in a non-blocking manner.
+ */
+
+#include <libssh2.h>
+
+#ifndef WIN32
+# include <netinet/in.h>
+# include <sys/socket.h>
+# include <unistd.h>
+#else
+# include <winsock2.h>
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+
+int main(int argc, char *argv[])
+{
+	int sock, i, auth_pw = 1;
+	struct sockaddr_in sin;
+	const char *fingerprint;
+	LIBSSH2_SESSION *session;
+	LIBSSH2_CHANNEL *channel;
+	char *username=(char *)"username";
+	char *password=(char *)"password";
+	char *scppath=(char *)"/tmp/TEST";
+	struct stat fileinfo;
+	int rc;
+	off_t got=0;
+
+#ifdef WIN32
+	WSADATA wsadata;
+
+	WSAStartup(WINSOCK_VERSION, &wsadata);
+#endif
+
+	/* Ultra basic "connect to port 22 on localhost"
+	 * Your code is responsible for creating the socket establishing the
+	 * connection
+	 */
+	sock = socket(AF_INET, SOCK_STREAM, 0);
+
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(22);
+	sin.sin_addr.s_addr = htonl(0x7F000001);
+	if (connect(sock, (struct sockaddr*)(&sin),
+		    sizeof(struct sockaddr_in)) != 0) {
+		fprintf(stderr, "failed to connect!\n");
+		return -1;
+	}
+
+	/* We set the socket non-blocking. We do it after the connect just to
+	   simplify the example code. */
+#ifdef F_SETFL
+	/* FIXME: this can/should be done in a more portable manner */
+	rc = fcntl(sock, F_GETFL, 0);
+	fcntl(sock, F_SETFL, rc | O_NONBLOCK);
+#else
+#error "add support for setting the socket non-blocking here"
+#endif
+
+	/* Create a session instance
+	 */
+	session = libssh2_session_init();
+	if(!session)
+		return -1;
+
+	/* ... start it up. This will trade welcome banners, exchange keys,
+	 * and setup crypto, compression, and MAC layers
+	 */
+	rc = libssh2_session_startup(session, sock);
+	if(rc) {
+		fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
+		return -1;
+	}
+
+	/* At this point we havn't yet authenticated.  The first thing to do
+	 * is check the hostkey's fingerprint against our known hosts Your app
+	 * may have it hard coded, may go to a file, may present it to the
+	 * user, that's your call
+	 */
+	fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
+	printf("Fingerprint: ");
+	for(i = 0; i < 16; i++) {
+		printf("%02X ", (unsigned char)fingerprint[i]);
+	}
+	printf("\n");
+
+	if(argc > 1) {
+		username = argv[1];
+	}
+	if(argc > 2) {
+		password = argv[2];
+	}
+	if(argc > 3) {
+		scppath = argv[3];
+	}
+
+	if (auth_pw) {
+		/* We could authenticate via password */
+		if (libssh2_userauth_password(session, username, password)) {
+			printf("Authentication by password failed.\n");
+			goto shutdown;
+		}
+	} else {
+		/* Or by public key */
+		if (libssh2_userauth_publickey_fromfile(session, username,
+							"/home/username/.ssh/id_rsa.pub",
+							"/home/username/.ssh/id_rsa",
+							password)) {
+			printf("\tAuthentication by public key failed\n");
+			goto shutdown;
+		}
+	}
+
+	/* Request a file via SCP */
+	channel = libssh2_scp_recv(session, scppath, &fileinfo);
+
+	if (!channel) {
+		fprintf(stderr, "Unable to open a session\n");
+		goto shutdown;
+	}
+	fprintf(stderr, "libssh2_scp_recv() is done, now receive data!\n");
+
+	while(got < fileinfo.st_size) {
+		char mem[1000];
+
+		struct timeval timeout;
+		int rc;
+		fd_set fd;
+
+		do {
+			int amount=sizeof(mem);
+
+			if((fileinfo.st_size -got) < amount) {
+				amount = fileinfo.st_size -got;
+			}
+
+			/* loop until we block */
+			rc = libssh2_channel_readnb(channel, mem, amount);
+			if(rc > 0) {
+				write(2, mem, rc);
+				got += rc;
+			}
+		} while (rc > 0);
+
+		if(rc == LIBSSH2CHANNEL_EAGAIN) {
+			/* this is due to blocking that would occur otherwise
+			   so we loop on this condition */
+
+			timeout.tv_sec = 10;
+			timeout.tv_usec = 0;
+
+			FD_ZERO(&fd);
+
+			FD_SET(sock, &fd);
+
+			rc = select(sock+1, &fd, &fd, NULL, &timeout);
+			if(rc <= 0) {
+				/* negative is error
+				   0 is timeout */
+				fprintf(stderr, "SCP timed out: %d\n", rc);
+			}
+			continue;
+		}
+		break;
+	}
+
+	libssh2_channel_free(channel);
+	channel = NULL;
+
+ shutdown:
+
+	libssh2_session_disconnect(session,
+				   "Normal Shutdown, Thank you for playing");
+	libssh2_session_free(session);
+
+#ifdef WIN32
+	Sleep(1000);
+	closesocket(sock);
+#else
+	sleep(1);
+	close(sock);
+#endif
+printf("all done\n");
+	return 0;
+}
diff --git a/example/simple/sftp.c b/example/simple/sftp.c
index 6a75fca..c9aa756 100644
--- a/example/simple/sftp.c
+++ b/example/simple/sftp.c
@@ -1,5 +1,5 @@
 /*
- * $Id: sftp.c,v 1.1 2007/01/24 14:15:36 bagder Exp $
+ * $Id: sftp.c,v 1.2 2007/02/02 16:21:20 bagder Exp $
  *
  * Sample showing how to do SFTP transfers.
  */
@@ -109,6 +109,7 @@ int main(int argc, char *argv[])
 		}
 	}
 
+	fprintf(stderr, "libssh2_sftp_init()!\n");
 	sftp_session = libssh2_sftp_init(session);
 
 	if (!sftp_session) {
@@ -116,6 +117,7 @@ int main(int argc, char *argv[])
 		goto shutdown;
 	}
 
+	fprintf(stderr, "libssh2_sftp_open()!\n");
 	/* Request a file via SFTP */
 	sftp_handle =
 		libssh2_sftp_open(sftp_session, sftppath, LIBSSH2_FXF_READ, 0);
@@ -129,6 +131,7 @@ int main(int argc, char *argv[])
 		char mem[512];
 
 		/* loop until we fail */
+		fprintf(stderr, "libssh2_sftp_read()!\n");
 		rc = libssh2_sftp_read(sftp_handle, mem, sizeof(mem));
 		if(rc > 0) {
 			write(2, mem, rc);
diff --git a/example/simple/sftp_nonblock.c b/example/simple/sftp_nonblock.c
new file mode 100644
index 0000000..f24f4e2
--- /dev/null
+++ b/example/simple/sftp_nonblock.c
@@ -0,0 +1,281 @@
+/*
+ * $Id: sftp_nonblock.c,v 1.1 2007/02/02 16:21:20 bagder Exp $
+ *
+ * Sample showing how to do SFTP transfers in a non-blocking manner.
+ *
+ * It will first download a given source file, store it locally and then
+ * upload the file again to a given destination file.
+ *
+ * Using the SFTP server running on 127.0.0.1
+ */
+
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+
+#ifndef WIN32
+# include <netinet/in.h>
+# include <sys/socket.h>
+# include <unistd.h>
+#else
+# include <winsock2.h>
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#define STORAGE "/tmp/sftp-storage" /* this is the local file name this
+                                       example uses to store the downloaded
+                                       file in */
+
+int main(int argc, char *argv[])
+{
+        int sock, i, auth_pw = 1;
+        struct sockaddr_in sin;
+        const char *fingerprint;
+        LIBSSH2_SESSION *session;
+        char *username=(char *)"username";
+        char *password=(char *)"password";
+        char *sftppath=(char *)"/tmp/TEST"; /* source path */
+        char *dest=(char *)"/tmp/TEST2";    /* destination path */
+        int rc;
+        LIBSSH2_SFTP *sftp_session;
+        LIBSSH2_SFTP_HANDLE *sftp_handle;
+        FILE *tempstorage;
+        char mem[1000];
+        struct timeval timeout;
+        fd_set fd;
+
+#ifdef WIN32
+        WSADATA wsadata;
+
+        WSAStartup(WINSOCK_VERSION, &wsadata);
+#endif
+
+        /* Ultra basic "connect to port 22 on localhost"
+         * The application is responsible for creating the socket establishing
+         * the connection
+         */
+        sock = socket(AF_INET, SOCK_STREAM, 0);
+
+        sin.sin_family = AF_INET;
+        sin.sin_port = htons(22);
+        sin.sin_addr.s_addr = htonl(0x7F000001);
+        if (connect(sock, (struct sockaddr*)(&sin),
+                    sizeof(struct sockaddr_in)) != 0) {
+                fprintf(stderr, "failed to connect!\n");
+                return -1;
+        }
+
+        /* We set the socket non-blocking. We do it after the connect just to
+           simplify the example code. */
+#ifdef F_SETFL
+        /* FIXME: this can/should be done in a more portable manner */
+        rc = fcntl(sock, F_GETFL, 0);
+        fcntl(sock, F_SETFL, rc | O_NONBLOCK);
+#else
+#error "add support for setting the socket non-blocking here"
+#endif
+
+        /* Create a session instance
+         */
+        session = libssh2_session_init();
+        if(!session)
+                return -1;
+
+        /* ... start it up. This will trade welcome banners, exchange keys,
+         * and setup crypto, compression, and MAC layers
+         */
+        rc = libssh2_session_startup(session, sock);
+        if(rc) {
+                fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
+                return -1;
+        }
+
+        /* At this point we havn't yet authenticated.  The first thing to do
+         * is check the hostkey's fingerprint against our known hosts Your app
+         * may have it hard coded, may go to a file, may present it to the
+         * user, that's your call
+         */
+        fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
+        printf("Fingerprint: ");
+        for(i = 0; i < 16; i++) {
+                printf("%02X ", (unsigned char)fingerprint[i]);
+        }
+        printf("\n");
+
+        if(argc > 1) {
+                username = argv[1];
+        }
+        if(argc > 2) {
+                password = argv[2];
+        }
+        if(argc > 3) {
+                sftppath = argv[3];
+        }
+        if(argc > 4) {
+                dest = argv[4];
+        }
+
+        tempstorage = fopen(STORAGE, "wb");
+        if(!tempstorage) {
+                printf("Can't open temp storage file %s\n", STORAGE);
+                goto shutdown;
+        }
+
+        if (auth_pw) {
+                /* We could authenticate via password */
+                if (libssh2_userauth_password(session, username, password)) {
+                        printf("Authentication by password failed.\n");
+                        goto shutdown;
+                }
+        } else {
+                /* Or by public key */
+                if (libssh2_userauth_publickey_fromfile(session, username,
+                                                        "/home/username/.ssh/id_rsa.pub",
+                                                        "/home/username/.ssh/id_rsa",
+                                                        password)) {
+                        printf("\tAuthentication by public key failed\n");
+                        goto shutdown;
+                }
+        }
+
+        sftp_session = libssh2_sftp_init(session);
+
+        if (!sftp_session) {
+                fprintf(stderr, "Unable to init SFTP session\n");
+                goto shutdown;
+        }
+
+        /* Request a file via SFTP */
+        sftp_handle =
+                libssh2_sftp_open(sftp_session, sftppath, LIBSSH2_FXF_READ, 0);
+
+        if (!sftp_handle) {
+                fprintf(stderr, "Unable to open file with SFTP\n");
+                goto shutdown;
+        }
+        fprintf(stderr, "libssh2_sftp_open() is done, now receive data!\n");
+        do {
+                do {
+                        /* read in a loop until we block */
+                        rc = libssh2_sftp_readnb(sftp_handle, mem,
+						 sizeof(mem));
+                        fprintf(stderr, "libssh2_sftp_read returned %d\n",
+                                rc);
+
+                        if(rc > 0) {
+                                /* write to stderr */
+                                write(2, mem, rc);
+                                /* write to temporary storage area */
+                                fwrite(mem, rc, 1, tempstorage);
+                        }
+                } while (rc > 0);
+
+                if(rc != LIBSSH2SFTP_EAGAIN) {
+                        /* error or end of file */
+                        break;
+                }
+
+                timeout.tv_sec = 10;
+                timeout.tv_usec = 0;
+
+                FD_ZERO(&fd);
+
+                FD_SET(sock, &fd);
+
+                /* wait for readable or writeable */
+                rc = select(sock+1, &fd, &fd, NULL, &timeout);
+                if(rc <= 0) {
+                        /* negative is error
+                           0 is timeout */
+                        fprintf(stderr, "SFTP download timed out: %d\n", rc);
+                        break;
+                }
+
+        } while (1);
+
+        libssh2_sftp_close(sftp_handle);
+        fclose(tempstorage);
+
+        tempstorage = fopen(STORAGE, "rb");
+        if(!tempstorage) {
+                /* weird, we can't read the file we just wrote to... */
+                fprintf(stderr, "can't open %s for reading\n", STORAGE);
+                goto shutdown;
+        }
+
+        /* we're done downloading, now reverse the process and upload the
+           temporarily stored data to the destination path */
+        sftp_handle =
+                libssh2_sftp_open(sftp_session, dest,
+                                  LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT,
+                                  LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
+                                  LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
+        if(sftp_handle) {
+                size_t nread;
+		char *ptr;
+                do {
+                        nread = fread(mem, 1, sizeof(mem), tempstorage);
+                        if(nread <= 0) {
+                                /* end of file */
+                                break;
+                        }
+			ptr = mem;
+
+                        do {
+                                /* write data in a loop until we block */
+                                rc = libssh2_sftp_writenb(sftp_handle, ptr,
+							  nread);
+				ptr += rc;
+				nread -= nread;
+                        } while (rc > 0);
+
+                        if(rc != LIBSSH2SFTP_EAGAIN) {
+                                /* error or end of file */
+                                break;
+                        }
+
+                        timeout.tv_sec = 10;
+                        timeout.tv_usec = 0;
+
+                        FD_ZERO(&fd);
+
+                        FD_SET(sock, &fd);
+
+                        /* wait for readable or writeable */
+                        rc = select(sock+1, &fd, &fd, NULL, &timeout);
+                        if(rc <= 0) {
+                                /* negative is error
+                                   0 is timeout */
+                                fprintf(stderr, "SFTP upload timed out: %d\n",
+                                        rc);
+                                break;
+                        }
+                } while (1);
+		fprintf(stderr, "SFTP upload done!\n");
+        }
+        else {
+                fprintf(stderr, "SFTP failed to open destination path: %s\n",
+                        dest);
+        }
+
+        libssh2_sftp_shutdown(sftp_session);
+
+ shutdown:
+
+        libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
+        libssh2_session_free(session);
+
+#ifdef WIN32
+        Sleep(1000);
+        closesocket(sock);
+#else
+        sleep(1);
+        close(sock);
+#endif
+printf("all done\n");
+        return 0;
+}
diff --git a/include/libssh2.h b/include/libssh2.h
index 70addd7..6bb3f73 100644
--- a/include/libssh2.h
+++ b/include/libssh2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms,
@@ -347,9 +347,22 @@ LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const
 #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 int 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))
+LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel,
+					int stream_id, char *buf,
+					size_t buflen);
+LIBSSH2_API int libssh2_channel_readnb_ex(LIBSSH2_CHANNEL *channel,
+					  int stream_id, char *buf,
+					  size_t buflen);
+
+/* This is a public error code from libssh2_channel_read() that is returned
+   when it would otherwise block. */
+#define LIBSSH2CHANNEL_EAGAIN -2
+
+#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))
+#define libssh2_channel_readnb(channel, buf, buflen) \
+  libssh2_channel_readnb_ex((channel), 0, (buf), (buflen))
 
 LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended);
 
@@ -358,14 +371,25 @@ LIBSSH2_API unsigned long libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channe
 
 LIBSSH2_API unsigned long libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, unsigned long adjustment, unsigned char force);
 
-LIBSSH2_API int 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))
+LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel,
+					 int stream_id, const char *buf,
+					 size_t buflen);
+LIBSSH2_API int libssh2_channel_writenb_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_writenb(channel, buf, buflen) \
+  libssh2_channel_writenb_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_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
+LIBSSH2_API int libssh2_channel_get_blocking(LIBSSH2_CHANNEL *channel);
+
 LIBSSH2_API void libssh2_channel_handle_extended_data(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
diff --git a/include/libssh2_sftp.h b/include/libssh2_sftp.h
index d65a044..12884c6 100644
--- a/include/libssh2_sftp.h
+++ b/include/libssh2_sftp.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms,
@@ -38,6 +38,8 @@
 #ifndef LIBSSH2_SFTP_H
 #define LIBSSH2_SFTP_H 1
 
+#include <unistd.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -179,9 +181,19 @@ LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *
 #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 size_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen);
+/* This is a public error code from libssh2_sftp_read() that is returned
+   when it would otherwise block. */
+#define LIBSSH2SFTP_EAGAIN -2
+LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle,
+				      char *buffer, size_t buffer_maxlen);
+LIBSSH2_API ssize_t libssh2_sftp_readnb(LIBSSH2_SFTP_HANDLE *handle,
+					char *buffer, size_t buffer_maxlen);
+
 LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs);
-LIBSSH2_API size_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, size_t count);
+LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle,
+				       const char *buffer, size_t count);
+LIBSSH2_API ssize_t libssh2_sftp_writenb(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)
diff --git a/src/Makefile.am b/src/Makefile.am
index 1940446..cdf1a31 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS = foreign nostdinc
 
 libssh2_la_SOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c	\
 misc.c packet.c publickey.c scp.c session.c sftp.c userauth.c		\
-libssh2_priv.h openssl.h libgcrypt.h pem.c
+libssh2_priv.h openssl.h libgcrypt.h pem.c transport.c
 
 if LIBGCRYPT
 libssh2_la_SOURCES += libgcrypt.c
diff --git a/src/channel.c b/src/channel.c
index 6f7b674..131fe21 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms,
@@ -38,8 +38,11 @@
 #include "libssh2_priv.h"
 #ifndef WIN32
 #include <unistd.h>
+#include <fcntl.h>
 #endif
 
+#include <inttypes.h>
+
 /* {{{ libssh2_channel_nextid
  * Determine the next channel ID we can use at our end
  */
@@ -89,14 +92,14 @@ LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long
 
 #define libssh2_channel_add(session, channel)	\
 {	\
-	if ((session)->channels.tail) {	\
+	if ((session)->channels.tail) { \
 		(session)->channels.tail->next = (channel);	\
 		(channel)->prev = (session)->channels.tail;	\
 	} else {	\
 		(session)->channels.head = (channel);	\
-		(channel)->prev = NULL;	\
+		(channel)->prev = NULL; \
 	}	\
-	(channel)->next = NULL;	\
+	(channel)->next = NULL; \
 	(session)->channels.tail = (channel);	\
 	(channel)->session = (session); \
 }
@@ -104,81 +107,111 @@ LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long
 /* {{{ libssh2_channel_open_session
  * 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)
+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)
 {
-	unsigned char reply_codes[3] = { SSH_MSG_CHANNEL_OPEN_CONFIRMATION, SSH_MSG_CHANNEL_OPEN_FAILURE, 0 };
+	unsigned char reply_codes[3] = {
+		SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
+		SSH_MSG_CHANNEL_OPEN_FAILURE,
+		0
+	};
 	LIBSSH2_CHANNEL *channel = NULL;
 	unsigned long local_channel = libssh2_channel_nextid(session);
 	unsigned char *s, *packet = NULL;
-	unsigned long packet_len = channel_type_len + message_len + 17; /* packet_type(1) + channel_type_len(4) + sender_channel(4) +
-																	   window_size(4) + packet_size(4) */
+	unsigned long packet_len =
+		channel_type_len + message_len + 17; /* packet_type(1) +
+							channel_type_len(4) +
+							sender_channel(4) +
+							window_size(4) +
+							packet_size(4) */
 	unsigned char *data = NULL;
 	unsigned long data_len;
 
 #ifdef LIBSSH2_DEBUG_CONNECTION
-	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Opening Channel - win %d pack %d", window_size, packet_size);
+	_libssh2_debug(session, LIBSSH2_DBG_CONN,
+		       "Opening Channel - win %d pack %d",
+		       window_size, packet_size);
 #endif
 	channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
 	if (!channel) {
-		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate space for channel data", 0);
+		libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+			      "Unable to allocate space for channel data", 0);
 		return NULL;
 	}
 	memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
 
-	channel->channel_type_len	= channel_type_len;
-	channel->channel_type		= LIBSSH2_ALLOC(session, channel_type_len);
+	channel->channel_type_len = channel_type_len;
+	channel->channel_type = LIBSSH2_ALLOC(session, channel_type_len);
 	if (!channel->channel_type) {
-		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating memory for channel type name", 0);
+		libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+			      "Failed allocating memory for channel type name", 0);
 		LIBSSH2_FREE(session, channel);
 		return NULL;
 	}
 	memcpy(channel->channel_type, channel_type, channel_type_len);
 
 	/* REMEMBER: local as in locally sourced */
-	channel->local.id					= local_channel;
-	channel->remote.window_size 		= window_size;
+	channel->local.id			= local_channel;
+	channel->remote.window_size		= window_size;
 	channel->remote.window_size_initial	= window_size;
-	channel->remote.packet_size 		= packet_size;
+	channel->remote.packet_size		= packet_size;
 
 	libssh2_channel_add(session, channel);
 
 	s = packet = LIBSSH2_ALLOC(session, packet_len);
 	if (!packet) {
-		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate temporary space for packet", 0);
+		libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+			      "Unable to allocate temporary space for packet",
+			      0);
 		return NULL;
 	}
 	*(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, channel_type_len);
+	s += 4;
 
-	libssh2_htonu32(s, local_channel);					s += 4;
-	libssh2_htonu32(s, window_size);					s += 4;
-	libssh2_htonu32(s, packet_size);					s += 4;
+	memcpy(s, channel_type, channel_type_len);
+	s += channel_type_len;
+
+	libssh2_htonu32(s, 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;
+		memcpy(s, message, message_len);
+		s += message_len;
 	}
 
 	if (libssh2_packet_write(session, packet, packet_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel-open request", 0);
+		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+			      "Unable to send channel-open request", 0);
 		goto channel_error;
 	}
 
-	if (libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len, 1, packet + 5 + channel_type_len, 4)) {
+	if (libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
+				       1, packet + 5 + channel_type_len, 4)) {
 		goto channel_error;
 	}
 
 	if (data[0] == SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
-		channel->remote.id					= libssh2_ntohu32(data + 5);
-		channel->local.window_size			= libssh2_ntohu32(data + 9);
-		channel->local.window_size_initial	= libssh2_ntohu32(data + 9);
-		channel->local.packet_size			= libssh2_ntohu32(data + 13);
+		channel->remote.id		   = libssh2_ntohu32(data + 5);
+		channel->local.window_size	   = libssh2_ntohu32(data + 9);
+		channel->local.window_size_initial = libssh2_ntohu32(data + 9);
+		channel->local.packet_size	  = libssh2_ntohu32(data + 13);
 #ifdef LIBSSH2_DEBUG_CONNECTION
-		_libssh2_debug(session, LIBSSH2_DBG_CONN, "Connection Established - ID: %lu/%lu win: %lu/%lu pack: %lu/%lu",
-												channel->local.id, channel->remote.id,
-												channel->local.window_size, channel->remote.window_size,
-												channel->local.packet_size, channel->remote.packet_size);
+		_libssh2_debug(session, LIBSSH2_DBG_CONN,
+			       "Connection Established - ID: %lu/%lu win: %lu/%lu pack: %lu/%lu",
+			       channel->local.id, channel->remote.id,
+			       channel->local.window_size, channel->remote.window_size,
+			       channel->local.packet_size, channel->remote.packet_size);
 #endif
 		LIBSSH2_FREE(session, packet);
 		LIBSSH2_FREE(session, data);
@@ -187,7 +220,8 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c
 	}
 
 	if (data[0] == SSH_MSG_CHANNEL_OPEN_FAILURE) {
-		libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Channel open failure", 0);
+		libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
+			      "Channel open failure", 0);
 	}
 
  channel_error:
@@ -217,8 +251,12 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, c
 
 		/* 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, 1) >= 0) ||
-				(libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, &data_len, 1, channel_id, 4, 1) >= 0)) {
+		while  ((libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_DATA,
+					       &data, &data_len, 1, channel_id,
+					       4, 1) >= 0) ||
+			(libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_EXTENDED_DATA,
+					       &data, &data_len, 1, channel_id,
+					       4, 1) >= 0)) {
 			LIBSSH2_FREE(session, data);
 		}
 
@@ -257,10 +295,10 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *se
 	libssh2_htonu32(s, sport);						s += 4;
 
 	channel = libssh2_channel_open_ex(session, "direct-tcpip",
-                                          sizeof("direct-tcpip") - 1,
-                                          LIBSSH2_CHANNEL_WINDOW_DEFAULT,
-                                          LIBSSH2_CHANNEL_PACKET_DEFAULT,
-                                          (char *)message, message_len);
+					  sizeof("direct-tcpip") - 1,
+					  LIBSSH2_CHANNEL_WINDOW_DEFAULT,
+					  LIBSSH2_CHANNEL_PACKET_DEFAULT,
+					  (char *)message, message_len);
 	LIBSSH2_FREE(session, message);
 
 	return channel;
@@ -430,9 +468,18 @@ LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener)
 /* {{{ libssh2_channel_forward_accept
  * Accept a connection
  */
-LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener)
+LIBSSH2_API LIBSSH2_CHANNEL *
+libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener)
 {
-	while (libssh2_packet_read(listener->session, 0) > 0);
+	libssh2pack_t rc;
+	int loop=-1;
+	do {
+		rc = libssh2_packet_read(listener->session);
+		loop++;
+	} while (rc > 0);
+
+	/* dast: now this might have returned with EAGAIN status which might
+	   be somehow signalled to the caller... */
 
 	if (listener->queue) {
 		LIBSSH2_SESSION *session = listener->session;
@@ -515,7 +562,8 @@ LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varnam
 	}
 
 	LIBSSH2_FREE(session, data);
-	libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, "Unable to complete request for channel-setenv", 0);
+	libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
+		      "Unable to complete request for channel-setenv", 0);
 	return -1;
 }
 /* }}} */
@@ -678,6 +726,7 @@ LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const
 	unsigned char *s, *packet, *data, reply_codes[3] = { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }, local_channel[4];
 	unsigned long data_len;
 	unsigned long packet_len = request_len + 10; /* packet_type(1) + channel(4) + request_len(4) + want_reply(1) */
+	libssh2pack_t rc;
 
 	if (message) {
 		packet_len += message_len + 4;
@@ -705,7 +754,8 @@ LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const
 		memcpy(s, message, message_len);					s += message_len;
 	}
 
-	if (libssh2_packet_write(session, packet, packet_len)) {
+	rc = libssh2_packet_write(session, packet, packet_len);
+	if(rc) {
 		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel request", 0);
 		LIBSSH2_FREE(session, packet);
 		return -1;
@@ -728,15 +778,61 @@ LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const
 }
 /* }}} */
 
-/* {{{ 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_channel_set_blocking
+ * Set a channel's blocking mode on or off, return the status when this
+ * function is called.
  */
-LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking)
+int _libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel,
+				  int blocking)
 {
+	int rc;
+	int bl = channel->blocking;
 #ifdef LIBSSH2_DEBUG_CONNECTION
-	_libssh2_debug(channel->session, LIBSSH2_DBG_CONN, "Setting blocking mode on channel %lu/%lu to %d", channel->local.id, channel->remote.id, blocking);
+	_libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
+		       "Setting blocking mode on channel %lu/%lu to %d",
+		       channel->local.id, channel->remote.id, blocking);
 #endif
+	if(blocking == channel->blocking) {
+		/* avoid if already correct */
+		return bl;
+	}
 	channel->blocking = blocking;
+
+#ifdef F_SETFL
+	/* FIXME: this can/should be done in a more portable manner */
+	rc = fcntl(channel->session->socket_fd, F_GETFL, 0);
+	if(!blocking) {
+		rc |= O_NONBLOCK;
+	}
+	else {
+		rc &= ~O_NONBLOCK;
+	}
+
+	fcntl(channel->session->socket_fd, F_SETFL, rc);
+#else
+#error "add support for setting the socket non-blocking here"
+#endif
+	return bl;
+}
+/* }}} */
+
+/* {{{ 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_channel_set_blocking(channel, blocking);
+}
+/* }}} */
+
+/* {{{ libssh2_channel_get_blocking
+ * Returns a channel's blocking mode on or off
+ */
+int libssh2_channel_get_blocking(LIBSSH2_CHANNEL *channel)
+{
+	return channel->blocking;
 }
 /* }}} */
 
@@ -753,14 +849,21 @@ LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid)
 		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)) {
+		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 */
-			unsigned long packet_stream_id = (packet_type == SSH_MSG_CHANNEL_DATA) ? 0 : libssh2_ntohu32(packet->data + 5);
+			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;
+			    ((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;
 #ifdef LIBSSH2_DEBUG_CONNECTION
 	_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);
@@ -870,39 +973,89 @@ LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel,
 }
 /* }}} */
 
-/* {{{ libssh2_channel_read_ex
- * Read data from a channel
+/* {{{ _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 int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, size_t buflen)
+ssize_t _libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel,
+				 int stream_id, char *buf, size_t buflen)
 {
 	LIBSSH2_SESSION *session = channel->session;
-	int bytes_read = 0, blocking_read = 0;
+	int bytes_read = 0;
+	LIBSSH2_PACKET *packet;
+	libssh2pack_t rc=0;
+	int bl;
+	int block=0;
 
 #ifdef LIBSSH2_DEBUG_CONNECTION
-	_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);
+	_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);
 #endif
+
+	/* set non-blocking and remember previous state */
+	bl = _libssh2_channel_set_blocking(channel, 0);
+
+	/* process all incoming packets */
 	do {
-		LIBSSH2_PACKET *packet;
+		rc = libssh2_packet_read(session);
+	} while (rc > 0);
+	rc = 0;
 
-		/* Process any waiting packets */
-		while (libssh2_packet_read(session, blocking_read) > 0) blocking_read = 0;
-		packet = session->packets.head;
+	/* restore blocking state */
+	_libssh2_channel_set_blocking(channel, bl);
 
-		while (packet && (bytes_read < buflen)) {
-			/* In case packet gets destroyed during this iteration */
+	packet = session->packets.head;
+
+	do {
+
+		if(block) {
+			/* in the second lap and onwards, do this */
+			rc = libssh2_packet_read(session);
+			packet = session->packets.head;
+		}
+
+		if(rc < 0) {
+			/* no packets available */
+			return rc;
+		}
+
+		while (packet && (bytes_read < (int)buflen)) {
+			/* In case packet gets destroyed during this
+			   iteration */
 			LIBSSH2_PACKET *next = packet->next;
 
-			/* Either we asked for a specific extended data stream (and data was available),
+			uint32_t local_id = libssh2_ntohu32(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
+			 * or the standard stream with extended_data_merge
+			 * enabled and data was available
 			 */
-			if ((stream_id  && (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1)) && (stream_id == libssh2_ntohu32(packet->data + 5))) ||
-				(!stream_id && (packet->data[0] == SSH_MSG_CHANNEL_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
-				(!stream_id && (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (channel->local.id == libssh2_ntohu32(packet->data + 1)) && (channel->remote.extended_data_ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) {
+			if ((stream_id	&&
+			     (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) &&
+			     (channel->local.id == local_id) &&
+			     (stream_id == (int)libssh2_ntohu32(packet->data + 5))) ||
+
+			    (!stream_id &&
+			     (packet->data[0] == SSH_MSG_CHANNEL_DATA) &&
+			     (channel->local.id == local_id)) ||
+
+			    (!stream_id &&
+			     (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) &&
+			     (channel->local.id == local_id) &&
+			     (channel->remote.extended_data_ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) {
+
 				int want = buflen - bytes_read;
 				int unlink_packet = 0;
 
-				if (want >= (packet->data_len - packet->data_head)) {
+				if (want >= (int)(packet->data_len - packet->data_head)) {
 					want = packet->data_len - packet->data_head;
 					unlink_packet = 1;
 				}
@@ -936,21 +1089,78 @@ LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id,
 			}
 			packet = next;
 		}
-		blocking_read = 1;
-	} while (channel->blocking && (bytes_read == 0) && !channel->remote.close);
+		block=1;
 
-	if (channel->blocking && (bytes_read == 0)) {
-		libssh2_error(session, LIBSSH2_ERROR_CHANNEL_CLOSED, "Remote end has closed this channel", 0);
+	} while (channel->blocking && (bytes_read == 0) &&
+		 !channel->remote.close);
+
+	if (bytes_read == 0) {
+		if(channel->blocking) {
+			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;
+			}
+		}
 	}
 
 	return bytes_read;
 }
 /* }}} */
 
+
+LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel,
+					int stream_id,
+					char *buf, size_t buflen)
+{
+	ssize_t rc;
+	int bl;
+
+	/* set blocking */
+	bl = _libssh2_channel_set_blocking(channel, 1);
+
+	rc = _libssh2_channel_read_ex(channel, stream_id, buf, buflen);
+
+	/* restore state */
+	_libssh2_channel_set_blocking(channel, bl);
+
+	if(rc < 0) {
+		/* precent accidental returning of other return codes since
+		   this API does not support/provide those */
+		return -1;
+	}
+
+	return rc;
+}
+
+LIBSSH2_API int libssh2_channel_readnb_ex(LIBSSH2_CHANNEL *channel,
+					  int stream_id,
+					  char *buf, size_t buflen)
+{
+	ssize_t rc;
+
+	/* set non-blocking */
+	int bl = _libssh2_channel_set_blocking(channel, 0);
+
+	rc = _libssh2_channel_read_ex(channel, stream_id, buf, buflen);
+
+	/* restore state */
+	_libssh2_channel_set_blocking(channel, bl);
+
+	return rc;
+}
+
+
 /* {{{ libssh2_channel_write_ex
  * Send data to a channel
  */
-LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id, const char *buf, size_t buflen)
+int _libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel,
+			      int stream_id,
+			      const char *buf, size_t buflen)
 {
 	LIBSSH2_SESSION *session = channel->session;
 	unsigned char *packet;
@@ -983,6 +1193,7 @@ LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id
 	while (buflen > 0) {
 		size_t bufwrite = buflen;
 		unsigned char *s = packet;
+		libssh2pack_t rc;
 
 		*(s++) = stream_id ? SSH_MSG_CHANNEL_EXTENDED_DATA : SSH_MSG_CHANNEL_DATA;
 		libssh2_htonu32(s, channel->remote.id);					s += 4;
@@ -992,11 +1203,18 @@ LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id
 
 		/* 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 */
-			if (libssh2_packet_read(session, 1) < 0) {
-				/* Error occured, disconnect? */
-				return -1;
+			/* 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 occured, disconnect? */
+				return rc;
 			}
+
+			/* FIXME: (dast) if rc == 0 here then this busyloops
+			   like hell until data arrives on the network which
+			   seems like a very bad idea */
 		}
 
 		/* Don't exceed the remote end's limits */
@@ -1017,9 +1235,10 @@ LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id
 		memcpy(s, buf, bufwrite);								s += bufwrite;
 
 #ifdef LIBSSH2_DEBUG_CONNECTION
-	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Sending %d bytes on channel %lu/%lu, stream_id=%d", (int)bufwrite, channel->local.id, channel->remote.id, stream_id);
+		_libssh2_debug(session, LIBSSH2_DBG_CONN, "Sending %d bytes on channel %lu/%lu, stream_id=%d", (int)bufwrite, channel->local.id, channel->remote.id, stream_id);
 #endif
-		if (libssh2_packet_write(session, packet, s - packet)) {
+		rc = libssh2_packet_write(session, packet, s - packet);
+		if(rc) {
 			libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel data", 0);
 			LIBSSH2_FREE(session, packet);
 			return -1;
@@ -1043,6 +1262,50 @@ LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id
 }
 /* }}} */
 
+/* {{{ libssh2_channel_write_ex
+ * Send data to a channel blocking
+ */
+LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel,
+					 int stream_id,
+					 const char *buf, size_t buflen)
+{
+	ssize_t rc;
+	/* set blocking */
+	int bl = _libssh2_channel_set_blocking(channel, 1);
+
+	rc = _libssh2_channel_write_ex(channel, stream_id, buf, buflen);
+
+	/* restore state */
+	_libssh2_channel_set_blocking(channel, bl);
+
+	return rc;
+
+}
+/* }}} */
+
+/* {{{ libssh2_channel_writenb_ex
+ * Send data to a channel non-blocking
+ */
+LIBSSH2_API int libssh2_channel_writenb_ex(LIBSSH2_CHANNEL *channel,
+					   int stream_id,
+					   const char *buf, size_t buflen)
+{
+	ssize_t rc;
+	int bl;
+
+	/* set non-blocking */
+	bl = _libssh2_channel_set_blocking(channel, 0);
+
+	rc = _libssh2_channel_write_ex(channel, stream_id, buf, buflen);
+
+	/* restore state */
+	(void)_libssh2_channel_set_blocking(channel, bl);
+
+	return rc;
+}
+/* }}} */
+
+
 /* {{{ libssh2_channel_send_eof
  * Send EOF on channel
  */
@@ -1143,7 +1406,7 @@ LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel)
 	 * Either or channel will be closed
 	 * or network timeout will occur
 	 */
-	while (!channel->remote.close && libssh2_packet_read(session, 1) > 0)
+	while (!channel->remote.close && libssh2_packet_read(session) > 0)
 		;
 
 	return 1;
@@ -1176,7 +1439,7 @@ LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel)
 
 	/* 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, 1) >= 0) ||
+	while  ((libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_DATA,		  &data, &data_len, 1, channel_id, 4, 1) >= 0) ||
 			(libssh2_packet_ask_ex(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, &data_len, 1, channel_id, 4, 1) >= 0)) {
 		LIBSSH2_FREE(session, data);
 	}
diff --git a/src/crypt.c b/src/crypt.c
index f562d50..b6efb57 100644
--- a/src/crypt.c
+++ b/src/crypt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms,
@@ -37,7 +37,7 @@
 
 #include "libssh2_priv.h"
 
-#if LIBSSH2_CRYPT_NONE
+#ifdef LIBSSH2_CRYPT_NONE
 /* {{{ libssh2_crypt_none_crypt
  * Minimalist cipher: VERY secure *wink*
  */
@@ -93,6 +93,7 @@ static int init (LIBSSH2_SESSION *session,
 static int crypt(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);
 }
@@ -234,7 +235,7 @@ static LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = {
 #if LIBSSH2_3DES
 	&libssh2_crypt_method_3des_cbc,
 #endif /*  LIBSSH2_DES */
-#if LIBSSH2_CRYPT_NONE
+#ifdef LIBSSH2_CRYPT_NONE
 	&libssh2_crypt_method_none,
 #endif
 	NULL
diff --git a/src/kex.c b/src/kex.c
index 185e71b..4a0f138 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms,
@@ -79,6 +79,7 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
 	unsigned char *s, *f_value, *k_value = NULL, *h_sig;
 	unsigned long f_value_len, k_value_len, h_sig_len;
 	libssh2_sha1_ctx exchange_hash;
+	int rc;
 
 	/* Generate x and e */
 	_libssh2_bn_rand(x, group_order, 0, -1);
@@ -108,7 +109,8 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
 #ifdef LIBSSH2_DEBUG_KEX
 	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending KEX packet %d", (int)packet_type_init);
 #endif
-	if (libssh2_packet_write(session, e_packet, e_packet_len)) {
+	rc = libssh2_packet_write(session, e_packet, e_packet_len);
+	if (rc) {
 		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send KEX init message", 0);
 		ret = -11;
 		goto clean_exit;
@@ -135,8 +137,11 @@ static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_S
 	}
 
 	/* Wait for KEX reply */
-	if (libssh2_packet_require(session, packet_type_reply, &s_packet, &s_packet_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, "Timed out waiting for KEX reply", 0);
+	rc = libssh2_packet_require(session, packet_type_reply, &s_packet,
+				    &s_packet_len);
+	if (rc) {
+		libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
+			      "Timed out waiting for KEX reply", 0);
 		ret = -1;
 		goto clean_exit;
 	}
@@ -514,7 +519,7 @@ static int libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_S
 		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,
+		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,
@@ -599,7 +604,7 @@ static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LI
 		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send Group Exchange Request", 0);
 		ret = -1;
 		goto dh_gex_clean_exit;
-	}	
+	}
 
 	if (libssh2_packet_require(session, SSH_MSG_KEX_DH_GEX_GROUP, &data, &data_len)) {
 		libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, "Timeout waiting for GEX_GROUP reply", 0);
@@ -813,7 +818,7 @@ static int libssh2_kexinit(LIBSSH2_SESSION *session)
 
 	return 0;
 }
-/* }}}  */
+/* }}}	*/
 
 /* {{{ libssh2_kex_agree_instr
  * Kex specific variant of strstr()
@@ -907,7 +912,9 @@ static int libssh2_kex_agree_hostkey(LIBSSH2_SESSION *session, unsigned long kex
 	}
 
 	while (hostkeyp && (*hostkeyp)->name) {
-		s = libssh2_kex_agree_instr(hostkey, hostkey_len, (*hostkeyp)->name, strlen((*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) ||
@@ -972,7 +979,9 @@ static int libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION *session, unsigned char
 	}
 
 	while (*kexp && (*kexp)->name) {
-		s = libssh2_kex_agree_instr(kex, kex_len, (*kexp)->name, strlen((*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?
@@ -1014,7 +1023,7 @@ static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session,
 
 			if (libssh2_kex_agree_instr(crypt, crypt_len, s, method_len)) {
 				LIBSSH2_CRYPT_METHOD *method =
-					(LIBSSH2_CRYPT_METHOD*)libssh2_get_method_by_name(s, method_len, (LIBSSH2_COMMON_METHOD**)cryptp);
+					(LIBSSH2_CRYPT_METHOD*)libssh2_get_method_by_name((char *)s, method_len, (LIBSSH2_COMMON_METHOD**)cryptp);
 
 				if (!method) {
 					/* Invalid method -- Should never be reached */
@@ -1031,7 +1040,9 @@ static int libssh2_kex_agree_crypt(LIBSSH2_SESSION *session,
 	}
 
 	while (*cryptp && (*cryptp)->name) {
-		s = libssh2_kex_agree_instr(crypt, crypt_len, (*cryptp)->name, strlen((*cryptp)->name));
+		s = libssh2_kex_agree_instr(crypt, crypt_len,
+					    (unsigned char *)(*cryptp)->name,
+					    strlen((*cryptp)->name));
 		if (s) {
 			endpoint->crypt = *cryptp;
 			return 0;
@@ -1076,7 +1087,9 @@ static int libssh2_kex_agree_mac(LIBSSH2_SESSION *session, libssh2_endpoint_data
 	}
 
 	while (*macp && (*macp)->name) {
-		s = libssh2_kex_agree_instr(mac, mac_len, (*macp)->name, strlen((*macp)->name));
+		s = libssh2_kex_agree_instr(mac, mac_len,
+					    (unsigned char *)(*macp)->name,
+					    strlen((*macp)->name));
 		if (s) {
 			endpoint->mac = *macp;
 			return 0;
@@ -1121,7 +1134,9 @@ static int libssh2_kex_agree_comp(LIBSSH2_SESSION *session, libssh2_endpoint_dat
 	}
 
 	while (*compp && (*compp)->name) {
-		s = libssh2_kex_agree_instr(comp, comp_len, (*compp)->name, strlen((*compp)->name));
+		s = libssh2_kex_agree_instr(comp, comp_len,
+					    (unsigned char *)(*compp)->name,
+					    strlen((*compp)->name));
 		if (s) {
 			endpoint->comp = *compp;
 			return 0;
@@ -1261,7 +1276,7 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
 			}
 			session->local.kexinit = oldlocal;
 			session->local.kexinit_len = oldlocal_len;
-			return -1;
+			return -2;
 		}
 
 		if (session->remote.kexinit) {
@@ -1271,13 +1286,13 @@ int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange) /* session->f
 		session->remote.kexinit_len = data_len;
 
 		if (libssh2_kex_agree_methods(session, data, data_len)) {
-			return -1;
+			return -3;
 		}
 	}
 
 	if (session->kex->exchange_keys(session)) {
 		libssh2_error(session, LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE, "Unrecoverable error exchanging keys", 0);
-		return -1;
+		return -4;
 	}
 
 	/* Done with kexinit buffers */
diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h
index 400c88d..8891e84 100644
--- a/src/libssh2_priv.h
+++ b/src/libssh2_priv.h
@@ -54,6 +54,15 @@
 #include "openssl.h"
 #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)
@@ -173,6 +182,43 @@ typedef struct _libssh2_endpoint_data {
 	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_SESSION {
 	/* Memory management callbacks */
 	void *abstract;
@@ -240,6 +286,9 @@ struct _LIBSSH2_SESSION {
 	unsigned long err_msglen;
 	int err_should_free;
 	int err_code;
+
+	/* struct members for packet-level reading */
+	struct transportpacket packet;
 };
 
 /* session.state bits */
@@ -345,7 +394,7 @@ void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, .
 	if (session->err_msg && session->err_should_free) { \
 		LIBSSH2_FREE(session, session->err_msg); \
 	} \
-	session->err_msg = errmsg; \
+	session->err_msg = (char *)errmsg; \
 	session->err_msglen = strlen(errmsg); \
 	session->err_should_free = should_free; \
 	session->err_code = errcode; \
@@ -359,7 +408,7 @@ void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, .
 	if (session->err_msg && session->err_should_free) { \
 		LIBSSH2_FREE(session, session->err_msg); \
 	} \
-	session->err_msg = errmsg; \
+	session->err_msg = (char *)errmsg; \
 	session->err_msglen = strlen(errmsg); \
 	session->err_should_free = should_free; \
 	session->err_code = errcode; \
@@ -440,7 +489,27 @@ 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);
 
-int libssh2_packet_read(LIBSSH2_SESSION *session, int block);
+#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. */
+typedef int libssh2pack_t;
+
+#define PACKET_TIMEOUT -7
+#define PACKET_BADUSE -6
+#define PACKET_COMPRESS -5
+#define PACKET_TOOBIG -4
+#define PACKET_ENOMEM -3
+#define PACKET_EAGAIN -2
+#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);
 #define libssh2_packet_ask(session, packet_type, data, data_len, poll_socket)	\
 		libssh2_packet_ask_ex((session), (packet_type), (data), (data_len), 0, NULL, 0, (poll_socket))
@@ -448,16 +517,32 @@ int libssh2_packet_askv_ex(LIBSSH2_SESSION *session, unsigned char *packet_types
 #define libssh2_packet_askv(session, packet_types, data, data_len, poll_socket)	\
 		libssh2_packet_askv_ex((session), (packet_types), (data), (data_len), 0, NULL, 0, (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);
-#define libssh2_packet_require(session, packet_type, data, data_len)			\
-		libssh2_packet_require_ex((session), (packet_type), (data), (data_len), 0, NULL, 0)
+#define libssh2_packet_require(session, packet_type, data, data_len) \
+ libssh2_packet_require_ex((session), (packet_type), (data), (data_len), 0, NULL, 0)
 int libssh2_packet_requirev_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len);
 #define libssh2_packet_requirev(session, packet_types, data, data_len)			\
 		libssh2_packet_requirev_ex((session), (packet_types), (data), (data_len), 0, NULL, 0)
 int libssh2_packet_burn(LIBSSH2_SESSION *session);
 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);
 unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session);
 LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long channel_id);
+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))
+#undef libssh2_channel_read /* never use this internally */
+#define libssh2_channel_read fix this code
+
+int _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))
+
+/* this is the lib-internal set blocking function */
+int _libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
 
 /* Let crypt.c/hostkey.c/comp.c/mac.c expose their method structs */
 LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void);
diff --git a/src/misc.c b/src/misc.c
index 12e4d00..5d22876 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -181,15 +181,15 @@ void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, .
 	int len;
 	va_list vargs;
 	char *contexts[9] = {	"Unknown",
-							"Transport",
-							"Key Exhange",
-							"Userauth",
-							"Connection",
-							"scp",
-							"SFTP Subsystem",
-							"Failure Event",
-							"Publickey Subsystem",
-						 };
+				"Transport",
+				"Key Exhange",
+				"Userauth",
+				"Connection",
+				"scp",
+				"SFTP Subsystem",
+				"Failure Event",
+				"Publickey Subsystem",
+	};
 
 	if (context < 1 || context > 8) {
 		context = 0;
diff --git a/src/packet.c b/src/packet.c
index fa5ebd3..15eba72 100644
--- a/src/packet.c
+++ b/src/packet.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms,
@@ -47,6 +47,9 @@
 #include <sys/uio.h>
 #endif
 
+#include <sys/time.h>
+#include <sys/types.h>
+
 #ifdef HAVE_POLL
 # include <sys/poll.h>
 #else
@@ -62,1014 +65,729 @@
 
 #include <inttypes.h>
 
-/* 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
-
 inline int libssh2_packet_queue_listener(LIBSSH2_SESSION *session, unsigned char *data, unsigned long datalen);
 inline int libssh2_packet_x11_open(LIBSSH2_SESSION *session, unsigned char *data, unsigned long datalen);
 
 /* {{{ libssh2_packet_queue_listener
  * Queue a connection request for a listener
  */
-inline int libssh2_packet_queue_listener(LIBSSH2_SESSION *session, unsigned char *data, unsigned long datalen)
+inline int libssh2_packet_queue_listener(LIBSSH2_SESSION *session,
+                                         unsigned char *data,
+                                         unsigned long datalen)
 {
-	/* 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("Forward not requested") - 1);
-	unsigned char *p, packet[17 + (sizeof("Forward not requested") - 1)];
-	LIBSSH2_LISTENER *l = session->listeners;
-	char failure_code = 1; /* SSH_OPEN_ADMINISTRATIVELY_PROHIBITED */
+        /* 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("Forward not requested") - 1);
+        unsigned char *p, packet[17 + (sizeof("Forward not requested") - 1)];
+        LIBSSH2_LISTENER *l = session->listeners;
+        char failure_code = 1; /* SSH_OPEN_ADMINISTRATIVELY_PROHIBITED */
         uint32_t sender_channel, initial_window_size, packet_size;
-	unsigned char *host, *shost;
+        unsigned char *host, *shost;
         uint32_t port, sport, host_len, shost_len;
+        (void)datalen;
 
-	sender_channel = libssh2_ntohu32(s);		s += 4;
+        sender_channel = libssh2_ntohu32(s);            s += 4;
 
-	initial_window_size = libssh2_ntohu32(s);	s += 4;
-	packet_size = libssh2_ntohu32(s);			s += 4;
+        initial_window_size = libssh2_ntohu32(s);       s += 4;
+        packet_size = libssh2_ntohu32(s);                       s += 4;
 
-	host_len = libssh2_ntohu32(s);				s += 4;
-	host = s;									s += host_len;
-	port = libssh2_ntohu32(s);					s += 4;
+        host_len = libssh2_ntohu32(s);                          s += 4;
+        host = s;                                                                       s += host_len;
+        port = libssh2_ntohu32(s);                                      s += 4;
 
-	shost_len = libssh2_ntohu32(s);				s += 4;
-	shost = s;									s += shost_len;
-	sport = libssh2_ntohu32(s);					s += 4;
+        shost_len = libssh2_ntohu32(s);                         s += 4;
+        shost = s;                                                                      s += shost_len;
+        sport = libssh2_ntohu32(s);                                     s += 4;
 
 #ifdef LIBSSH2_DEBUG_CONNECTION
-	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Remote received connection from %s:%ld to %s:%ld", shost, sport, host, port);
+        _libssh2_debug(session, LIBSSH2_DBG_CONN, "Remote received connection from %s:%ld to %s:%ld", shost, sport, host, port);
 #endif
-	while (l) {
-		if ((l->port == port) &&
-			(strlen(l->host) == host_len) &&
-			(memcmp(l->host, host, host_len) == 0)) {
-			/* This is our listener */
-			LIBSSH2_CHANNEL *channel, *last_queued = l->queue;
 
-			if (l->queue_maxsize &&
-				(l->queue_maxsize <= l->queue_size)) {
-				/* Queue is full */
-				failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
+        while (l) {
+                if ((l->port == (int)port) &&
+                        (strlen(l->host) == host_len) &&
+                        (memcmp(l->host, host, host_len) == 0)) {
+                        /* This is our listener */
+                        LIBSSH2_CHANNEL *channel, *last_queued = l->queue;
+
+                        if (l->queue_maxsize &&
+                                (l->queue_maxsize <= l->queue_size)) {
+                                /* Queue is full */
+                                failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
 #ifdef LIBSSH2_DEBUG_CONNECTION
-	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Listener queue full, ignoring");
+        _libssh2_debug(session, LIBSSH2_DBG_CONN, "Listener queue full, ignoring");
 #endif
-				break;
-			}
+                                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 */
-				break;
-			}
-			memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
+                        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 */
+                                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 */
-				break;
-			}
-			memcpy(channel->channel_type, "forwarded-tcpip", channel->channel_type_len + 1);
+                        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 */
+                                break;
+                        }
+                        memcpy(channel->channel_type, "forwarded-tcpip", channel->channel_type_len + 1);
 
-			channel->remote.id = 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->remote.id = 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 = initial_window_size;
-			channel->local.window_size = initial_window_size;
-			channel->local.packet_size = packet_size;
+                        channel->local.id = libssh2_channel_nextid(session);
+                        channel->local.window_size_initial = initial_window_size;
+                        channel->local.window_size = initial_window_size;
+                        channel->local.packet_size = packet_size;
 
 #ifdef LIBSSH2_DEBUG_CONNECTION
-	_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);
+        _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);
 #endif
 
-			p = 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;
+                        p = 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;
 
-			if (libssh2_packet_write(session, packet, 17)) {
-				libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0);
-				return -1;
-			}
+                        if (libssh2_packet_write(session, packet, 17)) {
+                                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0);
+                                return -1;
+                        }
 
-			/* Link the channel into the end of the queue list */
+                        /* Link the channel into the end of the queue list */
 
-			if (!last_queued) {
-				l->queue = channel;
-				return 0;
-			}
+                        if (!last_queued) {
+                                l->queue = channel;
+                                return 0;
+                        }
 
-			while (last_queued->next) last_queued = last_queued->next;
+                        while (last_queued->next) last_queued = last_queued->next;
 
-			last_queued->next = channel;
-			channel->prev = last_queued;
+                        last_queued->next = channel;
+                        channel->prev = last_queued;
 
-			l->queue_size++;
+                        l->queue_size++;
 
-			return 0;
-		}
+                        return 0;
+                }
 
-		l = l->next;
-	}
+                l = l->next;
+        }
 
-	/* We're not listening to you */
-	{
+        /* We're not listening to you */
+        {
 
-		p = packet;
-		*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
-		libssh2_htonu32(p, sender_channel);		p += 4;
-		libssh2_htonu32(p, failure_code);		p += 4;
-		libssh2_htonu32(p, sizeof("Forward not requested") - 1);	p += 4;
-		memcpy(s, "Forward not requested", sizeof("Forward not requested") - 1);	p += sizeof("Forward not requested") - 1;
-		libssh2_htonu32(p, 0);
+                p = packet;
+                *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
+                libssh2_htonu32(p, sender_channel);             p += 4;
+                libssh2_htonu32(p, failure_code);               p += 4;
+                libssh2_htonu32(p, sizeof("Forward not requested") - 1);        p += 4;
+                memcpy(s, "Forward not requested", sizeof("Forward not requested") - 1);        p += sizeof("Forward not requested") - 1;
+                libssh2_htonu32(p, 0);
 
-		if (libssh2_packet_write(session, packet, packet_len)) {
-			libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send open failure", 0);
-			return -1;
-		}
-		return 0;
-	}
+                if (libssh2_packet_write(session, packet, packet_len)) {
+                        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send open failure", 0);
+                        return -1;
+                }
+                return 0;
+        }
 }
 /* }}} */
 
 /* {{{ libssh2_packet_x11_open
  * Accept a forwarded X11 connection
  */
-inline int libssh2_packet_x11_open(LIBSSH2_SESSION *session, unsigned char *data, unsigned long datalen)
+inline int libssh2_packet_x11_open(LIBSSH2_SESSION *session,
+                                   unsigned char *data, unsigned long datalen)
 {
-	int failure_code = 2; /* SSH_OPEN_CONNECT_FAILED */
-	unsigned char *s = data + (sizeof("x11") - 1) + 5;
-	unsigned long packet_len = 17 + (sizeof("X11 Forward Unavailable") - 1);
-	unsigned char *p, packet[17 + (sizeof("X11 Forward Unavailable") - 1)];
-					/* packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
-	LIBSSH2_CHANNEL *channel;
-	unsigned long sender_channel, initial_window_size, packet_size;
-	unsigned char *shost;
-	unsigned long sport, shost_len;
+        int failure_code = 2; /* SSH_OPEN_CONNECT_FAILED */
+        unsigned char *s = data + (sizeof("x11") - 1) + 5;
+        unsigned long packet_len = 17 + (sizeof("X11 Forward Unavailable") - 1);
+        unsigned char *p, packet[17 + (sizeof("X11 Forward Unavailable") - 1)];
+                                        /* packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
+        LIBSSH2_CHANNEL *channel;
+        unsigned long sender_channel, initial_window_size, packet_size;
+        unsigned char *shost;
+        unsigned long sport, shost_len;
+        (void)datalen;
 
-	sender_channel = libssh2_ntohu32(s);			s += 4;
-	initial_window_size = libssh2_ntohu32(s);		s += 4;
-	packet_size = libssh2_ntohu32(s);				s += 4;
-	shost_len = libssh2_ntohu32(s);					s += 4;
-	shost = s;										s += shost_len;
-	sport = libssh2_ntohu32(s);						s += 4;
+        sender_channel = libssh2_ntohu32(s);                    s += 4;
+        initial_window_size = libssh2_ntohu32(s);               s += 4;
+        packet_size = libssh2_ntohu32(s);                               s += 4;
+        shost_len = libssh2_ntohu32(s);                                 s += 4;
+        shost = s;                                                                              s += shost_len;
+        sport = libssh2_ntohu32(s);                                             s += 4;
 
 #ifdef LIBSSH2_DEBUG_CONNECTION
-	_libssh2_debug(session, LIBSSH2_DBG_CONN, "X11 Connection Received from %s:%ld on channel %lu", shost, sport, sender_channel);
+        _libssh2_debug(session, LIBSSH2_DBG_CONN, "X11 Connection Received from %s:%ld on channel %lu", shost, sport, sender_channel);
 #endif
-	if (session->x11) {
-		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));
+        if (session->x11) {
+                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->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 = 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->remote.id = 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 = initial_window_size;
-		channel->local.window_size = initial_window_size;
-		channel->local.packet_size = packet_size;
+                channel->local.id = libssh2_channel_nextid(session);
+                channel->local.window_size_initial = initial_window_size;
+                channel->local.window_size = initial_window_size;
+                channel->local.packet_size = packet_size;
 
 #ifdef LIBSSH2_DEBUG_CONNECTION
-	_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);
+        _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);
 #endif
-		p = 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;
+                p = 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;
 
-		if (libssh2_packet_write(session, packet, 17)) {
-			libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0);
-			return -1;
-		}
+                if (libssh2_packet_write(session, packet, 17)) {
+                        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0);
+                        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 *)shost, sport);
-		
-		return 0;
-	} else {
-		failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
-	}
+                /* 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 *)shost, sport);
+
+                return 0;
+        } else {
+                failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */
+        }
 
  x11_exit:
-	p = packet;
-	*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
-	libssh2_htonu32(p, sender_channel);				p += 4;
-	libssh2_htonu32(p, failure_code);				p += 4;
-	libssh2_htonu32(p, sizeof("X11 Forward Unavailable") - 1);		p += 4;
-	memcpy(s, "X11 Forward Unavailable", sizeof("X11 Forward Unavailable") - 1); p += sizeof("X11 Forward Unavailable") - 1;
-	libssh2_htonu32(p, 0);
+        p = packet;
+        *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
+        libssh2_htonu32(p, sender_channel);                             p += 4;
+        libssh2_htonu32(p, failure_code);                               p += 4;
+        libssh2_htonu32(p, sizeof("X11 Forward Unavailable") - 1);              p += 4;
+        memcpy(s, "X11 Forward Unavailable", sizeof("X11 Forward Unavailable") - 1); p += sizeof("X11 Forward Unavailable") - 1;
+        libssh2_htonu32(p, 0);
 
-	if (libssh2_packet_write(session, packet, packet_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send open failure", 0);
-		return -1;
-	}
-	return 0;
+        if (libssh2_packet_write(session, packet, packet_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send open failure", 0);
+                return -1;
+        }
+        return 0;
 }
 /* }}} */
 
 /* {{{ libssh2_packet_new
  * Create a new packet and attach it to the brigade
  */
-static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, size_t datalen, int macstate)
+int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, size_t datalen, int macstate)
 {
-	LIBSSH2_PACKET *packet;
-	unsigned long data_head = 0;
+        LIBSSH2_PACKET *packet;
+        unsigned long data_head = 0;
 
 #ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Packet type %d received, length=%d", (int)data[0], (int)datalen);
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Packet type %d received, length=%d", (int)data[0], (int)datalen);
 #endif
-	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);
-				}
-				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);
-			}
-			return -1;
-		}
-	}
+        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);
+                                }
+                                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);
+                        }
+                        return -1;
+                }
+        }
 
-	/* A couple exceptions to the packet adding rule: */
-	switch (data[0]) {
-		case SSH_MSG_DISCONNECT:
-		{
-			char *message, *language;
-			int reason, message_len, language_len;
+        /* 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);
-			message = (char *)data + 9; /* packet_type(1) + reason(4) + message_len(4) */
-			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';
+                        reason = libssh2_ntohu32(data + 1);
+                        message_len = libssh2_ntohu32(data + 5);
+                        message = (char *)data + 9; /* packet_type(1) + reason(4) + message_len(4) */
+                        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);
-			}
+                        if (session->ssh_msg_disconnect) {
+                                LIBSSH2_DISCONNECT(session, reason, message, message_len, language, language_len);
+                        }
 #ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Disconnect(%d): %s(%s)", reason, message, language);
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Disconnect(%d): %s(%s)", reason, message, language);
 #endif
-			LIBSSH2_FREE(session, data);
-			session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
-			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, (char *)data);
-			return 0;
-			break;
-		case SSH_MSG_DEBUG:
-		{
-			int always_display = data[0];
-			char *message, *language;
-			int message_len, language_len;
+                        LIBSSH2_FREE(session, data);
+                        session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
+                        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, (char *)data);
+                        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);
-			message = (char *)data + 6; /* packet_type(1) + display(1) + message_len(4) */
-			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';
+                        message_len = libssh2_ntohu32(data + 2);
+                        message = (char *)data + 6; /* packet_type(1) + display(1) + message_len(4) */
+                        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);
-			}
+                        if (session->ssh_msg_debug) {
+                                LIBSSH2_DEBUG(session, always_display, message, message_len, language, language_len);
+                        }
 #ifdef LIBSSH2_DEBUG_TRANSPORT
-	/* _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_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);
 #endif
-			LIBSSH2_FREE(session, data);
-			return 0;
-		}
-			break;
-		case SSH_MSG_CHANNEL_EXTENDED_DATA:
-			data_head += 4; /* streamid(4) */
-		case SSH_MSG_CHANNEL_DATA:
-			data_head += 9; /* packet_type(1) + channelno(4) + datalen(4) */
-			{
-				LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
+                        LIBSSH2_FREE(session, data);
+                        return 0;
+                }
+                        break;
+                case SSH_MSG_CHANNEL_EXTENDED_DATA:
+                        data_head += 4; /* streamid(4) */
+                case SSH_MSG_CHANNEL_DATA:
+                        data_head += 9; /* packet_type(1) + channelno(4) + datalen(4) */
+                        {
+                                LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
 
-				if (!channel) {
-					libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN, "Packet received for unknown channel, ignoring", 0);
-					LIBSSH2_FREE(session, data);
-					return 0;
-				}
+                                if (!channel) {
+                                        libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN, "Packet received for unknown channel, ignoring", 0);
+                                        LIBSSH2_FREE(session, data);
+                                        return 0;
+                                }
 #ifdef LIBSSH2_DEBUG_CONNECTION
 {
-	unsigned long stream_id = 0;
+        unsigned long stream_id = 0;
 
-	if (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) {
-		stream_id = libssh2_ntohu32(data + 5);
-	}
+        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 - data_head), channel->local.id, channel->remote.id, stream_id);
+        _libssh2_debug(session, LIBSSH2_DBG_CONN, "%d bytes received for channel %lu/%lu stream #%lu", (int)(datalen - data_head), channel->local.id, channel->remote.id, stream_id);
 }
 #endif
-				if ((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);
+                                if ((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);
 
 #ifdef LIBSSH2_DEBUG_CONNECTION
-	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Ignoring extended data and refunding %d bytes", (int)(datalen - 13));
+        _libssh2_debug(session, LIBSSH2_DBG_CONN, "Ignoring extended data and refunding %d bytes", (int)(datalen - 13));
 #endif
-					/* Adjust the window based on the block we just freed */
-					libssh2_channel_receive_window_adjust(channel, datalen - 13, 0);
+                                        /* Adjust the window based on the block we just freed */
+                                        libssh2_channel_receive_window_adjust(channel, datalen - 13, 0);
 
-					return 0;
-				}
+                                        return 0;
+                                }
 
-				/* REMEMBER! remote means remote as source of data, NOT remote window! */
-				if (channel->remote.packet_size < (datalen - 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 = channel->remote.packet_size + data_head;
-				}
-				if (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);
-					return 0;
-				}
-				/* Reset EOF status */
-				channel->remote.eof = 0;
+                                /* REMEMBER! remote means remote as source of data, NOT remote window! */
+                                if (channel->remote.packet_size < (datalen - 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 = channel->remote.packet_size + data_head;
+                                }
+                                if (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);
+                                        return 0;
+                                }
+                                /* Reset EOF status */
+                                channel->remote.eof = 0;
 
-				if ((datalen - data_head) > channel->remote.window_size) {
-					libssh2_error(session, LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, "Remote sent more data than current window allows, truncating", 0);
-					datalen = channel->remote.window_size + data_head;
-				} else {
-					/* Now that we've received it, shrink our window */
-					channel->remote.window_size -= datalen - data_head;
-				}
-			}
-			break;
-		case SSH_MSG_CHANNEL_EOF:
-			{
-				LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
+                                if ((datalen - data_head) > channel->remote.window_size) {
+                                        libssh2_error(session, LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, "Remote sent more data than current window allows, truncating", 0);
+                                        datalen = channel->remote.window_size + data_head;
+                                } else {
+                                        /* Now that we've received it, shrink our window */
+                                        channel->remote.window_size -= datalen - data_head;
+                                }
+                        }
+                        break;
+                case SSH_MSG_CHANNEL_EOF:
+                        {
+                                LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
 
-				if (!channel) {
-					/* We may have freed already, just quietly ignore this... */
-					LIBSSH2_FREE(session, data);
-					return 0;
-				}
+                                if (!channel) {
+                                        /* We may have freed already, just quietly ignore this... */
+                                        LIBSSH2_FREE(session, data);
+                                        return 0;
+                                }
 
 #ifdef LIBSSH2_DEBUG_CONNECTION
-	_libssh2_debug(session, LIBSSH2_DBG_CONN, "EOF received for channel %lu/%lu", channel->local.id, channel->remote.id);
+        _libssh2_debug(session, LIBSSH2_DBG_CONN, "EOF received for channel %lu/%lu", channel->local.id, channel->remote.id);
 #endif
-				channel->remote.eof = 1;
+                                channel->remote.eof = 1;
 
-				LIBSSH2_FREE(session, data);
-				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)) {
+                                LIBSSH2_FREE(session, data);
+                                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 */
-					LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data+1));
+                                        /* we've got "exit-status" packet. Set the session value */
+                                        LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data+1));
 
-					if (channel) {
-						channel->exit_status = libssh2_ntohu32(data + 9 + sizeof("exit-status"));
+                                        if (channel) {
+                                                channel->exit_status = libssh2_ntohu32(data + 9 + sizeof("exit-status"));
 #ifdef LIBSSH2_DEBUG_CONNECTION
-						_libssh2_debug(session, LIBSSH2_DBG_CONN, "Exit status %lu received for channel %lu/%lu", channel->exit_status, channel->local.id, channel->remote.id);
+                                                _libssh2_debug(session, LIBSSH2_DBG_CONN, "Exit status %lu received for channel %lu/%lu", channel->exit_status, channel->local.id, channel->remote.id);
 #endif
-					}
+                                        }
 
-					LIBSSH2_FREE(session, data);
-					return 0;
-				}
-			}
-			break;
-		case SSH_MSG_CHANNEL_CLOSE:
-			{
-				LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
+                                        LIBSSH2_FREE(session, data);
+                                        return 0;
+                                }
+                        }
+                        break;
+                case SSH_MSG_CHANNEL_CLOSE:
+                        {
+                                LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
 
-				if (!channel) {
-					/* We may have freed already, just quietly ignore this... */
-					LIBSSH2_FREE(session, data);
-					return 0;
-				}
+                                if (!channel) {
+                                        /* We may have freed already, just quietly ignore this... */
+                                        LIBSSH2_FREE(session, data);
+                                        return 0;
+                                }
 #ifdef LIBSSH2_DEBUG_CONNECTION
-	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Close received for channel %lu/%lu", channel->local.id, channel->remote.id);
+        _libssh2_debug(session, LIBSSH2_DBG_CONN, "Close received for channel %lu/%lu", channel->local.id, channel->remote.id);
 #endif
 
-				channel->remote.close = 1;
-				channel->remote.eof = 1;
-				/* TODO: Add a callback for this */
+                                channel->remote.close = 1;
+                                channel->remote.eof = 1;
+                                /* TODO: Add a callback for this */
 
-				LIBSSH2_FREE(session, data);
-				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)) {
-				int retval = libssh2_packet_queue_listener(session, data, datalen);
+                                LIBSSH2_FREE(session, data);
+                                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)) {
+                                int retval = libssh2_packet_queue_listener(session, data, datalen);
 
-				LIBSSH2_FREE(session, data);
-				return retval;
-			}
-			if ((datalen >= (sizeof("x11") + 4)) &&
-				((sizeof("x11")-1) == libssh2_ntohu32(data + 1)) &&
-				(memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {
-				int retval = libssh2_packet_x11_open(session, data, datalen);
+                                LIBSSH2_FREE(session, data);
+                                return retval;
+                        }
+                        if ((datalen >= (sizeof("x11") + 4)) &&
+                                ((sizeof("x11")-1) == libssh2_ntohu32(data + 1)) &&
+                                (memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {
+                                int retval = libssh2_packet_x11_open(session, data, datalen);
 
-				LIBSSH2_FREE(session, data);
-				return retval;
-			}
-			break;
-		case SSH_MSG_CHANNEL_WINDOW_ADJUST:
-			{
-				LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
-				unsigned long bytestoadd = libssh2_ntohu32(data + 5);
+                                LIBSSH2_FREE(session, data);
+                                return retval;
+                        }
+                        break;
+                case SSH_MSG_CHANNEL_WINDOW_ADJUST:
+                        {
+                                LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
+                                unsigned long bytestoadd = libssh2_ntohu32(data + 5);
 
-				if (channel && bytestoadd) {
-					channel->local.window_size += bytestoadd;
-				}
+                                if (channel && bytestoadd) {
+                                        channel->local.window_size += bytestoadd;
+                                }
 #ifdef LIBSSH2_DEBUG_CONNECTION
-	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Window adjust received for channel %lu/%lu, adding %lu bytes, new window_size=%lu", channel->local.id, channel->remote.id, bytestoadd, channel->local.window_size);
+        _libssh2_debug(session, LIBSSH2_DBG_CONN, "Window adjust received for channel %lu/%lu, adding %lu bytes, new window_size=%lu", channel->local.id, channel->remote.id, bytestoadd, channel->local.window_size);
 #endif
 
-				LIBSSH2_FREE(session, data);
-				return 0;
-			}
-			break;
-	}
+                                LIBSSH2_FREE(session, data);
+                                return 0;
+                        }
+                        break;
+        }
 
-	packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
-	memset(packet, 0, sizeof(LIBSSH2_PACKET));
+        packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
+        memset(packet, 0, sizeof(LIBSSH2_PACKET));
 
-	packet->data = data;
-	packet->data_len = datalen;
-	packet->data_head = data_head;
-	packet->mac = macstate;
-	packet->brigade = &session->packets;
-	packet->next = NULL;
+        packet->data = data;
+        packet->data_len = datalen;
+        packet->data_head = data_head;
+        packet->mac = macstate;
+        packet->brigade = &session->packets;
+        packet->next = NULL;
 
-	if (session->packets.tail) {
-		packet->prev = session->packets.tail;
-		packet->prev->next = packet;
-		session->packets.tail = packet;
-	} else {
-		session->packets.head = packet;
-		session->packets.tail = packet;
-		packet->prev = NULL;
-	}
+        if (session->packets.tail) {
+                packet->prev = session->packets.tail;
+                packet->prev->next = packet;
+                session->packets.tail = packet;
+        } else {
+                session->packets.head = packet;
+                session->packets.tail = packet;
+                packet->prev = NULL;
+        }
 
-	if (data[0] == SSH_MSG_KEXINIT && !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) {
-		/* Remote wants new keys
-		 * Well, it's already in the brigade,
-		 * let's just call back into ourselves
-		 */
+        if (data[0] == SSH_MSG_KEXINIT && !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) {
+                /* Remote wants new keys
+                 * Well, it's already in the brigade,
+                 * let's just call back into ourselves
+                 */
 #ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Renegotiating Keys");
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Renegotiating Keys");
 #endif
-		libssh2_kex_exchange(session, 1);
-		/* 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 */
-	}
+                libssh2_kex_exchange(session, 1);
+                /* 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 */
+        }
 
-	return 0;
-}
-/* }}} */
-
-/* {{{ libssh2_blocking_read
- * Force a blocking read, regardless of socket settings
- */
-static ssize_t libssh2_blocking_read(LIBSSH2_SESSION *session, unsigned char *buf, size_t count)
-{
-	size_t bytes_read = 0;
-#if !defined(HAVE_POLL) && !defined(HAVE_SELECT)
-	int polls = 0;
-#endif
-
-#ifndef WIN32
-	fcntl(session->socket_fd, F_SETFL, 0);
-#else
-	{
-		u_long block = FALSE;
-		ioctlsocket(session->socket_fd, FIONBIO, &block);
-	}
-#endif
-
-#ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking read: %d bytes", (int)count);
-#endif
-
-	while (bytes_read < count) {
-		int ret;
-
-		ret = recv(session->socket_fd, buf + bytes_read, count - bytes_read, 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 = ENOTCONN;	break;
-				case WSAEINTR:			errno = EINTR;		break;
-			}
-#endif
-			if (errno == EAGAIN) {
-#ifdef HAVE_POLL
-				struct pollfd read_socket;
-
-				read_socket.fd = session->socket_fd;
-				read_socket.events = POLLIN;
-
-				if (poll(&read_socket, 1, 30000) <= 0) {
-					return -1;
-				}
-#elif defined(HAVE_SELECT)
-				fd_set read_socket;
-				struct timeval timeout;
-
-				FD_ZERO(&read_socket);
-				FD_SET(session->socket_fd, &read_socket);
-
-				timeout.tv_sec = 30;
-				timeout.tv_usec = 0;
-
-				if (select(session->socket_fd + 1, &read_socket, NULL, NULL, &timeout) <= 0) {
-					return -1;
-				}
-#else
-				if (polls++ > LIBSSH2_SOCKET_POLL_MAXLOOPS) {
-					return -1;
-				}
-				usleep(LIBSSH2_SOCKET_POLL_UDELAY);
-#endif /* POLL/SELECT/SLEEP */
-				continue;
-			}
-			if (errno == EINTR) {
-				continue;
-			}
-			if ((errno == EBADF) || (errno == EIO) || (errno == ENOTCONN)) {
-				session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
-			}
-			return -1;
-		}
-		if (ret == 0) continue;
-
-		bytes_read += ret;
-	}
-
-#ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking read: %d bytes actually read", (int)bytes_read);
-#endif
-
-	return bytes_read;
-}
-/* }}} */
-
-/* {{{ 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 (0 if nothing added), or -1 on failure
- */
-int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
-{
-	int packet_type = -1;
-
-	if (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
-		return 0;
-	}
-
-#ifndef WIN32
-	fcntl(session->socket_fd, F_SETFL, O_NONBLOCK);
-#else
-	{
-		u_long non_block = TRUE;
-		ioctlsocket(session->socket_fd, FIONBIO, &non_block);
-	}
-#endif
-
-#ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Checking for packet: will%s block", should_block ? "" : " not");
-#endif
-	if (session->state & LIBSSH2_STATE_NEWKEYS) {
-		/* Temporary Buffer
-		 * The largest blocksize (currently) is 32, the largest MAC (currently) is 20
-		 */
-		unsigned char block[2 * 32], *payload, *s, *p, tmp[6];
-		ssize_t read_len;
-		unsigned long blocksize = session->remote.crypt->blocksize;
-		unsigned long packet_len, payload_len;
-		int padding_len;
-		int macstate;
-		int free_payload = 1;
-
-		/* Note: If we add any cipher with a blocksize less than 6 we'll need to get more creative with this
-		 * For now, all blocksize sizes are 8+
-		 */
-		if (should_block) {
-			read_len = libssh2_blocking_read(session, block, blocksize);
-			if(read_len <= 0)
-				return read_len;
-		} else {
-                        ssize_t nread;
-			read_len = recv(session->socket_fd, block, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
-			if (read_len <= 0) {
-				return 0;
-			}
-			nread = libssh2_blocking_read(session, block + read_len, blocksize - read_len);
-			if(nread <= 0)
-				return nread;
-
-			read_len += nread;
-		}
-		if (read_len < blocksize) {
-			return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
-		}
-
-		if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
-			libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
-			return -1;
-		}
-
-		packet_len = libssh2_ntohu32(block);
-		
-		/* 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(packet_len > MAX_SSH_PACKET_LEN) {
-			return -1;
-		}
-		
-		padding_len = block[4];
-#ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Processing packet %lu bytes long (with %lu bytes padding)", packet_len, padding_len);
-#endif
-		memcpy(tmp, block, 5); /* Use this for MAC later */
-
-		payload_len = packet_len - 1; /* padding_len(1) */
-		/* Sanity Check */
-		if ((payload_len > LIBSSH2_PACKET_MAXPAYLOAD) ||
-			((packet_len + 4) % blocksize)) {
-			/* If something goes horribly wrong during the decryption phase, just bailout and die gracefully */
-			session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
-			libssh2_error(session, LIBSSH2_ERROR_PROTO, "Fatal protocol error, invalid payload size", 0);
-			return -1;
-		}
-
-		s = payload = LIBSSH2_ALLOC(session, payload_len);
-		memcpy(s, block + 5, blocksize - 5);
-		s += blocksize - 5;
-
-		p = s;
-		while (p - payload < payload_len) {
-			read_len = payload_len - (p - payload);
-			if (read_len > 4096) read_len = 4096;
-
-			if (libssh2_blocking_read(session, p, read_len) < read_len) {
-				LIBSSH2_FREE(session, payload);
-				return -1;
-			}
-
-			p += read_len;
-
-    			while (s < p) {
-				memcpy(block, s, blocksize);
-
-				if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
-					libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
-					LIBSSH2_FREE(session, payload);
-					return -1;
-				}
-				memcpy(s, block, blocksize);
-
-				s += blocksize;
-			}
-		}
-
-		read_len = libssh2_blocking_read(session, block, session->remote.mac->mac_len);
-		if (read_len < session->remote.mac->mac_len) {
-			LIBSSH2_FREE(session, payload);
-			return -1;
-		}
-
-		/* Calculate MAC hash */
- 		session->remote.mac->hash(session, block + session->remote.mac->mac_len, session->remote.seqno, tmp, 5, payload, payload_len, &session->remote.mac_abstract);
-
-		macstate =  (strncmp((char *)block, (char *)block + session->remote.mac->mac_len, session->remote.mac->mac_len) == 0) ? LIBSSH2_MAC_CONFIRMED : LIBSSH2_MAC_INVALID;
-
-		session->remote.seqno++;
-
-		/* Ignore padding */
-		payload_len -= padding_len;
-
-		if (session->remote.comp &&
-			strcmp(session->remote.comp->name, "none")) {
-			/* Decompress */
-			unsigned char *data;
-			unsigned long data_len;
-
-			if (session->remote.comp->comp(session, 0, &data, &data_len, LIBSSH2_PACKET_MAXDECOMP, &free_payload, payload, payload_len, &session->remote.comp_abstract)) {
-				LIBSSH2_FREE(session, payload);
-				return -1;
-			}
-#ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Payload decompressed: %lu bytes(compressed) to %lu bytes(uncompressed)", data_len, payload_len);
-#endif
-			if (free_payload) {
-				LIBSSH2_FREE(session, payload);
-				payload = data;
-				payload_len = data_len;
-			} else {
-				if (data == payload) {
-					/* It's not to be freed, because the compression layer reused payload,
-					 * So let's do the same!
-					 */
-					payload_len = data_len;
-				} else {
-					/* No comp_method actually lets this happen, but let's prepare for the future */
-
-					LIBSSH2_FREE(session, payload);
-
-					/* We need a freeable struct otherwise the brigade won't know what to do with it */
-					payload = LIBSSH2_ALLOC(session, data_len);
-					if (!payload) {
-						libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for copy of uncompressed data", 0);
-						return -1;
-					}
-					memcpy(payload, data, data_len);
-					payload_len = data_len;
-				}
-			}
-		}
-
-		packet_type = payload[0];
-		libssh2_packet_add(session, payload, payload_len, macstate);
-
-	} else { /* No cipher active */
-		unsigned char *payload;
-		unsigned char buf[24];
-		ssize_t buf_len;
-		unsigned long payload_len;
-		uint32_t packet_length;
-		unsigned long padding_length;
-
-		if (should_block) {
-			buf_len = libssh2_blocking_read(session, buf, 5);
-		} else {
-			ssize_t nread;
-			buf_len = recv(session->socket_fd, buf, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
-			if (buf_len <= 0) {
-                                return buf_len;
-			}
-			nread = libssh2_blocking_read(session, buf, 5 - buf_len);
-			if(nread <= 0)
-				return -1;
-
-			buf_len += nread;
-		}
-		if (buf_len < 5) {
-			/* Something bad happened */
-			return -1;
-		}
-		packet_length = libssh2_ntohu32(buf);
-		
-		/* 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(packet_length > MAX_SSH_PACKET_LEN) {
-			return -1;
-		}
-		
-		padding_length = buf[4];
-#ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Processing plaintext packet %lu bytes long (with %lu bytes padding)", packet_length, padding_length);
-#endif
-
-		payload_len = packet_length - padding_length - 1; /* padding_length(1) */
-		payload = LIBSSH2_ALLOC(session, payload_len);
-		if (!payload) {
-			libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for copy of plaintext data", 0);
-			return -1;
-		}
-
-		if (libssh2_blocking_read(session, payload, payload_len) < payload_len) {
-			return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
-		}
-		while (padding_length) {
-			int l;
-			/* Flush padding */
-			l = libssh2_blocking_read(session, buf, padding_length);
-			if (l > 0)
-				padding_length -= l;
-			else
-				break;
-		}
-
-		packet_type = payload[0];
-
-		/* MACs don't exist in non-encrypted mode */
-		libssh2_packet_add(session, payload, payload_len, LIBSSH2_MAC_CONFIRMED);
-		session->remote.seqno++;
-	}
-	return packet_type;
+        return 0;
 }
 /* }}} */
 
 /* {{{ libssh2_packet_ask
- * Scan the brigade for a matching packet type, optionally poll the socket for a packet first
+ * 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)
+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;
+        LIBSSH2_PACKET *packet = session->packets.head;
 
-	if (poll_socket) {
-		if (libssh2_packet_read(session, 0) < 0) {
-			return -1;
-		}
-	}
+        if (poll_socket) {
+                libssh2pack_t rc = libssh2_packet_read(session);
+                if ((rc < 0) && !packet) {
+                        return rc;
+                }
+        }
 #ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Looking for packet of type: %d", (int)packet_type);
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Looking for packet of type: %d", (int)packet_type);
 #endif
-	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;
+        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->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;
-			}
+                        if (packet->next) {
+                                packet->next->prev = packet->prev;
+                        } else {
+                                session->packets.tail = packet->prev;
+                        }
 
-			LIBSSH2_FREE(session, packet);
+                        LIBSSH2_FREE(session, packet);
 
-			return 0;
-		}
-		packet = packet->next;
-	}
-	return -1;
+                        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
+ * 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,
-						   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)
+                           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);
+        int i, packet_types_len = strlen((char *)packet_types);
 
-	for(i = 0; i < packet_types_len; i++) {
-		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;
-		}
-	}
+        for(i = 0; i < packet_types_len; i++) {
+                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;
+        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
+ * [BLOCKING] for LIBSSH2_READ_TIMEOUT seconds
  * 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)
+
+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)
 {
-	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;
-	}
+        time_t start = time(NULL);
+
+        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;
+        }
 
 #ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking until packet of type %d becomes available", (int)packet_type);
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
+                       "Blocking until packet of type %d becomes available",
+                       (int)packet_type);
 #endif
-	while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
-		int ret = libssh2_packet_read(session, 1);
-		if (ret < 0) {
-			return -1;
-		}
-		if (ret == 0) continue;
+        while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
+                libssh2pack_t ret = libssh2_packet_read(session);
+                if ((ret < 0)  && (ret != PACKET_EAGAIN)) {
+			/* an error which is not just because of blocking */
+                        return ret;
+                }
+                if (packet_type == ret) {
+                        /* 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);
+                        return ret;
+                }
+                else if (ret <= 0) {
+                        /* nothing available, wait until data arrives or
+                           we time out */
+                        long left = LIBSSH2_READ_TIMEOUT -
+                                (time(NULL) - start);
 
-		if (packet_type == ret) {
-			/* Be lazy, let packet_ask pull it out of the brigade */
-			return libssh2_packet_ask_ex(session, packet_type, data, data_len, match_ofs, match_buf, match_len, 0);
-		}
-	}
+                        if((left <= 0) ||
+			   (libssh2_waitsocket(session, left) <= 0)) {
+                                return PACKET_TIMEOUT;
+                        }
+                }
+        }
 
-	/* Only reached if the socket died */
-	return -1;
+        /* Only reached if the socket died */
+        return -1;
 }
 /* }}} */
 
@@ -1079,203 +797,97 @@ int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_typ
  */
 int libssh2_packet_burn(LIBSSH2_SESSION *session)
 {
-	unsigned char *data;
-	unsigned long data_len;
-	unsigned char all_packets[255];
-	int i;
-	for(i = 1; i < 256; i++) all_packets[i - 1] = i;
+        unsigned char *data;
+        unsigned long data_len;
+        unsigned char all_packets[255];
+        int i;
+        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;
-	}
+        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;
+        }
 
 #ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking until packet becomes available to burn");
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Blocking until packet becomes available to burn");
 #endif
-	while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
-		int ret = libssh2_packet_read(session, 1);
-		if (ret < 0) {
-			return -1;
-		}
-		if (ret == 0) continue;
+        while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
+                int ret = libssh2_packet_read(session);
+                if (ret < 0) {
+                        return ret;
+                }
+                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);
-			return ret;
-		}
-	}
+                /* 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);
+                        return ret;
+                }
+        }
 
-	/* Only reached if the socket died */
-	return -1;
+        /* 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
+ * [BLOCKING]
+ * 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, 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 libssh2_packet_requirev_ex(LIBSSH2_SESSION *session,
+                               unsigned char *packet_types,
+                               unsigned char **data, unsigned long *data_len,
+                               unsigned long match_ofs,
+                               const unsigned char *match_buf,
+                               unsigned long match_len)
 {
-	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 */
-		return 0;
-	}
+        time_t start = time(NULL);
 
-	while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
-		int ret = libssh2_packet_read(session, 1);
-		if (ret < 0) {
-			return -1;
-		}
-		if (ret == 0) {
-			continue;
-		}
+        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 */
+                return 0;
+        }
 
-		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);
-		}
-	}
+        while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
+                int ret = libssh2_packet_read(session);
+                if ((ret < 0) && (ret != PACKET_EAGAIN)) {
+                        return ret;
+                }
+                if (ret <= 0) {
+                        long left = LIBSSH2_READ_TIMEOUT -
+                                (time(NULL) - start);
 
-	/* Only reached if the socket died */
-	return -1;
-}
-/* }}} */
-
-/* {{{ libssh2_packet_write
- * Send a packet, encrypting it and adding a MAC code if necessary
- * Returns 0 on success, non-zero on failure
- */
-int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len)
-{
-	unsigned long packet_length = data_len + 1;
-	unsigned long block_size = (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->blocksize : 8;
-	/* At this point packet_length doesn't include the packet_len field itself */
-	unsigned long padding_length;
-	int free_data = 0;
-	unsigned char buf[246]; /* 6 byte header plus max padding size(240) */
-
-#ifdef LIBSSH2_DEBUG_TRANSPORT
-{
-	/* Show a hint of what's being sent */
-	char excerpt[32];
-	int ex_len = 0, db_ofs = 0;
-
-	for (; ex_len < 24 && db_ofs < data_len; ex_len += 3, db_ofs++) snprintf(excerpt + ex_len, 4, "%02X ", data[db_ofs]);
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending packet type %d, length=%lu, %s", (int)data[0], data_len, excerpt);
-}
-#endif
-	if ((session->state & LIBSSH2_STATE_NEWKEYS) &&
-		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 -1;
-		}
-#ifdef LIBSSH2_DEBUG_TRANSPORT
-		_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Compressed payload to %lu bytes", data_len);
-#endif
-	}
-
-#ifndef WIN32
-	fcntl(session->socket_fd, F_SETFL, 0);
-#else
-	{
-		u_long non_block = FALSE;
-		ioctlsocket(session->socket_fd, FIONBIO, &non_block);
-	}
-#endif
-
-	packet_length = data_len + 1; /* padding_length(1) -- MAC doesn't count -- Padding to be added soon */
-	padding_length = block_size - ((packet_length + 4) % block_size);
-	if (padding_length < 4) {
-		padding_length += block_size;
-	}
-	/* TODO: Maybe add 1 or 2 times block_size to padding_length randomly -- shake things up a bit... */
-
-	packet_length += padding_length;
-	libssh2_htonu32(buf, packet_length);
-	buf[4] = padding_length;
-#ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending packet with total length %lu (%lu bytes padding)", packet_length, padding_length);
-#endif
-
-	if (session->state & LIBSSH2_STATE_NEWKEYS) {
-		/* Encryption is in effect */
-		unsigned char *encbuf, *s;
-		int ret, size, written = 0;
-
-		/* include packet_length(4) itself and room for the hash at the end */
-		encbuf = LIBSSH2_ALLOC(session, 4 + packet_length + session->local.mac->mac_len);
-		if (!encbuf) {
-			libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate encryption buffer", 0);
-			if (free_data) {
-				LIBSSH2_FREE(session, data);
-			}
-			return -1;
-		}
-
-		/* Copy packet to encoding buffer */
-		memcpy(encbuf, buf, 5);
-		memcpy(encbuf + 5, data, data_len);
-		libssh2_random(encbuf + 5 + data_len, padding_length);
-		if (free_data) {
-			LIBSSH2_FREE(session, data);
-		}
-
-		/* Calculate MAC hash */
- 		session->local.mac->hash(session, encbuf + 4 + packet_length , session->local.seqno, encbuf, 4 + packet_length, NULL, 0, &session->local.mac_abstract);
-
-		/* Encrypt data */
-		for(s = encbuf; (s - encbuf) < (4 + packet_length) ; s += session->local.crypt->blocksize) {
-			session->local.crypt->crypt(session, s, &session->local.crypt_abstract);
-		}
-
-		session->local.seqno++;
-
-		/* Send It */
-		size = 4 + packet_length + session->local.mac->mac_len;
-		written = 0;
-
-		while(written < size) {
-		    ret = send(session->socket_fd, encbuf + written, size - written, LIBSSH2_SOCKET_SEND_FLAGS(session));
-		    if(ret > 0) written += ret;
-		    else break;
-		}
-
-		ret = written == size ? 0 : -1;
-
-		/* Cleanup environment */
-		LIBSSH2_FREE(session, encbuf);
-
-		return ret;
-	} else { /* LIBSSH2_ENDPOINT_CRYPT_NONE */
-		/* Simplified write for non-encrypted mode */
-		struct iovec data_vector[3];
-
-		/* Using vectors means we don't have to alloc a new buffer -- a byte saved is a byte earned
-		 * No MAC during unencrypted phase
-		 */
-		data_vector[0].iov_base = buf;
-		data_vector[0].iov_len = 5;
-		data_vector[1].iov_base = (char*)data;
-		data_vector[1].iov_len = data_len;
-		data_vector[2].iov_base = buf + 5;
-		data_vector[2].iov_len = padding_length;
-
-		session->local.seqno++;
-
-		/* Ignore this, it can't actually happen :) */
-		if (free_data) {
-			LIBSSH2_FREE(session, data);
-		}
-
-		return ((packet_length + 4) == writev(session->socket_fd, data_vector, 3)) ? 0 : 1;
-	}
+                        if((left <= 0) ||
+			   (libssh2_waitsocket(session, left) <= 0 )) {
+                                return PACKET_TIMEOUT;
+                        }
+                }
+
+                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 */
+        return -1;
 }
 /* }}} */
diff --git a/src/publickey.c b/src/publickey.c
index ff331f0..524d7ca 100644
--- a/src/publickey.c
+++ b/src/publickey.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms,
@@ -147,7 +147,7 @@ static int libssh2_publickey_packet_receive(LIBSSH2_PUBLICKEY *pkey, unsigned ch
 	unsigned long packet_len;
 	unsigned char *packet;
 
-	if (libssh2_channel_read(channel, (char *)buffer, 4) != 4) {
+	if (_libssh2_channel_read(channel, (char *)buffer, 4) != 4) {
 		libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid response from publickey subsystem", 0);
 		return -1;
 	}
@@ -159,7 +159,7 @@ static int libssh2_publickey_packet_receive(LIBSSH2_PUBLICKEY *pkey, unsigned ch
 		return -1;
 	}
 
-	if (libssh2_channel_read(channel, (char *)packet, packet_len) != packet_len) {
+	if (_libssh2_channel_read(channel, (char *)packet, packet_len) != packet_len) {
 		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for publickey subsystem response packet", 0);
 		LIBSSH2_FREE(session, packet);
 		return -1;
diff --git a/src/scp.c b/src/scp.c
index 95e4d3f..8866b06 100644
--- a/src/scp.c
+++ b/src/scp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms,
@@ -42,9 +42,12 @@
 #define LIBSSH2_SCP_RESPONSE_BUFLEN		256
 
 /* {{{ libssh2_scp_recv
+ * [BLOCKING]
  * Open a channel and request a remote file via SCP
  */
-LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb)
+LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session,
+					      const char *path,
+					      struct stat *sb)
 {
 	int path_len = strlen(path);
 	unsigned char *command, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
@@ -103,8 +106,10 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const ch
 	response_len = 0;
 	while (sb && (response_len < LIBSSH2_SCP_RESPONSE_BUFLEN)) {
 		unsigned char *s, *p;
+		int rc;
 
-		if (libssh2_channel_read(channel, response + response_len, 1) <= 0) {
+		rc = _libssh2_channel_read(channel, response + response_len, 1);
+		if(rc <= 0) {
 			/* Timeout, give up */
 			libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Timed out waiting for SCP response", 0);
 			libssh2_channel_free(channel);
@@ -118,9 +123,9 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const ch
 			return NULL;
 		}
 
-		if ((response_len > 1) && 
-			((response[response_len-1] < '0') || (response[response_len-1] > '9')) && 
-			(response[response_len-1] != ' ') && 
+		if ((response_len > 1) &&
+			((response[response_len-1] < '0') || (response[response_len-1] > '9')) &&
+			(response[response_len-1] != ' ') &&
 			(response[response_len-1] != '\r') &&
 			(response[response_len-1] != '\n')) {
 			libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid data in SCP response", 0);
@@ -135,7 +140,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const ch
 				libssh2_channel_free(channel);
 				return NULL;
 			}
-			/* Way too short to be an SCP response,  or not done yet, short circuit */
+			/* Way too short to be an SCP response,	 or not done yet, short circuit */
 			continue;
 		}
 
@@ -215,7 +220,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const ch
 	while (response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) {
 		char *s, *p, *e = NULL;
 
-		if (libssh2_channel_read(channel, response + response_len, 1) <= 0) {
+		if (_libssh2_channel_read(channel, response + response_len, 1) <= 0) {
 			/* Timeout, give up */
 			libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Timed out waiting for SCP response", 0);
 			libssh2_channel_free(channel);
@@ -229,7 +234,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const ch
 			return NULL;
 		}
 
-		if ((response_len > 1) && 
+		if ((response_len > 1) &&
 			(response[response_len-1] != '\r') &&
 			(response[response_len-1] != '\n') &&
 			((response[response_len-1] < 32) || (response[response_len-1] > 126))) {
@@ -245,7 +250,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const ch
 				libssh2_channel_free(channel);
 				return NULL;
 			}
-			/* Way too short to be an SCP response,  or not done yet, short circuit */
+			/* Way too short to be an SCP response,	 or not done yet, short circuit */
 			continue;
 		}
 
@@ -261,7 +266,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const ch
 		}
 
 		s = response + 1;
-		
+
 		p = strchr(s, ' ');
 		if (!p || ((p - s) <= 0)) {
 			/* No spaces or space in the wrong spot */
@@ -362,7 +367,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const
 #endif
 	/* Allocate a channel */
 	if ((channel = libssh2_channel_open_session(session)) == NULL) {
-	        /* previous call set libssh2_session_last_error(), pass it through */
+		/* previous call set libssh2_session_last_error(), pass it through */
 		LIBSSH2_FREE(session, command);
 		return NULL;
 	}
@@ -371,7 +376,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const
 
 	/* Request SCP for the desired file */
 	if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, command, command_len)) {
-	        /* previous call set libssh2_session_last_error(), pass it through */
+		/* previous call set libssh2_session_last_error(), pass it through */
 		LIBSSH2_FREE(session, command);
 		libssh2_channel_free(channel);
 		return NULL;
@@ -379,7 +384,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const
 	LIBSSH2_FREE(session, command);
 
 	/* Wait for ACK */
-	if ((libssh2_channel_read(channel, response, 1) <= 0) || (response[0] != 0)) {
+	if ((_libssh2_channel_read(channel, response, 1) <= 0) || (response[0] != 0)) {
 		libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0);
 		libssh2_channel_free(channel);
 		return NULL;
@@ -397,7 +402,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const
 			return NULL;
 		}
 		/* Wait for ACK */
-		if ((libssh2_channel_read(channel, response, 1) <= 0) || (response[0] != 0)) {
+		if ((_libssh2_channel_read(channel, response, 1) <= 0) || (response[0] != 0)) {
 			libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0);
 			libssh2_channel_free(channel);
 			return NULL;
@@ -422,7 +427,7 @@ LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const
 		return NULL;
 	}
 	/* Wait for ACK */
-	if ((libssh2_channel_read(channel, response, 1) <= 0) || (response[0] != 0)) {
+	if ((_libssh2_channel_read(channel, response, 1) <= 0) || (response[0] != 0)) {
 		libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0);
 		libssh2_channel_free(channel);
 		return NULL;
diff --git a/src/session.c b/src/session.c
index 9d42c2d..14bd382 100644
--- a/src/session.c
+++ b/src/session.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms,
@@ -66,6 +66,7 @@
  */
 static LIBSSH2_ALLOC_FUNC(libssh2_default_alloc)
 {
+	(void)abstract;
 	return malloc(count);
 }
 /* }}} */
@@ -74,6 +75,7 @@ static LIBSSH2_ALLOC_FUNC(libssh2_default_alloc)
  */
 static LIBSSH2_FREE_FUNC(libssh2_default_free)
 {
+	(void)abstract;
 	free(ptr);
 }
 /* }}} */
@@ -82,6 +84,7 @@ static LIBSSH2_FREE_FUNC(libssh2_default_free)
  */
 static LIBSSH2_REALLOC_FUNC(libssh2_default_realloc)
 {
+	(void)abstract;
 	return realloc(ptr, count);
 }
 /* }}} */
@@ -96,8 +99,8 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
 	char banner[256];
 	int banner_len = 0;
 
-	while ((banner_len < sizeof(banner)) &&
-			((banner_len == 0) || (banner[banner_len-1] != '\n'))) {
+	while ((banner_len < (int)sizeof(banner)) &&
+	       ((banner_len == 0) || (banner[banner_len-1] != '\n'))) {
 		char c = '\0';
 		int ret;
 
@@ -159,13 +162,13 @@ static int libssh2_banner_receive(LIBSSH2_SESSION *session)
  */
 static int libssh2_banner_send(LIBSSH2_SESSION *session)
 {
-	char *banner = LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF;
+	char *banner = (char *)LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF;
 	int banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1;
 
 	if (session->local.banner) {
 		/* setopt_string will have given us our \r\n characters */
-		banner_len = strlen(session->local.banner);
-		banner = session->local.banner;
+		banner_len = strlen((char *)session->local.banner);
+		banner = (char *)session->local.banner;
 	}
 #ifdef LIBSSH2_DEBUG_TRANSPORT
 {
@@ -206,14 +209,16 @@ LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, const char *banner)
 
 	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);
+		libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+			      "Unable to allocate memory for local banner", 0);
 		return -1;
 	}
 
 	memcpy(session->local.banner, banner, banner_len);
 #ifdef LIBSSH2_DEBUG_TRANSPORT
 	session->local.banner[banner_len] = '\0';
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting local Banner: %s", session->local.banner);
+	_libssh2_debug(session, LIBSSH2_DBG_TRANS,
+		       "Setting local Banner: %s", session->local.banner);
 #endif
 	session->local.banner[banner_len++] = '\r';
 	session->local.banner[banner_len++] = '\n';
@@ -235,14 +240,17 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(
 			LIBSSH2_REALLOC_FUNC((*my_realloc)),
 			void *abstract)
 {
-	LIBSSH2_ALLOC_FUNC((*local_alloc))		= libssh2_default_alloc;
-	LIBSSH2_FREE_FUNC((*local_free))		= libssh2_default_free;
+	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;
+	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);
 	memset(session, 0, sizeof(LIBSSH2_SESSION));
@@ -251,7 +259,8 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(
 	session->realloc	= local_realloc;
 	session->abstract	= abstract;
 #ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "New session resource allocated");
+	_libssh2_debug(session, LIBSSH2_DBG_TRANS,
+		       "New session resource allocated");
 #endif
 
 	libssh2_crypto_init ();
@@ -264,7 +273,9 @@ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(
  * Set (or reset) a callback function
  * Returns the prior address
  */
-LIBSSH2_API void* libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbtype, void *callback)
+LIBSSH2_API void* libssh2_session_callback_set(LIBSSH2_SESSION *session,
+					       int cbtype,
+					       void *callback)
 {
 	void *oldcb;
 
@@ -273,27 +284,27 @@ LIBSSH2_API void* libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbt
 			oldcb = session->ssh_msg_ignore;
 			session->ssh_msg_ignore = callback;
 			return oldcb;
-			break;
+
 		case LIBSSH2_CALLBACK_DEBUG:
 			oldcb = session->ssh_msg_debug;
 			session->ssh_msg_debug = callback;
 			return oldcb;
-			break;
+
 		case LIBSSH2_CALLBACK_DISCONNECT:
 			oldcb = session->ssh_msg_disconnect;
 			session->ssh_msg_disconnect = callback;
 			return oldcb;
-			break;
+
 		case LIBSSH2_CALLBACK_MACERROR:
 			oldcb = session->macerror;
 			session->macerror = callback;
 			return oldcb;
-			break;
+
 		case LIBSSH2_CALLBACK_X11:
 			oldcb = session->x11;
 			session->x11 = callback;
 			return oldcb;
-			break;
+
 	}
 #ifdef LIBSSH2_DEBUG_TRANSPORT
 	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting Callback %d", cbtype);
@@ -306,8 +317,9 @@ LIBSSH2_API void* libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbt
 /* {{{ 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 socket
+ * 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 socket)
 {
@@ -315,13 +327,17 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
 	unsigned long data_len;
 	unsigned char service[sizeof("ssh-userauth") + 5 - 1];
 	unsigned long service_length;
+	int rc;
 
 #ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "session_startup for socket %d", socket);
+	_libssh2_debug(session, LIBSSH2_DBG_TRANS,
+		       "session_startup for socket %d", socket);
 #endif
+	/* FIXME: on some platforms (like win32) sockets are unsigned */
 	if (socket < 0) {
 		/* Did we forget something? */
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE, "Bad socket provided", 0);
+		libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE,
+			      "Bad socket provided", 0);
 		return LIBSSH2_ERROR_SOCKET_NONE;
 	}
 	session->socket_fd = socket;
@@ -329,42 +345,52 @@ LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
 	/* TODO: Liveness check */
 	if (libssh2_banner_send(session)) {
 		/* Unable to send banner? */
-		libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND, "Error sending banner to remote host", 0);
+		libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND,
+			      "Error sending banner to remote host", 0);
 		return LIBSSH2_ERROR_BANNER_SEND;
 	}
 
 	if (libssh2_banner_receive(session)) {
 		/* Unable to receive banner from remote */
-		libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE, "Timeout waiting for banner", 0);
+		libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE,
+			      "Timeout waiting for banner", 0);
 		return LIBSSH2_ERROR_BANNER_NONE;
 	}
 
-	if (libssh2_kex_exchange(session, 0)) {
-		libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, "Unable to exchange encryption keys", 0);
+	rc = libssh2_kex_exchange(session, 0);
+	if(rc) {
+		libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
+			      "Unable to exchange encryption keys", 0);
 		return LIBSSH2_ERROR_KEX_FAILURE;
 	}
 
 #ifdef LIBSSH2_DEBUG_TRANSPORT
-	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Requesting userauth service");
+	_libssh2_debug(session, LIBSSH2_DBG_TRANS,
+		       "Requesting userauth service");
 #endif
 	/* Request the userauth service */
 	service[0] = SSH_MSG_SERVICE_REQUEST;
 	libssh2_htonu32(service + 1, sizeof("ssh-userauth") - 1);
 	memcpy(service + 5, "ssh-userauth", sizeof("ssh-userauth") - 1);
-	if (libssh2_packet_write(session, service, sizeof("ssh-userauth") + 5 - 1)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to ask for ssh-userauth service", 0);
+	if (libssh2_packet_write(session, service,
+				 sizeof("ssh-userauth") + 5 - 1)) {
+		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+			      "Unable to ask for ssh-userauth service", 0);
 		return LIBSSH2_ERROR_SOCKET_SEND;
 	}
 
-	if (libssh2_packet_require(session, SSH_MSG_SERVICE_ACCEPT, &data, &data_len)) {
+	rc = libssh2_packet_require(session, SSH_MSG_SERVICE_ACCEPT, &data,
+				   &data_len);
+	if(rc) {
 		return LIBSSH2_ERROR_SOCKET_DISCONNECT;
 	}
 	service_length = libssh2_ntohu32(data + 1);
 
 	if ((service_length != (sizeof("ssh-userauth") - 1)) ||
-		strncmp("ssh-userauth", data + 5, service_length)) {
+	    strncmp("ssh-userauth", (char *)data + 5, service_length)) {
 		LIBSSH2_FREE(session, data);
-		libssh2_error(session, LIBSSH2_ERROR_PROTO, "Invalid response received from server", 0);
+		libssh2_error(session, LIBSSH2_ERROR_PROTO,
+			      "Invalid response received from server", 0);
 		return LIBSSH2_ERROR_PROTO;
 	}
 	LIBSSH2_FREE(session, data);
@@ -619,7 +645,9 @@ LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session)
  * 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)
+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) {
@@ -630,7 +658,7 @@ LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errm
 					**errmsg = 0;
 				}
 			} else {
-				*errmsg = "";
+				*errmsg = (char *)"";
 			}
 		}
 		if (errmsg_len) {
@@ -640,7 +668,8 @@ LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errm
 	}
 
 	if (errmsg) {
-		char *serrmsg = session->err_msg ? session->err_msg : "";
+		char *serrmsg = session->err_msg ? session->err_msg :
+			(char *)"";
 		int ownbuf = session->err_msg ? session->err_should_free : 0;
 
 		if (want_buf) {
@@ -707,6 +736,9 @@ LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended
 }
 /* }}} */
 
+inline int libssh2_poll_channel_write(LIBSSH2_CHANNEL *channel);
+inline int libssh2_poll_listener_queued(LIBSSH2_LISTENER *listener);
+
 /* {{{ libssh2_poll_channel_write
  * Returns 0 if writing to channel would block,
  * non-0 if data can be written without blocking
@@ -730,13 +762,18 @@ inline int libssh2_poll_listener_queued(LIBSSH2_LISTENER *listener)
 /* {{{ libssh2_poll
  * Poll sockets, channels, and listeners for activity
  */
-LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout)
+LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds,
+			     long timeout)
 {
 	long timeout_remaining;
-	int i, active_fds;
+	unsigned int i, active_fds;
 #ifdef HAVE_POLL
 	LIBSSH2_SESSION *session = NULL;
 	struct pollfd sockets[nfds];
+	/* FIXME: (dast) this is not C89 code! However, the prototype for this
+	   function doesn't provide a session struct so we can't easily use
+	   the user-provided malloc replacement here... I suggest we modify
+	   the proto to make it possible. */
 
 	/* Setup sockets for polling */
 	for(i = 0; i < nfds; i++) {
@@ -893,7 +930,7 @@ LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeou
 					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) > 0);
+							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;
@@ -903,7 +940,7 @@ LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeou
 					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) > 0);
+							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;
diff --git a/src/sftp.c b/src/sftp.c
index dcdf563..a6a801c 100644
--- a/src/sftp.c
+++ b/src/sftp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms,
@@ -46,73 +46,73 @@
  */
 
 /* 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 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
 
 struct _LIBSSH2_SFTP {
-	LIBSSH2_CHANNEL *channel;
+        LIBSSH2_CHANNEL *channel;
 
-	unsigned long request_id, version;
+        unsigned long request_id, version;
 
-	LIBSSH2_PACKET_BRIGADE packets;
+        LIBSSH2_PACKET_BRIGADE packets;
 
-	LIBSSH2_SFTP_HANDLE *handles;
+        LIBSSH2_SFTP_HANDLE *handles;
 
-	unsigned long last_errno;
+        unsigned long last_errno;
 };
 
-#define LIBSSH2_SFTP_HANDLE_FILE	0
-#define LIBSSH2_SFTP_HANDLE_DIR		1
+#define LIBSSH2_SFTP_HANDLE_FILE        0
+#define LIBSSH2_SFTP_HANDLE_DIR         1
 
 /* S_IFREG */
-#define LIBSSH2_SFTP_ATTR_PFILETYPE_FILE	0100000
+#define LIBSSH2_SFTP_ATTR_PFILETYPE_FILE        0100000
 /* S_IFDIR */
-#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR		0040000
+#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR         0040000
 
 struct _LIBSSH2_SFTP_HANDLE {
-	LIBSSH2_SFTP *sftp;
-	LIBSSH2_SFTP_HANDLE *prev, *next;
+        LIBSSH2_SFTP *sftp;
+        LIBSSH2_SFTP_HANDLE *prev, *next;
 
-	char *handle;
-	int handle_len;
+        char *handle;
+        int handle_len;
 
-	char handle_type;
+        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;
+        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;
 };
 
 /* {{{ libssh2_sftp_packet_add
@@ -120,33 +120,33 @@ struct _LIBSSH2_SFTP_HANDLE {
  */
 static int libssh2_sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data, unsigned long data_len)
 {
-	LIBSSH2_SESSION *session = sftp->channel->session;
-	LIBSSH2_PACKET *packet;
+        LIBSSH2_SESSION *session = sftp->channel->session;
+        LIBSSH2_PACKET *packet;
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Received packet %d", (int)data[0]);
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Received packet %d", (int)data[0]);
 #endif
-	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 = 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;
+        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;
+        return 0;
 }
 /* }}} */
 
@@ -155,66 +155,59 @@ static int libssh2_sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data, unsi
  */
 static int libssh2_sftp_packet_read(LIBSSH2_SFTP *sftp, int should_block)
 {
-	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;
+        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;
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Waiting for packet: %s block", should_block ? "will" : "willnot");
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Waiting for packet: %s block", should_block ? "will" : "willnot");
 #endif
-	if (should_block) {
-		libssh2_channel_set_blocking(channel, 1);
-		if (4 != libssh2_channel_read(channel, buffer, 4)) {
-			libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for FXP packet", 0);
-			return -1;
-		}
-	} else {
-		libssh2_channel_set_blocking(channel, 0);
-		if (1 != libssh2_channel_read(channel, buffer, 1)) {
-			libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for FXP packet", 0);
-			return 0;
-		}
-		libssh2_channel_set_blocking(channel, 1);
-		if (3 != libssh2_channel_read(channel, buffer + 1, 3)) {
-			libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for FXP packet", 0);
-			return -1;
-		}
+	libssh2_channel_set_blocking(channel, should_block);
+	if (4 != _libssh2_channel_read(channel, (char *)buffer, 4)) {
+		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+			      "Timeout waiting for FXP packet", 0);
+		return -1;
 	}
-	packet_len = libssh2_ntohu32(buffer);
+
+        packet_len = libssh2_ntohu32(buffer);
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Data begin - Packet Length: %lu", packet_len);
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
+                       "Data begin - Packet Length: %lu", packet_len);
 #endif
-	if (packet_len > LIBSSH2_SFTP_PACKET_MAXLEN) {
-		libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, "SFTP packet too large", 0);
-		return -1;
-	}
+        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 = LIBSSH2_ALLOC(session, packet_len);
+        if (!packet) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate SFTP packet", 0);
+                return -1;
+        }
 
-	packet_received = 0;
-	while (packet_len > packet_received) {
-		long bytes_received = libssh2_channel_read(channel, packet + packet_received, packet_len - packet_received);
+        packet_received = 0;
+        while (packet_len > packet_received) {
+                long bytes_received =
+                        _libssh2_channel_read(channel,
+                                              (char *)packet + packet_received,
+                                              packet_len - packet_received);
 
-		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 (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 (libssh2_sftp_packet_add(sftp, packet, packet_len)) {
-		LIBSSH2_FREE(session, packet);
-		return -1;
-	}
+        if (libssh2_sftp_packet_add(sftp, packet, packet_len)) {
+                LIBSSH2_FREE(session, packet);
+                return -1;
+        }
 
-	return packet[0];
+        return packet[0];
 }
 /* }}} */
 
@@ -223,52 +216,53 @@ static int libssh2_sftp_packet_read(LIBSSH2_SFTP *sftp, int should_block)
  */
 static int libssh2_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_SESSION *session = sftp->channel->session;
+        LIBSSH2_PACKET *packet = sftp->packets.head;
+        unsigned char match_buf[5];
+        int match_len = 5;
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Asking for %d packet", (int)packet_type);
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Asking for %d packet", (int)packet_type);
 #endif
-	if (poll_channel) {
-		if (libssh2_sftp_packet_read(sftp, 0) < 0) {
-			return -1;
-		}
-	}
+        if (poll_channel) {
+                if (libssh2_sftp_packet_read(sftp, 0) < 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);
-	}
+        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(packet->data, match_buf, match_len) == 0) {
-			*data = packet->data;
-			*data_len = packet->data_len;
+        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->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;
-			}
+                        if (packet->next) {
+                                packet->next->prev = packet->prev;
+                        } else {
+                                sftp->packets.tail = packet->prev;
+                        }
 
-			LIBSSH2_FREE(session, packet);
+                        LIBSSH2_FREE(session, packet);
 
-			return 0;
-		}
-		packet = packet->next;
-	}
-	return -1;
+                        return 0;
+                }
+                packet = packet->next;
+        }
+        return -1;
 }
 /* }}} */
 
@@ -277,59 +271,77 @@ static int libssh2_sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type
  */
 static int libssh2_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;
+        LIBSSH2_SESSION *session = sftp->channel->session;
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Requiring %d packet", (int)packet_type);
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Requiring %d packet", (int)packet_type);
 #endif
-	if (libssh2_sftp_packet_ask(sftp, packet_type, request_id, data, data_len, 0) == 0) {
-		/* A packet was available in the packet brigade */
-		return 0;
-	}
+        if (libssh2_sftp_packet_ask(sftp, packet_type, request_id, data, data_len, 0) == 0) {
+                /* A packet was available in the packet brigade */
+                return 0;
+        }
 
-	while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
-		int ret = libssh2_sftp_packet_read(sftp, 1);
-		if (ret < 0) {
-			return -1;
-		}
-		if (ret == 0) continue;
+        while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
+                int ret = libssh2_sftp_packet_read(sftp, 1);
+                if (ret <= 0) {
+                        return -1;
+                }
 
-		if (packet_type == ret) {
-			/* Be lazy, let packet_ask pull it out of the brigade */
-			return libssh2_sftp_packet_ask(sftp, packet_type, request_id, data, data_len, 0);
-		}
-	}
+                if (packet_type == ret) {
+                        /* Be lazy, let packet_ask pull it out of the brigade */
+                        return libssh2_sftp_packet_ask(sftp, packet_type, request_id, data, data_len, 0);
+                }
+        }
 
-	/* Only reached if the socket died */
-	return -1;
+        /* Only reached if the socket died */
+        return -1;
 }
 /* }}} */
 
 /* {{{ libssh2_sftp_packet_requirev
  * Requie one of N possible reponses
  */
-static int libssh2_sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses, unsigned char *valid_responses, unsigned long request_id, unsigned char **data, unsigned long *data_len)
+static int libssh2_sftp_packet_requirev(LIBSSH2_SFTP *sftp,
+                                        int num_valid_responses,
+                                        unsigned char *valid_responses,
+                                        unsigned long request_id,
+                                        unsigned char **data,
+                                        unsigned long *data_len)
 {
-	int i;
+        int i;
+        time_t start = time(NULL);
 
-	/* Flush */
-	while (libssh2_sftp_packet_read(sftp, 0) > 0);
+        /* Flush */
+        while (libssh2_sftp_packet_read(sftp, 0) > 0);
 
-	while (sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
-		int ret;
-		for(i = 0; i < num_valid_responses; i++) {
-			if (libssh2_sftp_packet_ask(sftp, valid_responses[i], request_id, data, data_len, 0) == 0) {
-				return 0;
-			}
-		}
-		ret = libssh2_sftp_packet_read(sftp, 1);
-		if (ret < 0) {
-			return -1;
-		}
-		if (ret == 0) continue;
-	}
+        while (sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
+                int ret;
+                for(i = 0; i < num_valid_responses; i++) {
+                        if (libssh2_sftp_packet_ask(sftp, valid_responses[i],
+                                                    request_id, data,
+                                                    data_len, 0) == 0) {
+                                return 0;
+                        }
+                }
 
-	return -1;
+                ret = libssh2_sftp_packet_read(sftp, 1);
+                if (ret < 0) {
+                        return -1;
+                }
+                if (ret == 0) {
+                        /* prevent busy-looping */
+                        long left = LIBSSH2_READ_TIMEOUT -
+                                (time(NULL) - start);
+
+                        if((left <= 0) ||
+                           (libssh2_waitsocket(sftp->channel->session,
+                                               left)<=0)) {
+                                return PACKET_TIMEOUT;
+                        }
+                }
+        }
+
+        return -1;
 }
 /* }}} */
 
@@ -338,18 +350,18 @@ static int libssh2_sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_respon
  */
 static int libssh2_sftp_attrsize(LIBSSH2_SFTP_ATTRIBUTES *attrs)
 {
-	int attrsize = 4; /* flags(4) */
+        int attrsize = 4; /* flags(4) */
 
-	if (!attrs) {
-		return attrsize;
-	}
+        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 */
+        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;
+        return attrsize;
 }
 /* }}} */
 
@@ -358,37 +370,37 @@ static int libssh2_sftp_attrsize(LIBSSH2_SFTP_ATTRIBUTES *attrs)
  */
 static int libssh2_sftp_attr2bin(unsigned char *p, 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;
+        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 */
+        /* TODO: When we add SFTP4+ functionality flag_mask can get additional bits */
 
-	if (!attrs) {
-		libssh2_htonu32(s, 0);
-		return 4;
-	}
+        if (!attrs) {
+                libssh2_htonu32(s, 0);
+                return 4;
+        }
 
-	libssh2_htonu32(s, attrs->flags & flag_mask);				s += 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_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_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_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;
-	}
+        if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
+                libssh2_htonu32(s, attrs->atime);                                               s += 4;
+                libssh2_htonu32(s, attrs->mtime);                                               s += 4;
+        }
 
-	return (s - p);
+        return (s - p);
 }
 /* }}} */
 
@@ -396,30 +408,30 @@ static int libssh2_sftp_attr2bin(unsigned char *p, LIBSSH2_SFTP_ATTRIBUTES *attr
  */
 static int libssh2_sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES *attrs, unsigned char *p)
 {
-	unsigned char *s = p;
+        unsigned char *s = p;
 
-	memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
-	attrs->flags = libssh2_ntohu32(s);				s += 4;
+        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_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_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_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;
-	}
+        if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
+                attrs->atime = libssh2_ntohu32(s);                      s += 4;
+                attrs->mtime = libssh2_ntohu32(s);                      s += 4;
+        }
 
-	return (s - p);
+        return (s - p);
 }
 /* }}} */
 
@@ -427,18 +439,24 @@ static int libssh2_sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES *attrs, unsigned char *
    * 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);
+LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor)
+{
+        LIBSSH2_SFTP *sftp = (LIBSSH2_SFTP*)(*channel_abstract);
 
-	/* Loop through handles closing them */
-	while (sftp->handles) {
-		libssh2_sftp_close_handle(sftp->handles);
-	}
+        (void)session_abstract;
+        (void)channel;
 
-	LIBSSH2_FREE(session, sftp);
+        /* Loop through handles closing them */
+        while (sftp->handles) {
+                libssh2_sftp_close_handle(sftp->handles);
+        }
+
+        LIBSSH2_FREE(session, sftp);
 }
 /* }}} */
 
@@ -447,104 +465,109 @@ LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor) {
  */
 LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session)
 {
-	LIBSSH2_SFTP *sftp;
-	LIBSSH2_CHANNEL *channel;
-	unsigned char *data, *s, buffer[9]; /* sftp_header(5){excludes request_id} + version_id(4) */
-	unsigned long data_len;
+        LIBSSH2_SFTP *sftp;
+        LIBSSH2_CHANNEL *channel;
+        unsigned char *data, *s, buffer[9]; /* sftp_header(5){excludes request_id} + version_id(4) */
+        unsigned long data_len;
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Initializing SFTP subsystem");
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Initializing SFTP subsystem");
 #endif
-	channel = libssh2_channel_open_session(session);
-	if (!channel) {
-		libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to startup channel", 0);
-		return NULL;
-	}
-	if (libssh2_channel_subsystem(channel, "sftp")) {
-		libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to request SFTP subsystem", 0);
-		libssh2_channel_free(channel);
-		return NULL;
-	}
+        channel = libssh2_channel_open_session(session);
+        if (!channel) {
+                libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to startup channel", 0);
+                return NULL;
+        }
 
-	libssh2_channel_set_blocking(channel, 1);
+        if (libssh2_channel_subsystem(channel, "sftp")) {
+                libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to request SFTP subsystem", 0);
+                libssh2_channel_free(channel);
+                return NULL;
+        }
 
-	libssh2_channel_handle_extended_data(channel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
+        libssh2_channel_set_blocking(channel, 1);
 
-	sftp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP));
-	if (!sftp) {
-		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a new SFTP structure", 0);
-		libssh2_channel_free(channel);
-		return NULL;
-	}
-	memset(sftp, 0, sizeof(LIBSSH2_SFTP));
-	sftp->channel = channel;
-	sftp->request_id = 0;
+        libssh2_channel_handle_extended_data(channel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
 
-	libssh2_htonu32(buffer, 5);
-	buffer[4] = SSH_FXP_INIT;
-	libssh2_htonu32(buffer + 5, LIBSSH2_SFTP_VERSION);
+        sftp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP));
+        if (!sftp) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a new SFTP structure", 0);
+                libssh2_channel_free(channel);
+                return NULL;
+        }
+        memset(sftp, 0, sizeof(LIBSSH2_SFTP));
+        sftp->channel = channel;
+        sftp->request_id = 0;
+
+        libssh2_htonu32(buffer, 5);
+        buffer[4] = SSH_FXP_INIT;
+        libssh2_htonu32(buffer + 5, LIBSSH2_SFTP_VERSION);
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending FXP_INIT packet advertising version %d support", (int)LIBSSH2_SFTP_VERSION);
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending FXP_INIT packet advertising version %d support", (int)LIBSSH2_SFTP_VERSION);
 #endif
-	if (9 != libssh2_channel_write(channel, buffer, 9)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send SSH_FXP_INIT", 0);
-		libssh2_channel_free(channel);
-		LIBSSH2_FREE(session, sftp);
-		return NULL;
-	}
+        if (9 != libssh2_channel_write(channel, (char *)buffer, 9)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                              "Unable to send SSH_FXP_INIT", 0);
+                libssh2_channel_free(channel);
+                LIBSSH2_FREE(session, sftp);
+                return NULL;
+        }
 
-	if (libssh2_sftp_packet_require(sftp, SSH_FXP_VERSION, 0, &data, &data_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from SFTP subsystem", 0);
-		libssh2_channel_free(channel);
-		LIBSSH2_FREE(session, sftp);
-		return NULL;
-	}
-	if (data_len < 5) {
-		libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Invalid SSH_FXP_VERSION response", 0);
-		libssh2_channel_free(channel);
-		LIBSSH2_FREE(session, sftp);
-		return NULL;
-	}
+        if (libssh2_sftp_packet_require(sftp, SSH_FXP_VERSION, 0,
+                                        &data, &data_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                              "Timeout waiting for response from SFTP subsystem", 0);
+                libssh2_channel_free(channel);
+                LIBSSH2_FREE(session, sftp);
+                return NULL;
+        }
+        if (data_len < 5) {
+                libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Invalid SSH_FXP_VERSION response", 0);
+                libssh2_channel_free(channel);
+                LIBSSH2_FREE(session, sftp);
+                return NULL;
+        }
 
-	s = data + 1;
-	sftp->version = libssh2_ntohu32(s);					s += 4;
-	if (sftp->version > LIBSSH2_SFTP_VERSION) {
+        s = data + 1;
+        sftp->version = libssh2_ntohu32(s);                                     s += 4;
+        if (sftp->version > LIBSSH2_SFTP_VERSION) {
 #ifdef LIBSSH2_DEBUG_SFTP
-		_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Truncating remote SFTP version from %lu", sftp->version);
+                _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Truncating remote SFTP version from %lu", sftp->version);
 #endif
-		sftp->version = LIBSSH2_SFTP_VERSION;
-	}
+                sftp->version = LIBSSH2_SFTP_VERSION;
+        }
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Enabling SFTP version %lu compatability", sftp->version);
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Enabling SFTP version %lu compatability", sftp->version);
 #endif
-	while (s < (data + data_len)) {
-		char *extension_name, *extension_data;
-		unsigned long extname_len, extdata_len;
+        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;
+                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;
+                extdata_len = libssh2_ntohu32(s);                               s += 4;
+                extension_data = s;                                                             s += extdata_len;
 
-		/* TODO: Actually process extensions */
-	}
-	LIBSSH2_FREE(session, data);
+                /* TODO: Actually process extensions */
+        }
+        LIBSSH2_FREE(session, data);
 
-	/* Make sure that when the channel gets closed, the SFTP service is shut down too */
-	sftp->channel->abstract = sftp;
-	sftp->channel->close_cb = libssh2_sftp_dtor;
+        /* Make sure that when the channel gets closed, the SFTP service is shut down too */
+        sftp->channel->abstract = sftp;
+        sftp->channel->close_cb = libssh2_sftp_dtor;
 
-	return sftp;
+        return sftp;
 }
 /* }}} */
 
 /* {{{ libssh2_sftp_shutdown
  * Shutsdown the SFTP subsystem
  */
-LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp) {
-	return libssh2_channel_free(sftp->channel);
+LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp)
+{
+        return libssh2_channel_free(sftp->channel);
 }
 /* }}} */
 
@@ -557,350 +580,467 @@ LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp) {
  */
 LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, 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 };
-	unsigned long data_len, packet_len = filename_len + 13 + ((open_type == LIBSSH2_SFTP_OPENFILE) ? (4 + libssh2_sftp_attrsize(&attrs)) : 0);
-							/* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) + flags(4) */
-	unsigned char *packet, *data, *s;
-	unsigned char fopen_responses[2] = { SSH_FXP_HANDLE,	SSH_FXP_STATUS	};
-	unsigned long request_id;
+        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;
+	ssize_t packet_len = filename_len + 13 + ((open_type == LIBSSH2_SFTP_OPENFILE) ? (4 + libssh2_sftp_attrsize(&attrs)) : 0);
+                                                        /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) + flags(4) */
+        unsigned char *packet, *data, *s;
+        unsigned char fopen_responses[2] = { SSH_FXP_HANDLE,    SSH_FXP_STATUS  };
+        unsigned long request_id;
 
-	s = packet = LIBSSH2_ALLOC(session, packet_len);
-	if (!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);
+        s = packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!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, packet_len - 4);					s += 4;
-	*(s++) = (open_type == LIBSSH2_SFTP_OPENFILE) ? SSH_FXP_OPEN : SSH_FXP_OPENDIR;
-	request_id = sftp->request_id++;
-	libssh2_htonu32(s, 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_htonu32(s, packet_len - 4);                                     s += 4;
+        *(s++) = (open_type == LIBSSH2_SFTP_OPENFILE) ? SSH_FXP_OPEN : SSH_FXP_OPENDIR;
+        request_id = sftp->request_id++;
+        libssh2_htonu32(s, 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);
+        }
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending %s open request", (open_type == LIBSSH2_SFTP_OPENFILE) ? "file" : "directory");
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending %s open request", (open_type == LIBSSH2_SFTP_OPENFILE) ? "file" : "directory");
 #endif
-	if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_OPEN or FXP_OPENDIR command", 0);
-		LIBSSH2_FREE(session, packet);
-		return NULL;
-	}
-	LIBSSH2_FREE(session, packet);
+        if (packet_len != _libssh2_channel_write(channel, (char *)packet,
+						 packet_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_OPEN or FXP_OPENDIR command", 0);
+                LIBSSH2_FREE(session, packet);
+                return NULL;
+        }
+        LIBSSH2_FREE(session, packet);
 
-	if (libssh2_sftp_packet_requirev(sftp, 2, fopen_responses, request_id, &data, &data_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
-		return NULL;
-	}
+        if (libssh2_sftp_packet_requirev(sftp, 2, fopen_responses, request_id, &data, &data_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
+                return NULL;
+        }
 
-	if (data[0] == SSH_FXP_STATUS) {
-		libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Failed opening remote file", 0);
-		sftp->last_errno = libssh2_ntohu32(data + 5);
-		LIBSSH2_FREE(session, data);
-		return NULL;
-	}
+        if (data[0] == SSH_FXP_STATUS) {
+                libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Failed opening remote file", 0);
+                sftp->last_errno = libssh2_ntohu32(data + 5);
+                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 = 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 > 256) {
-		/* SFTP doesn't allow handles longer than 256 characters */
-		fp->handle_len = 256;
-	}
-	fp->handle = LIBSSH2_ALLOC(session, fp->handle_len);
-	if (!fp->handle) {
-		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate space for SFTP file/dir handle", 0);
-		LIBSSH2_FREE(session, data);
-		LIBSSH2_FREE(session, fp);
-		return NULL;
-	}
-	memcpy(fp->handle, data + 9, fp->handle_len);
-	LIBSSH2_FREE(session, data);
+        fp->handle_len = libssh2_ntohu32(data + 5);
+        if (fp->handle_len > 256) {
+                /* SFTP doesn't allow handles longer than 256 characters */
+                fp->handle_len = 256;
+        }
+        fp->handle = LIBSSH2_ALLOC(session, fp->handle_len);
+        if (!fp->handle) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate space for SFTP file/dir handle", 0);
+                LIBSSH2_FREE(session, data);
+                LIBSSH2_FREE(session, fp);
+                return NULL;
+        }
+        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;
+        /* 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;
+        fp->u.file.offset = 0;
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Open command successful");
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Open command successful");
 #endif
-	return fp;
+        return fp;
 }
 /* }}} */
 
-/* {{{ libssh2_sftp_read
- * Read from an SFTP file handle
+/* {{{ _libssh2_sftp_read
+ * Read from an SFTP file handle blocking/non-blocking depending on state
  */
-LIBSSH2_API size_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen) 
+
+static 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;
-	unsigned long packet_len = handle->handle_len + 25; /* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) + offset(8) + length(4) */
-	unsigned char *packet, *s, *data;
-	unsigned char read_responses[2] = { SSH_FXP_DATA,		SSH_FXP_STATUS };
-	size_t bytes_read = 0;
+        LIBSSH2_SFTP    *sftp    = handle->sftp;
+        LIBSSH2_CHANNEL *channel = sftp->channel;
+        LIBSSH2_SESSION *session = channel->session;
+        unsigned long data_len, request_id;
+        ssize_t packet_len = handle->handle_len + 25; /* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) + offset(8) + length(4) */
+        unsigned char *packet, *s, *data;
+        unsigned char read_responses[2] = { SSH_FXP_DATA,               SSH_FXP_STATUS };
+        size_t bytes_read = 0;
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Reading %lu bytes from SFTP handle", (unsigned long)buffer_maxlen);
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Reading %lu bytes from SFTP handle", (unsigned long)buffer_maxlen);
 #endif
-	s = packet = LIBSSH2_ALLOC(session, packet_len);
-	if (!packet) {
-		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_CLOSE packet", 0);
-		return -1;
-	}
+        s = packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!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_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, buffer_maxlen);					s += 4;
+        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;
 
-	if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_READ command", 0);
-		LIBSSH2_FREE(session, packet);
-		return -1;
-	}
-	LIBSSH2_FREE(session, packet);
+        memcpy(s, handle->handle, handle->handle_len);
+        s += handle->handle_len;
 
-	if (libssh2_sftp_packet_requirev(sftp, 2, read_responses, request_id, &data, &data_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
-		return -1;
-	}
+        libssh2_htonu64(s, handle->u.file.offset);
+        s += 8;
 
-	switch (data[0]) {
-		case SSH_FXP_STATUS:
-			sftp->last_errno = libssh2_ntohu32(data + 5);
-			libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
-			LIBSSH2_FREE(session, data);
-			return -1;
-		case SSH_FXP_DATA:
-			bytes_read = libssh2_ntohu32(data + 5);
-			if (bytes_read > (data_len - 9)) {
-				return -1;
-			}
+        libssh2_htonu32(s, buffer_maxlen);
+        s += 4;
+
+        if (packet_len != libssh2_channel_write(channel, (char *)packet,
+						packet_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                              "Unable to send FXP_READ command", 0);
+                LIBSSH2_FREE(session, packet);
+                return -1;
+        }
+        LIBSSH2_FREE(session, packet);
+
+        if (libssh2_sftp_packet_requirev(sftp, 2, read_responses, request_id,
+                                         &data, &data_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                              "Timeout waiting for status message", 0);
+                return -1;
+        }
+
+        switch (data[0]) {
+                case SSH_FXP_STATUS:
+                        sftp->last_errno = libssh2_ntohu32(data + 5);
+                        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                                      "SFTP Protocol Error", 0);
+                        LIBSSH2_FREE(session, data);
+                        return -1;
+                case SSH_FXP_DATA:
+                        bytes_read = libssh2_ntohu32(data + 5);
+                        if (bytes_read > (data_len - 9)) {
+                                return -1;
+                        }
 #ifdef LIBSSH2_DEBUG_SFTP
-			_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu bytes returned", (unsigned long)bytes_read);
+                        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
+                                       "%lu bytes returned",
+                                       (unsigned long)bytes_read);
 #endif
-			memcpy(buffer, data + 9, bytes_read);
-			handle->u.file.offset += bytes_read;
-			LIBSSH2_FREE(session, data);
-			return bytes_read;
+                        memcpy(buffer, data + 9, bytes_read);
+                        handle->u.file.offset += bytes_read;
+                        LIBSSH2_FREE(session, data);
+                        return bytes_read;
+        }
+
+        return -1;
+}
+/* {{{ libssh2_sftp_read
+ * Read from an SFTP file handle blocking
+ */
+LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle,
+                                      char *buffer, size_t buffer_maxlen)
+{
+        ssize_t rc;
+        LIBSSH2_CHANNEL *ch = handle->sftp->channel;
+        int bl = libssh2_channel_get_blocking(ch);
+
+        /* set blocking */
+        libssh2_channel_set_blocking(ch, 1);
+
+        rc = _libssh2_sftp_read(handle, buffer, buffer_maxlen);
+
+        /* restore state */
+        libssh2_channel_set_blocking(ch, bl);
+
+	if(rc < 0) {
+		/* precent accidental returning of other return codes since
+		   this API does not support/provide those */
+		return -1;
 	}
 
-	return -1;
+        return rc;
+}
+/* }}} */
+
+/* {{{ libssh2_sftp_readnb
+ * Read from an SFTP file handle non-blocking
+ */
+LIBSSH2_API ssize_t libssh2_sftp_readnb(LIBSSH2_SFTP_HANDLE *handle,
+                                        char *buffer, size_t buffer_maxlen)
+{
+        ssize_t rc;
+        LIBSSH2_CHANNEL *ch = handle->sftp->channel;
+        int bl = libssh2_channel_get_blocking(ch);
+
+        /* set non-blocking */
+        libssh2_channel_set_blocking(ch, 0);
+
+        rc = _libssh2_sftp_read(handle, buffer, buffer_maxlen);
+
+        /* restore state */
+        libssh2_channel_set_blocking(ch, bl);
+
+        return rc;
 }
 /* }}} */
 
 /* {{{ libssh2_sftp_readdir
  * Read from an SFTP directory handle
  */
-LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs) 
+LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_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, request_id, filename_len, num_names;
-	unsigned long packet_len = handle->handle_len + 13; /* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
-	unsigned char *packet, *s, *data;
-	unsigned char read_responses[2] = { SSH_FXP_NAME,		SSH_FXP_STATUS };
+        LIBSSH2_SFTP    *sftp    = handle->sftp;
+        LIBSSH2_CHANNEL *channel = sftp->channel;
+        LIBSSH2_SESSION *session = channel->session;
+        LIBSSH2_SFTP_ATTRIBUTES attrs_dummy;
+        unsigned long data_len, request_id, filename_len, num_names;
+        ssize_t packet_len = handle->handle_len + 13; /* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
+        unsigned char *packet, *s, *data;
+        unsigned char read_responses[2] = { SSH_FXP_NAME,               SSH_FXP_STATUS };
 
-	if (handle->u.dir.names_left) {
-		/* A prior request returned more than one directory entry, feed it back from the buffer */
-		unsigned char *s = handle->u.dir.next_name;
-		unsigned long real_filename_len = libssh2_ntohu32(s);
+        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';
-		}
+                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;
 
-		/* Skip longname */
-		s += 4 + libssh2_ntohu32(s);
+                /* 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));
-		}
-		s += libssh2_sftp_bin2attr(attrs ? attrs : &attrs_dummy, s);
+                /* Skip longname */
+                s += 4 + libssh2_ntohu32(s);
 
-		handle->u.dir.next_name = s;
-		if ((--handle->u.dir.names_left) == 0) {
-			LIBSSH2_FREE(session, handle->u.dir.names_packet);
-		}
+                if (attrs) {
+                        memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+                }
+                s += libssh2_sftp_bin2attr(attrs ? attrs : &attrs_dummy, s);
 
-		return filename_len;
-	}
+                handle->u.dir.next_name = (char *)s;
+                if ((--handle->u.dir.names_left) == 0) {
+                        LIBSSH2_FREE(session, handle->u.dir.names_packet);
+                }
 
-	/* Request another entry(entries?) */
+                return filename_len;
+        }
 
-	s = packet = LIBSSH2_ALLOC(session, packet_len);
-	if (!packet) {
-		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_READDIR packet", 0);
-		return -1;
-	}
+        /* Request another entry(entries?) */
 
-	libssh2_htonu32(s, packet_len - 4);					s += 4;
-	*(s++) = SSH_FXP_READDIR;
-	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;
+        s = packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!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;
+        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;
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Reading entries from directory handle");
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Reading entries from directory handle");
 #endif
-	if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_READ command", 0);
-		LIBSSH2_FREE(session, packet);
-		return -1;
-	}
-	LIBSSH2_FREE(session, packet);
+        if (packet_len != libssh2_channel_write(channel, (char *)packet,
+						packet_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_READ command", 0);
+                LIBSSH2_FREE(session, packet);
+                return -1;
+        }
+        LIBSSH2_FREE(session, packet);
 
-	if (libssh2_sftp_packet_requirev(sftp, 2, read_responses, request_id, &data, &data_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
-		return -1;
-	}
+        if (libssh2_sftp_packet_requirev(sftp, 2, read_responses, request_id, &data, &data_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
+                return -1;
+        }
 
-	if (data[0] == SSH_FXP_STATUS) {
-		int retcode;
+        if (data[0] == SSH_FXP_STATUS) {
+                int retcode;
 
-		retcode = libssh2_ntohu32(data + 5);
-		LIBSSH2_FREE(session, data);
-		if (retcode == LIBSSH2_FX_EOF) {
-			return 0;
-		} else {
-			sftp->last_errno = retcode;
-			libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
-			return -1;
-		}
-	}
+                retcode = libssh2_ntohu32(data + 5);
+                LIBSSH2_FREE(session, data);
+                if (retcode == LIBSSH2_FX_EOF) {
+                        return 0;
+                } else {
+                        sftp->last_errno = retcode;
+                        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
+                        return -1;
+                }
+        }
 
-	num_names = libssh2_ntohu32(data + 5);
+        num_names = libssh2_ntohu32(data + 5);
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu entries returned", num_names);
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu entries returned", num_names);
 #endif
-	if (num_names <= 0) {
-		LIBSSH2_FREE(session, data);
-		return (num_names == 0) ? 0 : -1;
-	}
+        if (num_names <= 0) {
+                LIBSSH2_FREE(session, data);
+                return (num_names == 0) ? 0 : -1;
+        }
 
-	if (num_names == 1) {
-		unsigned long real_filename_len = libssh2_ntohu32(data + 9);
+        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);
+                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);
+                /* The filename is not null terminated, make it so if possible */
+                if (filename_len < buffer_maxlen) {
+                        buffer[filename_len] = '\0';
+                }
 
-		return filename_len; 
-	}
+                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);
 
-	handle->u.dir.names_left = num_names;
-	handle->u.dir.names_packet = data;
-	handle->u.dir.next_name = data + 9;
+                return filename_len;
+        }
 
-	/* Be lazy, just use the name popping mechanism from the start of the function */
-	return libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs);
+        handle->u.dir.names_left = num_names;
+        handle->u.dir.names_packet = data;
+        handle->u.dir.next_name = (char *)data + 9;
+
+        /* Be lazy, just use the name popping mechanism from the start of the function */
+        return libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs);
+}
+/* }}} */
+
+/* {{{ _libssh2_sftp_write
+ * Write data to a file handle
+ */
+static 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, request_id, retcode;
+        ssize_t packet_len = handle->handle_len + count + 25; /* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) + offset(8) + count(4) */
+        unsigned char *packet, *s, *data;
+
+#ifdef LIBSSH2_DEBUG_SFTP
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Writing %lu bytes", (unsigned long)count);
+#endif
+        s = packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!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;
+        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, count);                                                      s += 4;
+        memcpy(s, buffer, count);                                                       s += count;
+
+        if (packet_len != libssh2_channel_write(channel, (char *)packet, packet_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_WRITE command", 0);
+                LIBSSH2_FREE(session, packet);
+                return -1;
+        }
+        LIBSSH2_FREE(session, packet);
+
+        if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
+                return -1;
+        }
+
+        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_write
- * Write data to a file handle
+ * Write data to a SFTP handle blocking
  */
-LIBSSH2_API size_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, size_t count)
+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, request_id, retcode;
-	unsigned long packet_len = handle->handle_len + count + 25; /* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) + offset(8) + count(4) */
-	unsigned char *packet, *s, *data;
+        ssize_t rc;
+        LIBSSH2_CHANNEL *ch = handle->sftp->channel;
+        int bl = libssh2_channel_get_blocking(ch);
 
-#ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Writing %lu bytes", (unsigned long)count);
-#endif
-	s = packet = LIBSSH2_ALLOC(session, packet_len);
-	if (!packet) {
-		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_WRITE packet", 0);
-		return -1;
-	}
+        /* set blocking */
+        libssh2_channel_set_blocking(ch, 1);
 
-	libssh2_htonu32(s, packet_len - 4);					s += 4;
-	*(s++) = SSH_FXP_WRITE;
-	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, count);							s += 4;
-	memcpy(s, buffer, count);							s += count;
+        rc = _libssh2_sftp_write(handle, buffer, count);
 
-	if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_WRITE command", 0);
-		LIBSSH2_FREE(session, packet);
-		return -1;
-	}
-	LIBSSH2_FREE(session, packet);
+        /* restore state */
+        libssh2_channel_set_blocking(ch, bl);
 
-	if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
-		return -1;
-	}
+        return rc;
+}
+/* }}} */
 
-	retcode = libssh2_ntohu32(data + 5);
-	LIBSSH2_FREE(session, data);
+/* {{{ libssh2_sftp_write
+ * Write data to a SFTP handle non-blocking
+ */
+LIBSSH2_API ssize_t libssh2_sftp_writenb(LIBSSH2_SFTP_HANDLE *handle,
+					 const char *buffer, size_t count)
+{
+        ssize_t rc;
+        LIBSSH2_CHANNEL *ch = handle->sftp->channel;
+        int bl = libssh2_channel_get_blocking(ch);
 
-	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;
+        /* set non-blocking */
+        libssh2_channel_set_blocking(ch, 0);
 
-	return -1;
+        rc = _libssh2_sftp_write(handle, buffer, count);
+
+        /* restore state */
+        libssh2_channel_set_blocking(ch, bl);
+
+        return rc;
 }
 /* }}} */
 
@@ -909,63 +1049,63 @@ LIBSSH2_API size_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *b
  */
 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, request_id;
-	unsigned long packet_len = handle->handle_len + 13 + (setstat ? libssh2_sftp_attrsize(attrs) : 0); 
-											/* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
-	unsigned char *packet, *s, *data;
-	unsigned char fstat_responses[2] = { SSH_FXP_ATTRS,		SSH_FXP_STATUS };
+        LIBSSH2_SFTP    *sftp    = handle->sftp;
+        LIBSSH2_CHANNEL *channel = sftp->channel;
+        LIBSSH2_SESSION *session = channel->session;
+        unsigned long data_len, request_id;
+        ssize_t packet_len = handle->handle_len + 13 + (setstat ? libssh2_sftp_attrsize(attrs) : 0);
+                                                                                        /* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
+        unsigned char *packet, *s, *data;
+        unsigned char fstat_responses[2] = { SSH_FXP_ATTRS,             SSH_FXP_STATUS };
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Issuing %s command", setstat ? "set-stat" : "stat");
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Issuing %s command", setstat ? "set-stat" : "stat");
 #endif
-	s = packet = LIBSSH2_ALLOC(session, packet_len);
-	if (!packet) {
-		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FSTAT/FSETSTAT packet", 0);
-		return -1;
-	}
+        s = packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!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;
-	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;
-	if (setstat) {
-		s += libssh2_sftp_attr2bin(s, attrs);
-	}
+        libssh2_htonu32(s, packet_len - 4);                                     s += 4;
+        *(s++) = setstat ? SSH_FXP_FSETSTAT : SSH_FXP_FSTAT;
+        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;
+        if (setstat) {
+                s += libssh2_sftp_attr2bin(s, attrs);
+        }
 
-	if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, setstat ? "Unable to send FXP_FSETSTAT" : "Unable to send FXP_FSTAT command", 0);
-		LIBSSH2_FREE(session, packet);
-		return -1;
-	}
-	LIBSSH2_FREE(session, packet);
+        if (packet_len != libssh2_channel_write(channel, (char *)packet, packet_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, setstat ? (char *)"Unable to send FXP_FSETSTAT" : (char *)"Unable to send FXP_FSTAT command", 0);
+                LIBSSH2_FREE(session, packet);
+                return -1;
+        }
+        LIBSSH2_FREE(session, packet);
 
-	if (libssh2_sftp_packet_requirev(sftp, 2, fstat_responses, request_id, &data, &data_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
-		return -1;
-	}
+        if (libssh2_sftp_packet_requirev(sftp, 2, fstat_responses, request_id, &data, &data_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
+                return -1;
+        }
 
-	if (data[0] == SSH_FXP_STATUS) {
-		int retcode;
+        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;
-		}
-	}
+                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);
+        libssh2_sftp_bin2attr(attrs, data + 5);
 
-	return 0;
+        return 0;
 }
 /* }}} */
 
@@ -974,7 +1114,7 @@ LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_
  */
 LIBSSH2_API void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset)
 {
-	handle->u.file.offset = offset;
+        handle->u.file.offset = offset;
 }
 /* }}} */
 
@@ -983,7 +1123,7 @@ LIBSSH2_API void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset)
  */
 LIBSSH2_API size_t libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle)
 {
-	return handle->u.file.offset;
+        return handle->u.file.offset;
 }
 /* }}} */
 
@@ -994,66 +1134,66 @@ LIBSSH2_API size_t libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle)
  */
 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, request_id;
-	unsigned long packet_len = handle->handle_len + 13; /* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
-	unsigned char *packet, *s, *data;
+        LIBSSH2_SFTP    *sftp    = handle->sftp;
+        LIBSSH2_CHANNEL *channel = sftp->channel;
+        LIBSSH2_SESSION *session = channel->session;
+        unsigned long data_len, retcode, request_id;
+        ssize_t packet_len = handle->handle_len + 13; /* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
+        unsigned char *packet, *s, *data;
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Closing handle");
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Closing handle");
 #endif
-	s = packet = LIBSSH2_ALLOC(session, packet_len);
-	if (!packet) {
-		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_CLOSE packet", 0);
-		return -1;
-	}
+        s = packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!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;
-	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_htonu32(s, packet_len - 4);                                     s += 4;
+        *(s++) = SSH_FXP_CLOSE;
+        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;
 
-	if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_CLOSE command", 0);
-		LIBSSH2_FREE(session, packet);
-		return -1;
-	}
-	LIBSSH2_FREE(session, packet);
+        if (packet_len != libssh2_channel_write(channel, (char *)packet, packet_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_CLOSE command", 0);
+                LIBSSH2_FREE(session, packet);
+                return -1;
+        }
+        LIBSSH2_FREE(session, packet);
 
-	if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
-		return -1;
-	}
+        if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
+                return -1;
+        }
 
-	retcode = libssh2_ntohu32(data + 5);
-	LIBSSH2_FREE(session, data);
+        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);
-		return -1;
-	}
+        if (retcode != LIBSSH2_FX_OK) {
+                sftp->last_errno = retcode;
+                libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
+                return -1;
+        }
 
-	if (handle == sftp->handles) {
-		sftp->handles = handle->next;
-	}
-	if (handle->next) {
-		handle->next->prev = NULL;
-	}
+        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);
-	}
+        if ((handle->handle_type == LIBSSH2_SFTP_HANDLE_DIR) &&
+                handle->u.dir.names_left) {
+                LIBSSH2_FREE(session, handle->u.dir.names_packet);
+        }
 
-	LIBSSH2_FREE(session, handle->handle);
-	LIBSSH2_FREE(session, handle);
+        LIBSSH2_FREE(session, handle->handle);
+        LIBSSH2_FREE(session, handle);
 
-	return 0;
+        return 0;
 }
 /* }}} */
 
@@ -1066,131 +1206,133 @@ LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle)
  */
 LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, unsigned int filename_len)
 {
-	LIBSSH2_CHANNEL *channel = sftp->channel;
-	LIBSSH2_SESSION *session = channel->session;
-	unsigned long data_len, retcode, request_id;
-	unsigned long packet_len = filename_len + 13; /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */
-	unsigned char *packet, *s, *data;
+        LIBSSH2_CHANNEL *channel = sftp->channel;
+        LIBSSH2_SESSION *session = channel->session;
+        unsigned long data_len, retcode, request_id;
+        ssize_t packet_len = filename_len + 13; /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */
+        unsigned char *packet, *s, *data;
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Unlinking %s", filename);
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Unlinking %s", filename);
 #endif
-	s = packet = LIBSSH2_ALLOC(session, packet_len);
-	if (!packet) {
-		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_REMOVE packet", 0);
-		return -1;
-	}
+        s = packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!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;
-	request_id = sftp->request_id++;
-	libssh2_htonu32(s, request_id);						s += 4;
-	libssh2_htonu32(s, filename_len);					s += 4;
-	memcpy(s, filename, filename_len);					s += filename_len;
+        libssh2_htonu32(s, packet_len - 4);                                     s += 4;
+        *(s++) = SSH_FXP_REMOVE;
+        request_id = sftp->request_id++;
+        libssh2_htonu32(s, request_id);                                         s += 4;
+        libssh2_htonu32(s, filename_len);                                       s += 4;
+        memcpy(s, filename, filename_len);                                      s += filename_len;
 
-	if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0);
-		LIBSSH2_FREE(session, packet);
-		return -1;
-	}
-	LIBSSH2_FREE(session, packet);
+        if (packet_len != libssh2_channel_write(channel, (char *)packet,
+						packet_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_REMOVE command", 0);
+                LIBSSH2_FREE(session, packet);
+                return -1;
+        }
+        LIBSSH2_FREE(session, packet);
 
-	if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
-		return -1;
-	}
+        if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
+                return -1;
+        }
 
-	retcode = libssh2_ntohu32(data + 5);
-	LIBSSH2_FREE(session, data);
+        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 (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,  char *source_filename,	unsigned int source_filename_len,
-															char *dest_filename,	unsigned int dest_filename_len,
-															long flags)
+LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp,  char *source_filename,      unsigned int source_filename_len,
+                                                                                                                        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 = -1, request_id;
-	unsigned long 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 *packet, *s, *data;
+        LIBSSH2_CHANNEL *channel = sftp->channel;
+        LIBSSH2_SESSION *session = channel->session;
+        unsigned long data_len, retcode = -1, request_id;
+        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 *packet, *s, *data;
 
-	if (sftp->version < 2) {
-		libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Server does not support RENAME", 0);
-		return -1;
-	}
+        if (sftp->version < 2) {
+                libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Server does not support RENAME", 0);
+                return -1;
+        }
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Renaming %s to %s", source_filename, dest_filename);
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Renaming %s to %s", source_filename, dest_filename);
 #endif
-	s = packet = LIBSSH2_ALLOC(session, packet_len);
-	if (!packet) {
-		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_RENAME packet", 0);
-		return -1;
-	}
+        s = packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!packet) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_RENAME packet", 0);
+                return -1;
+        }
 
-	libssh2_htonu32(s, packet_len - 4);					s += 4;
-	*(s++) = SSH_FXP_RENAME;
-	request_id = sftp->request_id++;
-	libssh2_htonu32(s, request_id);						s += 4;
-	libssh2_htonu32(s, source_filename_len);			s += 4;
-	memcpy(s, source_filename, source_filename_len);	s += source_filename_len;
-	libssh2_htonu32(s, dest_filename_len);				s += 4;
-	memcpy(s, dest_filename, dest_filename_len);		s += dest_filename_len;
+        libssh2_htonu32(s, packet_len - 4);                                     s += 4;
+        *(s++) = SSH_FXP_RENAME;
+        request_id = sftp->request_id++;
+        libssh2_htonu32(s, request_id);                                         s += 4;
+        libssh2_htonu32(s, source_filename_len);                        s += 4;
+        memcpy(s, source_filename, source_filename_len);        s += source_filename_len;
+        libssh2_htonu32(s, dest_filename_len);                          s += 4;
+        memcpy(s, dest_filename, dest_filename_len);            s += dest_filename_len;
 
-	if (sftp->version >= 5) {
-		libssh2_htonu32(s, flags);						s += 4;
-	}
+        if (sftp->version >= 5) {
+                libssh2_htonu32(s, flags);                                              s += 4;
+        }
 
-	if (packet_len != libssh2_channel_write(channel, packet, s - packet)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_RENAME command", 0);
-		LIBSSH2_FREE(session, packet);
-		return -1;
-	}
-	LIBSSH2_FREE(session, packet);
+        if (packet_len != libssh2_channel_write(channel, (char *)packet,
+						s - packet)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_RENAME command", 0);
+                LIBSSH2_FREE(session, packet);
+                return -1;
+        }
+        LIBSSH2_FREE(session, packet);
 
-	if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
-		return -1;
-	}
+        if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
+                return -1;
+        }
 
-	retcode = libssh2_ntohu32(data + 5);
-	LIBSSH2_FREE(session, data);
+        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;
-	}
+        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;
+        return retcode;
 }
 /* }}} */
 
@@ -1199,55 +1341,58 @@ LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp,  char *source_filenam
  */
 LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, 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 };
-	unsigned long data_len, retcode, request_id;
-	unsigned long packet_len = path_len + 13 + libssh2_sftp_attrsize(&attrs);
-			/* packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
-	unsigned char *packet, *s, *data;
+        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;
+        ssize_t packet_len = path_len + 13 + libssh2_sftp_attrsize(&attrs);
+                        /* packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
+        unsigned char *packet, *s, *data;
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Creating directory %s with mode 0%lo", path, mode);
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Creating directory %s with mode 0%lo", path, mode);
 #endif
-	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;
+        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);
+        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);
 
-	if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_MKDIR command", 0);
-		LIBSSH2_FREE(session, packet);
-		return -1;
-	}
-	LIBSSH2_FREE(session, packet);
+        if (packet_len != libssh2_channel_write(channel, (char *)packet,
+						packet_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_MKDIR command", 0);
+                LIBSSH2_FREE(session, packet);
+                return -1;
+        }
+        LIBSSH2_FREE(session, packet);
 
-	if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
-		return -1;
-	}
+        if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
+                return -1;
+        }
 
-	retcode = libssh2_ntohu32(data + 5);
-	LIBSSH2_FREE(session, data);
+        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;
-	}
+        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;
+        }
 }
 /* }}} */
 
@@ -1256,50 +1401,50 @@ LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, unsigned i
  */
 LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, unsigned int path_len)
 {
-	LIBSSH2_CHANNEL *channel = sftp->channel;
-	LIBSSH2_SESSION *session = channel->session;
-	unsigned long data_len, retcode, request_id;
-	unsigned long packet_len = path_len + 13; /* packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
-	unsigned char *packet, *s, *data;
+        LIBSSH2_CHANNEL *channel = sftp->channel;
+        LIBSSH2_SESSION *session = channel->session;
+        unsigned long data_len, retcode, request_id;
+        ssize_t packet_len = path_len + 13; /* packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
+        unsigned char *packet, *s, *data;
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Removing directory: %s", path);
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Removing directory: %s", path);
 #endif
-	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;
-	}
+        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;
+        }
 
-	libssh2_htonu32(s, packet_len - 4);					s += 4;
-	*(s++) = SSH_FXP_RMDIR;
-	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;
+        libssh2_htonu32(s, packet_len - 4);                                     s += 4;
+        *(s++) = SSH_FXP_RMDIR;
+        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;
 
-	if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_MKDIR command", 0);
-		LIBSSH2_FREE(session, packet);
-		return -1;
-	}
-	LIBSSH2_FREE(session, packet);
+        if (packet_len != libssh2_channel_write(channel, (char *)packet, packet_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_MKDIR command", 0);
+                LIBSSH2_FREE(session, packet);
+                return -1;
+        }
+        LIBSSH2_FREE(session, packet);
 
-	if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
-		return -1;
-	}
+        if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
+                return -1;
+        }
 
-	retcode = libssh2_ntohu32(data + 5);
-	LIBSSH2_FREE(session, data);
+        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 (retcode == LIBSSH2_FX_OK) {
+                return 0;
+        } else {
+                sftp->last_errno = retcode;
+                libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
+                return -1;
+        }
 }
 /* }}} */
 
@@ -1308,74 +1453,75 @@ LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, unsigned i
  */
 LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, 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, request_id;
-	unsigned long packet_len = path_len + 13 + ((stat_type == LIBSSH2_SFTP_SETSTAT) ? libssh2_sftp_attrsize(attrs) : 0); 
-									/* packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
-	unsigned char *packet, *s, *data;
-	unsigned char stat_responses[2] = { SSH_FXP_ATTRS,		SSH_FXP_STATUS	};
+        LIBSSH2_CHANNEL *channel = sftp->channel;
+        LIBSSH2_SESSION *session = channel->session;
+        unsigned long data_len, request_id;
+        ssize_t packet_len = path_len + 13 + ((stat_type == LIBSSH2_SFTP_SETSTAT) ? libssh2_sftp_attrsize(attrs) : 0);
+                                                                        /* packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
+        unsigned char *packet, *s, *data;
+        unsigned char stat_responses[2] = { SSH_FXP_ATTRS,              SSH_FXP_STATUS  };
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s", (stat_type == LIBSSH2_SFTP_SETSTAT) ? "Set-statting" : (stat_type == LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path);
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s", (stat_type == LIBSSH2_SFTP_SETSTAT) ? "Set-statting" : (stat_type == LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path);
 #endif
-	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;
-	}
+        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;
+        }
 
-	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;
-	}
-	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;
-	if (stat_type == LIBSSH2_SFTP_SETSTAT) {
-		s += libssh2_sftp_attr2bin(s, attrs);
-	}
+        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;
+        }
+        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;
+        if (stat_type == LIBSSH2_SFTP_SETSTAT) {
+                s += libssh2_sftp_attr2bin(s, attrs);
+        }
 
-	if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send STAT/LSTAT/SETSTAT command", 0);
-		LIBSSH2_FREE(session, packet);
-		return -1;
-	}
-	LIBSSH2_FREE(session, packet);
+        if (packet_len != libssh2_channel_write(channel, (char *)packet,
+						packet_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send STAT/LSTAT/SETSTAT command", 0);
+                LIBSSH2_FREE(session, packet);
+                return -1;
+        }
+        LIBSSH2_FREE(session, packet);
 
-	if (libssh2_sftp_packet_requirev(sftp, 2, stat_responses, request_id, &data, &data_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
-		return -1;
-	}
+        if (libssh2_sftp_packet_requirev(sftp, 2, stat_responses, request_id, &data, &data_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
+                return -1;
+        }
 
-	if (data[0] == SSH_FXP_STATUS) {
-		int retcode;
+        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;
-		}
-	}
+                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);
+        memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+        libssh2_sftp_bin2attr(attrs, data + 5);
+        LIBSSH2_FREE(session, data);
 
-	return 0;
+        return 0;
 }
 /* }}} */
 
@@ -1384,92 +1530,93 @@ LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, unsigned in
  */
 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, request_id, link_len;
-	unsigned long packet_len = path_len + 13 + ((link_type == LIBSSH2_SFTP_SYMLINK) ? (4 + target_len) : 0); 
-									/* packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
-	unsigned char *packet, *s, *data;
-	unsigned char link_responses[2] = { SSH_FXP_NAME,		SSH_FXP_STATUS	};
+        LIBSSH2_CHANNEL *channel = sftp->channel;
+        LIBSSH2_SESSION *session = channel->session;
+        unsigned long data_len, request_id, link_len;
+        ssize_t packet_len = path_len + 13 + ((link_type == LIBSSH2_SFTP_SYMLINK) ? (4 + target_len) : 0);
+                                                                        /* packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
+        unsigned char *packet, *s, *data;
+        unsigned char link_responses[2] = { SSH_FXP_NAME,               SSH_FXP_STATUS  };
 
-	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->version < 3) &&
+                (link_type != LIBSSH2_SFTP_REALPATH)) {
+                libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Server does not support SYMLINK or READLINK", 0);
+                return -1;
+        }
 
-	s = packet = LIBSSH2_ALLOC(session, packet_len);
-	if (!packet) {
-		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for SYMLINK/READLINK/REALPATH packet", 0);
-		return -1;
-	}
+        s = packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!packet) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for SYMLINK/READLINK/REALPATH packet", 0);
+                return -1;
+        }
 
 #ifdef LIBSSH2_DEBUG_SFTP
-	_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_debug(session, LIBSSH2_DBG_SFTP, "%s %s on %s", (link_type == LIBSSH2_SFTP_SYMLINK) ? "Creating" : "Reading",
+                                                                                                                         (link_type == LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", path);
 #endif
-	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;
-	}
-	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;
-	if (link_type == LIBSSH2_SFTP_SYMLINK) {
-		libssh2_htonu32(s, target_len);					s += 4;
-		memcpy(s, target, target_len);					s += target_len;
-	}
+        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;
+        }
+        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;
+        if (link_type == LIBSSH2_SFTP_SYMLINK) {
+                libssh2_htonu32(s, target_len);                                 s += 4;
+                memcpy(s, target, target_len);                                  s += target_len;
+        }
 
-	if (packet_len != libssh2_channel_write(channel, packet, packet_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send SYMLINK/READLINK command", 0);
-		LIBSSH2_FREE(session, packet);
-		return -1;
-	}
-	LIBSSH2_FREE(session, packet);
+        if (packet_len != libssh2_channel_write(channel, (char *)packet,
+						packet_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send SYMLINK/READLINK command", 0);
+                LIBSSH2_FREE(session, packet);
+                return -1;
+        }
+        LIBSSH2_FREE(session, packet);
 
-	if (libssh2_sftp_packet_requirev(sftp, 2, link_responses, request_id, &data, &data_len)) {
-		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
-		return -1;
-	}
+        if (libssh2_sftp_packet_requirev(sftp, 2, link_responses, request_id, &data, &data_len)) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
+                return -1;
+        }
 
-	if (data[0] == SSH_FXP_STATUS) {
-		int retcode;
+        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;
-		}
-	}
+                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;
-	}
+        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);
+        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;
+        return link_len;
 }
 /* }}} */
 
@@ -1478,6 +1625,6 @@ LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, un
  */
 LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp)
 {
-	return sftp->last_errno;
+        return sftp->last_errno;
 }
 /* }}} */
diff --git a/src/transport.c b/src/transport.c
new file mode 100644
index 0000000..607362f
--- /dev/null
+++ b/src/transport.c
@@ -0,0 +1,706 @@
+/* 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(const char *desc, unsigned char *ptr, unsigned long size)
+{
+  size_t i;
+  size_t c;
+  FILE *stream = stdout;
+
+  unsigned int width=0x10;
+
+  fprintf(stream, "=> %s (%d bytes)\n", desc, (int)size);
+
+  for(i=0; i<size; i+= width) {
+
+    fprintf(stream, "%04x: ", 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(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;
+        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 payload_len = p->packet_length-1;
+        libssh2pack_t packet_type;
+        int macstate = LIBSSH2_MAC_CONFIRMED;
+
+        if(encrypted) {
+
+                /* Calculate MAC hash */
+                session->remote.mac->hash(session,
+                                          macbuf, /* store hash here */
+                                          session->remote.seqno,
+                                          p->init, 5,
+                                          p->payload, 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 + payload_len,
+                          session->remote.mac->mac_len)) {
+                        macstate = LIBSSH2_MAC_INVALID;
+                }
+        }
+
+        session->remote.seqno++;
+
+        /* ignore the padding */
+        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, 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;
+                        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!
+                                 */
+                                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);
+                                payload_len = data_len;
+                        }
+                }
+        }
+
+        packet_type = p->payload[0];
+
+	debugdump("libssh2_packet_read() plain",
+		  p->payload, payload_len);
+        libssh2_packet_add(session, p->payload, payload_len, macstate);
+
+        return 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;
+
+        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 */
+                                if(errno == EAGAIN) {
+                                        return PACKET_EAGAIN;
+                                }
+                                return PACKET_FAIL;
+                        }
+			debugdump("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(numbytes < blocksize) {
+                        /* we can't act on anything less than blocksize */
+                        return PACKET_EAGAIN;
+                }
+
+                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(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 = blocksize-5;
+
+                        /* 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 {
+                                numdecrypt = numbytes;
+                        }
+                }
+                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 */
+                        rc = fullpacket(session, encrypted);
+
+                        p->total_num = 0; /* no packet buffer available */
+
+                        return rc;
+                }
+        } while (1); /* loop */
+
+        return PACKET_FAIL; /* we never reach this point */
+}
+/* }}} */
+
+#ifndef OLDSEND
+
+static libssh2pack_t send_existing(LIBSSH2_SESSION *session,
+                                   unsigned char *data,
+                                   unsigned long data_len,
+                                   int *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;
+                }
+                return PACKET_EAGAIN;
+        }
+
+	debugdump("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.
+ */
+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("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("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 */
+                        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 */
+}
+
+/* }}} */
+#endif
diff --git a/ssh2_sample.c b/ssh2_sample.c
deleted file mode 100644
index 4a3fab3..0000000
--- a/ssh2_sample.c
+++ /dev/null
@@ -1,152 +0,0 @@
-#include "libssh2.h"
-
-#ifndef WIN32
-# include <netinet/in.h>
-# include <sys/socket.h>
-# include <unistd.h>
-#else
-# include <winsock2.h>
-#endif
-
-#include <sys/types.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdio.h>
-#include <ctype.h>
-
-int main(int argc, char *argv[])
-{
-	int sock, i, auth_pw = 1;
-	struct sockaddr_in sin;
-	const char *fingerprint;
-	LIBSSH2_SESSION *session;
-	LIBSSH2_CHANNEL *channel;
-	char *username=(char *)"username";
-	char *password=(char *)"password";
-#ifdef WIN32
-	WSADATA wsadata;
-
-	WSAStartup(WINSOCK_VERSION, &wsadata);
-#endif
-
-	/* Ultra basic "connect to port 22 on localhost"
-	 * Your code is responsible for creating the socket establishing the connection
-	 */
-	sock = socket(AF_INET, SOCK_STREAM, 0);
-#ifndef WIN32
-	fcntl(sock, F_SETFL, 0);
-#endif
-	sin.sin_family = AF_INET;
-	sin.sin_port = htons(22);
-	sin.sin_addr.s_addr = htonl(0x7F000001);
-	if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) {
-		fprintf(stderr, "failed to connect!\n");
-		return -1;
-	}
-
-	/* Create a session instance and start it up
-	 * This will trade welcome banners, exchange keys, and setup crypto, compression, and MAC layers
-	 */
-	session = libssh2_session_init();
-	if (libssh2_session_startup(session, sock)) {
-		fprintf(stderr, "Failure establishing SSH session\n");
-		return -1;
-	}
-
-	/* At this point we havn't authenticated,
-	 * The first thing to do is check the hostkey's fingerprint against our known hosts
-	 * Your app may have it hard coded, may go to a file, may present it to the user, that's your call
-	 */
-	fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5);
-	printf("Fingerprint: ");
-	for(i = 0; i < 16; i++) {
-		printf("%02X ", (unsigned char)fingerprint[i]);
-	}
-	printf("\n");
-
-	if(argc > 1) {
-		username = argv[1];
-	}
-	if(argc > 2) {
-		password = argv[2];
-	}
-
-	if (auth_pw) {
-		/* We could authenticate via password */
-		if (libssh2_userauth_password(session, username, password)) {
-			printf("Authentication by password failed.\n");
-			goto shutdown;
-		}
-	} else {
-		/* Or by public key */
-		if (libssh2_userauth_publickey_fromfile(session, username, "/home/username/.ssh/id_rsa.pub", "/home/username/.ssh/id_rsa", password)) {
-			printf("\tAuthentication by public key failed\n");
-			goto shutdown;
-		}
-	}
-
-	/* Request a shell */
-	if (!(channel = libssh2_channel_open_session(session))) {
-		fprintf(stderr, "Unable to open a session\n");
-		goto shutdown;
-	}
-
-	/* Some environment variables may be set,
-	 * It's up to the server which ones it'll allow though
-	 */
-	libssh2_channel_setenv(channel, (char *)"FOO", (char *)"bar");
-
-	/* Request a terminal with 'vanilla' terminal emulation
-	 * See /etc/termcap for more options
-	 */
-	if (libssh2_channel_request_pty(channel, (char *)"vanilla")) {
-		fprintf(stderr, "Failed requesting pty\n");
-		goto skip_shell;
-	}
-
-	/* Open a SHELL on that pty */
-	if (libssh2_channel_shell(channel)) {
-		fprintf(stderr, "Unable to request shell on allocated pty\n");
-		goto shutdown;
-	}
-
-	/* At this point the shell can be interacted with using
-	 * libssh2_channel_read()
-	 * libssh2_channel_read_stderr()
-	 * libssh2_channel_write()
-	 * libssh2_channel_write_stderr()
-	 *
-	 * Blocking mode may be (en|dis)abled with: libssh2_channel_set_blocking()
-	 * If the server send EOF, libssh2_channel_eof() will return non-0
-	 * To send EOF to the server use: libssh2_channel_send_eof()
-	 * A channel can be closed with: libssh2_channel_close()
-	 * A channel can be freed with: libssh2_channel_free()
-	 */
-
- skip_shell:
-	if (channel) {
-		libssh2_channel_free(channel);
-		channel = NULL;
-	}
-
-	/* Other channel types are supported via:
-	 * libssh2_scp_send()
-	 * libssh2_scp_recv()
-	 * libssh2_channel_direct_tcpip()
-	 */
-
- shutdown:
-
-	libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
-	libssh2_session_free(session);
-
-#ifdef WIN32
-	Sleep(1000);
-	closesocket(sock);
-#else
-	sleep(1);
-	close(sock);
-#endif
-printf("all done\n");
-	return 0;
-}