We now build libssh2 in Xcode and it's a much better UB/10.4 citizen
authorRobert Sesek <rsesek@bluestatic.org>
Tue, 26 Feb 2008 18:22:26 +0000 (13:22 -0500)
committerRobert Sesek <rsesek@bluestatic.org>
Tue, 26 Feb 2008 18:22:26 +0000 (13:22 -0500)
87 files changed:
PrintDrop.xcodeproj/project.pbxproj
Source/AppController.m
Vendor/build-libssh2.sh [deleted file]
Vendor/libssh2-0.18.tar.gz [deleted file]
Vendor/libssh2/Headers/libgcrypt.h [new file with mode: 0644]
Vendor/libssh2/Headers/libssh2.h [moved from libssh2/include/libssh2.h with 100% similarity]
Vendor/libssh2/Headers/libssh2_config.h [new file with mode: 0644]
Vendor/libssh2/Headers/libssh2_priv.h [new file with mode: 0644]
Vendor/libssh2/Headers/libssh2_publickey.h [moved from libssh2/include/libssh2_publickey.h with 100% similarity]
Vendor/libssh2/Headers/libssh2_sftp.h [moved from libssh2/include/libssh2_sftp.h with 100% similarity]
Vendor/libssh2/Headers/openssl.h [new file with mode: 0644]
Vendor/libssh2/Source/channel.c [new file with mode: 0644]
Vendor/libssh2/Source/comp.c [new file with mode: 0644]
Vendor/libssh2/Source/crypt.c [new file with mode: 0644]
Vendor/libssh2/Source/hostkey.c [new file with mode: 0644]
Vendor/libssh2/Source/kex.c [new file with mode: 0644]
Vendor/libssh2/Source/mac.c [new file with mode: 0644]
Vendor/libssh2/Source/misc.c [new file with mode: 0644]
Vendor/libssh2/Source/openssl.c [new file with mode: 0644]
Vendor/libssh2/Source/packet.c [new file with mode: 0644]
Vendor/libssh2/Source/pem.c [new file with mode: 0644]
Vendor/libssh2/Source/publickey.c [new file with mode: 0644]
Vendor/libssh2/Source/scp.c [new file with mode: 0644]
Vendor/libssh2/Source/session.c [new file with mode: 0644]
Vendor/libssh2/Source/sftp.c [new file with mode: 0644]
Vendor/libssh2/Source/transport.c [new file with mode: 0644]
Vendor/libssh2/Source/userauth.c [new file with mode: 0644]
libssh2/lib/libssh2.a [deleted file]
libssh2/lib/libssh2.la [deleted file]
libssh2/share/man/man3/libssh2_banner_set.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_close.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_direct_tcpip_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_eof.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_flush_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_forward_accept.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_forward_cancel.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_forward_listen_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_free.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_get_exit_status.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_handle_extended_data.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_handle_extended_data2.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_open_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_process_startup.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_read_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_request_pty_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_send_eof.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_set_blocking.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_setenv_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_wait_eof.3 [deleted file]
libssh2/share/man/man3/libssh2_channel_x11_req_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_hostkey_hash.3 [deleted file]
libssh2/share/man/man3/libssh2_poll.3 [deleted file]
libssh2/share/man/man3/libssh2_poll_channel_read.3 [deleted file]
libssh2/share/man/man3/libssh2_scp_recv.3 [deleted file]
libssh2/share/man/man3/libssh2_scp_send_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_session_abstract.3 [deleted file]
libssh2/share/man/man3/libssh2_session_callback_set.3 [deleted file]
libssh2/share/man/man3/libssh2_session_disconnect_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_session_free.3 [deleted file]
libssh2/share/man/man3/libssh2_session_init.3 [deleted file]
libssh2/share/man/man3/libssh2_session_last_errno.3 [deleted file]
libssh2/share/man/man3/libssh2_session_last_error.3 [deleted file]
libssh2/share/man/man3/libssh2_session_method_pref.3 [deleted file]
libssh2/share/man/man3/libssh2_session_methods.3 [deleted file]
libssh2/share/man/man3/libssh2_session_set_blocking.3 [deleted file]
libssh2/share/man/man3/libssh2_session_startup.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_close_handle.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_fstat_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_init.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_last_error.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_mkdir_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_open_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_read.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_readdir.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_rename_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_rmdir_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_seek.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_shutdown.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_stat_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_symlink_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_tell.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_unlink_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_sftp_write.3 [deleted file]
libssh2/share/man/man3/libssh2_userauth_authenticated.3 [deleted file]
libssh2/share/man/man3/libssh2_userauth_list.3 [deleted file]
libssh2/share/man/man3/libssh2_userauth_password_ex.3 [deleted file]
libssh2/share/man/man3/libssh2_userauth_publickey_fromfile.3 [deleted file]

index 19e2ea9985394787a39fb54663459baec058bf5c..812d65a0e60b502592abae2ac97a50c4f894a697 100644 (file)
                1E1624F30D736C500067F3B4 /* GradientBackView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E1624F20D736C500067F3B4 /* GradientBackView.m */; };
                1E1625410D736EF20067F3B4 /* DraggableImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E1625400D736EF20067F3B4 /* DraggableImageView.m */; };
                1E1626560D7388110067F3B4 /* AppController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E1626550D7388110067F3B4 /* AppController.m */; };
-               1EE1E1D90D744BB8002999AD /* libssh2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1EE1E1D80D744BB8002999AD /* libssh2.a */; };
                1EE1E3E50D7482E7002999AD /* gradient.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EE1E3E30D7482E7002999AD /* gradient.png */; };
+               1EE1E4710D748AE4002999AD /* libgcrypt.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EE1E4580D748AE4002999AD /* libgcrypt.h */; };
+               1EE1E4720D748AE4002999AD /* libssh2.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EE1E4590D748AE4002999AD /* libssh2.h */; };
+               1EE1E4730D748AE4002999AD /* libssh2_config.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EE1E45A0D748AE4002999AD /* libssh2_config.h */; };
+               1EE1E4740D748AE4002999AD /* libssh2_priv.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EE1E45B0D748AE4002999AD /* libssh2_priv.h */; };
+               1EE1E4750D748AE4002999AD /* libssh2_publickey.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EE1E45C0D748AE4002999AD /* libssh2_publickey.h */; };
+               1EE1E4760D748AE4002999AD /* libssh2_sftp.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EE1E45D0D748AE4002999AD /* libssh2_sftp.h */; };
+               1EE1E4770D748AE4002999AD /* openssl.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EE1E45E0D748AE4002999AD /* openssl.h */; };
+               1EE1E4780D748AE4002999AD /* channel.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E4600D748AE4002999AD /* channel.c */; };
+               1EE1E4790D748AE4002999AD /* comp.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E4610D748AE4002999AD /* comp.c */; };
+               1EE1E47A0D748AE4002999AD /* crypt.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E4620D748AE4002999AD /* crypt.c */; };
+               1EE1E47B0D748AE4002999AD /* hostkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E4630D748AE4002999AD /* hostkey.c */; };
+               1EE1E47C0D748AE4002999AD /* kex.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E4640D748AE4002999AD /* kex.c */; };
+               1EE1E47E0D748AE4002999AD /* mac.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E4660D748AE4002999AD /* mac.c */; };
+               1EE1E47F0D748AE4002999AD /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E4670D748AE4002999AD /* misc.c */; };
+               1EE1E4800D748AE4002999AD /* openssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E4680D748AE4002999AD /* openssl.c */; };
+               1EE1E4810D748AE4002999AD /* packet.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E4690D748AE4002999AD /* packet.c */; };
+               1EE1E4820D748AE4002999AD /* pem.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E46A0D748AE4002999AD /* pem.c */; };
+               1EE1E4830D748AE4002999AD /* publickey.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E46B0D748AE4002999AD /* publickey.c */; };
+               1EE1E4840D748AE4002999AD /* scp.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E46C0D748AE4002999AD /* scp.c */; };
+               1EE1E4850D748AE4002999AD /* session.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E46D0D748AE4002999AD /* session.c */; };
+               1EE1E4860D748AE4002999AD /* sftp.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E46E0D748AE4002999AD /* sftp.c */; };
+               1EE1E4870D748AE4002999AD /* transport.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E46F0D748AE4002999AD /* transport.c */; };
+               1EE1E4880D748AE4002999AD /* userauth.c in Sources */ = {isa = PBXBuildFile; fileRef = 1EE1E4700D748AE4002999AD /* userauth.c */; };
+               1EE1E48C0D748B19002999AD /* liblibssh2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1EE1E4500D748AC9002999AD /* liblibssh2.a */; };
                8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; };
                8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
                8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
                1E1625400D736EF20067F3B4 /* DraggableImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DraggableImageView.m; path = Source/DraggableImageView.m; sourceTree = "<group>"; };
                1E1626540D7388110067F3B4 /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppController.h; path = Source/AppController.h; sourceTree = "<group>"; };
                1E1626550D7388110067F3B4 /* AppController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppController.m; path = Source/AppController.m; sourceTree = "<group>"; };
-               1EE1E1D80D744BB8002999AD /* libssh2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libssh2.a; path = libssh2/lib/libssh2.a; sourceTree = "<group>"; };
                1EE1E3E40D7482E7002999AD /* English */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = English; path = English.lproj/gradient.png; sourceTree = "<group>"; };
+               1EE1E4500D748AC9002999AD /* liblibssh2.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = liblibssh2.a; sourceTree = BUILT_PRODUCTS_DIR; };
+               1EE1E4580D748AE4002999AD /* libgcrypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libgcrypt.h; sourceTree = "<group>"; };
+               1EE1E4590D748AE4002999AD /* libssh2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libssh2.h; sourceTree = "<group>"; };
+               1EE1E45A0D748AE4002999AD /* libssh2_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libssh2_config.h; sourceTree = "<group>"; };
+               1EE1E45B0D748AE4002999AD /* libssh2_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libssh2_priv.h; sourceTree = "<group>"; };
+               1EE1E45C0D748AE4002999AD /* libssh2_publickey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libssh2_publickey.h; sourceTree = "<group>"; };
+               1EE1E45D0D748AE4002999AD /* libssh2_sftp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libssh2_sftp.h; sourceTree = "<group>"; };
+               1EE1E45E0D748AE4002999AD /* openssl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = openssl.h; sourceTree = "<group>"; };
+               1EE1E4600D748AE4002999AD /* channel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = channel.c; sourceTree = "<group>"; };
+               1EE1E4610D748AE4002999AD /* comp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = comp.c; sourceTree = "<group>"; };
+               1EE1E4620D748AE4002999AD /* crypt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = crypt.c; sourceTree = "<group>"; };
+               1EE1E4630D748AE4002999AD /* hostkey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hostkey.c; sourceTree = "<group>"; };
+               1EE1E4640D748AE4002999AD /* kex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kex.c; sourceTree = "<group>"; };
+               1EE1E4660D748AE4002999AD /* mac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mac.c; sourceTree = "<group>"; };
+               1EE1E4670D748AE4002999AD /* misc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = misc.c; sourceTree = "<group>"; };
+               1EE1E4680D748AE4002999AD /* openssl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = openssl.c; sourceTree = "<group>"; };
+               1EE1E4690D748AE4002999AD /* packet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = packet.c; sourceTree = "<group>"; };
+               1EE1E46A0D748AE4002999AD /* pem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pem.c; sourceTree = "<group>"; };
+               1EE1E46B0D748AE4002999AD /* publickey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = publickey.c; sourceTree = "<group>"; };
+               1EE1E46C0D748AE4002999AD /* scp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scp.c; sourceTree = "<group>"; };
+               1EE1E46D0D748AE4002999AD /* session.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = session.c; sourceTree = "<group>"; };
+               1EE1E46E0D748AE4002999AD /* sftp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sftp.c; sourceTree = "<group>"; };
+               1EE1E46F0D748AE4002999AD /* transport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = transport.c; sourceTree = "<group>"; };
+               1EE1E4700D748AE4002999AD /* userauth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = userauth.c; sourceTree = "<group>"; };
                29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
                29B97319FDCFA39411CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = "<group>"; };
                29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
+               1EE1E44E0D748AC9002999AD /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                8D11072E0486CEB800E47090 /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               1EE1E48C0D748B19002999AD /* liblibssh2.a in Frameworks */,
                                8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
-                               1EE1E1D90D744BB8002999AD /* libssh2.a in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
                        isa = PBXGroup;
                        children = (
-                               1EE1E1D80D744BB8002999AD /* libssh2.a */,
                                1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
                        );
                        name = "Linked Frameworks";
                        isa = PBXGroup;
                        children = (
                                8D1107320486CEB800E47090 /* PrintDrop.app */,
+                               1EE1E4500D748AC9002999AD /* liblibssh2.a */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                };
+               1EE1E4560D748AE4002999AD /* libssh2 */ = {
+                       isa = PBXGroup;
+                       children = (
+                               1EE1E4570D748AE4002999AD /* Headers */,
+                               1EE1E45F0D748AE4002999AD /* Source */,
+                       );
+                       name = libssh2;
+                       path = Vendor/libssh2;
+                       sourceTree = "<group>";
+               };
+               1EE1E4570D748AE4002999AD /* Headers */ = {
+                       isa = PBXGroup;
+                       children = (
+                               1EE1E4580D748AE4002999AD /* libgcrypt.h */,
+                               1EE1E4590D748AE4002999AD /* libssh2.h */,
+                               1EE1E45A0D748AE4002999AD /* libssh2_config.h */,
+                               1EE1E45B0D748AE4002999AD /* libssh2_priv.h */,
+                               1EE1E45C0D748AE4002999AD /* libssh2_publickey.h */,
+                               1EE1E45D0D748AE4002999AD /* libssh2_sftp.h */,
+                               1EE1E45E0D748AE4002999AD /* openssl.h */,
+                       );
+                       path = Headers;
+                       sourceTree = "<group>";
+               };
+               1EE1E45F0D748AE4002999AD /* Source */ = {
+                       isa = PBXGroup;
+                       children = (
+                               1EE1E4600D748AE4002999AD /* channel.c */,
+                               1EE1E4610D748AE4002999AD /* comp.c */,
+                               1EE1E4620D748AE4002999AD /* crypt.c */,
+                               1EE1E4630D748AE4002999AD /* hostkey.c */,
+                               1EE1E4640D748AE4002999AD /* kex.c */,
+                               1EE1E4660D748AE4002999AD /* mac.c */,
+                               1EE1E4670D748AE4002999AD /* misc.c */,
+                               1EE1E4680D748AE4002999AD /* openssl.c */,
+                               1EE1E4690D748AE4002999AD /* packet.c */,
+                               1EE1E46A0D748AE4002999AD /* pem.c */,
+                               1EE1E46B0D748AE4002999AD /* publickey.c */,
+                               1EE1E46C0D748AE4002999AD /* scp.c */,
+                               1EE1E46D0D748AE4002999AD /* session.c */,
+                               1EE1E46E0D748AE4002999AD /* sftp.c */,
+                               1EE1E46F0D748AE4002999AD /* transport.c */,
+                               1EE1E4700D748AE4002999AD /* userauth.c */,
+                       );
+                       path = Source;
+                       sourceTree = "<group>";
+               };
                29B97314FDCFA39411CA2CEA /* PrintDrop */ = {
                        isa = PBXGroup;
                        children = (
                                080E96DDFE201D6D7F000001 /* Classes */,
                                29B97315FDCFA39411CA2CEA /* Other Sources */,
                                29B97317FDCFA39411CA2CEA /* Resources */,
+                               1EE1E4560D748AE4002999AD /* libssh2 */,
                                29B97323FDCFA39411CA2CEA /* Frameworks */,
                                19C28FACFE9D520D11CA2CBB /* Products */,
                        );
                };
 /* End PBXGroup section */
 
+/* Begin PBXHeadersBuildPhase section */
+               1EE1E44C0D748AC9002999AD /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               1EE1E4710D748AE4002999AD /* libgcrypt.h in Headers */,
+                               1EE1E4720D748AE4002999AD /* libssh2.h in Headers */,
+                               1EE1E4730D748AE4002999AD /* libssh2_config.h in Headers */,
+                               1EE1E4740D748AE4002999AD /* libssh2_priv.h in Headers */,
+                               1EE1E4750D748AE4002999AD /* libssh2_publickey.h in Headers */,
+                               1EE1E4760D748AE4002999AD /* libssh2_sftp.h in Headers */,
+                               1EE1E4770D748AE4002999AD /* openssl.h in Headers */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXHeadersBuildPhase section */
+
 /* Begin PBXNativeTarget section */
+               1EE1E44F0D748AC9002999AD /* libssh2 */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 1EE1E4550D748ADB002999AD /* Build configuration list for PBXNativeTarget "libssh2" */;
+                       buildPhases = (
+                               1EE1E44C0D748AC9002999AD /* Headers */,
+                               1EE1E44D0D748AC9002999AD /* Sources */,
+                               1EE1E44E0D748AC9002999AD /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = libssh2;
+                       productName = libssh2;
+                       productReference = 1EE1E4500D748AC9002999AD /* liblibssh2.a */;
+                       productType = "com.apple.product-type.library.static";
+               };
                8D1107260486CEB800E47090 /* PrintDrop */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "PrintDrop" */;
                        projectRoot = "";
                        targets = (
                                8D1107260486CEB800E47090 /* PrintDrop */,
+                               1EE1E44F0D748AC9002999AD /* libssh2 */,
                        );
                };
 /* End PBXProject section */
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
+               1EE1E44D0D748AC9002999AD /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               1EE1E4780D748AE4002999AD /* channel.c in Sources */,
+                               1EE1E4790D748AE4002999AD /* comp.c in Sources */,
+                               1EE1E47A0D748AE4002999AD /* crypt.c in Sources */,
+                               1EE1E47B0D748AE4002999AD /* hostkey.c in Sources */,
+                               1EE1E47C0D748AE4002999AD /* kex.c in Sources */,
+                               1EE1E47E0D748AE4002999AD /* mac.c in Sources */,
+                               1EE1E47F0D748AE4002999AD /* misc.c in Sources */,
+                               1EE1E4800D748AE4002999AD /* openssl.c in Sources */,
+                               1EE1E4810D748AE4002999AD /* packet.c in Sources */,
+                               1EE1E4820D748AE4002999AD /* pem.c in Sources */,
+                               1EE1E4830D748AE4002999AD /* publickey.c in Sources */,
+                               1EE1E4840D748AE4002999AD /* scp.c in Sources */,
+                               1EE1E4850D748AE4002999AD /* session.c in Sources */,
+                               1EE1E4860D748AE4002999AD /* sftp.c in Sources */,
+                               1EE1E4870D748AE4002999AD /* transport.c in Sources */,
+                               1EE1E4880D748AE4002999AD /* userauth.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                8D11072C0486CEB800E47090 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
 /* End PBXVariantGroup section */
 
 /* Begin XCBuildConfiguration section */
+               1EE1E4510D748AC9002999AD /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               INSTALL_PATH = /usr/local/lib;
+                               PREBINDING = NO;
+                               PRODUCT_NAME = libssh2;
+                               ZERO_LINK = YES;
+                       };
+                       name = Debug;
+               };
+               1EE1E4520D748AC9002999AD /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_MODEL_TUNING = G5;
+                               INSTALL_PATH = /usr/local/lib;
+                               PREBINDING = NO;
+                               PRODUCT_NAME = libssh2;
+                               ZERO_LINK = NO;
+                       };
+                       name = Release;
+               };
                C01FCF4B08A954540054247B /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_PRECOMPILE_PREFIX_HEADER = YES;
                                GCC_PREFIX_HEADER = PrintDrop_Prefix.pch;
-                               HEADER_SEARCH_PATHS = "\"$(SRCROOT)/libssh2/include\"";
+                               HEADER_SEARCH_PATHS = "\"$(SRCROOT)/Vendor/libssh2/Headers\"";
                                INFOPLIST_FILE = Info.plist;
                                INSTALL_PATH = "$(HOME)/Applications";
-                               LIBRARY_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "\"$(SRCROOT)/libssh2/lib\"",
-                               );
+                               LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/build/Release\"";
                                OTHER_LDFLAGS = (
                                        "-undefined",
                                        suppress,
                                GCC_MODEL_TUNING = G5;
                                GCC_PRECOMPILE_PREFIX_HEADER = YES;
                                GCC_PREFIX_HEADER = PrintDrop_Prefix.pch;
-                               HEADER_SEARCH_PATHS = "\"$(SRCROOT)/libssh2/include\"";
+                               HEADER_SEARCH_PATHS = "\"$(SRCROOT)/Vendor/libssh2/Headers\"";
                                INFOPLIST_FILE = Info.plist;
                                INSTALL_PATH = "$(HOME)/Applications";
-                               LIBRARY_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "\"$(SRCROOT)/libssh2/lib\"",
-                               );
+                               LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/build/Release\"";
                                OTHER_LDFLAGS = (
                                        "-undefined",
                                        suppress,
                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                PREBINDING = NO;
-                               SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
+                               SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.4u.sdk";
                        };
                        name = Debug;
                };
                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                PREBINDING = NO;
-                               SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
+                               SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.4u.sdk";
                        };
                        name = Release;
                };
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
+               1EE1E4550D748ADB002999AD /* Build configuration list for PBXNativeTarget "libssh2" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               1EE1E4510D748AC9002999AD /* Debug */,
+                               1EE1E4520D748AC9002999AD /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "PrintDrop" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
index f6b3fb8674ad722832cf7e90e408c31e11aa0348..d9e6f3cb00e455cd261b0e57588aa9dc4d1cbb63 100644 (file)
 shutdown:
        if (channel)
        {
-               libssh2_channel_free(channel);
+               //libssh2_channel_free(channel);
                channel = NULL;
        }
        libssh2_session_disconnect(ssh, "Normal disconnect.");
diff --git a/Vendor/build-libssh2.sh b/Vendor/build-libssh2.sh
deleted file mode 100755 (executable)
index c0fab69..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-
-NAME=libssh2-0.18
-DEST=`cd ..; pwd`/libssh2
-CONFIG="--prefix=$DEST --disable-shared --enable-static"
-
-# cleanup
-rm -rf $NAME
-
-# unzip
-tar xzvf $NAME.tar.gz
-cd $NAME
-
-# build ppc
-./configure $CONFIG CFLAGS="-arch ppc"
-make
-mv src/.libs src/libs-ppc
-
-make clean
-
-# build i386
-./configure $CONFIG
-make
-mv src/.libs/libssh2.a src/libssh2-i386.a
-
-# make universal
-lipo -create src/libs-ppc/libssh2.a src/libssh2-i386.a -output src/.libs/libssh2.a
-
-# put it in the right place
-make install
-ranlib $DEST/lib/libssh2.a
\ No newline at end of file
diff --git a/Vendor/libssh2-0.18.tar.gz b/Vendor/libssh2-0.18.tar.gz
deleted file mode 100644 (file)
index 096afb6..0000000
Binary files a/Vendor/libssh2-0.18.tar.gz and /dev/null differ
diff --git a/Vendor/libssh2/Headers/libgcrypt.h b/Vendor/libssh2/Headers/libgcrypt.h
new file mode 100644 (file)
index 0000000..ea53246
--- /dev/null
@@ -0,0 +1,186 @@
+/* Copyright (C) 2006, 2007 The Written Word, Inc.  All rights reserved.
+ * Author: Simon Josefsson
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include <gcrypt.h>
+
+#define LIBSSH2_MD5 1
+
+#define LIBSSH2_HMAC_RIPEMD 1
+
+#define LIBSSH2_AES 1
+#define LIBSSH2_BLOWFISH 1
+#define LIBSSH2_RC4 1
+#define LIBSSH2_CAST 1
+#define LIBSSH2_3DES 1
+
+#define LIBSSH2_RSA 1
+#define LIBSSH2_DSA 1
+
+#define MD5_DIGEST_LENGTH 16
+#define SHA_DIGEST_LENGTH 20
+
+#define libssh2_random(buf, len)                \
+  (gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1)
+
+#define libssh2_sha1_ctx gcry_md_hd_t
+#define libssh2_sha1_init(ctx) gcry_md_open (ctx,  GCRY_MD_SHA1, 0);
+#define libssh2_sha1_update(ctx, data, len) gcry_md_write (ctx, data, len)
+#define libssh2_sha1_final(ctx, out) \
+  memcpy (out, gcry_md_read (ctx, 0), 20), gcry_md_close (ctx)
+#define libssh2_sha1(message, len, out) \
+  gcry_md_hash_buffer (GCRY_MD_SHA1, out, message, len)
+
+#define libssh2_md5_ctx gcry_md_hd_t
+#define libssh2_md5_init(ctx) gcry_md_open (ctx,  GCRY_MD_MD5, 0);
+#define libssh2_md5_update(ctx, data, len) gcry_md_write (ctx, data, len)
+#define libssh2_md5_final(ctx, out) \
+  memcpy (out, gcry_md_read (ctx, 0), 20), gcry_md_close (ctx)
+#define libssh2_md5(message, len, out) \
+  gcry_md_hash_buffer (GCRY_MD_MD5, out, message, len)
+
+#define libssh2_hmac_ctx gcry_md_hd_t
+#define libssh2_hmac_sha1_init(ctx, key, keylen) \
+  gcry_md_open (ctx, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC), \
+    gcry_md_setkey (*ctx, key, keylen)
+#define libssh2_hmac_md5_init(ctx, key, keylen) \
+  gcry_md_open (ctx, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC), \
+    gcry_md_setkey (*ctx, key, keylen)
+#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
+  gcry_md_open (ctx, GCRY_MD_RMD160, GCRY_MD_FLAG_HMAC), \
+    gcry_md_setkey (*ctx, key, keylen)
+#define libssh2_hmac_update(ctx, data, datalen) \
+  gcry_md_write (ctx, data, datalen)
+#define libssh2_hmac_final(ctx, data) \
+  memcpy (data, gcry_md_read (ctx, 0), \
+      gcry_md_get_algo_dlen (gcry_md_get_algo (ctx)))
+#define libssh2_hmac_cleanup(ctx) gcry_md_close (*ctx);
+
+#define libssh2_crypto_init() gcry_control (GCRYCTL_DISABLE_SECMEM)
+
+#define libssh2_rsa_ctx struct gcry_sexp
+
+int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
+                     const unsigned char *edata,
+                     unsigned long elen,
+                     const unsigned char *ndata,
+                     unsigned long nlen,
+                     const unsigned char *ddata,
+                     unsigned long dlen,
+                     const unsigned char *pdata,
+                     unsigned long plen,
+                     const unsigned char *qdata,
+                     unsigned long qlen,
+                     const unsigned char *e1data,
+                     unsigned long e1len,
+                     const unsigned char *e2data,
+                     unsigned long e2len,
+                     const unsigned char *coeffdata, unsigned long coefflen);
+int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
+                             LIBSSH2_SESSION * session,
+                             FILE * fp, unsigned const char *passphrase);
+int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
+                             const unsigned char *sig,
+                             unsigned long sig_len,
+                             const unsigned char *m, unsigned long m_len);
+int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
+                           libssh2_rsa_ctx * rsactx,
+                           const unsigned char *hash,
+                           unsigned long hash_len,
+                           unsigned char **signature,
+                           unsigned long *signature_len);
+
+#define _libssh2_rsa_free(rsactx)  gcry_sexp_release (rsactx)
+
+#define libssh2_dsa_ctx struct gcry_sexp
+
+int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
+                     const unsigned char *pdata,
+                     unsigned long plen,
+                     const unsigned char *qdata,
+                     unsigned long qlen,
+                     const unsigned char *gdata,
+                     unsigned long glen,
+                     const unsigned char *ydata,
+                     unsigned long ylen,
+                     const unsigned char *x, unsigned long x_len);
+int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
+                             LIBSSH2_SESSION * session,
+                             FILE * fp, unsigned const char *passphrase);
+int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsa,
+                             const unsigned char *sig,
+                             const unsigned char *m, unsigned long m_len);
+int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
+                           const unsigned char *hash,
+                           unsigned long hash_len, unsigned char *sig);
+
+#define _libssh2_dsa_free(dsactx)  gcry_sexp_release (dsactx)
+
+#define _libssh2_cipher_type(name) int name
+#define _libssh2_cipher_ctx gcry_cipher_hd_t
+
+#define _libssh2_cipher_aes256 GCRY_CIPHER_AES256
+#define _libssh2_cipher_aes192 GCRY_CIPHER_AES192
+#define _libssh2_cipher_aes128 GCRY_CIPHER_AES128
+#define _libssh2_cipher_blowfish GCRY_CIPHER_BLOWFISH
+#define _libssh2_cipher_arcfour GCRY_CIPHER_ARCFOUR
+#define _libssh2_cipher_cast5 GCRY_CIPHER_CAST5
+#define _libssh2_cipher_3des GCRY_CIPHER_3DES
+
+int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
+                         _libssh2_cipher_type(algo),
+                         unsigned char *iv,
+                         unsigned char *secret, int encrypt);
+
+int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
+                          _libssh2_cipher_type(algo),
+                          int encrypt, unsigned char *block);
+
+#define _libssh2_cipher_dtor(ctx) gcry_cipher_close(*(ctx))
+
+#define _libssh2_bn struct gcry_mpi
+#define _libssh2_bn_ctx int
+#define _libssh2_bn_ctx_new() 0
+#define _libssh2_bn_ctx_free(bnctx) 0
+#define _libssh2_bn_init() gcry_mpi_new(0)
+#define _libssh2_bn_rand(bn, bits, top, bottom) gcry_mpi_randomize (bn, bits, GCRY_WEAK_RANDOM)
+#define _libssh2_bn_mod_exp(r, a, p, m, ctx) gcry_mpi_powm (r, a, p, m)
+#define _libssh2_bn_set_word(bn, val) gcry_mpi_set_ui(bn, val)
+#define _libssh2_bn_from_bin(bn, len, val) gcry_mpi_scan(&((bn)), GCRYMPI_FMT_USG, val, len, NULL)
+#define _libssh2_bn_to_bin(bn, val) gcry_mpi_print (GCRYMPI_FMT_USG, val, _libssh2_bn_bytes(bn), NULL, bn)
+#define _libssh2_bn_bytes(bn) (gcry_mpi_get_nbits (bn) / 8 + ((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1))
+#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn)
+#define _libssh2_bn_free(bn) gcry_mpi_release(bn)
diff --git a/Vendor/libssh2/Headers/libssh2_config.h b/Vendor/libssh2/Headers/libssh2_config.h
new file mode 100644 (file)
index 0000000..30af66f
--- /dev/null
@@ -0,0 +1,173 @@
+/* src/libssh2_config.h.  Generated from libssh2_config.h.in by configure.  */
+/* src/libssh2_config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+   systems. This function is required for `alloca.c' support on those systems.
+   */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define to 1 if using `alloca.c'. */
+/* #undef C_ALLOCA */
+
+/* Define to 1 if you have `alloca', as a function or macro. */
+#define HAVE_ALLOCA 1
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+   */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* disabled non-blocking sockets */
+/* #undef HAVE_DISABLED_NONBLOCKING */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* use FIONBIO for non-blocking sockets */
+/* #undef HAVE_FIONBIO */
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* use ioctlsocket() for non-blocking sockets */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* use Ioctlsocket() for non-blocking sockets */
+/* #undef HAVE_IOCTLSOCKET_CASE */
+
+/* Define if you have the gcrypt library. */
+/* #undef HAVE_LIBGCRYPT */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* use O_NONBLOCK for non-blocking sockets */
+#define HAVE_O_NONBLOCK 1
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* use SO_NONBLOCK for non-blocking sockets */
+/* #undef HAVE_SO_NONBLOCK */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Enable "none" cipher -- NOT RECOMMENDED */
+/* #undef LIBSSH2_CRYPT_NONE */
+
+/* Enable newer diffie-hellman-group-exchange-sha1 syntax */
+#define LIBSSH2_DH_GEX_NEW 1
+
+/* Compile in zlib support */
+#define LIBSSH2_HAVE_ZLIB 1
+
+/* Use libgcrypt */
+/* #undef LIBSSH2_LIBGCRYPT */
+
+/* Enable "none" MAC -- NOT RECOMMENDED */
+/* #undef LIBSSH2_MAC_NONE */
+
+/* Name of package */
+#define PACKAGE "libssh2"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "libssh2-devel@lists.sourceforge.net"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libssh2"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "libssh2 -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libssh2"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at runtime.
+       STACK_DIRECTION > 0 => grows toward higher addresses
+       STACK_DIRECTION < 0 => grows toward lower addresses
+       STACK_DIRECTION = 0 => direction of growth unknown */
+/* #undef STACK_DIRECTION */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.18"
+
+/* Define to 1 if your processor stores words with the most significant byte
+   first (like Motorola and SPARC, unlike Intel and VAX). */
+/* #undef WORDS_BIGENDIAN */
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
diff --git a/Vendor/libssh2/Headers/libssh2_priv.h b/Vendor/libssh2/Headers/libssh2_priv.h
new file mode 100644 (file)
index 0000000..ee06a24
--- /dev/null
@@ -0,0 +1,1144 @@
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#ifndef LIBSSH2_PRIV_H
+#define LIBSSH2_PRIV_H 1
+
+#define LIBSSH2_LIBRARY
+#include "libssh2_config.h"
+
+/* The following CPP block should really only be in session.c and
+   packet.c.  However, AIX have #define's for 'events' and 'revents'
+   and we are using those names in libssh2.h, so we need to include
+   the AIX headers first, to make sure all code is compiled with
+   consistent names of these fields.  While arguable the best would to
+   change libssh2.h to use other names, that would break backwards
+   compatibility.  For more information, see:
+   http://www.mail-archive.com/libssh2-devel%40lists.sourceforge.net/msg00003.html
+   http://www.mail-archive.com/libssh2-devel%40lists.sourceforge.net/msg00224.html
+*/
+#include <stdio.h>
+
+#ifdef HAVE_POLL
+# include <sys/poll.h>
+#else
+# ifdef HAVE_SELECT
+# ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+# else
+# include <sys/time.h>
+# include <sys/types.h>
+# endif
+# endif
+#endif
+
+#include "libssh2.h"
+#include "libssh2_publickey.h"
+#include "libssh2_sftp.h"
+
+/* Needed for struct iovec on some platforms */
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#ifdef LIBSSH2_LIBGCRYPT
+#include "libgcrypt.h"
+#else
+#include "openssl.h"
+#endif
+
+/* RFC4253 section 6.1 Maximum Packet Length says:
+ *
+ * "All implementations MUST be able to process packets with
+ * uncompressed payload length of 32768 bytes or less and
+ * total packet size of 35000 bytes or less (including length,
+ * padding length, payload, padding, and MAC.)."
+ */
+#define MAX_SSH_PACKET_LEN 35000
+
+#define LIBSSH2_ALLOC(session, count)                               session->alloc((count), &(session)->abstract)
+#define LIBSSH2_REALLOC(session, ptr, count)                        ((ptr) ? session->realloc((ptr), (count), &(session)->abstract) : session->alloc((count), &(session)->abstract))
+#define LIBSSH2_FREE(session, ptr)                                  session->free((ptr), &(session)->abstract)
+
+#define LIBSSH2_IGNORE(session, data, datalen)                      session->ssh_msg_ignore((session), (data), (datalen), &(session)->abstract)
+#define LIBSSH2_DEBUG(session, always_display, message, message_len, language, language_len)    \
+                session->ssh_msg_disconnect((session), (always_display), (message), (message_len), (language), (language_len), &(session)->abstract)
+#define LIBSSH2_DISCONNECT(session, reason, message, message_len, language, language_len)   \
+                session->ssh_msg_disconnect((session), (reason), (message), (message_len), (language), (language_len), &(session)->abstract)
+
+#define LIBSSH2_MACERROR(session, data, datalen)                    session->macerror((session), (data), (datalen), &(session)->abstract)
+#define LIBSSH2_X11_OPEN(channel, shost, sport)                     channel->session->x11(((channel)->session), (channel), (shost), (sport), (&(channel)->session->abstract))
+
+#define LIBSSH2_CHANNEL_CLOSE(session, channel)                     channel->close_cb((session), &(session)->abstract, (channel), &(channel)->abstract)
+
+typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD;
+typedef struct _LIBSSH2_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD;
+typedef struct _LIBSSH2_MAC_METHOD LIBSSH2_MAC_METHOD;
+typedef struct _LIBSSH2_CRYPT_METHOD LIBSSH2_CRYPT_METHOD;
+typedef struct _LIBSSH2_COMP_METHOD LIBSSH2_COMP_METHOD;
+
+typedef struct _LIBSSH2_PACKET LIBSSH2_PACKET;
+typedef struct _LIBSSH2_PACKET_BRIGADE LIBSSH2_PACKET_BRIGADE;
+typedef struct _LIBSSH2_CHANNEL_BRIGADE LIBSSH2_CHANNEL_BRIGADE;
+
+typedef int libssh2pack_t;
+
+typedef enum
+{
+    libssh2_NB_state_idle = 0,
+    libssh2_NB_state_allocated,
+    libssh2_NB_state_created,
+    libssh2_NB_state_sent,
+    libssh2_NB_state_sent1,
+    libssh2_NB_state_sent2,
+    libssh2_NB_state_sent3,
+    libssh2_NB_state_sent4,
+    libssh2_NB_state_sent5,
+    libssh2_NB_state_sent6,
+    libssh2_NB_state_sent7,
+    libssh2_NB_state_jump1,
+    libssh2_NB_state_jump2,
+    libssh2_NB_state_jump3
+} libssh2_nonblocking_states;
+
+typedef struct packet_require_state_t
+{
+    libssh2_nonblocking_states state;
+    time_t start;
+} packet_require_state_t;
+
+typedef struct packet_requirev_state_t
+{
+    time_t start;
+} packet_requirev_state_t;
+
+typedef struct kmdhgGPsha1kex_state_t
+{
+    libssh2_nonblocking_states state;
+    unsigned char *e_packet;
+    unsigned char *s_packet;
+    unsigned char *tmp;
+    unsigned char h_sig_comp[SHA_DIGEST_LENGTH];
+    unsigned char c;
+    unsigned long e_packet_len;
+    unsigned long s_packet_len;
+    unsigned long tmp_len;
+    _libssh2_bn_ctx *ctx;
+    _libssh2_bn *x;
+    _libssh2_bn *e;
+    _libssh2_bn *f;
+    _libssh2_bn *k;
+    unsigned char *s;
+    unsigned char *f_value;
+    unsigned char *k_value;
+    unsigned char *h_sig;
+    unsigned long f_value_len;
+    unsigned long k_value_len;
+    unsigned long h_sig_len;
+    libssh2_sha1_ctx exchange_hash;
+    packet_require_state_t req_state;
+    libssh2_nonblocking_states burn_state;
+} kmdhgGPsha1kex_state_t;
+
+typedef struct key_exchange_state_low_t
+{
+    libssh2_nonblocking_states state;
+    packet_require_state_t req_state;
+    kmdhgGPsha1kex_state_t exchange_state;
+    _libssh2_bn *p;             /* SSH2 defined value (p_value) */
+    _libssh2_bn *g;             /* SSH2 defined value (2) */
+    unsigned char request[13];
+    unsigned char *data;
+    unsigned long request_len;
+    unsigned long data_len;
+} key_exchange_state_low_t;
+
+typedef struct key_exchange_state_t
+{
+    libssh2_nonblocking_states state;
+    packet_require_state_t req_state;
+    key_exchange_state_low_t key_state_low;
+    unsigned char *data;
+    unsigned long data_len;
+    unsigned char *oldlocal;
+    unsigned long oldlocal_len;
+} key_exchange_state_t;
+
+#define FwdNotReq "Forward not requested"
+
+typedef struct packet_queue_listener_state_t
+{
+    libssh2_nonblocking_states state;
+    unsigned char packet[17 + (sizeof(FwdNotReq) - 1)];
+    unsigned char *host;
+    unsigned char *shost;
+    uint32_t sender_channel;
+    uint32_t initial_window_size;
+    uint32_t packet_size;
+    uint32_t port;
+    uint32_t sport;
+    uint32_t host_len;
+    uint32_t shost_len;
+} packet_queue_listener_state_t;
+
+#define X11FwdUnAvil "X11 Forward Unavailable"
+
+typedef struct packet_x11_open_state_t
+{
+    libssh2_nonblocking_states state;
+    unsigned char packet[17 + (sizeof(X11FwdUnAvil) - 1)];
+    unsigned char *shost;
+    uint32_t sender_channel;
+    uint32_t initial_window_size;
+    uint32_t packet_size;
+    uint32_t sport;
+    uint32_t shost_len;
+} packet_x11_open_state_t;
+
+struct _LIBSSH2_PACKET
+{
+    unsigned char type;
+
+    /* Unencrypted Payload (no type byte, no padding, just the facts ma'am) */
+    unsigned char *data;
+    unsigned long data_len;
+
+    /* Where to start reading data from,
+     * used for channel data that's been partially consumed */
+    unsigned long data_head;
+
+    /* Can the message be confirmed? */
+    int mac;
+
+    LIBSSH2_PACKET_BRIGADE *brigade;
+
+    LIBSSH2_PACKET *next, *prev;
+};
+
+struct _LIBSSH2_PACKET_BRIGADE
+{
+    LIBSSH2_PACKET *head, *tail;
+};
+
+typedef struct _libssh2_channel_data
+{
+    /* Identifier */
+    unsigned long id;
+
+    /* Limits and restrictions */
+    unsigned long window_size_initial, window_size, packet_size;
+
+    /* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */
+    char close, eof, extended_data_ignore_mode;
+} libssh2_channel_data;
+
+struct _LIBSSH2_CHANNEL
+{
+    unsigned char *channel_type;
+    unsigned channel_type_len;
+
+    /* channel's program exit status */
+    int exit_status;
+
+    libssh2_channel_data local, remote;
+    /* Amount of bytes to be refunded to receive window (but not yet sent) */
+    unsigned long adjust_queue;
+
+    LIBSSH2_SESSION *session;
+
+    LIBSSH2_CHANNEL *next, *prev;
+
+    void *abstract;
+      LIBSSH2_CHANNEL_CLOSE_FUNC((*close_cb));
+
+    /* State variables used in libssh2_channel_setenv_ex() */
+    libssh2_nonblocking_states setenv_state;
+    unsigned char *setenv_packet;
+    unsigned long setenv_packet_len;
+    unsigned char setenv_local_channel[4];
+    packet_requirev_state_t setenv_packet_requirev_state;
+
+    /* State variables used in libssh2_channel_request_pty_ex() */
+    libssh2_nonblocking_states reqPTY_state;
+    unsigned char *reqPTY_packet;
+    unsigned long reqPTY_packet_len;
+    unsigned char reqPTY_local_channel[4];
+    packet_requirev_state_t reqPTY_packet_requirev_state;
+
+    /* State variables used in libssh2_channel_x11_req_ex() */
+    libssh2_nonblocking_states reqX11_state;
+    unsigned char *reqX11_packet;
+    unsigned long reqX11_packet_len;
+    unsigned char reqX11_local_channel[4];
+    packet_requirev_state_t reqX11_packet_requirev_state;
+
+    /* State variables used in libssh2_channel_process_startup() */
+    libssh2_nonblocking_states process_state;
+    unsigned char *process_packet;
+    unsigned long process_packet_len;
+    unsigned char process_local_channel[4];
+    packet_requirev_state_t process_packet_requirev_state;
+
+    /* State variables used in libssh2_channel_flush_ex() */
+    libssh2_nonblocking_states flush_state;
+    unsigned long flush_refund_bytes;
+    unsigned long flush_flush_bytes;
+
+    /* State variables used in libssh2_channel_receive_window_adjust() */
+    libssh2_nonblocking_states adjust_state;
+    unsigned char adjust_adjust[9];     /* packet_type(1) + channel(4) + adjustment(4) */
+
+    /* State variables used in libssh2_channel_read_ex() */
+    libssh2_nonblocking_states read_state;
+    LIBSSH2_PACKET *read_packet;
+    LIBSSH2_PACKET *read_next;
+    int read_block;
+    int read_bytes_read;
+    uint32_t read_local_id;
+    int read_want;
+    int read_unlink_packet;
+
+    /* State variables used in libssh2_channel_write_ex() */
+    libssh2_nonblocking_states write_state;
+    unsigned char *write_packet;
+    unsigned char *write_s;
+    unsigned long write_packet_len;
+    unsigned long write_bufwrote;
+    size_t write_bufwrite;
+
+    /* State variables used in libssh2_channel_close() */
+    libssh2_nonblocking_states close_state;
+    unsigned char close_packet[5];
+
+    /* State variables used in libssh2_channel_wait_closedeof() */
+    libssh2_nonblocking_states wait_eof_state;
+
+    /* State variables used in libssh2_channel_wait_closed() */
+    libssh2_nonblocking_states wait_closed_state;
+
+    /* State variables used in libssh2_channel_free() */
+    libssh2_nonblocking_states free_state;
+
+    /* State variables used in libssh2_channel_handle_extended_data2() */
+    libssh2_nonblocking_states extData2_state;
+};
+
+struct _LIBSSH2_CHANNEL_BRIGADE
+{
+    LIBSSH2_CHANNEL *head, *tail;
+};
+
+struct _LIBSSH2_LISTENER
+{
+    LIBSSH2_SESSION *session;
+
+    char *host;
+    int port;
+
+    LIBSSH2_CHANNEL *queue;
+    int queue_size;
+    int queue_maxsize;
+
+    LIBSSH2_LISTENER *prev, *next;
+
+    /* State variables used in libssh2_channel_forward_cancel() */
+    libssh2_nonblocking_states chanFwdCncl_state;
+    unsigned char *chanFwdCncl_data;
+    size_t chanFwdCncl_data_len;
+};
+
+typedef struct _libssh2_endpoint_data
+{
+    unsigned char *banner;
+
+    unsigned char *kexinit;
+    unsigned long kexinit_len;
+
+    const LIBSSH2_CRYPT_METHOD *crypt;
+    void *crypt_abstract;
+
+    const LIBSSH2_MAC_METHOD *mac;
+    unsigned long seqno;
+    void *mac_abstract;
+
+    const LIBSSH2_COMP_METHOD *comp;
+    void *comp_abstract;
+
+    /* Method Preferences -- NULL yields "load order" */
+    char *crypt_prefs;
+    char *mac_prefs;
+    char *comp_prefs;
+    char *lang_prefs;
+} libssh2_endpoint_data;
+
+#define PACKETBUFSIZE 4096
+
+struct transportpacket
+{
+    /* ------------- for incoming data --------------- */
+    unsigned char buf[PACKETBUFSIZE];
+    unsigned char init[5];      /* first 5 bytes of the incoming data stream,
+                                   still encrypted */
+    int writeidx;               /* at what array index we do the next write into
+                                   the buffer */
+    int readidx;                /* at what array index we do the next read from
+                                   the buffer */
+    int packet_length;          /* the most recent packet_length as read from the
+                                   network data */
+    int padding_length;         /* the most recent padding_length as read from the
+                                   network data */
+    int data_num;               /* How much of the total package that has been read
+                                   so far. */
+    int total_num;              /* How much a total package is supposed to be, in
+                                   number of bytes. A full package is
+                                   packet_length + padding_length + 4 +
+                                   mac_length. */
+    unsigned char *payload;     /* this is a pointer to a LIBSSH2_ALLOC()
+                                   area to which we write decrypted data */
+    unsigned char *wptr;        /* write pointer into the payload to where we
+                                   are currently writing decrypted data */
+
+    /* ------------- for outgoing data --------------- */
+    unsigned char *outbuf;      /* pointer to a LIBSSH2_ALLOC() area for the
+                                   outgoing data */
+    int ototal_num;             /* size of outbuf in number of bytes */
+    unsigned char *odata;       /* original pointer to the data we stored in
+                                   outbuf */
+    unsigned long olen;         /* original size of the data we stored in
+                                   outbuf */
+    unsigned long osent;        /* number of bytes already sent */
+};
+
+struct _LIBSSH2_PUBLICKEY
+{
+    LIBSSH2_CHANNEL *channel;
+    unsigned long version;
+
+    /* State variables used in libssh2_publickey_packet_receive() */
+    libssh2_nonblocking_states receive_state;
+    unsigned char *receive_packet;
+    unsigned long receive_packet_len;
+
+    /* State variables used in libssh2_publickey_add_ex() */
+    libssh2_nonblocking_states add_state;
+    unsigned char *add_packet;
+    unsigned char *add_s;
+
+    /* State variables used in libssh2_publickey_remove_ex() */
+    libssh2_nonblocking_states remove_state;
+    unsigned char *remove_packet;
+    unsigned char *remove_s;
+
+    /* State variables used in libssh2_publickey_list_fetch() */
+    libssh2_nonblocking_states listFetch_state;
+    unsigned char *listFetch_s;
+    unsigned char listFetch_buffer[12];
+    unsigned char *listFetch_data;
+    unsigned long listFetch_data_len;
+};
+
+struct _LIBSSH2_SFTP_HANDLE
+{
+    LIBSSH2_SFTP *sftp;
+    LIBSSH2_SFTP_HANDLE *prev, *next;
+
+    char *handle;
+    int handle_len;
+
+    char handle_type;
+
+    union _libssh2_sftp_handle_data
+    {
+        struct _libssh2_sftp_handle_file_data
+        {
+            libssh2_uint64_t offset;
+        } file;
+        struct _libssh2_sftp_handle_dir_data
+        {
+            unsigned long names_left;
+            void *names_packet;
+            char *next_name;
+        } dir;
+    } u;
+
+    /* State variables used in libssh2_sftp_close_handle() */
+    libssh2_nonblocking_states close_state;
+    unsigned long close_request_id;
+    unsigned char *close_packet;
+};
+
+struct _LIBSSH2_SFTP
+{
+    LIBSSH2_CHANNEL *channel;
+
+    unsigned long request_id, version;
+
+    LIBSSH2_PACKET_BRIGADE packets;
+
+    LIBSSH2_SFTP_HANDLE *handles;
+
+    unsigned long last_errno;
+
+    /* Holder for partial packet, use in libssh2_sftp_packet_read() */
+    unsigned char *partial_packet;      /* The data                */
+    unsigned long partial_len;  /* Desired number of bytes */
+    unsigned long partial_received;     /* Bytes received so far   */
+
+    /* Time that libssh2_sftp_packet_requirev() started reading */
+    time_t requirev_start;
+
+    /* State variables used in libssh2_sftp_open_ex() */
+    libssh2_nonblocking_states open_state;
+    unsigned char *open_packet;
+    ssize_t open_packet_len;
+    unsigned long open_request_id;
+
+    /* State variables used in libssh2_sftp_read() */
+    libssh2_nonblocking_states read_state;
+    unsigned char *read_packet;
+    unsigned long read_request_id;
+    size_t read_total_read;
+
+    /* State variables used in libssh2_sftp_readdir() */
+    libssh2_nonblocking_states readdir_state;
+    unsigned char *readdir_packet;
+    unsigned long readdir_request_id;
+
+    /* State variables used in libssh2_sftp_write() */
+    libssh2_nonblocking_states write_state;
+    unsigned char *write_packet;
+    unsigned long write_request_id;
+
+    /* State variables used in libssh2_sftp_fstat_ex() */
+    libssh2_nonblocking_states fstat_state;
+    unsigned char *fstat_packet;
+    unsigned long fstat_request_id;
+
+    /* State variables used in libssh2_sftp_unlink_ex() */
+    libssh2_nonblocking_states unlink_state;
+    unsigned char *unlink_packet;
+    unsigned long unlink_request_id;
+
+    /* State variables used in libssh2_sftp_rename_ex() */
+    libssh2_nonblocking_states rename_state;
+    unsigned char *rename_packet;
+    unsigned char *rename_s;
+    unsigned long rename_request_id;
+
+    /* State variables used in libssh2_sftp_mkdir() */
+    libssh2_nonblocking_states mkdir_state;
+    unsigned char *mkdir_packet;
+    unsigned long mkdir_request_id;
+
+    /* State variables used in libssh2_sftp_rmdir() */
+    libssh2_nonblocking_states rmdir_state;
+    unsigned char *rmdir_packet;
+    unsigned long rmdir_request_id;
+
+    /* State variables used in libssh2_sftp_stat() */
+    libssh2_nonblocking_states stat_state;
+    unsigned char *stat_packet;
+    unsigned long stat_request_id;
+
+    /* State variables used in libssh2_sftp_symlink() */
+    libssh2_nonblocking_states symlink_state;
+    unsigned char *symlink_packet;
+    unsigned long symlink_request_id;
+};
+
+#define LIBSSH2_SCP_RESPONSE_BUFLEN     256
+
+struct _LIBSSH2_SESSION
+{
+    /* Memory management callbacks */
+    void *abstract;
+      LIBSSH2_ALLOC_FUNC((*alloc));
+      LIBSSH2_REALLOC_FUNC((*realloc));
+      LIBSSH2_FREE_FUNC((*free));
+
+    /* Other callbacks */
+      LIBSSH2_IGNORE_FUNC((*ssh_msg_ignore));
+      LIBSSH2_DEBUG_FUNC((*ssh_msg_debug));
+      LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect));
+      LIBSSH2_MACERROR_FUNC((*macerror));
+      LIBSSH2_X11_OPEN_FUNC((*x11));
+
+    /* Method preferences -- NULL yields "load order" */
+    char *kex_prefs;
+    char *hostkey_prefs;
+
+    int state;
+    int flags;
+
+    /* Agreed Key Exchange Method */
+    const LIBSSH2_KEX_METHOD *kex;
+    int burn_optimistic_kexinit:1;
+
+    unsigned char *session_id;
+    unsigned long session_id_len;
+
+    /* Server's public key */
+    const LIBSSH2_HOSTKEY_METHOD *hostkey;
+    void *server_hostkey_abstract;
+
+    /* Either set with libssh2_session_hostkey() (for server mode)
+     * Or read from server in (eg) KEXDH_INIT (for client mode)
+     */
+    unsigned char *server_hostkey;
+    unsigned long server_hostkey_len;
+#if LIBSSH2_MD5
+    unsigned char server_hostkey_md5[MD5_DIGEST_LENGTH];
+#endif                          /* ! LIBSSH2_MD5 */
+    unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH];
+
+    /* (remote as source of data -- packet_read ) */
+    libssh2_endpoint_data remote;
+
+    /* (local as source of data -- packet_write ) */
+    libssh2_endpoint_data local;
+
+    /* Inbound Data buffer -- Sometimes the packet that comes in isn't the packet we're ready for */
+    LIBSSH2_PACKET_BRIGADE packets;
+
+    /* Active connection channels */
+    LIBSSH2_CHANNEL_BRIGADE channels;
+    unsigned long next_channel;
+
+    LIBSSH2_LISTENER *listeners;
+
+    /* Actual I/O socket */
+    int socket_fd;
+    int socket_block;
+    int socket_state;
+
+    /* Error tracking */
+    char *err_msg;
+    unsigned long err_msglen;
+    int err_should_free;
+    int err_code;
+
+    /* struct members for packet-level reading */
+    struct transportpacket packet;
+#ifdef LIBSSH2DEBUG
+    int showmask;               /* what debug/trace messages to display */
+#endif
+
+    /* State variables used in libssh2_banner_send() */
+    libssh2_nonblocking_states banner_TxRx_state;
+    char banner_TxRx_banner[256];
+    ssize_t banner_TxRx_total_send;
+
+    /* State variables used in libssh2_kexinit() */
+    libssh2_nonblocking_states kexinit_state;
+    unsigned char *kexinit_data;
+    size_t kexinit_data_len;
+
+    /* State variables used in libssh2_session_startup() */
+    libssh2_nonblocking_states startup_state;
+    unsigned char *startup_data;
+    unsigned long startup_data_len;
+    unsigned char startup_service[sizeof("ssh-userauth") + 5 - 1];
+    unsigned long startup_service_length;
+    packet_require_state_t startup_req_state;
+    key_exchange_state_t startup_key_state;
+
+    /* State variables used in libssh2_session_free() */
+    libssh2_nonblocking_states free_state;
+
+    /* State variables used in libssh2_session_disconnect_ex() */
+    libssh2_nonblocking_states disconnect_state;
+    unsigned char *disconnect_data;
+    unsigned long disconnect_data_len;
+
+    /* State variables used in libssh2_packet_read() */
+    libssh2_nonblocking_states readPack_state;
+    int readPack_encrypted;
+
+    /* State variables used in libssh2_userauth_list() */
+    libssh2_nonblocking_states userauth_list_state;
+    unsigned char *userauth_list_data;
+    unsigned long userauth_list_data_len;
+    packet_requirev_state_t userauth_list_packet_requirev_state;
+
+    /* State variables used in libssh2_userauth_password_ex() */
+    libssh2_nonblocking_states userauth_pswd_state;
+    unsigned char *userauth_pswd_data;
+    unsigned char userauth_pswd_data0;
+    unsigned long userauth_pswd_data_len;
+    char *userauth_pswd_newpw;
+    int userauth_pswd_newpw_len;
+    packet_requirev_state_t userauth_pswd_packet_requirev_state;
+
+    /* State variables used in libssh2_userauth_hostbased_fromfile_ex() */
+    libssh2_nonblocking_states userauth_host_state;
+    unsigned char *userauth_host_data;
+    unsigned long userauth_host_data_len;
+    unsigned char *userauth_host_packet;
+    unsigned long userauth_host_packet_len;
+    unsigned char *userauth_host_method;
+    unsigned long userauth_host_method_len;
+    unsigned char *userauth_host_s;
+    packet_requirev_state_t userauth_host_packet_requirev_state;
+
+    /* State variables used in libssh2_userauth_publickey_fromfile_ex() */
+    libssh2_nonblocking_states userauth_pblc_state;
+    unsigned char *userauth_pblc_data;
+    unsigned long userauth_pblc_data_len;
+    unsigned char *userauth_pblc_packet;
+    unsigned long userauth_pblc_packet_len;
+    unsigned char *userauth_pblc_method;
+    unsigned long userauth_pblc_method_len;
+    unsigned char *userauth_pblc_s;
+    unsigned char *userauth_pblc_b;
+    packet_requirev_state_t userauth_pblc_packet_requirev_state;
+
+    /* State variables used in llibssh2_userauth_keyboard_interactive_ex() */
+    libssh2_nonblocking_states userauth_kybd_state;
+    unsigned char *userauth_kybd_data;
+    unsigned long userauth_kybd_data_len;
+    unsigned char *userauth_kybd_packet;
+    unsigned long userauth_kybd_packet_len;
+    unsigned int userauth_kybd_auth_name_len;
+    char *userauth_kybd_auth_name;
+    unsigned userauth_kybd_auth_instruction_len;
+    char *userauth_kybd_auth_instruction;
+    unsigned int userauth_kybd_num_prompts;
+    int userauth_kybd_auth_failure;
+    LIBSSH2_USERAUTH_KBDINT_PROMPT *userauth_kybd_prompts;
+    LIBSSH2_USERAUTH_KBDINT_RESPONSE *userauth_kybd_responses;
+    packet_requirev_state_t userauth_kybd_packet_requirev_state;
+
+    /* State variables used in libssh2_channel_open_ex() */
+    libssh2_nonblocking_states open_state;
+    packet_requirev_state_t open_packet_requirev_state;
+    LIBSSH2_CHANNEL *open_channel;
+    unsigned char *open_packet;
+    unsigned long open_packet_len;
+    unsigned char *open_data;
+    unsigned long open_data_len;
+    unsigned long open_local_channel;
+
+    /* State variables used in libssh2_channel_direct_tcpip_ex() */
+    libssh2_nonblocking_states direct_state;
+    unsigned char *direct_message;
+    unsigned long direct_host_len;
+    unsigned long direct_shost_len;
+    unsigned long direct_message_len;
+
+    /* State variables used in libssh2_channel_forward_listen_ex() */
+    libssh2_nonblocking_states fwdLstn_state;
+    unsigned char *fwdLstn_packet;
+    unsigned long fwdLstn_host_len;
+    unsigned long fwdLstn_packet_len;
+    packet_requirev_state_t fwdLstn_packet_requirev_state;
+
+    /* State variables used in libssh2_publickey_init() */
+    libssh2_nonblocking_states pkeyInit_state;
+    LIBSSH2_PUBLICKEY *pkeyInit_pkey;
+    LIBSSH2_CHANNEL *pkeyInit_channel;
+    unsigned char *pkeyInit_data;
+    unsigned long pkeyInit_data_len;
+
+    /* State variables used in libssh2_packet_add() */
+    libssh2_nonblocking_states packAdd_state;
+    LIBSSH2_PACKET *packAdd_packet;
+    LIBSSH2_CHANNEL *packAdd_channel;
+    unsigned long packAdd_data_head;
+    key_exchange_state_t packAdd_key_state;
+    packet_queue_listener_state_t packAdd_Qlstn_state;
+    packet_x11_open_state_t packAdd_x11open_state;
+
+    /* State variables used in fullpacket() */
+    libssh2_nonblocking_states fullpacket_state;
+    int fullpacket_macstate;
+    int fullpacket_payload_len;
+    libssh2pack_t fullpacket_packet_type;
+
+    /* State variables used in libssh2_sftp_init() */
+    libssh2_nonblocking_states sftpInit_state;
+    LIBSSH2_SFTP *sftpInit_sftp;
+    LIBSSH2_CHANNEL *sftpInit_channel;
+    unsigned char sftpInit_buffer[9];   /* sftp_header(5){excludes request_id} + version_id(4) */
+
+    /* State variables used in libssh2_scp_recv() */
+    libssh2_nonblocking_states scpRecv_state;
+    unsigned char *scpRecv_command;
+    unsigned long scpRecv_command_len;
+    unsigned char scpRecv_response[LIBSSH2_SCP_RESPONSE_BUFLEN];
+    unsigned long scpRecv_response_len;
+    long scpRecv_mode;
+    long scpRecv_size;
+    long scpRecv_mtime;
+    long scpRecv_atime;
+    char *scpRecv_err_msg;
+    long scpRecv_err_len;
+    LIBSSH2_CHANNEL *scpRecv_channel;
+
+    /* State variables used in libssh2_scp_send_ex() */
+    libssh2_nonblocking_states scpSend_state;
+    unsigned char *scpSend_command;
+    unsigned long scpSend_command_len;
+    unsigned char scpSend_response[LIBSSH2_SCP_RESPONSE_BUFLEN];
+    unsigned long scpSend_response_len;
+    char *scpSend_err_msg;
+    long scpSend_err_len;
+    LIBSSH2_CHANNEL *scpSend_channel;
+};
+
+/* session.state bits */
+#define LIBSSH2_STATE_EXCHANGING_KEYS   0x00000001
+#define LIBSSH2_STATE_NEWKEYS           0x00000002
+#define LIBSSH2_STATE_AUTHENTICATED     0x00000004
+
+/* session.flag helpers */
+#ifdef MSG_NOSIGNAL
+#define LIBSSH2_SOCKET_SEND_FLAGS(session)      (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
+#define LIBSSH2_SOCKET_RECV_FLAGS(session)      (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
+#else
+/* If MSG_NOSIGNAL isn't defined we're SOL on blocking SIGPIPE */
+#define LIBSSH2_SOCKET_SEND_FLAGS(session)      0
+#define LIBSSH2_SOCKET_RECV_FLAGS(session)      0
+#endif
+
+/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional methods via .so/.dll */
+
+struct _LIBSSH2_KEX_METHOD
+{
+    const char *name;
+
+    /* Key exchange, populates session->* and returns 0 on success, non-0 on error */
+    int (*exchange_keys) (LIBSSH2_SESSION * session,
+                          key_exchange_state_low_t * key_state);
+
+    long flags;
+};
+
+struct _LIBSSH2_HOSTKEY_METHOD
+{
+    const char *name;
+    unsigned long hash_len;
+
+    int (*init) (LIBSSH2_SESSION * session, const unsigned char *hostkey_data,
+                 unsigned long hostkey_data_len, void **abstract);
+    int (*initPEM) (LIBSSH2_SESSION * session, const char *privkeyfile,
+                    unsigned const char *passphrase, void **abstract);
+    int (*sig_verify) (LIBSSH2_SESSION * session, const unsigned char *sig,
+                       unsigned long sig_len, const unsigned char *m,
+                       unsigned long m_len, void **abstract);
+    int (*signv) (LIBSSH2_SESSION * session, unsigned char **signature,
+                  unsigned long *signature_len, unsigned long veccount,
+                  const struct iovec datavec[], void **abstract);
+    int (*encrypt) (LIBSSH2_SESSION * session, unsigned char **dst,
+                    unsigned long *dst_len, const unsigned char *src,
+                    unsigned long src_len, void **abstract);
+    int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
+};
+
+struct _LIBSSH2_CRYPT_METHOD
+{
+    const char *name;
+
+    int blocksize;
+
+    /* iv and key sizes (-1 for variable length) */
+    int iv_len;
+    int secret_len;
+
+    long flags;
+
+    int (*init) (LIBSSH2_SESSION * session,
+                 const LIBSSH2_CRYPT_METHOD * method, unsigned char *iv,
+                 int *free_iv, unsigned char *secret, int *free_secret,
+                 int encrypt, void **abstract);
+    int (*crypt) (LIBSSH2_SESSION * session, unsigned char *block,
+                  void **abstract);
+    int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
+
+      _libssh2_cipher_type(algo);
+};
+
+struct _LIBSSH2_COMP_METHOD
+{
+    const char *name;
+
+    int (*init) (LIBSSH2_SESSION * session, int compress, void **abstract);
+    int (*comp) (LIBSSH2_SESSION * session, int compress, unsigned char **dest,
+                 unsigned long *dest_len, unsigned long payload_limit,
+                 int *free_dest, const unsigned char *src,
+                 unsigned long src_len, void **abstract);
+    int (*dtor) (LIBSSH2_SESSION * session, int compress, void **abstract);
+};
+
+struct _LIBSSH2_MAC_METHOD
+{
+    const char *name;
+
+    /* The length of a given MAC packet */
+    int mac_len;
+
+    /* integrity key length */
+    int key_len;
+
+    /* Message Authentication Code Hashing algo */
+    int (*init) (LIBSSH2_SESSION * session, unsigned char *key, int *free_key,
+                 void **abstract);
+    int (*hash) (LIBSSH2_SESSION * session, unsigned char *buf,
+                 unsigned long seqno, const unsigned char *packet,
+                 unsigned long packet_len, const unsigned char *addtl,
+                 unsigned long addtl_len, void **abstract);
+    int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
+};
+
+#define LIBSSH2_DBG_TRANS   1
+#define LIBSSH2_DBG_KEX     2
+#define LIBSSH2_DBG_AUTH    3
+#define LIBSSH2_DBG_CONN    4
+#define LIBSSH2_DBG_SCP     5
+#define LIBSSH2_DBG_SFTP    6
+#define LIBSSH2_DBG_ERROR   7
+#define LIBSSH2_DBG_PUBLICKEY   8
+#ifdef LIBSSH2DEBUG
+void _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format,
+                    ...);
+#else
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+/* C99 style */
+#define _libssh2_debug(x,y,z, __VA_ARGS__) do {} while (0)
+#elif defined(__GNUC__)
+/* GNU style */
+#define _libssh2_debug(x,y,z,...) do {} while (0)
+#else
+/* no gcc and not C99, do static and hopefully inline */
+static inline void
+_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
+{
+}
+#endif
+#endif
+
+#ifdef LIBSSH2DEBUG
+#define libssh2_error(session, errcode, errmsg, should_free)    \
+{ \
+    if (session->err_msg && session->err_should_free) { \
+        LIBSSH2_FREE(session, session->err_msg); \
+    } \
+    session->err_msg = (char *)errmsg; \
+    session->err_msglen = strlen(errmsg); \
+    session->err_should_free = should_free; \
+    session->err_code = errcode; \
+    _libssh2_debug(session, LIBSSH2_DBG_ERROR, "%d - %s", session->err_code, session->err_msg); \
+}
+
+#else /* ! LIBSSH2DEBUG */
+
+#define libssh2_error(session, errcode, errmsg, should_free)    \
+{ \
+    if (session->err_msg && session->err_should_free) { \
+        LIBSSH2_FREE(session, session->err_msg); \
+    } \
+    session->err_msg = (char *)errmsg; \
+    session->err_msglen = strlen(errmsg); \
+    session->err_should_free = should_free; \
+    session->err_code = errcode; \
+}
+
+#endif /* ! LIBSSH2DEBUG */
+
+
+#define LIBSSH2_SOCKET_UNKNOWN                   1
+#define LIBSSH2_SOCKET_CONNECTED                 0
+#define LIBSSH2_SOCKET_DISCONNECTED             -1
+
+/* Initial packet state, prior to MAC check */
+#define LIBSSH2_MAC_UNCONFIRMED                  1
+/* When MAC type is "none" (proto initiation phase) all packets are deemed "confirmed" */
+#define LIBSSH2_MAC_CONFIRMED                    0
+/* Something very bad is going on */
+#define LIBSSH2_MAC_INVALID                     -1
+
+/* SSH Packet Types -- Defined by internet draft */
+/* Transport Layer */
+#define SSH_MSG_DISCONNECT                          1
+#define SSH_MSG_IGNORE                              2
+#define SSH_MSG_UNIMPLEMENTED                       3
+#define SSH_MSG_DEBUG                               4
+#define SSH_MSG_SERVICE_REQUEST                     5
+#define SSH_MSG_SERVICE_ACCEPT                      6
+
+#define SSH_MSG_KEXINIT                             20
+#define SSH_MSG_NEWKEYS                             21
+
+/* diffie-hellman-group1-sha1 */
+#define SSH_MSG_KEXDH_INIT                          30
+#define SSH_MSG_KEXDH_REPLY                         31
+
+/* diffie-hellman-group-exchange-sha1 */
+#define SSH_MSG_KEX_DH_GEX_REQUEST_OLD              30
+#define SSH_MSG_KEX_DH_GEX_REQUEST                  34
+#define SSH_MSG_KEX_DH_GEX_GROUP                    31
+#define SSH_MSG_KEX_DH_GEX_INIT                     32
+#define SSH_MSG_KEX_DH_GEX_REPLY                    33
+
+/* User Authentication */
+#define SSH_MSG_USERAUTH_REQUEST                    50
+#define SSH_MSG_USERAUTH_FAILURE                    51
+#define SSH_MSG_USERAUTH_SUCCESS                    52
+#define SSH_MSG_USERAUTH_BANNER                     53
+
+/* "public key" method */
+#define SSH_MSG_USERAUTH_PK_OK                      60
+/* "password" method */
+#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ           60
+/* "keyboard-interactive" method */
+#define SSH_MSG_USERAUTH_INFO_REQUEST               60
+#define SSH_MSG_USERAUTH_INFO_RESPONSE              61
+
+/* Channels */
+#define SSH_MSG_GLOBAL_REQUEST                      80
+#define SSH_MSG_REQUEST_SUCCESS                     81
+#define SSH_MSG_REQUEST_FAILURE                     82
+
+#define SSH_MSG_CHANNEL_OPEN                        90
+#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION           91
+#define SSH_MSG_CHANNEL_OPEN_FAILURE                92
+#define SSH_MSG_CHANNEL_WINDOW_ADJUST               93
+#define SSH_MSG_CHANNEL_DATA                        94
+#define SSH_MSG_CHANNEL_EXTENDED_DATA               95
+#define SSH_MSG_CHANNEL_EOF                         96
+#define SSH_MSG_CHANNEL_CLOSE                       97
+#define SSH_MSG_CHANNEL_REQUEST                     98
+#define SSH_MSG_CHANNEL_SUCCESS                     99
+#define SSH_MSG_CHANNEL_FAILURE                     100
+
+void libssh2_session_shutdown(LIBSSH2_SESSION * session);
+
+unsigned long libssh2_ntohu32(const unsigned char *buf);
+libssh2_uint64_t libssh2_ntohu64(const unsigned char *buf);
+void libssh2_htonu32(unsigned char *buf, unsigned long val);
+void libssh2_htonu64(unsigned char *buf, libssh2_uint64_t val);
+
+#define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when
+                                   waiting for more data to arrive */
+int libssh2_waitsocket(LIBSSH2_SESSION * session, long seconds);
+
+
+/* CAUTION: some of these error codes are returned in the public API and is
+   there known with other #defined names from the public header file. They
+   should not be changed. */
+
+#define PACKET_TIMEOUT  -7
+#define PACKET_BADUSE   -6
+#define PACKET_COMPRESS -5
+#define PACKET_TOOBIG   -4
+#define PACKET_ENOMEM   -3
+#define PACKET_EAGAIN   LIBSSH2_ERROR_EAGAIN
+#define PACKET_FAIL     -1
+#define PACKET_NONE      0
+
+libssh2pack_t libssh2_packet_read(LIBSSH2_SESSION * session);
+
+int libssh2_packet_ask_ex(LIBSSH2_SESSION * session, unsigned char packet_type,
+                          unsigned char **data, unsigned long *data_len,
+                          unsigned long match_ofs,
+                          const unsigned char *match_buf,
+                          unsigned long match_len, int poll_socket);
+
+int libssh2_packet_askv_ex(LIBSSH2_SESSION * session,
+                           const unsigned char *packet_types,
+                           unsigned char **data, unsigned long *data_len,
+                           unsigned long match_ofs,
+                           const unsigned char *match_buf,
+                           unsigned long match_len, int poll_socket);
+int libssh2_packet_require_ex(LIBSSH2_SESSION * session,
+                              unsigned char packet_type, unsigned char **data,
+                              unsigned long *data_len, unsigned long match_ofs,
+                              const unsigned char *match_buf,
+                              unsigned long match_len,
+                              packet_require_state_t * state);
+int libssh2_packet_requirev_ex(LIBSSH2_SESSION * session,
+                               const unsigned char *packet_types,
+                               unsigned char **data, unsigned long *data_len,
+                               unsigned long match_ofs,
+                               const unsigned char *match_buf,
+                               unsigned long match_len,
+                               packet_requirev_state_t * state);
+int libssh2_packet_burn(LIBSSH2_SESSION * session,
+                        libssh2_nonblocking_states * state);
+int libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
+                         unsigned long data_len);
+int libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
+                       size_t datalen, int macstate);
+int libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
+                         key_exchange_state_t * state);
+unsigned long libssh2_channel_nextid(LIBSSH2_SESSION * session);
+LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION * session,
+                                        unsigned long channel_id);
+unsigned long libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel,
+                                              int stream_id);
+
+/* this is the lib-internal set blocking function */
+int _libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking);
+
+/* Let crypt.c/hostkey.c/comp.c/mac.c expose their method structs */
+const LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void);
+const LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void);
+const LIBSSH2_COMP_METHOD **libssh2_comp_methods(void);
+const LIBSSH2_MAC_METHOD **libssh2_mac_methods(void);
+
+/* Language API doesn't exist yet.  Just act like we've agreed on a language */
+#define libssh2_kex_agree_lang(session, endpoint, str, str_len) 0
+
+/* pem.c */
+int _libssh2_pem_parse(LIBSSH2_SESSION * session,
+                       const char *headerbegin,
+                       const char *headerend,
+                       FILE * fp, char **data, unsigned int *datalen);
+int _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen);
+int _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
+                                unsigned char **i, unsigned int *ilen);
+
+#endif /* LIBSSH2_H */
diff --git a/Vendor/libssh2/Headers/openssl.h b/Vendor/libssh2/Headers/openssl.h
new file mode 100644 (file)
index 0000000..cc7949b
--- /dev/null
@@ -0,0 +1,224 @@
+/* Copyright (C) 2006, 2007 The Written Word, Inc.  All rights reserved.
+ * Author: Simon Josefsson
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include <openssl/opensslconf.h>
+#include <openssl/sha.h>
+#ifndef OPENSSL_NO_MD5
+#include <openssl/md5.h>
+#endif
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/bn.h>
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+
+#ifdef OPENSSL_NO_RSA
+# define LIBSSH2_RSA 0
+#else
+# define LIBSSH2_RSA 1
+#endif
+
+#ifdef OPENSSL_NO_DSA
+# define LIBSSH2_DSA 0
+#else
+# define LIBSSH2_DSA 1
+#endif
+
+#ifdef OPENSSL_NO_MD5
+# define LIBSSH2_MD5 0
+#else
+# define LIBSSH2_MD5 1
+#endif
+
+#ifdef OPENSSL_NO_RIPEMD
+# define LIBSSH2_HMAC_RIPEMD 0
+#else
+# define LIBSSH2_HMAC_RIPEMD 1
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)
+# define LIBSSH2_AES 1
+#else
+# define LIBSSH2_AES 0
+#endif
+
+#ifdef OPENSSL_NO_BLOWFISH
+# define LIBSSH2_BLOWFISH 0
+#else
+# define LIBSSH2_BLOWFISH 1
+#endif
+
+#ifdef OPENSSL_NO_RC4
+# define LIBSSH2_RC4 0
+#else
+# define LIBSSH2_RC4 1
+#endif
+
+#ifdef OPENSSL_NO_CAST
+# define LIBSSH2_CAST 0
+#else
+# define LIBSSH2_CAST 1
+#endif
+
+#ifdef OPENSSL_NO_DES
+# define LIBSSH2_3DES 0
+#else
+# define LIBSSH2_3DES 1
+#endif
+
+#define libssh2_random(buf, len)        \
+  RAND_bytes ((buf), (len))
+
+#define libssh2_sha1_ctx SHA_CTX
+#define libssh2_sha1_init(ctx) SHA1_Init(ctx)
+#define libssh2_sha1_update(ctx, data, len) SHA1_Update(&(ctx), data, len)
+#define libssh2_sha1_final(ctx, out) SHA1_Final(out, &(ctx))
+#define libssh2_sha1(message, len, out) SHA1(message, len, out)
+
+#define libssh2_md5_ctx MD5_CTX
+#define libssh2_md5_init(ctx) MD5_Init(ctx)
+#define libssh2_md5_update(ctx, data, len) MD5_Update(&(ctx), data, len)
+#define libssh2_md5_final(ctx, out) MD5_Final(out, &(ctx))
+#define libssh2_md5(message, len, out) MD5(message, len, out)
+
+#define libssh2_hmac_ctx HMAC_CTX
+#define libssh2_hmac_sha1_init(ctx, key, keylen) \
+  HMAC_Init(ctx, key, keylen, EVP_sha1())
+#define libssh2_hmac_md5_init(ctx, key, keylen) \
+  HMAC_Init(ctx, key, keylen, EVP_md5())
+#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
+  HMAC_Init(ctx, key, keylen, EVP_ripemd160())
+#define libssh2_hmac_update(ctx, data, datalen) \
+  HMAC_Update(&(ctx), data, datalen)
+#define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL)
+#define libssh2_hmac_cleanup(ctx) HMAC_cleanup(ctx)
+
+#define libssh2_crypto_init()
+
+#define libssh2_rsa_ctx RSA
+
+int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
+                     const unsigned char *edata,
+                     unsigned long elen,
+                     const unsigned char *ndata,
+                     unsigned long nlen,
+                     const unsigned char *ddata,
+                     unsigned long dlen,
+                     const unsigned char *pdata,
+                     unsigned long plen,
+                     const unsigned char *qdata,
+                     unsigned long qlen,
+                     const unsigned char *e1data,
+                     unsigned long e1len,
+                     const unsigned char *e2data,
+                     unsigned long e2len,
+                     const unsigned char *coeffdata, unsigned long coefflen);
+int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
+                             LIBSSH2_SESSION * session,
+                             FILE * fp, unsigned const char *passphrase);
+int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
+                             const unsigned char *sig,
+                             unsigned long sig_len,
+                             const unsigned char *m, unsigned long m_len);
+int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
+                           libssh2_rsa_ctx * rsactx,
+                           const unsigned char *hash,
+                           unsigned long hash_len,
+                           unsigned char **signature,
+                           unsigned long *signature_len);
+
+#define _libssh2_rsa_free(rsactx) RSA_free(rsactx)
+
+#define libssh2_dsa_ctx DSA
+
+int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
+                     const unsigned char *pdata,
+                     unsigned long plen,
+                     const unsigned char *qdata,
+                     unsigned long qlen,
+                     const unsigned char *gdata,
+                     unsigned long glen,
+                     const unsigned char *ydata,
+                     unsigned long ylen,
+                     const unsigned char *x, unsigned long x_len);
+int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
+                             LIBSSH2_SESSION * session,
+                             FILE * fp, unsigned const char *passphrase);
+int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
+                             const unsigned char *sig,
+                             const unsigned char *m, unsigned long m_len);
+int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
+                           const unsigned char *hash,
+                           unsigned long hash_len, unsigned char *sig);
+
+#define _libssh2_dsa_free(dsactx) DSA_free(dsactx)
+
+#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void)
+#define _libssh2_cipher_ctx EVP_CIPHER_CTX
+
+#define _libssh2_cipher_aes256 EVP_aes_256_cbc
+#define _libssh2_cipher_aes192 EVP_aes_192_cbc
+#define _libssh2_cipher_aes128 EVP_aes_128_cbc
+#define _libssh2_cipher_blowfish EVP_bf_cbc
+#define _libssh2_cipher_arcfour EVP_rc4
+#define _libssh2_cipher_cast5 EVP_cast5_cbc
+#define _libssh2_cipher_3des EVP_des_ede3_cbc
+
+int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
+                         _libssh2_cipher_type(algo),
+                         unsigned char *iv,
+                         unsigned char *secret, int encrypt);
+
+int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
+                          _libssh2_cipher_type(algo),
+                          int encrypt, unsigned char *block);
+
+#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_cleanup(ctx)
+
+#define _libssh2_bn BIGNUM
+#define _libssh2_bn_ctx BN_CTX
+#define _libssh2_bn_ctx_new() BN_CTX_new()
+#define _libssh2_bn_ctx_free(bnctx) BN_CTX_free(bnctx)
+#define _libssh2_bn_init() BN_new()
+#define _libssh2_bn_rand(bn, bits, top, bottom) BN_rand(bn, bits, top, bottom)
+#define _libssh2_bn_mod_exp(r, a, p, m, ctx) BN_mod_exp(r, a, p, m, ctx)
+#define _libssh2_bn_set_word(bn, val) BN_set_word(bn, val)
+#define _libssh2_bn_from_bin(bn, len, val) BN_bin2bn(val, len, bn)
+#define _libssh2_bn_to_bin(bn, val) BN_bn2bin(bn, val)
+#define _libssh2_bn_bytes(bn) BN_num_bytes(bn)
+#define _libssh2_bn_bits(bn) BN_num_bits(bn)
+#define _libssh2_bn_free(bn) BN_clear_free(bn)
diff --git a/Vendor/libssh2/Source/channel.c b/Vendor/libssh2/Source/channel.c
new file mode 100644 (file)
index 0000000..61702a1
--- /dev/null
@@ -0,0 +1,2168 @@
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+
+/* {{{ libssh2_channel_nextid
+ * Determine the next channel ID we can use at our end
+ */
+unsigned long
+libssh2_channel_nextid(LIBSSH2_SESSION * session)
+{
+    unsigned long id = session->next_channel;
+    LIBSSH2_CHANNEL *channel;
+
+    channel = session->channels.head;
+
+    while (channel) {
+        if (channel->local.id > id) {
+            id = channel->local.id;
+        }
+        channel = channel->next;
+    }
+
+    /* This is a shortcut to avoid waiting for close packets on channels we've forgotten about,
+     * This *could* be a problem if we request and close 4 billion or so channels in too rapid succession
+     * for the remote end to respond, but the worst case scenario is that some data meant for another channel
+     * Gets picked up by the new one.... Pretty unlikely all told...
+     */
+    session->next_channel = id + 1;
+    _libssh2_debug(session, LIBSSH2_DBG_CONN, "Allocated new channel ID#%lu",
+                   id);
+    return id;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_locate
+ * Locate a channel pointer by number
+ */
+LIBSSH2_CHANNEL *
+libssh2_channel_locate(LIBSSH2_SESSION * session, unsigned long channel_id)
+{
+    LIBSSH2_CHANNEL *channel = session->channels.head;
+    while (channel) {
+        if (channel->local.id == channel_id) {
+            return channel;
+        }
+        channel = channel->next;
+    }
+
+    return NULL;
+}
+
+/* }}} */
+
+#define libssh2_channel_add(session, channel)   \
+{   \
+    if ((session)->channels.tail) { \
+        (session)->channels.tail->next = (channel); \
+        (channel)->prev = (session)->channels.tail; \
+    } else {    \
+        (session)->channels.head = (channel);   \
+        (channel)->prev = NULL; \
+    }   \
+    (channel)->next = NULL; \
+    (session)->channels.tail = (channel);   \
+    (channel)->session = (session); \
+}
+
+/* {{{ libssh2_channel_open_ex
+ * Establish a generic session channel
+ */
+LIBSSH2_API LIBSSH2_CHANNEL *
+libssh2_channel_open_ex(LIBSSH2_SESSION * session, const char *channel_type,
+                        unsigned int channel_type_len,
+                        unsigned int window_size, unsigned int packet_size,
+                        const char *message, unsigned int message_len)
+{
+    static const unsigned char reply_codes[3] = {
+        SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
+        SSH_MSG_CHANNEL_OPEN_FAILURE,
+        0
+    };
+    unsigned char *s;
+    int rc;
+
+    if (session->open_state == libssh2_NB_state_idle) {
+        session->open_channel = NULL;
+        session->open_packet = NULL;
+        session->open_data = NULL;
+        /* 17 = packet_type(1) + channel_type_len(4) + sender_channel(4) + window_size(4) + packet_size(4) */
+        session->open_packet_len = channel_type_len + message_len + 17;
+        session->open_local_channel = libssh2_channel_nextid(session);
+
+        /* Zero the whole thing out */
+        memset(&session->open_packet_requirev_state, 0,
+               sizeof(session->open_packet_requirev_state));
+
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "Opening Channel - win %d pack %d", window_size,
+                       packet_size);
+        session->open_channel =
+            LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
+        if (!session->open_channel) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate space for channel data", 0);
+            return NULL;
+        }
+        memset(session->open_channel, 0, sizeof(LIBSSH2_CHANNEL));
+
+        session->open_channel->channel_type_len = channel_type_len;
+        session->open_channel->channel_type =
+            LIBSSH2_ALLOC(session, channel_type_len);
+        if (!session->open_channel->channel_type) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Failed allocating memory for channel type name", 0);
+            LIBSSH2_FREE(session, session->open_channel);
+            session->open_channel = NULL;
+            return NULL;
+        }
+        memcpy(session->open_channel->channel_type, channel_type,
+               channel_type_len);
+
+        /* REMEMBER: local as in locally sourced */
+        session->open_channel->local.id = session->open_local_channel;
+        session->open_channel->remote.window_size = window_size;
+        session->open_channel->remote.window_size_initial = window_size;
+        session->open_channel->remote.packet_size = packet_size;
+
+        libssh2_channel_add(session, session->open_channel);
+
+        s = session->open_packet =
+            LIBSSH2_ALLOC(session, session->open_packet_len);
+        if (!session->open_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate temporary space for packet", 0);
+            goto channel_error;
+        }
+        *(s++) = SSH_MSG_CHANNEL_OPEN;
+        libssh2_htonu32(s, channel_type_len);
+        s += 4;
+
+        memcpy(s, channel_type, channel_type_len);
+        s += channel_type_len;
+
+        libssh2_htonu32(s, session->open_local_channel);
+        s += 4;
+
+        libssh2_htonu32(s, window_size);
+        s += 4;
+
+        libssh2_htonu32(s, packet_size);
+        s += 4;
+
+        if (message && message_len) {
+            memcpy(s, message, message_len);
+            s += message_len;
+        }
+
+        session->open_state = libssh2_NB_state_created;
+    }
+
+    if (session->open_state == libssh2_NB_state_created) {
+        rc = libssh2_packet_write(session, session->open_packet,
+                                  session->open_packet_len);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block sending channel-open request", 0);
+            return NULL;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send channel-open request", 0);
+            goto channel_error;
+        }
+
+        session->open_state = libssh2_NB_state_sent;
+    }
+
+    if (session->open_state == libssh2_NB_state_sent) {
+        rc = libssh2_packet_requirev_ex(session, reply_codes,
+                                        &session->open_data,
+                                        &session->open_data_len, 1,
+                                        session->open_packet + 5 +
+                                        channel_type_len, 4,
+                                        &session->open_packet_requirev_state);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block", 0);
+            return NULL;
+        } else if (rc) {
+            goto channel_error;
+        }
+
+        if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
+            session->open_channel->remote.id =
+                libssh2_ntohu32(session->open_data + 5);
+            session->open_channel->local.window_size =
+                libssh2_ntohu32(session->open_data + 9);
+            session->open_channel->local.window_size_initial =
+                libssh2_ntohu32(session->open_data + 9);
+            session->open_channel->local.packet_size =
+                libssh2_ntohu32(session->open_data + 13);
+            _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                           "Connection Established - ID: %lu/%lu win: %lu/%lu pack: %lu/%lu",
+                           session->open_channel->local.id,
+                           session->open_channel->remote.id,
+                           session->open_channel->local.window_size,
+                           session->open_channel->remote.window_size,
+                           session->open_channel->local.packet_size,
+                           session->open_channel->remote.packet_size);
+            LIBSSH2_FREE(session, session->open_packet);
+            session->open_packet = NULL;
+            LIBSSH2_FREE(session, session->open_data);
+            session->open_data = NULL;
+
+            session->open_state = libssh2_NB_state_idle;
+            return session->open_channel;
+        }
+
+        if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_FAILURE) {
+            libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
+                          "Channel open failure", 0);
+        }
+    }
+
+  channel_error:
+
+    if (session->open_data) {
+        LIBSSH2_FREE(session, session->open_data);
+        session->open_data = NULL;
+    }
+    if (session->open_packet) {
+        LIBSSH2_FREE(session, session->open_packet);
+        session->open_packet = NULL;
+    }
+    if (session->open_channel) {
+        unsigned char channel_id[4];
+        LIBSSH2_FREE(session, session->open_channel->channel_type);
+
+        if (session->open_channel->next) {
+            session->open_channel->next->prev = session->open_channel->prev;
+        }
+        if (session->open_channel->prev) {
+            session->open_channel->prev->next = session->open_channel->next;
+        }
+        if (session->channels.head == session->open_channel) {
+            session->channels.head = session->open_channel->next;
+        }
+        if (session->channels.tail == session->open_channel) {
+            session->channels.tail = session->open_channel->prev;
+        }
+
+        /* Clear out packets meant for this channel */
+        libssh2_htonu32(channel_id, session->open_channel->local.id);
+        while ((libssh2_packet_ask_ex
+                (session, SSH_MSG_CHANNEL_DATA, &session->open_data,
+                 &session->open_data_len, 1, channel_id, 4, 0) >= 0)
+               ||
+               (libssh2_packet_ask_ex
+                (session, SSH_MSG_CHANNEL_EXTENDED_DATA, &session->open_data,
+                 &session->open_data_len, 1, channel_id, 4, 0) >= 0)) {
+            LIBSSH2_FREE(session, session->open_data);
+            session->open_data = NULL;
+        }
+
+        /* Free any state variables still holding data */
+        if (session->open_channel->write_packet) {
+            LIBSSH2_FREE(session, session->open_channel->write_packet);
+            session->open_channel->write_packet = NULL;
+        }
+
+        LIBSSH2_FREE(session, session->open_channel);
+        session->open_channel = NULL;
+    }
+
+    session->open_state = libssh2_NB_state_idle;
+    return NULL;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_direct_tcpip_ex
+ * Tunnel TCP/IP connect through the SSH session to direct host/port
+ */
+LIBSSH2_API LIBSSH2_CHANNEL *
+libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION * session, const char *host,
+                                int port, const char *shost, int sport)
+{
+    LIBSSH2_CHANNEL *channel;
+    unsigned char *s;
+
+    if (session->direct_state == libssh2_NB_state_idle) {
+        session->direct_host_len = strlen(host);
+        session->direct_shost_len = strlen(shost);
+        /* host_len(4) + port(4) + shost_len(4) + sport(4) */
+        session->direct_message_len =
+            session->direct_host_len + session->direct_shost_len + 16;
+
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "Requesting direct-tcpip session to from %s:%d to %s:%d",
+                       shost, sport, host, port);
+
+        s = session->direct_message =
+            LIBSSH2_ALLOC(session, session->direct_message_len);
+        if (!session->direct_message) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for direct-tcpip connection",
+                          0);
+            return NULL;
+        }
+        libssh2_htonu32(s, session->direct_host_len);
+        s += 4;
+        memcpy(s, host, session->direct_host_len);
+        s += session->direct_host_len;
+        libssh2_htonu32(s, port);
+        s += 4;
+
+        libssh2_htonu32(s, session->direct_shost_len);
+        s += 4;
+        memcpy(s, shost, session->direct_shost_len);
+        s += session->direct_shost_len;
+        libssh2_htonu32(s, sport);
+        s += 4;
+
+        session->direct_state = libssh2_NB_state_created;
+    }
+
+    channel =
+        libssh2_channel_open_ex(session, "direct-tcpip",
+                                sizeof("direct-tcpip") - 1,
+                                LIBSSH2_CHANNEL_WINDOW_DEFAULT,
+                                LIBSSH2_CHANNEL_PACKET_DEFAULT,
+                                (char *) session->direct_message,
+                                session->direct_message_len);
+    if (!channel) {
+        if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
+            /* The error code is still set to LIBSSH2_ERROR_EAGAIN */
+            return NULL;
+        } else {
+            LIBSSH2_FREE(session, session->direct_message);
+            session->direct_message = NULL;
+            return NULL;
+        }
+    }
+
+    LIBSSH2_FREE(session, session->direct_message);
+    session->direct_message = NULL;
+
+    return channel;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_forward_listen_ex
+ * Bind a port on the remote host and listen for connections
+ */
+LIBSSH2_API LIBSSH2_LISTENER *
+libssh2_channel_forward_listen_ex(LIBSSH2_SESSION * session, const char *host,
+                                  int port, int *bound_port, int queue_maxsize)
+{
+    unsigned char *s, *data;
+    static const unsigned char reply_codes[3] =
+        { SSH_MSG_REQUEST_SUCCESS, SSH_MSG_REQUEST_FAILURE, 0 };
+    unsigned long data_len;
+    int rc;
+
+    if (session->fwdLstn_state == libssh2_NB_state_idle) {
+        session->fwdLstn_host_len =
+            (host ? strlen(host) : (sizeof("0.0.0.0") - 1));
+        /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + port(4) */
+        session->fwdLstn_packet_len =
+            session->fwdLstn_host_len + (sizeof("tcpip-forward") - 1) + 14;
+
+        /* Zero the whole thing out */
+        memset(&session->fwdLstn_packet_requirev_state, 0,
+               sizeof(session->fwdLstn_packet_requirev_state));
+
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "Requesting tcpip-forward session for %s:%d", host,
+                       port);
+
+        s = session->fwdLstn_packet =
+            LIBSSH2_ALLOC(session, session->fwdLstn_packet_len);
+        if (!session->fwdLstn_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memeory for setenv packet", 0);
+            return NULL;
+        }
+
+        *(s++) = SSH_MSG_GLOBAL_REQUEST;
+        libssh2_htonu32(s, sizeof("tcpip-forward") - 1);
+        s += 4;
+        memcpy(s, "tcpip-forward", sizeof("tcpip-forward") - 1);
+        s += sizeof("tcpip-forward") - 1;
+        *(s++) = 0x01;          /* want_reply */
+
+        libssh2_htonu32(s, session->fwdLstn_host_len);
+        s += 4;
+        memcpy(s, host ? host : "0.0.0.0", session->fwdLstn_host_len);
+        s += session->fwdLstn_host_len;
+        libssh2_htonu32(s, port);
+        s += 4;
+
+        session->fwdLstn_state = libssh2_NB_state_created;
+    }
+
+    if (session->fwdLstn_state == libssh2_NB_state_created) {
+        rc = libssh2_packet_write(session, session->fwdLstn_packet,
+                                  session->fwdLstn_packet_len);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block sending global-request packet for forward listen request",
+                          0);
+            return NULL;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send global-request packet for forward listen request",
+                          0);
+            LIBSSH2_FREE(session, session->fwdLstn_packet);
+            session->fwdLstn_packet = NULL;
+            session->fwdLstn_state = libssh2_NB_state_idle;
+            return NULL;
+        }
+        LIBSSH2_FREE(session, session->fwdLstn_packet);
+        session->fwdLstn_packet = NULL;
+
+        session->fwdLstn_state = libssh2_NB_state_sent;
+    }
+
+    if (session->fwdLstn_state == libssh2_NB_state_sent) {
+        rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
+                                        0, NULL, 0,
+                                        &session->
+                                        fwdLstn_packet_requirev_state);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block", 0);
+            return NULL;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_PROTO, "Unknown", 0);
+            session->fwdLstn_state = libssh2_NB_state_idle;
+            return NULL;
+        }
+
+        if (data[0] == SSH_MSG_REQUEST_SUCCESS) {
+            LIBSSH2_LISTENER *listener;
+
+            listener = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_LISTENER));
+            if (!listener) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                              "Unable to allocate memory for listener queue",
+                              0);
+                LIBSSH2_FREE(session, data);
+                session->fwdLstn_state = libssh2_NB_state_idle;
+                return NULL;
+            }
+            memset(listener, 0, sizeof(LIBSSH2_LISTENER));
+            listener->session = session;
+            listener->host =
+                LIBSSH2_ALLOC(session, session->fwdLstn_host_len + 1);
+            if (!listener->host) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                              "Unable to allocate memory for listener queue",
+                              0);
+                LIBSSH2_FREE(session, listener);
+                LIBSSH2_FREE(session, data);
+                session->fwdLstn_state = libssh2_NB_state_idle;
+                return NULL;
+            }
+            memcpy(listener->host, host ? host : "0.0.0.0",
+                   session->fwdLstn_host_len);
+            listener->host[session->fwdLstn_host_len] = 0;
+            if (data_len >= 5 && !port) {
+                listener->port = libssh2_ntohu32(data + 1);
+                _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                               "Dynamic tcpip-forward port allocated: %d",
+                               listener->port);
+            } else {
+                listener->port = port;
+            }
+
+            listener->queue_size = 0;
+            listener->queue_maxsize = queue_maxsize;
+
+            listener->next = session->listeners;
+            listener->prev = NULL;
+            if (session->listeners) {
+                session->listeners->prev = listener;
+            }
+            session->listeners = listener;
+
+            if (bound_port) {
+                *bound_port = listener->port;
+            }
+
+            LIBSSH2_FREE(session, data);
+            session->fwdLstn_state = libssh2_NB_state_idle;
+            return listener;
+        }
+
+        if (data[0] == SSH_MSG_REQUEST_FAILURE) {
+            LIBSSH2_FREE(session, data);
+            libssh2_error(session, LIBSSH2_ERROR_REQUEST_DENIED,
+                          "Unable to complete request for forward-listen", 0);
+            session->fwdLstn_state = libssh2_NB_state_idle;
+            return NULL;
+        }
+    }
+
+    session->fwdLstn_state = libssh2_NB_state_idle;
+
+    return NULL;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_forward_cancel
+ * Stop listening on a remote port and free the listener
+ * Toss out any pending (un-accept()ed) connections
+ *
+ * Return 0 on success, PACKET_EAGAIN if would block, -1 on error
+ */
+LIBSSH2_API int
+libssh2_channel_forward_cancel(LIBSSH2_LISTENER * listener)
+{
+    LIBSSH2_SESSION *session = listener->session;
+    LIBSSH2_CHANNEL *queued = listener->queue;
+    unsigned char *packet, *s;
+    unsigned long host_len = strlen(listener->host);
+    /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + port(4) */
+    unsigned long packet_len =
+        host_len + 14 + sizeof("cancel-tcpip-forward") - 1;
+    int rc;
+
+    if (listener->chanFwdCncl_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "Cancelling tcpip-forward session for %s:%d",
+                       listener->host, listener->port);
+
+        s = packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memeory for setenv packet", 0);
+            return -1;
+        }
+
+        *(s++) = SSH_MSG_GLOBAL_REQUEST;
+        libssh2_htonu32(s, sizeof("cancel-tcpip-forward") - 1);
+        s += 4;
+        memcpy(s, "cancel-tcpip-forward", sizeof("cancel-tcpip-forward") - 1);
+        s += sizeof("cancel-tcpip-forward") - 1;
+        *(s++) = 0x00;          /* want_reply */
+
+        libssh2_htonu32(s, host_len);
+        s += 4;
+        memcpy(s, listener->host, host_len);
+        s += host_len;
+        libssh2_htonu32(s, listener->port);
+        s += 4;
+
+        listener->chanFwdCncl_state = libssh2_NB_state_created;
+    } else {
+        packet = listener->chanFwdCncl_data;
+    }
+
+    if (listener->chanFwdCncl_state == libssh2_NB_state_created) {
+        rc = libssh2_packet_write(session, packet, packet_len);
+        if (rc == PACKET_EAGAIN) {
+            listener->chanFwdCncl_data = packet;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send global-request packet for forward listen request",
+                          0);
+            LIBSSH2_FREE(session, packet);
+            listener->chanFwdCncl_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, packet);
+
+        listener->chanFwdCncl_state = libssh2_NB_state_sent;
+    }
+
+    while (queued) {
+        LIBSSH2_CHANNEL *next = queued->next;
+
+        rc = libssh2_channel_free(queued);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        }
+        queued = next;
+    }
+    LIBSSH2_FREE(session, listener->host);
+
+    if (listener->next) {
+        listener->next->prev = listener->prev;
+    }
+    if (listener->prev) {
+        listener->prev->next = listener->next;
+    } else {
+        session->listeners = listener->next;
+    }
+
+    LIBSSH2_FREE(session, listener);
+
+    listener->chanFwdCncl_state = libssh2_NB_state_idle;
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_forward_accept
+ * Accept a connection
+ */
+LIBSSH2_API LIBSSH2_CHANNEL *
+libssh2_channel_forward_accept(LIBSSH2_LISTENER * listener)
+{
+    libssh2pack_t rc;
+
+    do {
+        rc = libssh2_packet_read(listener->session);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(listener->session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block waiting for packet", 0);
+            return NULL;
+        }
+    } while (rc > 0);
+
+    if (listener->queue) {
+        LIBSSH2_SESSION *session = listener->session;
+        LIBSSH2_CHANNEL *channel;
+
+        channel = listener->queue;
+
+        listener->queue = listener->queue->next;
+        if (listener->queue) {
+            listener->queue->prev = NULL;
+        }
+
+        channel->prev = NULL;
+        channel->next = session->channels.head;
+        session->channels.head = channel;
+
+        if (channel->next) {
+            channel->next->prev = channel;
+        } else {
+            session->channels.tail = channel;
+        }
+        listener->queue_size--;
+
+        return channel;
+    }
+
+    return NULL;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_setenv_ex
+ * Set an environment variable prior to requesting a shell/program/subsystem
+ */
+LIBSSH2_API int
+libssh2_channel_setenv_ex(LIBSSH2_CHANNEL * channel, const char *varname,
+                          unsigned int varname_len, const char *value,
+                          unsigned int value_len)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned char *s, *data;
+    static const unsigned char reply_codes[3] =
+        { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
+    unsigned long data_len;
+    int rc;
+
+    if (channel->setenv_state == libssh2_NB_state_idle) {
+        /* 21 = packet_type(1) + channel_id(4) + request_len(4) +
+         * request(3)"env" + want_reply(1) + varname_len(4) + value_len(4) */
+        channel->setenv_packet_len = varname_len + value_len + 21;
+
+        /* Zero the whole thing out */
+        memset(&channel->setenv_packet_requirev_state, 0,
+               sizeof(channel->setenv_packet_requirev_state));
+
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "Setting remote environment variable: %s=%s on channel %lu/%lu",
+                       varname, value, channel->local.id, channel->remote.id);
+
+        s = channel->setenv_packet =
+            LIBSSH2_ALLOC(session, channel->setenv_packet_len);
+        if (!channel->setenv_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memeory for setenv packet", 0);
+            return -1;
+        }
+
+        *(s++) = SSH_MSG_CHANNEL_REQUEST;
+        libssh2_htonu32(s, channel->remote.id);
+        s += 4;
+        libssh2_htonu32(s, sizeof("env") - 1);
+        s += 4;
+        memcpy(s, "env", sizeof("env") - 1);
+        s += sizeof("env") - 1;
+
+        *(s++) = 0x01;
+
+        libssh2_htonu32(s, varname_len);
+        s += 4;
+        memcpy(s, varname, varname_len);
+        s += varname_len;
+
+        libssh2_htonu32(s, value_len);
+        s += 4;
+        memcpy(s, value, value_len);
+        s += value_len;
+
+        channel->setenv_state = libssh2_NB_state_created;
+    }
+
+    if (channel->setenv_state == libssh2_NB_state_created) {
+        rc = libssh2_packet_write(session, channel->setenv_packet,
+                                  channel->setenv_packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send channel-request packet for setenv request",
+                          0);
+            LIBSSH2_FREE(session, channel->setenv_packet);
+            channel->setenv_packet = NULL;
+            channel->setenv_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, channel->setenv_packet);
+        channel->setenv_packet = NULL;
+
+        libssh2_htonu32(channel->setenv_local_channel, channel->local.id);
+
+        channel->setenv_state = libssh2_NB_state_sent;
+    }
+
+    if (channel->setenv_state == libssh2_NB_state_sent) {
+        rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
+                                        1, channel->setenv_local_channel, 4,
+                                        &channel->
+                                        setenv_packet_requirev_state);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        }
+        if (rc) {
+            channel->setenv_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
+            LIBSSH2_FREE(session, data);
+            channel->setenv_state = libssh2_NB_state_idle;
+            return 0;
+        }
+
+        LIBSSH2_FREE(session, data);
+    }
+
+    libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
+                  "Unable to complete request for channel-setenv", 0);
+    channel->setenv_state = libssh2_NB_state_idle;
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_request_pty_ex
+ * Duh... Request a PTY
+ */
+LIBSSH2_API int
+libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL * channel, const char *term,
+                               unsigned int term_len, const char *modes,
+                               unsigned int modes_len, int width, int height,
+                               int width_px, int height_px)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned char *s, *data;
+    static const unsigned char reply_codes[3] =
+        { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
+    unsigned long data_len;
+    int rc;
+
+    if (channel->reqPTY_state == libssh2_NB_state_idle) {
+        /* 41 = packet_type(1) + channel(4) + pty_req_len(4) + "pty_req"(7) +
+         * want_reply(1) + term_len(4) + width(4) + height(4) + width_px(4) +
+         * height_px(4) + modes_len(4) */
+        channel->reqPTY_packet_len = term_len + modes_len + 41;
+
+        /* Zero the whole thing out */
+        memset(&channel->reqPTY_packet_requirev_state, 0,
+               sizeof(channel->reqPTY_packet_requirev_state));
+
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "Allocating tty on channel %lu/%lu", channel->local.id,
+                       channel->remote.id);
+
+        s = channel->reqPTY_packet =
+            LIBSSH2_ALLOC(session, channel->reqPTY_packet_len);
+        if (!channel->reqPTY_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for pty-request", 0);
+            return -1;
+        }
+
+        *(s++) = SSH_MSG_CHANNEL_REQUEST;
+        libssh2_htonu32(s, channel->remote.id);
+        s += 4;
+        libssh2_htonu32(s, sizeof("pty-req") - 1);
+        s += 4;
+        memcpy(s, "pty-req", sizeof("pty-req") - 1);
+        s += sizeof("pty-req") - 1;
+
+        *(s++) = 0x01;
+
+        libssh2_htonu32(s, term_len);
+        s += 4;
+        if (term) {
+            memcpy(s, term, term_len);
+            s += term_len;
+        }
+
+        libssh2_htonu32(s, width);
+        s += 4;
+        libssh2_htonu32(s, height);
+        s += 4;
+        libssh2_htonu32(s, width_px);
+        s += 4;
+        libssh2_htonu32(s, height_px);
+        s += 4;
+
+        libssh2_htonu32(s, modes_len);
+        s += 4;
+        if (modes) {
+            memcpy(s, modes, modes_len);
+            s += modes_len;
+        }
+
+        channel->reqPTY_state = libssh2_NB_state_created;
+    }
+
+    if (channel->reqPTY_state == libssh2_NB_state_created) {
+        rc = libssh2_packet_write(session, channel->reqPTY_packet,
+                                  channel->reqPTY_packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send pty-request packet", 0);
+            LIBSSH2_FREE(session, channel->reqPTY_packet);
+            channel->reqPTY_packet = NULL;
+            channel->reqPTY_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, channel->reqPTY_packet);
+        channel->reqPTY_packet = NULL;
+
+        libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id);
+
+        channel->reqPTY_state = libssh2_NB_state_sent;
+    }
+
+    if (channel->reqPTY_state == libssh2_NB_state_sent) {
+        rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
+                                        1, channel->reqPTY_local_channel, 4,
+                                        &channel->
+                                        reqPTY_packet_requirev_state);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            channel->reqPTY_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
+            LIBSSH2_FREE(session, data);
+            channel->reqPTY_state = libssh2_NB_state_idle;
+            return 0;
+        }
+    }
+
+    LIBSSH2_FREE(session, data);
+    libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
+                  "Unable to complete request for channel request-pty", 0);
+    channel->reqPTY_state = libssh2_NB_state_idle;
+    return -1;
+}
+
+/* }}} */
+
+/* Keep this an even number */
+#define LIBSSH2_X11_RANDOM_COOKIE_LEN       32
+
+/* {{{ libssh2_channel_x11_req_ex
+ * Request X11 forwarding
+ */
+LIBSSH2_API int
+libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL * channel, int single_connection,
+                           const char *auth_proto, const char *auth_cookie,
+                           int screen_number)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned char *s, *data;
+    static const unsigned char reply_codes[3] =
+        { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
+    unsigned long data_len;
+    unsigned long proto_len =
+        auth_proto ? strlen(auth_proto) : (sizeof("MIT-MAGIC-COOKIE-1") - 1);
+    unsigned long cookie_len =
+        auth_cookie ? strlen(auth_cookie) : LIBSSH2_X11_RANDOM_COOKIE_LEN;
+    int rc;
+
+    if (channel->reqX11_state == libssh2_NB_state_idle) {
+        /* 30 = packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) +
+         * want_reply(1) + single_cnx(1) + proto_len(4) + cookie_len(4) +
+         * screen_num(4) */
+        channel->reqX11_packet_len = proto_len + cookie_len + 30;
+
+        /* Zero the whole thing out */
+        memset(&channel->reqX11_packet_requirev_state, 0,
+               sizeof(channel->reqX11_packet_requirev_state));
+
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "Requesting x11-req for channel %lu/%lu: single=%d proto=%s cookie=%s screen=%d",
+                       channel->local.id, channel->remote.id,
+                       single_connection,
+                       auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1",
+                       auth_cookie ? auth_cookie : "<random>", screen_number);
+
+        s = channel->reqX11_packet =
+            LIBSSH2_ALLOC(session, channel->reqX11_packet_len);
+        if (!channel->reqX11_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for pty-request", 0);
+            return -1;
+        }
+
+        *(s++) = SSH_MSG_CHANNEL_REQUEST;
+        libssh2_htonu32(s, channel->remote.id);
+        s += 4;
+        libssh2_htonu32(s, sizeof("x11-req") - 1);
+        s += 4;
+        memcpy(s, "x11-req", sizeof("x11-req") - 1);
+        s += sizeof("x11-req") - 1;
+
+        *(s++) = 0x01;          /* want_reply */
+        *(s++) = single_connection ? 0x01 : 0x00;
+
+        libssh2_htonu32(s, proto_len);
+        s += 4;
+        memcpy(s, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", proto_len);
+        s += proto_len;
+
+        libssh2_htonu32(s, cookie_len);
+        s += 4;
+        if (auth_cookie) {
+            memcpy(s, auth_cookie, cookie_len);
+        } else {
+            int i;
+            unsigned char buffer[LIBSSH2_X11_RANDOM_COOKIE_LEN / 2];
+
+            libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2);
+            for(i = 0; i < (LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); i++) {
+                snprintf((char *) s + (i * 2), 2, "%02X", buffer[i]);
+            }
+        }
+        s += cookie_len;
+
+        libssh2_htonu32(s, screen_number);
+        s += 4;
+
+        channel->reqX11_state = libssh2_NB_state_created;
+    }
+
+    if (channel->reqX11_state == libssh2_NB_state_created) {
+        rc = libssh2_packet_write(session, channel->reqX11_packet,
+                                  channel->reqX11_packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        }
+        if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send x11-req packet", 0);
+            LIBSSH2_FREE(session, channel->reqX11_packet);
+            channel->reqX11_packet = NULL;
+            channel->reqX11_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, channel->reqX11_packet);
+        channel->reqX11_packet = NULL;
+
+        libssh2_htonu32(channel->reqX11_local_channel, channel->local.id);
+
+        channel->reqX11_state = libssh2_NB_state_sent;
+    }
+
+    if (channel->reqX11_state == libssh2_NB_state_sent) {
+        rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
+                                        1, channel->reqX11_local_channel, 4,
+                                        &channel->
+                                        reqX11_packet_requirev_state);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            channel->reqX11_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
+            LIBSSH2_FREE(session, data);
+            channel->reqX11_state = libssh2_NB_state_idle;
+            return 0;
+        }
+    }
+
+    LIBSSH2_FREE(session, data);
+    libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
+                  "Unable to complete request for channel x11-req", 0);
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_process_startup
+ * Primitive for libssh2_channel_(shell|exec|subsystem)
+ */
+LIBSSH2_API int
+libssh2_channel_process_startup(LIBSSH2_CHANNEL * channel, const char *request,
+                                unsigned int request_len, const char *message,
+                                unsigned int message_len)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned char *s, *data;
+    static const unsigned char reply_codes[3] =
+        { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
+    unsigned long data_len;
+    libssh2pack_t rc;
+
+    if (channel->process_state == libssh2_NB_state_idle) {
+        /* 10 = packet_type(1) + channel(4) + request_len(4) + want_reply(1) */
+        channel->process_packet_len = request_len + 10;
+
+        /* Zero the whole thing out */
+        memset(&channel->process_packet_requirev_state, 0,
+               sizeof(channel->process_packet_requirev_state));
+
+        if (message) {
+            channel->process_packet_len += message_len + 4;
+        }
+
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "starting request(%s) on channel %lu/%lu, message=%s",
+                       request, channel->local.id, channel->remote.id,
+                       message);
+        s = channel->process_packet =
+            LIBSSH2_ALLOC(session, channel->process_packet_len);
+        if (!channel->process_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for channel-process request",
+                          0);
+            return -1;
+        }
+
+        *(s++) = SSH_MSG_CHANNEL_REQUEST;
+        libssh2_htonu32(s, channel->remote.id);
+        s += 4;
+        libssh2_htonu32(s, request_len);
+        s += 4;
+        memcpy(s, request, request_len);
+        s += request_len;
+
+        *(s++) = 0x01;
+
+        if (message) {
+            libssh2_htonu32(s, message_len);
+            s += 4;
+            memcpy(s, message, message_len);
+            s += message_len;
+        }
+
+        channel->process_state = libssh2_NB_state_created;
+    }
+
+    if (channel->process_state == libssh2_NB_state_created) {
+        rc = libssh2_packet_write(session, channel->process_packet,
+                                  channel->process_packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send channel request", 0);
+            LIBSSH2_FREE(session, channel->process_packet);
+            channel->process_packet = NULL;
+            channel->process_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, channel->process_packet);
+        channel->process_packet = NULL;
+
+        libssh2_htonu32(channel->process_local_channel, channel->local.id);
+
+        channel->process_state = libssh2_NB_state_sent;
+    }
+
+    if (channel->process_state == libssh2_NB_state_sent) {
+        rc = libssh2_packet_requirev_ex(session, reply_codes, &data, &data_len,
+                                        1, channel->process_local_channel, 4,
+                                        &channel->
+                                        process_packet_requirev_state);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            channel->process_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        if (data[0] == SSH_MSG_CHANNEL_SUCCESS) {
+            LIBSSH2_FREE(session, data);
+            channel->process_state = libssh2_NB_state_idle;
+            return 0;
+        }
+    }
+
+    LIBSSH2_FREE(session, data);
+    libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
+                  "Unable to complete request for channel-process-startup", 0);
+    channel->process_state = libssh2_NB_state_idle;
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_set_blocking
+ * Set a channel's blocking mode on or off, similar to a socket's
+ * fcntl(fd, F_SETFL, O_NONBLOCK); type command
+ */
+LIBSSH2_API void
+libssh2_channel_set_blocking(LIBSSH2_CHANNEL * channel, int blocking)
+{
+    (void) _libssh2_session_set_blocking(channel->session, blocking);
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_flush_ex
+ * Flush data from one (or all) stream
+ * Returns number of bytes flushed, or -1 on failure
+ */
+LIBSSH2_API int
+libssh2_channel_flush_ex(LIBSSH2_CHANNEL * channel, int streamid)
+{
+    LIBSSH2_PACKET *packet = channel->session->packets.head;
+
+    if (channel->flush_state == libssh2_NB_state_idle) {
+        channel->flush_refund_bytes = 0;
+        channel->flush_flush_bytes = 0;
+
+        while (packet) {
+            LIBSSH2_PACKET *next = packet->next;
+            unsigned char packet_type = packet->data[0];
+
+            if (((packet_type == SSH_MSG_CHANNEL_DATA)
+                 || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
+                && (libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
+                /* It's our channel at least */
+                long packet_stream_id =
+                    (packet_type ==
+                     SSH_MSG_CHANNEL_DATA) ? 0 : libssh2_ntohu32(packet->data +
+                                                                 5);
+                if ((streamid == LIBSSH2_CHANNEL_FLUSH_ALL)
+                    || ((packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)
+                        && ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA)
+                            || (streamid == packet_stream_id)))
+                    || ((packet_type == SSH_MSG_CHANNEL_DATA)
+                        && (streamid == 0))) {
+                    int bytes_to_flush = packet->data_len - packet->data_head;
+
+                    _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
+                                   "Flushing %d bytes of data from stream %lu on channel %lu/%lu",
+                                   bytes_to_flush, packet_stream_id,
+                                   channel->local.id, channel->remote.id);
+
+                    /* It's one of the streams we wanted to flush */
+                    channel->flush_refund_bytes += packet->data_len - 13;
+                    channel->flush_flush_bytes += bytes_to_flush;
+
+                    LIBSSH2_FREE(channel->session, packet->data);
+                    if (packet->prev) {
+                        packet->prev->next = packet->next;
+                    } else {
+                        channel->session->packets.head = packet->next;
+                    }
+                    if (packet->next) {
+                        packet->next->prev = packet->prev;
+                    } else {
+                        channel->session->packets.tail = packet->prev;
+                    }
+                    LIBSSH2_FREE(channel->session, packet);
+                }
+            }
+            packet = next;
+        }
+
+        channel->flush_state = libssh2_NB_state_created;
+    }
+
+    if (channel->flush_refund_bytes) {
+        int rc;
+
+        rc = libssh2_channel_receive_window_adjust(channel,
+                                                   channel->flush_refund_bytes,
+                                                   0);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        }
+    }
+
+    channel->flush_state = libssh2_NB_state_idle;
+
+    return channel->flush_flush_bytes;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_get_exit_status
+ * Return the channel's program exit status
+ */
+LIBSSH2_API int
+libssh2_channel_get_exit_status(LIBSSH2_CHANNEL * channel)
+{
+    return channel->exit_status;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_receive_window_adjust
+ * Adjust the receive window for a channel by adjustment bytes
+ * If the amount to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and
+ * force is 0 the adjustment amount will be queued for a later packet
+ *
+ * Returns the new size of the receive window (as understood by remote end)
+ */
+LIBSSH2_API unsigned long
+libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
+                                      unsigned long adjustment,
+                                      unsigned char force)
+{
+    int rc;
+
+    if (channel->adjust_state == libssh2_NB_state_idle) {
+        if (!force
+            && (adjustment + channel->adjust_queue <
+                LIBSSH2_CHANNEL_MINADJUST)) {
+            _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
+                           "Queueing %lu bytes for receive window adjustment for channel %lu/%lu",
+                           adjustment, channel->local.id, channel->remote.id);
+            channel->adjust_queue += adjustment;
+            return channel->remote.window_size;
+        }
+
+        if (!adjustment && !channel->adjust_queue) {
+            return channel->remote.window_size;
+        }
+
+        adjustment += channel->adjust_queue;
+        channel->adjust_queue = 0;
+
+
+        /* Adjust the window based on the block we just freed */
+        channel->adjust_adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST;
+        libssh2_htonu32(channel->adjust_adjust + 1, channel->remote.id);
+        libssh2_htonu32(channel->adjust_adjust + 5, adjustment);
+        _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
+                       "Adjusting window %lu bytes for data flushed from channel %lu/%lu",
+                       adjustment, channel->local.id, channel->remote.id);
+
+        channel->adjust_state = libssh2_NB_state_created;
+    }
+
+    rc = libssh2_packet_write(channel->session, channel->adjust_adjust, 9);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    } else if (rc) {
+        libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND,
+                      "Unable to send transfer-window adjustment packet, deferring",
+                      0);
+        channel->adjust_queue = adjustment;
+        channel->adjust_state = libssh2_NB_state_idle;
+    } else {
+        channel->adjust_state = libssh2_NB_state_idle;
+        channel->remote.window_size += adjustment;
+    }
+
+    return channel->remote.window_size;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_handle_extended_data
+ * How should extended data look to the calling app?
+ * Keep it in separate channels[_read() _read_stdder()]? (NORMAL)
+ * Merge the extended data to the standard data? [everything via _read()]? (MERGE)
+ * Ignore it entirely [toss out packets as they come in]? (IGNORE)
+ */
+LIBSSH2_API void
+libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL * channel,
+                                     int ignore_mode)
+{
+    while (libssh2_channel_handle_extended_data2(channel, ignore_mode) ==
+           PACKET_EAGAIN);
+}
+
+LIBSSH2_API int
+libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL * channel,
+                                      int ignore_mode)
+{
+    if (channel->extData2_state == libssh2_NB_state_idle) {
+        _libssh2_debug(channel->session, LIBSSH2_DBG_CONN,
+                       "Setting channel %lu/%lu handle_extended_data mode to %d",
+                       channel->local.id, channel->remote.id, ignore_mode);
+        channel->remote.extended_data_ignore_mode = ignore_mode;
+
+        channel->extData2_state = libssh2_NB_state_created;
+    }
+
+    if (channel->extData2_state == libssh2_NB_state_idle) {
+        if (ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) {
+            if (libssh2_channel_flush_ex
+                (channel,
+                 LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA) == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            }
+        }
+    }
+
+    channel->extData2_state = libssh2_NB_state_idle;
+    return 0;
+}
+
+/* }}} */
+
+/*
+ * {{{ libssh2_channel_read_ex
+ * Read data from a channel blocking or non-blocking depending on set state
+ *
+ * When this is done non-blocking, it is important to not return 0 until the
+ * currently read channel is complete. If we read stuff from the wire but it
+ * was no payload data to fill in the buffer with, we MUST make sure to return
+ * PACKET_EAGAIN.
+ */
+LIBSSH2_API ssize_t
+libssh2_channel_read_ex(LIBSSH2_CHANNEL * channel, int stream_id, char *buf,
+                        size_t buflen)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    libssh2pack_t rc = 0;
+
+    if (channel->read_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "Attempting to read %d bytes from channel %lu/%lu stream #%d",
+                       (int) buflen, channel->local.id, channel->remote.id,
+                       stream_id);
+
+        /* process all incoming packets */
+        do {
+            if (libssh2_waitsocket(session, 0) > 0) {
+                rc = libssh2_packet_read(session);
+            } else {
+                /* Set for PACKET_EAGAIN so we continue */
+                rc = PACKET_EAGAIN;
+            }
+        } while (rc > 0);
+
+        if ((rc < 0) && (rc != PACKET_EAGAIN)) {
+            fprintf(stderr, "return rc = %d\n", rc);
+            return rc;
+        }
+        channel->read_bytes_read = 0;
+        channel->read_block = 0;
+
+        channel->read_packet = session->packets.head;
+
+        channel->read_state = libssh2_NB_state_created;
+    }
+
+    /*
+     * =============================== NOTE ===============================
+     * I know this is very ugly and not a really good use of "goto", but
+     * this case statement would be even uglier to do it any other way
+     */
+    if (channel->read_state == libssh2_NB_state_jump1) {
+        goto channel_read_ex_point1;
+    }
+
+    rc = 0;
+
+    do {
+        if (channel->read_block) {
+            /* in the second lap and onwards, do this */
+            rc = libssh2_packet_read(session);
+            channel->read_packet = session->packets.head;
+        }
+
+        if (rc < 0) {
+            if (rc != PACKET_EAGAIN) {
+                channel->read_state = libssh2_NB_state_idle;
+            }
+            /* no packets available */
+            return rc;
+        }
+
+        while (channel->read_packet
+               && (channel->read_bytes_read < (int) buflen)) {
+            /* In case packet gets destroyed during this iteration */
+            channel->read_next = channel->read_packet->next;
+
+            channel->read_local_id =
+                libssh2_ntohu32(channel->read_packet->data + 1);
+
+            /*
+             * Either we asked for a specific extended data stream
+             * (and data was available),
+             * or the standard stream (and data was available),
+             * or the standard stream with extended_data_merge
+             * enabled and data was available
+             */
+            if ((stream_id
+                 && (channel->read_packet->data[0] ==
+                     SSH_MSG_CHANNEL_EXTENDED_DATA)
+                 && (channel->local.id == channel->read_local_id)
+                 && (stream_id ==
+                     (int) libssh2_ntohu32(channel->read_packet->data + 5)))
+                || (!stream_id
+                    && (channel->read_packet->data[0] == SSH_MSG_CHANNEL_DATA)
+                    && (channel->local.id == channel->read_local_id))
+                || (!stream_id
+                    && (channel->read_packet->data[0] ==
+                        SSH_MSG_CHANNEL_EXTENDED_DATA)
+                    && (channel->local.id == channel->read_local_id)
+                    && (channel->remote.extended_data_ignore_mode ==
+                        LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) {
+
+                channel->read_want = buflen - channel->read_bytes_read;
+                channel->read_unlink_packet = 0;
+
+                if (channel->read_want >=
+                    (int) (channel->read_packet->data_len -
+                           channel->read_packet->data_head)) {
+                    channel->read_want =
+                        channel->read_packet->data_len -
+                        channel->read_packet->data_head;
+                    channel->read_unlink_packet = 1;
+                }
+
+                _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                               "Reading %d of buffered data from %lu/%lu/%d",
+                               channel->read_want, channel->local.id,
+                               channel->remote.id, stream_id);
+                memcpy(buf + channel->read_bytes_read,
+                       channel->read_packet->data +
+                       channel->read_packet->data_head, channel->read_want);
+                channel->read_packet->data_head += channel->read_want;
+                channel->read_bytes_read += channel->read_want;
+
+                if (channel->read_unlink_packet) {
+                    if (channel->read_packet->prev) {
+                        channel->read_packet->prev->next =
+                            channel->read_packet->next;
+                    } else {
+                        session->packets.head = channel->read_packet->next;
+                    }
+                    if (channel->read_packet->next) {
+                        channel->read_packet->next->prev =
+                            channel->read_packet->prev;
+                    } else {
+                        session->packets.tail = channel->read_packet->prev;
+                    }
+                    LIBSSH2_FREE(session, channel->read_packet->data);
+
+
+                    _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                                   "Unlinking empty packet buffer from channel %lu/%lu",
+                                   channel->local.id, channel->remote.id);
+                  channel_read_ex_point1:
+                    channel->read_state = libssh2_NB_state_jump1;
+                    rc = libssh2_channel_receive_window_adjust(channel,
+                                                               channel->
+                                                               read_packet->
+                                                               data_len -
+                                                               (stream_id ? 13
+                                                                : 9), 0);
+                    if (rc == PACKET_EAGAIN) {
+                        return PACKET_EAGAIN;
+                    }
+                    channel->read_state = libssh2_NB_state_created;
+                    LIBSSH2_FREE(session, channel->read_packet);
+                    channel->read_packet = NULL;
+                }
+            }
+            channel->read_packet = channel->read_next;
+        }
+        channel->read_block = 1;
+    } while ((channel->read_bytes_read == 0) && !channel->remote.close);
+
+    channel->read_state = libssh2_NB_state_idle;
+    if (channel->read_bytes_read == 0) {
+        if (channel->session->socket_block) {
+            libssh2_error(session, LIBSSH2_ERROR_CHANNEL_CLOSED,
+                          "Remote end has closed this channel", 0);
+        } else {
+            /*
+             * when non-blocking, we must return PACKET_EAGAIN if we haven't
+             * completed reading the channel
+             */
+            if (!libssh2_channel_eof(channel)) {
+                return PACKET_EAGAIN;
+            }
+        }
+    }
+
+    channel->read_state = libssh2_NB_state_idle;
+    return channel->read_bytes_read;
+}
+
+/* }}} */
+
+/*
+ * {{{ libssh2_channel_packet_data_len
+ * Return the size of the data block of the current packet, or 0 if there
+ * isn't a packet.
+ */
+unsigned long
+libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    LIBSSH2_PACKET *read_packet;
+    uint32_t read_local_id;
+
+    if ((read_packet = session->packets.head) == NULL) {
+        return 0;
+    }
+
+    while (read_packet) {
+        read_local_id = libssh2_ntohu32(read_packet->data + 1);
+
+        /*
+         * Either we asked for a specific extended data stream
+         * (and data was available),
+         * or the standard stream (and data was available),
+         * or the standard stream with extended_data_merge
+         * enabled and data was available
+         */
+        if ((stream_id
+             && (read_packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)
+             && (channel->local.id == read_local_id)
+             && (stream_id == (int) libssh2_ntohu32(read_packet->data + 5)))
+            || (!stream_id && (read_packet->data[0] == SSH_MSG_CHANNEL_DATA)
+                && (channel->local.id == read_local_id)) || (!stream_id
+                                                             && (read_packet->
+                                                                 data[0] ==
+                                                                 SSH_MSG_CHANNEL_EXTENDED_DATA)
+                                                             && (channel->
+                                                                 local.id ==
+                                                                 read_local_id)
+                                                             && (channel->
+                                                                 remote.
+                                                                 extended_data_ignore_mode
+                                                                 ==
+                                                                 LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE)))
+        {
+
+            return (read_packet->data_len - read_packet->data_head);
+        }
+        read_packet = read_packet->next;
+    }
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_write_ex
+ * Send data to a channel
+ */
+LIBSSH2_API ssize_t
+libssh2_channel_write_ex(LIBSSH2_CHANNEL * channel, int stream_id,
+                         const char *buf, size_t buflen)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    libssh2pack_t rc;
+
+    if (channel->write_state == libssh2_NB_state_idle) {
+        channel->write_bufwrote = 0;
+
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "Writing %d bytes on channel %lu/%lu, stream #%d",
+                       (int) buflen, channel->local.id, channel->remote.id,
+                       stream_id);
+
+        if (channel->local.close) {
+            libssh2_error(session, LIBSSH2_ERROR_CHANNEL_CLOSED,
+                          "We've already closed this channel", 0);
+            return -1;
+        }
+
+        if (channel->local.eof) {
+            libssh2_error(session, LIBSSH2_ERROR_CHANNEL_EOF_SENT,
+                          "EOF has already been sight, data might be ignored",
+                          0);
+        }
+
+#if 0
+        /*
+          The following chunk of code is #ifdef'ed out, since I wanted it to
+          remain here with the given explanation why having the code in here
+          is not a good idea. The text is taken from the email Gavrie
+          Philipson wrote to libssh2-devel on Nov 8 2007.
+
+          The logic behind this is that in nonblocking mode, if the local
+          window size has shrunk to zero, there's no point in trying to send
+          anything more. However, exiting the function at that point does not
+          allow any adjusts from the remote side to be received, since
+          libssh2_packet_read (that is called further on in this function) is
+          never called in this case.
+
+          Removing this bit of code fixes the problem. This should not cause
+          busy waiting, since after the libssh2_packet_read, the function
+          correctly returns PACKET_EAGAIN if the window size was not adjusted.
+         */
+        if (!channel->session->socket_block &&
+            (channel->local.window_size <= 0)) {
+            /* Can't write anything */
+            return 0;
+        }
+#endif
+
+        /* [13] 9 = packet_type(1) + channelno(4) [ + streamid(4) ] + buflen(4) */
+        channel->write_packet_len = buflen + (stream_id ? 13 : 9);
+        channel->write_packet =
+            LIBSSH2_ALLOC(session, channel->write_packet_len);
+        if (!channel->write_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocte space for data transmission packet",
+                          0);
+            return -1;
+        }
+
+        channel->write_state = libssh2_NB_state_allocated;
+    }
+
+    while (buflen > 0) {
+        if (channel->write_state == libssh2_NB_state_allocated) {
+            channel->write_bufwrite = buflen;
+            channel->write_s = channel->write_packet;
+
+            *(channel->write_s++) =
+                stream_id ? SSH_MSG_CHANNEL_EXTENDED_DATA :
+                SSH_MSG_CHANNEL_DATA;
+            libssh2_htonu32(channel->write_s, channel->remote.id);
+            channel->write_s += 4;
+            if (stream_id) {
+                libssh2_htonu32(channel->write_s, stream_id);
+                channel->write_s += 4;
+            }
+
+            /* twiddle our thumbs until there's window space available */
+            while (channel->local.window_size <= 0) {
+                /* Don't worry -- This is never hit unless it's a
+                   blocking channel anyway */
+                rc = libssh2_packet_read(session);
+
+                if (rc < 0) {
+                    /* Error or EAGAIN occurred, disconnect? */
+                    if (rc != PACKET_EAGAIN) {
+                        channel->write_state = libssh2_NB_state_idle;
+                    }
+                    return rc;
+                }
+
+                if ((rc == 0) && (session->socket_block == 0)) {
+                    /*
+                     * if rc == 0 and in non-blocking, then fake EAGAIN
+                     * to prevent busyloops until data arriaves on the network
+                     * which seemed like a very bad idea
+                     */
+                    return PACKET_EAGAIN;
+                }
+            }
+
+            /* Don't exceed the remote end's limits */
+            /* REMEMBER local means local as the SOURCE of the data */
+            if (channel->write_bufwrite > channel->local.window_size) {
+                _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                               "Splitting write block due to %lu byte window_size on %lu/%lu/%d",
+                               channel->local.window_size, channel->local.id,
+                               channel->remote.id, stream_id);
+                channel->write_bufwrite = channel->local.window_size;
+            }
+            if (channel->write_bufwrite > channel->local.packet_size) {
+                _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                               "Splitting write block due to %lu byte packet_size on %lu/%lu/%d",
+                               channel->local.packet_size, channel->local.id,
+                               channel->remote.id, stream_id);
+                channel->write_bufwrite = channel->local.packet_size;
+            }
+            libssh2_htonu32(channel->write_s, channel->write_bufwrite);
+            channel->write_s += 4;
+            memcpy(channel->write_s, buf, channel->write_bufwrite);
+            channel->write_s += channel->write_bufwrite;
+
+            _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                           "Sending %d bytes on channel %lu/%lu, stream_id=%d",
+                           (int) channel->write_bufwrite, channel->local.id,
+                           channel->remote.id, stream_id);
+
+            channel->write_state = libssh2_NB_state_created;
+        }
+
+        if (channel->write_state == libssh2_NB_state_created) {
+            rc = libssh2_packet_write(session, channel->write_packet,
+                                      channel->write_s -
+                                      channel->write_packet);
+            if (rc == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            } else if (rc) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                              "Unable to send channel data", 0);
+                LIBSSH2_FREE(session, channel->write_packet);
+                channel->write_packet = NULL;
+                channel->write_state = libssh2_NB_state_idle;
+                return -1;
+            }
+            /* Shrink local window size */
+            channel->local.window_size -= channel->write_bufwrite;
+
+            /* Adjust buf for next iteration */
+            buflen -= channel->write_bufwrite;
+            buf += channel->write_bufwrite;
+            channel->write_bufwrote += channel->write_bufwrite;
+
+            channel->write_state = libssh2_NB_state_allocated;
+
+            /*
+             * Not sure this is still wanted
+             if (!channel->session->socket_block) {
+             break;
+             }
+             */
+        }
+    }
+
+    LIBSSH2_FREE(session, channel->write_packet);
+    channel->write_packet = NULL;
+
+    channel->write_state = libssh2_NB_state_idle;
+
+    return channel->write_bufwrote;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_send_eof
+ * Send EOF on channel
+ */
+LIBSSH2_API int
+libssh2_channel_send_eof(LIBSSH2_CHANNEL * channel)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned char packet[5];    /* packet_type(1) + channelno(4) */
+    int rc;
+
+    _libssh2_debug(session, LIBSSH2_DBG_CONN, "Sending EOF on channel %lu/%lu",
+                   channel->local.id, channel->remote.id);
+    packet[0] = SSH_MSG_CHANNEL_EOF;
+    libssh2_htonu32(packet + 1, channel->remote.id);
+    rc = libssh2_packet_write(session, packet, 5);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    } else if (rc) {
+        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                      "Unable to send EOF on channel", 0);
+        return -1;
+    }
+    channel->local.eof = 1;
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_eof
+ * Read channel's eof status
+ */
+LIBSSH2_API int
+libssh2_channel_eof(LIBSSH2_CHANNEL * channel)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    LIBSSH2_PACKET *packet = session->packets.head;
+
+    while (packet) {
+        if (((packet->data[0] == SSH_MSG_CHANNEL_DATA)
+             || (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA))
+            && (channel->local.id == libssh2_ntohu32(packet->data + 1))) {
+            /* There's data waiting to be read yet, mask the EOF status */
+            return 0;
+        }
+        packet = packet->next;
+    }
+
+    return channel->remote.eof;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_wait_closed
+* Awaiting channel EOF
+*/
+LIBSSH2_API int
+libssh2_channel_wait_eof(LIBSSH2_CHANNEL * channel)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    int rc;
+
+    if (channel->wait_eof_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "Awaiting close of channel %lu/%lu", channel->local.id,
+                       channel->remote.id);
+
+        channel->wait_eof_state = libssh2_NB_state_created;
+    }
+
+    /*
+     * While channel is not eof, read more packets from the network.
+     * Either the EOF will be set or network timeout will occur.
+     */
+    do {
+        if (channel->remote.eof) {
+            break;
+        }
+        rc = libssh2_packet_read(session);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc < 0) {
+            channel->wait_eof_state = libssh2_NB_state_idle;
+            return -1;
+        }
+    } while (1);
+
+    channel->wait_eof_state = libssh2_NB_state_idle;
+
+    return 0;
+}
+
+/* }}} */
+
+
+/* {{{ libssh2_channel_close
+ * Close a channel
+ */
+LIBSSH2_API int
+libssh2_channel_close(LIBSSH2_CHANNEL * channel)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    int rc = 0;
+    int retcode;
+
+    if (channel->local.close) {
+        /* Already closed, act like we sent another close,
+         * even though we didn't... shhhhhh */
+        channel->close_state = libssh2_NB_state_idle;
+        return 0;
+    }
+
+    if (channel->close_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_CONN, "Closing channel %lu/%lu",
+                       channel->local.id, channel->remote.id);
+
+        if (channel->close_cb) {
+            LIBSSH2_CHANNEL_CLOSE(session, channel);
+        }
+        channel->local.close = 1;
+
+        channel->close_packet[0] = SSH_MSG_CHANNEL_CLOSE;
+        libssh2_htonu32(channel->close_packet + 1, channel->remote.id);
+
+        channel->close_state = libssh2_NB_state_created;
+    }
+
+    if (channel->close_state == libssh2_NB_state_created) {
+        retcode = libssh2_packet_write(session, channel->close_packet, 5);
+        if (retcode == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (retcode) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send close-channel request", 0);
+            channel->close_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        channel->close_state = libssh2_NB_state_sent;
+    }
+
+    if (channel->close_state == libssh2_NB_state_sent) {
+        /* We must wait for the remote SSH_MSG_CHANNEL_CLOSE message */
+        if (!channel->remote.close) {
+            libssh2pack_t ret;
+
+            do {
+                ret = libssh2_packet_read(session);
+                if (ret == PACKET_EAGAIN) {
+                    return PACKET_EAGAIN;
+                } else if (ret < 0) {
+                    rc = -1;
+                }
+            } while ((ret != SSH_MSG_CHANNEL_CLOSE) && (rc == 0));
+        }
+    }
+
+    channel->close_state = libssh2_NB_state_idle;
+
+    return rc;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_wait_closed
+ * Awaiting channel close after EOF
+ */
+LIBSSH2_API int
+libssh2_channel_wait_closed(LIBSSH2_CHANNEL * channel)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    int rc;
+
+    if (!libssh2_channel_eof(channel)) {
+        libssh2_error(session, LIBSSH2_ERROR_INVAL,
+                      "libssh2_channel_wait_closed() invoked when channel is not in EOF state",
+                      0);
+        return -1;
+    }
+
+    if (channel->wait_closed_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "Awaiting close of channel %lu/%lu", channel->local.id,
+                       channel->remote.id);
+
+        channel->wait_closed_state = libssh2_NB_state_created;
+    }
+
+    /*
+     * While channel is not closed, read more packets from the network.
+     * Either the channel will be closed or network timeout will occur.
+     */
+    do {
+        if (!channel->remote.close) {
+            break;
+        }
+        rc = libssh2_packet_read(session);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc <= 0) {
+            break;
+        }
+    } while (1);
+
+    channel->wait_closed_state = libssh2_NB_state_idle;
+
+    return 1;
+}
+
+/* }}} */
+
+
+/* {{{ libssh2_channel_free
+ * Make sure a channel is closed, then remove the channel from the session
+ * and free its resource(s)
+ *
+ * Returns 0 on success, -1 on failure
+ */
+LIBSSH2_API int
+libssh2_channel_free(LIBSSH2_CHANNEL * channel)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned char channel_id[4];
+    unsigned char *data;
+    unsigned long data_len;
+    int rc;
+
+    if (channel->free_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "Freeing channel %lu/%lu resources", channel->local.id,
+                       channel->remote.id);
+
+        channel->free_state = libssh2_NB_state_created;
+    }
+
+    /* Allow channel freeing even when the socket has lost its connection */
+    if (!channel->local.close
+        && (session->socket_state == LIBSSH2_SOCKET_CONNECTED)) {
+        while ((rc = libssh2_channel_close(channel)) == PACKET_EAGAIN);
+        if (rc) {
+            channel->free_state = libssh2_NB_state_idle;
+            return -1;
+        }
+    }
+
+    channel->free_state = libssh2_NB_state_idle;
+
+    /*
+     * channel->remote.close *might* not be set yet, Well...
+     * We've sent the close packet, what more do you want?
+     * Just let packet_add ignore it when it finally arrives
+     */
+
+    /* Clear out packets meant for this channel */
+    libssh2_htonu32(channel_id, channel->local.id);
+    while ((libssh2_packet_ask_ex
+            (session, SSH_MSG_CHANNEL_DATA, &data, &data_len, 1, channel_id, 4,
+             0) >= 0)
+           ||
+           (libssh2_packet_ask_ex
+            (session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, &data_len, 1,
+             channel_id, 4, 0) >= 0)) {
+        LIBSSH2_FREE(session, data);
+    }
+
+    /* free "channel_type" */
+    if (channel->channel_type) {
+        LIBSSH2_FREE(session, channel->channel_type);
+    }
+
+    /* Unlink from channel brigade */
+    if (channel->prev) {
+        channel->prev->next = channel->next;
+    } else {
+        session->channels.head = channel->next;
+    }
+    if (channel->next) {
+        channel->next->prev = channel->prev;
+    } else {
+        session->channels.tail = channel->prev;
+    }
+
+    /*
+     * Make sure all memory used in the state variables are free
+     */
+    if (channel->setenv_packet) {
+        LIBSSH2_FREE(session, channel->setenv_packet);
+    }
+    if (channel->reqPTY_packet) {
+        LIBSSH2_FREE(session, channel->reqPTY_packet);
+    }
+    if (channel->reqX11_packet) {
+        LIBSSH2_FREE(session, channel->reqX11_packet);
+    }
+    if (channel->process_packet) {
+        LIBSSH2_FREE(session, channel->process_packet);
+    }
+    if (channel->write_packet) {
+        LIBSSH2_FREE(session, channel->write_packet);
+    }
+
+    LIBSSH2_FREE(session, channel);
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_window_read_ex
+ * Check the status of the read window
+ * Returns the number of bytes which the remote end may send without overflowing the window limit
+ * read_avail (if passed) will be populated with the number of bytes actually available to be read
+ * window_size_initial (if passed) will be populated with the window_size_initial as defined by the channel_open request
+ */
+LIBSSH2_API unsigned long
+libssh2_channel_window_read_ex(LIBSSH2_CHANNEL * channel,
+                               unsigned long *read_avail,
+                               unsigned long *window_size_initial)
+{
+    if (window_size_initial) {
+        *window_size_initial = channel->remote.window_size_initial;
+    }
+
+    if (read_avail) {
+        unsigned long bytes_queued = 0;
+        LIBSSH2_PACKET *packet = channel->session->packets.head;
+
+        while (packet) {
+            unsigned char packet_type = packet->data[0];
+
+            if (((packet_type == SSH_MSG_CHANNEL_DATA)
+                 || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA))
+                && (libssh2_ntohu32(packet->data + 1) == channel->local.id)) {
+                bytes_queued += packet->data_len - packet->data_head;
+            }
+
+            packet = packet->next;
+        }
+
+        *read_avail = bytes_queued;
+    }
+
+    return channel->remote.window_size;
+}
+
+/* }}} */
+
+/* {{{ libssh2_channel_window_write_ex
+ * Check the status of the write window
+ * Returns the number of bytes which may be safely writen on the channel without blocking
+ * window_size_initial (if passed) will be populated with the size of the initial window as defined by the channel_open request
+ */
+LIBSSH2_API unsigned long
+libssh2_channel_window_write_ex(LIBSSH2_CHANNEL * channel,
+                                unsigned long *window_size_initial)
+{
+    if (window_size_initial) {
+        /* For locally initiated channels this is very often 0, so it's not *that* useful as information goes */
+        *window_size_initial = channel->local.window_size_initial;
+    }
+
+    return channel->local.window_size;
+}
+
+/* }}} */
diff --git a/Vendor/libssh2/Source/comp.c b/Vendor/libssh2/Source/comp.c
new file mode 100644 (file)
index 0000000..e8c83c8
--- /dev/null
@@ -0,0 +1,340 @@
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+#ifdef LIBSSH2_HAVE_ZLIB
+# include <zlib.h>
+#endif
+
+/* ********
+   * none *
+   ******** */
+
+/* {{{ libssh2_comp_method_none_comp
+ * Minimalist compression: Absolutely none
+ */
+static int
+libssh2_comp_method_none_comp(LIBSSH2_SESSION * session,
+                              int compress,
+                              unsigned char **dest,
+                              unsigned long *dest_len,
+                              unsigned long payload_limit,
+                              int *free_dest,
+                              const unsigned char *src,
+                              unsigned long src_len, void **abstract)
+{
+    (void) session;
+    (void) compress;
+    (void) payload_limit;
+    (void) abstract;
+    *dest = (unsigned char *) src;
+    *dest_len = src_len;
+
+    *free_dest = 0;
+
+    return 0;
+}
+
+/* }}} */
+
+static const LIBSSH2_COMP_METHOD libssh2_comp_method_none = {
+    "none",
+    NULL,
+    libssh2_comp_method_none_comp,
+    NULL
+};
+
+#ifdef LIBSSH2_HAVE_ZLIB
+/* ********
+   * zlib *
+   ******** */
+
+/* {{{ Memory management wrappers
+ * Yes, I realize we're doing a callback to a callback,
+ * Deal...
+ */
+
+static voidpf
+libssh2_comp_method_zlib_alloc(voidpf opaque, uInt items, uInt size)
+{
+    LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;
+
+    return (voidpf) LIBSSH2_ALLOC(session, items * size);
+}
+
+static void
+libssh2_comp_method_zlib_free(voidpf opaque, voidpf address)
+{
+    LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;
+
+    LIBSSH2_FREE(session, address);
+}
+
+/* }}} */
+
+/* {{{ libssh2_comp_method_zlib_init
+ * All your bandwidth are belong to us (so save some)
+ */
+static int
+libssh2_comp_method_zlib_init(LIBSSH2_SESSION * session, int compress,
+                              void **abstract)
+{
+    z_stream *strm;
+    int status;
+
+    strm = LIBSSH2_ALLOC(session, sizeof(z_stream));
+    if (!strm) {
+        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                      "Unable to allocate memory for zlib compression/decompression",
+                      0);
+        return -1;
+    }
+    memset(strm, 0, sizeof(z_stream));
+
+    strm->opaque = (voidpf) session;
+    strm->zalloc = (alloc_func) libssh2_comp_method_zlib_alloc;
+    strm->zfree = (free_func) libssh2_comp_method_zlib_free;
+    if (compress) {
+        /* deflate */
+        status = deflateInit(strm, Z_DEFAULT_COMPRESSION);
+    } else {
+        /* inflate */
+        status = inflateInit(strm);
+    }
+
+    if (status != Z_OK) {
+        LIBSSH2_FREE(session, strm);
+        return -1;
+    }
+    *abstract = strm;
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_comp_method_zlib_comp
+ * zlib, a compression standard for all occasions
+ */
+static int
+libssh2_comp_method_zlib_comp(LIBSSH2_SESSION * session,
+                              int compress,
+                              unsigned char **dest,
+                              unsigned long *dest_len,
+                              unsigned long payload_limit,
+                              int *free_dest,
+                              const unsigned char *src,
+                              unsigned long src_len, void **abstract)
+{
+    z_stream *strm = *abstract;
+    /* A short-term alloc of a full data chunk is better than a series of
+       reallocs */
+    char *out;
+    int out_maxlen = compress ? (src_len + 4) : (2 * src_len);
+    int limiter = 0;
+
+    /* In practice they never come smaller than this */
+    if (out_maxlen < 25) {
+        out_maxlen = 25;
+    }
+
+    if (out_maxlen > (int) payload_limit) {
+        out_maxlen = payload_limit;
+    }
+
+    strm->next_in = (unsigned char *) src;
+    strm->avail_in = src_len;
+    strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen);
+    out = (char *) strm->next_out;
+    strm->avail_out = out_maxlen;
+    if (!strm->next_out) {
+        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                      "Unable to allocate compression/decompression buffer",
+                      0);
+        return -1;
+    }
+    while (strm->avail_in) {
+        int status;
+
+        if (compress) {
+            status = deflate(strm, Z_PARTIAL_FLUSH);
+        } else {
+            status = inflate(strm, Z_PARTIAL_FLUSH);
+        }
+        if (status != Z_OK) {
+            libssh2_error(session, LIBSSH2_ERROR_ZLIB,
+                          "compress/decompression failure", 0);
+            LIBSSH2_FREE(session, out);
+            return -1;
+        }
+        if (strm->avail_in) {
+            unsigned long out_ofs = out_maxlen - strm->avail_out;
+            char *newout;
+
+            out_maxlen +=
+                compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
+
+            if ((out_maxlen > (int) payload_limit) && !compress && limiter++) {
+                libssh2_error(session, LIBSSH2_ERROR_ZLIB,
+                              "Excessive growth in decompression phase", 0);
+                LIBSSH2_FREE(session, out);
+                return -1;
+            }
+
+            newout = LIBSSH2_REALLOC(session, out, out_maxlen);
+            if (!newout) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                              "Unable to expand compress/decompression buffer",
+                              0);
+                LIBSSH2_FREE(session, out);
+                return -1;
+            }
+            out = newout;
+            strm->next_out = (unsigned char *) out + out_ofs;
+            strm->avail_out +=
+                compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
+        } else
+            while (!strm->avail_out) {
+                /* Done with input, might be a byte or two in internal buffer during compress
+                 * Or potentially many bytes if it's a decompress
+                 */
+                int grow_size = compress ? 8 : 1024;
+                char *newout;
+
+                if (out_maxlen >= (int) payload_limit) {
+                    libssh2_error(session, LIBSSH2_ERROR_ZLIB,
+                                  "Excessive growth in decompression phase",
+                                  0);
+                    LIBSSH2_FREE(session, out);
+                    return -1;
+                }
+
+                if (grow_size > (int) (payload_limit - out_maxlen)) {
+                    grow_size = payload_limit - out_maxlen;
+                }
+
+                out_maxlen += grow_size;
+                strm->avail_out = grow_size;
+
+                newout = LIBSSH2_REALLOC(session, out, out_maxlen);
+                if (!newout) {
+                    libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                                  "Unable to expand final compress/decompress buffer",
+                                  0);
+                    LIBSSH2_FREE(session, out);
+                    return -1;
+                }
+                out = newout;
+                strm->next_out = (unsigned char *) out + out_maxlen -
+                    grow_size;
+
+                if (compress) {
+                    status = deflate(strm, Z_PARTIAL_FLUSH);
+                } else {
+                    status = inflate(strm, Z_PARTIAL_FLUSH);
+                }
+                if (status != Z_OK) {
+                    libssh2_error(session, LIBSSH2_ERROR_ZLIB,
+                                  "compress/decompression failure", 0);
+                    LIBSSH2_FREE(session, out);
+                    return -1;
+                }
+            }
+    }
+
+    *dest = (unsigned char *) out;
+    *dest_len = out_maxlen - strm->avail_out;
+    *free_dest = 1;
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_comp_method_zlib_dtor
+ * All done, no more compression for you
+ */
+static int
+libssh2_comp_method_zlib_dtor(LIBSSH2_SESSION * session, int compress,
+                              void **abstract)
+{
+    z_stream *strm = *abstract;
+
+    if (strm) {
+        if (compress) {
+            /* deflate */
+            deflateEnd(strm);
+        } else {
+            /* inflate */
+            inflateEnd(strm);
+        }
+
+        LIBSSH2_FREE(session, strm);
+    }
+
+    *abstract = NULL;
+
+    return 0;
+}
+
+/* }}} */
+
+static const LIBSSH2_COMP_METHOD libssh2_comp_method_zlib = {
+    "zlib",
+    libssh2_comp_method_zlib_init,
+    libssh2_comp_method_zlib_comp,
+    libssh2_comp_method_zlib_dtor,
+};
+#endif /* LIBSSH2_HAVE_ZLIB */
+
+/* ***********************
+   * Compression Methods *
+   *********************** */
+
+static const LIBSSH2_COMP_METHOD *_libssh2_comp_methods[] = {
+    &libssh2_comp_method_none,
+#ifdef LIBSSH2_HAVE_ZLIB
+    &libssh2_comp_method_zlib,
+#endif /* LIBSSH2_HAVE_ZLIB */
+    NULL
+};
+
+const LIBSSH2_COMP_METHOD **
+libssh2_comp_methods(void)
+{
+    return _libssh2_comp_methods;
+}
diff --git a/Vendor/libssh2/Source/crypt.c b/Vendor/libssh2/Source/crypt.c
new file mode 100644 (file)
index 0000000..2f32877
--- /dev/null
@@ -0,0 +1,256 @@
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+
+#ifdef LIBSSH2_CRYPT_NONE
+/* {{{ libssh2_crypt_none_crypt
+ * Minimalist cipher: VERY secure *wink*
+ */
+static int
+libssh2_crypt_none_crypt(LIBSSH2_SESSION * session, unsigned char *buf,
+                         void **abstract)
+{
+    /* Do nothing to the data! */
+    return 0;
+}
+
+/* }}} */
+
+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = {
+    "none",
+    8,                          /* blocksize (SSH2 defines minimum blocksize as 8) */
+    0,                          /* iv_len */
+    0,                          /* secret_len */
+    0,                          /* flags */
+    NULL,
+    libssh2_crypt_none_crypt,
+    NULL
+};
+#endif /* LIBSSH2_CRYPT_NONE */
+
+struct crypt_ctx
+{
+    int encrypt;
+      _libssh2_cipher_type(algo);
+    _libssh2_cipher_ctx h;
+};
+
+static int
+_libssh2_init(LIBSSH2_SESSION * session,
+              const LIBSSH2_CRYPT_METHOD * method,
+              unsigned char *iv, int *free_iv,
+              unsigned char *secret, int *free_secret,
+              int encrypt, void **abstract)
+{
+    struct crypt_ctx *ctx = LIBSSH2_ALLOC(session,
+                                          sizeof(struct crypt_ctx));
+    if (!ctx) {
+        return -1;
+    }
+    ctx->encrypt = encrypt;
+    ctx->algo = method->algo;
+    if (_libssh2_cipher_init(&ctx->h, ctx->algo, iv, secret, encrypt)) {
+        LIBSSH2_FREE(session, ctx);
+        return -1;
+    }
+    *abstract = ctx;
+    *free_iv = 1;
+    *free_secret = 1;
+    return 0;
+}
+
+static int
+_libssh2_encrypt(LIBSSH2_SESSION * session, unsigned char *block,
+                 void **abstract)
+{
+    struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract;
+    (void) session;
+    return _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block);
+}
+
+static int
+_libssh2_dtor(LIBSSH2_SESSION * session, void **abstract)
+{
+    struct crypt_ctx **cctx = (struct crypt_ctx **) abstract;
+    if (cctx && *cctx) {
+        _libssh2_cipher_dtor(&(*cctx)->h);
+        LIBSSH2_FREE(session, *cctx);
+        *abstract = NULL;
+    }
+    return 0;
+}
+
+#if LIBSSH2_AES
+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = {
+    "aes128-cbc",
+    16,                         /* blocksize */
+    16,                         /* initial value length */
+    16,                         /* secret length -- 16*8 == 128bit */
+    0,                          /* flags */
+    &_libssh2_init,
+    &_libssh2_encrypt,
+    &_libssh2_dtor,
+    _libssh2_cipher_aes128
+};
+
+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = {
+    "aes192-cbc",
+    16,                         /* blocksize */
+    16,                         /* initial value length */
+    24,                         /* secret length -- 24*8 == 192bit */
+    0,                          /* flags */
+    &_libssh2_init,
+    &_libssh2_encrypt,
+    &_libssh2_dtor,
+    _libssh2_cipher_aes192
+};
+
+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = {
+    "aes256-cbc",
+    16,                         /* blocksize */
+    16,                         /* initial value length */
+    32,                         /* secret length -- 32*8 == 256bit */
+    0,                          /* flags */
+    &_libssh2_init,
+    &_libssh2_encrypt,
+    &_libssh2_dtor,
+    _libssh2_cipher_aes256
+};
+
+/* rijndael-cbc@lysator.liu.se == aes256-cbc */
+static const LIBSSH2_CRYPT_METHOD
+    libssh2_crypt_method_rijndael_cbc_lysator_liu_se = {
+    "rijndael-cbc@lysator.liu.se",
+    16,                         /* blocksize */
+    16,                         /* initial value length */
+    32,                         /* secret length -- 32*8 == 256bit */
+    0,                          /* flags */
+    &_libssh2_init,
+    &_libssh2_encrypt,
+    &_libssh2_dtor,
+    _libssh2_cipher_aes256
+};
+#endif /* LIBSSH2_AES */
+
+#if LIBSSH2_BLOWFISH
+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = {
+    "blowfish-cbc",
+    8,                          /* blocksize */
+    8,                          /* initial value length */
+    16,                         /* secret length */
+    0,                          /* flags */
+    &_libssh2_init,
+    &_libssh2_encrypt,
+    &_libssh2_dtor,
+    _libssh2_cipher_blowfish
+};
+#endif /* LIBSSH2_BLOWFISH */
+
+#if LIBSSH2_RC4
+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = {
+    "arcfour",
+    8,                          /* blocksize */
+    8,                          /* initial value length */
+    16,                         /* secret length */
+    0,                          /* flags */
+    &_libssh2_init,
+    &_libssh2_encrypt,
+    &_libssh2_dtor,
+    _libssh2_cipher_arcfour
+};
+#endif /* LIBSSH2_RC4 */
+
+#if LIBSSH2_CAST
+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = {
+    "cast128-cbc",
+    8,                          /* blocksize */
+    8,                          /* initial value length */
+    16,                         /* secret length */
+    0,                          /* flags */
+    &_libssh2_init,
+    &_libssh2_encrypt,
+    &_libssh2_dtor,
+    _libssh2_cipher_cast5
+};
+#endif /* LIBSSH2_CAST */
+
+#if LIBSSH2_3DES
+static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = {
+    "3des-cbc",
+    8,                          /* blocksize */
+    8,                          /* initial value length */
+    24,                         /* secret length */
+    0,                          /* flags */
+    &_libssh2_init,
+    &_libssh2_encrypt,
+    &_libssh2_dtor,
+    _libssh2_cipher_3des
+};
+#endif
+
+static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = {
+#if LIBSSH2_AES
+    &libssh2_crypt_method_aes256_cbc,
+    &libssh2_crypt_method_rijndael_cbc_lysator_liu_se,  /* == aes256-cbc */
+    &libssh2_crypt_method_aes192_cbc,
+    &libssh2_crypt_method_aes128_cbc,
+#endif /* LIBSSH2_AES */
+#if LIBSSH2_BLOWFISH
+    &libssh2_crypt_method_blowfish_cbc,
+#endif /* LIBSSH2_BLOWFISH */
+#if LIBSSH2_RC4
+    &libssh2_crypt_method_arcfour,
+#endif /* LIBSSH2_RC4 */
+#if LIBSSH2_CAST
+    &libssh2_crypt_method_cast128_cbc,
+#endif /* LIBSSH2_CAST */
+#if LIBSSH2_3DES
+    &libssh2_crypt_method_3des_cbc,
+#endif /*  LIBSSH2_DES */
+#ifdef LIBSSH2_CRYPT_NONE
+    &libssh2_crypt_method_none,
+#endif
+    NULL
+};
+
+/* Expose to kex.c */
+const LIBSSH2_CRYPT_METHOD **
+libssh2_crypt_methods(void)
+{
+    return _libssh2_crypt_methods;
+}
diff --git a/Vendor/libssh2/Source/hostkey.c b/Vendor/libssh2/Source/hostkey.c
new file mode 100644 (file)
index 0000000..b25fd31
--- /dev/null
@@ -0,0 +1,455 @@
+/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+
+/* Needed for struct iovec on some platforms */
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#if LIBSSH2_RSA
+/* ***********
+   * ssh-rsa *
+   *********** */
+
+static int libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session,
+                                               void **abstract);
+
+/* {{{ libssh2_hostkey_method_ssh_rsa_init
+ * Initialize the server hostkey working area with e/n pair
+ */
+static int
+libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session,
+                                    const unsigned char *hostkey_data,
+                                    unsigned long hostkey_data_len,
+                                    void **abstract)
+{
+    libssh2_rsa_ctx *rsactx;
+    const unsigned char *s, *e, *n;
+    unsigned long len, e_len, n_len;
+
+    (void) hostkey_data_len;
+
+    if (*abstract) {
+        libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
+        *abstract = NULL;
+    }
+
+    s = hostkey_data;
+    len = libssh2_ntohu32(s);
+    s += 4;
+
+    if (len != 7 || strncmp((char *) s, "ssh-rsa", 7) != 0) {
+        return -1;
+    }
+    s += 7;
+
+    e_len = libssh2_ntohu32(s);
+    s += 4;
+
+    e = s;
+    s += e_len;
+    n_len = libssh2_ntohu32(s);
+    s += 4;
+    n = s;
+    s += n_len;
+
+    if (_libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0,
+                         NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0))
+        return -1;
+
+    *abstract = rsactx;
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_hostkey_method_ssh_rsa_initPEM
+ * Load a Private Key from a PEM file
+ */
+static int
+libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session,
+                                       const char *privkeyfile,
+                                       unsigned const char *passphrase,
+                                       void **abstract)
+{
+    libssh2_rsa_ctx *rsactx;
+    FILE *fp;
+    int ret;
+
+    if (*abstract) {
+        libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
+        *abstract = NULL;
+    }
+
+    fp = fopen(privkeyfile, "r");
+    if (!fp) {
+        return -1;
+    }
+
+    ret = _libssh2_rsa_new_private(&rsactx, session, fp, passphrase);
+    fclose(fp);
+    if (ret) {
+        return -1;
+    }
+
+    *abstract = rsactx;
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_hostkey_method_ssh_rsa_sign
+ * Verify signature created by remote
+ */
+static int
+libssh2_hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session,
+                                          const unsigned char *sig,
+                                          unsigned long sig_len,
+                                          const unsigned char *m,
+                                          unsigned long m_len, void **abstract)
+{
+    libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
+    (void) session;
+
+    /* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */
+    sig += 15;
+    sig_len -= 15;
+    return _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len);
+}
+
+/* }}} */
+
+/* {{{ libssh2_hostkey_method_ssh_rsa_signv
+ * Construct a signature from an array of vectors
+ */
+static int
+libssh2_hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session,
+                                     unsigned char **signature,
+                                     unsigned long *signature_len,
+                                     unsigned long veccount,
+                                     const struct iovec datavec[],
+                                     void **abstract)
+{
+    libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
+    int ret;
+    unsigned int i;
+    unsigned char hash[SHA_DIGEST_LENGTH];
+    libssh2_sha1_ctx ctx;
+
+    libssh2_sha1_init(&ctx);
+    for(i = 0; i < veccount; i++) {
+        libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
+    }
+    libssh2_sha1_final(ctx, hash);
+
+    ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH,
+                                 signature, signature_len);
+    if (ret) {
+        return -1;
+    }
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_hostkey_method_ssh_rsa_dtor
+ * Shutdown the hostkey
+ */
+static int
+libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, void **abstract)
+{
+    libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
+    (void) session;
+
+    _libssh2_rsa_free(rsactx);
+
+    *abstract = NULL;
+
+    return 0;
+}
+
+/* }}} */
+
+static const LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_rsa = {
+    "ssh-rsa",
+    MD5_DIGEST_LENGTH,
+    libssh2_hostkey_method_ssh_rsa_init,
+    libssh2_hostkey_method_ssh_rsa_initPEM,
+    libssh2_hostkey_method_ssh_rsa_sig_verify,
+    libssh2_hostkey_method_ssh_rsa_signv,
+    NULL,                       /* encrypt */
+    libssh2_hostkey_method_ssh_rsa_dtor,
+};
+#endif /* LIBSSH2_RSA */
+
+#if LIBSSH2_DSA
+/* ***********
+   * ssh-dss *
+   *********** */
+
+static int libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session,
+                                               void **abstract);
+
+/* {{{ libssh2_hostkey_method_ssh_dss_init
+ * Initialize the server hostkey working area with p/q/g/y set
+ */
+static int
+libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session,
+                                    const unsigned char *hostkey_data,
+                                    unsigned long hostkey_data_len,
+                                    void **abstract)
+{
+    libssh2_dsa_ctx *dsactx;
+    const unsigned char *p, *q, *g, *y, *s;
+    unsigned long p_len, q_len, g_len, y_len, len;
+    (void) hostkey_data_len;
+
+    if (*abstract) {
+        libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
+        *abstract = NULL;
+    }
+
+    s = hostkey_data;
+    len = libssh2_ntohu32(s);
+    s += 4;
+    if (len != 7 || strncmp((char *) s, "ssh-dss", 7) != 0) {
+        return -1;
+    }
+    s += 7;
+
+    p_len = libssh2_ntohu32(s);
+    s += 4;
+    p = s;
+    s += p_len;
+    q_len = libssh2_ntohu32(s);
+    s += 4;
+    q = s;
+    s += q_len;
+    g_len = libssh2_ntohu32(s);
+    s += 4;
+    g = s;
+    s += g_len;
+    y_len = libssh2_ntohu32(s);
+    s += 4;
+    y = s;
+    s += y_len;
+
+    _libssh2_dsa_new(&dsactx, p, p_len, q, q_len, g, g_len, y, y_len, NULL, 0);
+
+    *abstract = dsactx;
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_hostkey_method_ssh_dss_initPEM
+ * Load a Private Key from a PEM file
+ */
+static int
+libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session,
+                                       const char *privkeyfile,
+                                       unsigned const char *passphrase,
+                                       void **abstract)
+{
+    libssh2_dsa_ctx *dsactx;
+    FILE *fp;
+    int ret;
+
+    if (*abstract) {
+        libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
+        *abstract = NULL;
+    }
+
+    fp = fopen(privkeyfile, "r");
+    if (!fp) {
+        return -1;
+    }
+
+    ret = _libssh2_dsa_new_private(&dsactx, session, fp, passphrase);
+    fclose(fp);
+    if (ret) {
+        return -1;
+    }
+
+    *abstract = dsactx;
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_hostkey_method_ssh_dss_sign
+ * Verify signature created by remote
+ */
+static int
+libssh2_hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION * session,
+                                          const unsigned char *sig,
+                                          unsigned long sig_len,
+                                          const unsigned char *m,
+                                          unsigned long m_len, void **abstract)
+{
+    libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
+
+    /* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
+    sig += 15;
+    sig_len -= 15;
+    if (sig_len != 40) {
+        libssh2_error(session, LIBSSH2_ERROR_PROTO,
+                      "Invalid DSS signature length", 0);
+        return -1;
+    }
+    return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len);
+}
+
+/* }}} */
+
+/* {{{ libssh2_hostkey_method_ssh_dss_signv
+ * Construct a signature from an array of vectors
+ */
+static int
+libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session,
+                                     unsigned char **signature,
+                                     unsigned long *signature_len,
+                                     unsigned long veccount,
+                                     const struct iovec datavec[],
+                                     void **abstract)
+{
+    libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
+    unsigned char hash[SHA_DIGEST_LENGTH];
+    libssh2_sha1_ctx ctx;
+    unsigned int i;
+
+    *signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
+    if (!*signature) {
+        return -1;
+    }
+
+    *signature_len = 2 * SHA_DIGEST_LENGTH;
+    memset(*signature, 0, 2 * SHA_DIGEST_LENGTH);
+
+    libssh2_sha1_init(&ctx);
+    for(i = 0; i < veccount; i++) {
+        libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
+    }
+    libssh2_sha1_final(ctx, hash);
+
+    if (_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) {
+        LIBSSH2_FREE(session, *signature);
+        return -1;
+    }
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_hostkey_method_ssh_dss_dtor
+ * Shutdown the hostkey method
+ */
+static int
+libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, void **abstract)
+{
+    libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
+    (void) session;
+
+    _libssh2_dsa_free(dsactx);
+
+    *abstract = NULL;
+
+    return 0;
+}
+
+/* }}} */
+
+static const LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_dss = {
+    "ssh-dss",
+    MD5_DIGEST_LENGTH,
+    libssh2_hostkey_method_ssh_dss_init,
+    libssh2_hostkey_method_ssh_dss_initPEM,
+    libssh2_hostkey_method_ssh_dss_sig_verify,
+    libssh2_hostkey_method_ssh_dss_signv,
+    NULL,                       /* encrypt */
+    libssh2_hostkey_method_ssh_dss_dtor,
+};
+#endif /* LIBSSH2_DSA */
+
+static const LIBSSH2_HOSTKEY_METHOD *_libssh2_hostkey_methods[] = {
+#if LIBSSH2_RSA
+    &libssh2_hostkey_method_ssh_rsa,
+#endif /* LIBSSH2_RSA */
+#if LIBSSH2_DSA
+    &libssh2_hostkey_method_ssh_dss,
+#endif /* LIBSSH2_DSA */
+    NULL
+};
+
+const LIBSSH2_HOSTKEY_METHOD **
+libssh2_hostkey_methods(void)
+{
+    return _libssh2_hostkey_methods;
+}
+
+/* {{{ libssh2_hostkey_hash
+ * Returns hash signature
+ * Returned buffer should NOT be freed
+ * Length of buffer is determined by hash type
+ * i.e. MD5 == 16, SHA1 == 20
+ */
+LIBSSH2_API const char *
+libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type)
+{
+    switch (hash_type) {
+#if LIBSSH2_MD5
+    case LIBSSH2_HOSTKEY_HASH_MD5:
+        return (char *) session->server_hostkey_md5;
+        break;
+#endif /* LIBSSH2_MD5 */
+    case LIBSSH2_HOSTKEY_HASH_SHA1:
+        return (char *) session->server_hostkey_sha1;
+        break;
+    default:
+        return NULL;
+    }
+}
+
+/* }}} */
diff --git a/Vendor/libssh2/Source/kex.c b/Vendor/libssh2/Source/kex.c
new file mode 100644 (file)
index 0000000..9ae59c5
--- /dev/null
@@ -0,0 +1,1906 @@
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+
+/* TODO: Switch this to an inline and handle alloc() failures */
+/* Helper macro called from libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange */
+#define LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(value, reqlen, version) \
+{                                                                           \
+    libssh2_sha1_ctx hash;                                                  \
+    unsigned long len = 0;                                                  \
+    if (!(value)) {                                                         \
+        value = LIBSSH2_ALLOC(session, reqlen + SHA_DIGEST_LENGTH);         \
+    }                                                                       \
+    if (value)                                                              \
+        while (len < (unsigned long)reqlen) {                               \
+            libssh2_sha1_init(&hash);                                       \
+            libssh2_sha1_update(hash, exchange_state->k_value,              \
+                                exchange_state->k_value_len);               \
+            libssh2_sha1_update(hash, exchange_state->h_sig_comp,           \
+                                SHA_DIGEST_LENGTH);                         \
+            if (len > 0) {                                                  \
+                libssh2_sha1_update(hash, value, len);                      \
+            }    else {                                                     \
+                libssh2_sha1_update(hash, (version), 1);                    \
+                libssh2_sha1_update(hash, session->session_id,              \
+                                    session->session_id_len);               \
+            }                                                               \
+            libssh2_sha1_final(hash, (value) + len);                        \
+            len += SHA_DIGEST_LENGTH;                                       \
+        }                                                                   \
+}
+
+/* {{{ libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange
+ * Diffie Hellman Key Exchange, Group Agnostic
+ */
+static int
+libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *
+                                                            session,
+                                                            _libssh2_bn * g,
+                                                            _libssh2_bn * p,
+                                                            int group_order,
+                                                            unsigned char
+                                                            packet_type_init,
+                                                            unsigned char
+                                                            packet_type_reply,
+                                                            unsigned char
+                                                            *midhash,
+                                                            unsigned long
+                                                            midhash_len,
+                                                            kmdhgGPsha1kex_state_t
+                                                            * exchange_state)
+{
+    int ret = 0;
+    int rc;
+
+    if (exchange_state->state == libssh2_NB_state_idle) {
+        /* Setup initial values */
+        exchange_state->e_packet = NULL;
+        exchange_state->s_packet = NULL;
+        exchange_state->k_value = NULL;
+        exchange_state->ctx = _libssh2_bn_ctx_new();
+        exchange_state->x = _libssh2_bn_init(); /* Random from client */
+        exchange_state->e = _libssh2_bn_init(); /* g^x mod p */
+        exchange_state->f = _libssh2_bn_init(); /* g^(Random from server) mod p */
+        exchange_state->k = _libssh2_bn_init(); /* The shared secret: f^x mod p */
+
+        /* Zero the whole thing out */
+        memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t));
+
+        /* Generate x and e */
+        _libssh2_bn_rand(exchange_state->x, group_order, 0, -1);
+        _libssh2_bn_mod_exp(exchange_state->e, g, exchange_state->x, p,
+                            exchange_state->ctx);
+
+        /* Send KEX init */
+        /* packet_type(1) + String Length(4) + leading 0(1) */
+        exchange_state->e_packet_len =
+            _libssh2_bn_bytes(exchange_state->e) + 6;
+        if (_libssh2_bn_bits(exchange_state->e) % 8) {
+            /* Leading 00 not needed */
+            exchange_state->e_packet_len--;
+        }
+
+        exchange_state->e_packet =
+            LIBSSH2_ALLOC(session, exchange_state->e_packet_len);
+        if (!exchange_state->e_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Out of memory error",
+                          0);
+            ret = -1;
+            goto clean_exit;
+        }
+        exchange_state->e_packet[0] = packet_type_init;
+        libssh2_htonu32(exchange_state->e_packet + 1,
+                        exchange_state->e_packet_len - 5);
+        if (_libssh2_bn_bits(exchange_state->e) % 8) {
+            _libssh2_bn_to_bin(exchange_state->e,
+                               exchange_state->e_packet + 5);
+        } else {
+            exchange_state->e_packet[5] = 0;
+            _libssh2_bn_to_bin(exchange_state->e,
+                               exchange_state->e_packet + 6);
+        }
+
+        _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending KEX packet %d",
+                       (int) packet_type_init);
+        exchange_state->state = libssh2_NB_state_created;
+    }
+
+    if (exchange_state->state == libssh2_NB_state_created) {
+        rc = libssh2_packet_write(session, exchange_state->e_packet,
+                                  exchange_state->e_packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send KEX init message", 0);
+            ret = -1;
+            goto clean_exit;
+        }
+        exchange_state->state = libssh2_NB_state_sent;
+    }
+
+    if (exchange_state->state == libssh2_NB_state_sent) {
+        if (session->burn_optimistic_kexinit) {
+            /* The first KEX packet to come along will be the guess initially 
+             * sent by the server.  That guess turned out to be wrong so we
+             * need to silently ignore it */
+            int burn_type;
+
+            _libssh2_debug(session, LIBSSH2_DBG_KEX,
+                           "Waiting for badly guessed KEX packet (to be ignored)");
+            burn_type =
+                libssh2_packet_burn(session, &exchange_state->burn_state);
+            if (burn_type == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            } else if (burn_type <= 0) {
+                /* Failed to receive a packet */
+                ret = -1;
+                goto clean_exit;
+            }
+            session->burn_optimistic_kexinit = 0;
+
+            _libssh2_debug(session, LIBSSH2_DBG_KEX,
+                           "Burnt packet of type: %02x",
+                           (unsigned int) burn_type);
+        }
+
+        exchange_state->state = libssh2_NB_state_sent1;
+    }
+
+    if (exchange_state->state == libssh2_NB_state_sent1) {
+        /* Wait for KEX reply */
+        rc = libssh2_packet_require_ex(session, packet_type_reply,
+                                       &exchange_state->s_packet,
+                                       &exchange_state->s_packet_len, 0, NULL,
+                                       0, &exchange_state->req_state);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        }
+        if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
+                          "Timed out waiting for KEX reply", 0);
+            ret = -1;
+            goto clean_exit;
+        }
+
+        /* Parse KEXDH_REPLY */
+        exchange_state->s = exchange_state->s_packet + 1;
+
+        session->server_hostkey_len = libssh2_ntohu32(exchange_state->s);
+        exchange_state->s += 4;
+        session->server_hostkey =
+            LIBSSH2_ALLOC(session, session->server_hostkey_len);
+        if (!session->server_hostkey) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for a copy of the host key",
+                          0);
+            ret = -1;
+            goto clean_exit;
+        }
+        memcpy(session->server_hostkey, exchange_state->s,
+               session->server_hostkey_len);
+        exchange_state->s += session->server_hostkey_len;
+
+#if LIBSSH2_MD5
+        {
+            libssh2_md5_ctx fingerprint_ctx;
+
+            libssh2_md5_init(&fingerprint_ctx);
+            libssh2_md5_update(fingerprint_ctx, session->server_hostkey,
+                               session->server_hostkey_len);
+            libssh2_md5_final(fingerprint_ctx, session->server_hostkey_md5);
+        }
+#ifdef LIBSSH2DEBUG
+        {
+            char fingerprint[50], *fprint = fingerprint;
+            int i;
+            for(i = 0; i < 16; i++, fprint += 3) {
+                snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]);
+            }
+            *(--fprint) = '\0';
+            _libssh2_debug(session, LIBSSH2_DBG_KEX,
+                           "Server's MD5 Fingerprint: %s", fingerprint);
+        }
+#endif /* LIBSSH2DEBUG */
+#endif /* ! LIBSSH2_MD5 */
+
+        {
+            libssh2_sha1_ctx fingerprint_ctx;
+
+            libssh2_sha1_init(&fingerprint_ctx);
+            libssh2_sha1_update(fingerprint_ctx, session->server_hostkey,
+                                session->server_hostkey_len);
+            libssh2_sha1_final(fingerprint_ctx, session->server_hostkey_sha1);
+        }
+#ifdef LIBSSH2DEBUG
+        {
+            char fingerprint[64], *fprint = fingerprint;
+            int i;
+
+            for(i = 0; i < 20; i++, fprint += 3) {
+                snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]);
+            }
+            *(--fprint) = '\0';
+            _libssh2_debug(session, LIBSSH2_DBG_KEX,
+                           "Server's SHA1 Fingerprint: %s", fingerprint);
+        }
+#endif /* LIBSSH2DEBUG */
+
+        if (session->hostkey->
+            init(session, session->server_hostkey, session->server_hostkey_len,
+                 &session->server_hostkey_abstract)) {
+            libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT,
+                          "Unable to initialize hostkey importer", 0);
+            ret = -1;
+            goto clean_exit;
+        }
+
+        exchange_state->f_value_len = libssh2_ntohu32(exchange_state->s);
+        exchange_state->s += 4;
+        exchange_state->f_value = exchange_state->s;
+        exchange_state->s += exchange_state->f_value_len;
+        _libssh2_bn_from_bin(exchange_state->f, exchange_state->f_value_len,
+                             exchange_state->f_value);
+
+        exchange_state->h_sig_len = libssh2_ntohu32(exchange_state->s);
+        exchange_state->s += 4;
+        exchange_state->h_sig = exchange_state->s;
+
+        /* Compute the shared secret */
+        _libssh2_bn_mod_exp(exchange_state->k, exchange_state->f,
+                            exchange_state->x, p, exchange_state->ctx);
+        exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5;
+        if (_libssh2_bn_bits(exchange_state->k) % 8) {
+            /* don't need leading 00 */
+            exchange_state->k_value_len--;
+        }
+        exchange_state->k_value =
+            LIBSSH2_ALLOC(session, exchange_state->k_value_len);
+        if (!exchange_state->k_value) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate buffer for K", 0);
+            ret = -1;
+            goto clean_exit;
+        }
+        libssh2_htonu32(exchange_state->k_value,
+                        exchange_state->k_value_len - 4);
+        if (_libssh2_bn_bits(exchange_state->k) % 8) {
+            _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4);
+        } else {
+            exchange_state->k_value[4] = 0;
+            _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5);
+        }
+
+        libssh2_sha1_init(&exchange_state->exchange_hash);
+        if (session->local.banner) {
+            libssh2_htonu32(exchange_state->h_sig_comp,
+                            strlen((char *) session->local.banner) - 2);
+            libssh2_sha1_update(exchange_state->exchange_hash,
+                                exchange_state->h_sig_comp, 4);
+            libssh2_sha1_update(exchange_state->exchange_hash,
+                                (char *) session->local.banner,
+                                strlen((char *) session->local.banner) - 2);
+        } else {
+            libssh2_htonu32(exchange_state->h_sig_comp,
+                            sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
+            libssh2_sha1_update(exchange_state->exchange_hash,
+                                exchange_state->h_sig_comp, 4);
+            libssh2_sha1_update(exchange_state->exchange_hash,
+                                LIBSSH2_SSH_DEFAULT_BANNER,
+                                sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
+        }
+
+        libssh2_htonu32(exchange_state->h_sig_comp,
+                        strlen((char *) session->remote.banner));
+        libssh2_sha1_update(exchange_state->exchange_hash,
+                            exchange_state->h_sig_comp, 4);
+        libssh2_sha1_update(exchange_state->exchange_hash,
+                            session->remote.banner,
+                            strlen((char *) session->remote.banner));
+
+        libssh2_htonu32(exchange_state->h_sig_comp,
+                        session->local.kexinit_len);
+        libssh2_sha1_update(exchange_state->exchange_hash,
+                            exchange_state->h_sig_comp, 4);
+        libssh2_sha1_update(exchange_state->exchange_hash,
+                            session->local.kexinit,
+                            session->local.kexinit_len);
+
+        libssh2_htonu32(exchange_state->h_sig_comp,
+                        session->remote.kexinit_len);
+        libssh2_sha1_update(exchange_state->exchange_hash,
+                            exchange_state->h_sig_comp, 4);
+        libssh2_sha1_update(exchange_state->exchange_hash,
+                            session->remote.kexinit,
+                            session->remote.kexinit_len);
+
+        libssh2_htonu32(exchange_state->h_sig_comp,
+                        session->server_hostkey_len);
+        libssh2_sha1_update(exchange_state->exchange_hash,
+                            exchange_state->h_sig_comp, 4);
+        libssh2_sha1_update(exchange_state->exchange_hash,
+                            session->server_hostkey,
+                            session->server_hostkey_len);
+
+        if (packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) {
+            /* diffie-hellman-group-exchange hashes additional fields */
+#ifdef LIBSSH2_DH_GEX_NEW
+            libssh2_htonu32(exchange_state->h_sig_comp,
+                            LIBSSH2_DH_GEX_MINGROUP);
+            libssh2_htonu32(exchange_state->h_sig_comp + 4,
+                            LIBSSH2_DH_GEX_OPTGROUP);
+            libssh2_htonu32(exchange_state->h_sig_comp + 8,
+                            LIBSSH2_DH_GEX_MAXGROUP);
+            libssh2_sha1_update(exchange_state->exchange_hash,
+                                exchange_state->h_sig_comp, 12);
+#else
+            libssh2_htonu32(exchange_state->h_sig_comp,
+                            LIBSSH2_DH_GEX_OPTGROUP);
+            libssh2_sha1_update(exchange_state->exchange_hash,
+                                exchange_state->h_sig_comp, 4);
+#endif
+        }
+
+        if (midhash) {
+            libssh2_sha1_update(exchange_state->exchange_hash, midhash,
+                                midhash_len);
+        }
+
+        libssh2_sha1_update(exchange_state->exchange_hash,
+                            exchange_state->e_packet + 1,
+                            exchange_state->e_packet_len - 1);
+
+        libssh2_htonu32(exchange_state->h_sig_comp,
+                        exchange_state->f_value_len);
+        libssh2_sha1_update(exchange_state->exchange_hash,
+                            exchange_state->h_sig_comp, 4);
+        libssh2_sha1_update(exchange_state->exchange_hash,
+                            exchange_state->f_value,
+                            exchange_state->f_value_len);
+
+        libssh2_sha1_update(exchange_state->exchange_hash,
+                            exchange_state->k_value,
+                            exchange_state->k_value_len);
+
+        libssh2_sha1_final(exchange_state->exchange_hash,
+                           exchange_state->h_sig_comp);
+
+        if (session->hostkey->
+            sig_verify(session, exchange_state->h_sig,
+                       exchange_state->h_sig_len, exchange_state->h_sig_comp,
+                       20, &session->server_hostkey_abstract)) {
+            libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN,
+                          "Unable to verify hostkey signature", 0);
+            ret = -1;
+            goto clean_exit;
+        }
+
+        _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending NEWKEYS message");
+        exchange_state->c = SSH_MSG_NEWKEYS;
+
+        exchange_state->state = libssh2_NB_state_sent2;
+    }
+
+    if (exchange_state->state == libssh2_NB_state_sent2) {
+        rc = libssh2_packet_write(session, &exchange_state->c, 1);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send NEWKEYS message", 0);
+            ret = -1;
+            goto clean_exit;
+        }
+
+        exchange_state->state = libssh2_NB_state_sent3;
+    }
+
+    if (exchange_state->state == libssh2_NB_state_sent3) {
+        rc = libssh2_packet_require_ex(session, SSH_MSG_NEWKEYS,
+                                       &exchange_state->tmp,
+                                       &exchange_state->tmp_len, 0, NULL, 0,
+                                       &exchange_state->req_state);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
+                          "Timed out waiting for NEWKEYS", 0);
+            ret = -1;
+            goto clean_exit;
+        }
+        /* The first key exchange has been performed, 
+           switch to active crypt/comp/mac mode */
+        session->state |= LIBSSH2_STATE_NEWKEYS;
+        _libssh2_debug(session, LIBSSH2_DBG_KEX, "Received NEWKEYS message");
+
+        /* This will actually end up being just packet_type(1) 
+           for this packet type anyway */
+        LIBSSH2_FREE(session, exchange_state->tmp);
+
+        if (!session->session_id) {
+            session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH);
+            if (!session->session_id) {
+                ret = -1;
+                goto clean_exit;
+            }
+            memcpy(session->session_id, exchange_state->h_sig_comp,
+                   SHA_DIGEST_LENGTH);
+            session->session_id_len = SHA_DIGEST_LENGTH;
+            _libssh2_debug(session, LIBSSH2_DBG_KEX, "session_id calculated");
+        }
+
+        /* Cleanup any existing cipher */
+        if (session->local.crypt->dtor) {
+            session->local.crypt->dtor(session,
+                                       &session->local.crypt_abstract);
+        }
+
+        /* Calculate IV/Secret/Key for each direction */
+        if (session->local.crypt->init) {
+            unsigned char *iv = NULL, *secret = NULL;
+            int free_iv = 0, free_secret = 0;
+
+            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv,
+                                                        session->local.crypt->
+                                                        iv_len, "A");
+            if (!iv) {
+                ret = -1;
+                goto clean_exit;
+            }
+            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret,
+                                                        session->local.crypt->
+                                                        secret_len, "C");
+            if (!secret) {
+                LIBSSH2_FREE(session, iv);
+                ret = -1;
+                goto clean_exit;
+            }
+            if (session->local.crypt->
+                init(session, session->local.crypt, iv, &free_iv, secret,
+                     &free_secret, 1, &session->local.crypt_abstract)) {
+                LIBSSH2_FREE(session, iv);
+                LIBSSH2_FREE(session, secret);
+                ret = -1;
+                goto clean_exit;
+            }
+
+            if (free_iv) {
+                memset(iv, 0, session->local.crypt->iv_len);
+                LIBSSH2_FREE(session, iv);
+            }
+
+            if (free_secret) {
+                memset(secret, 0, session->local.crypt->secret_len);
+                LIBSSH2_FREE(session, secret);
+            }
+        }
+        _libssh2_debug(session, LIBSSH2_DBG_KEX,
+                       "Client to Server IV and Key calculated");
+
+        if (session->remote.crypt->dtor) {
+            /* Cleanup any existing cipher */
+            session->remote.crypt->dtor(session,
+                                        &session->remote.crypt_abstract);
+        }
+
+        if (session->remote.crypt->init) {
+            unsigned char *iv = NULL, *secret = NULL;
+            int free_iv = 0, free_secret = 0;
+
+            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv,
+                                                        session->remote.crypt->
+                                                        iv_len, "B");
+            if (!iv) {
+                ret = -1;
+                goto clean_exit;
+            }
+            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret,
+                                                        session->remote.crypt->
+                                                        secret_len, "D");
+            if (!secret) {
+                LIBSSH2_FREE(session, iv);
+                ret = -1;
+                goto clean_exit;
+            }
+            if (session->remote.crypt->
+                init(session, session->remote.crypt, iv, &free_iv, secret,
+                     &free_secret, 0, &session->remote.crypt_abstract)) {
+                LIBSSH2_FREE(session, iv);
+                LIBSSH2_FREE(session, secret);
+                ret = -1;
+                goto clean_exit;
+            }
+
+            if (free_iv) {
+                memset(iv, 0, session->remote.crypt->iv_len);
+                LIBSSH2_FREE(session, iv);
+            }
+
+            if (free_secret) {
+                memset(secret, 0, session->remote.crypt->secret_len);
+                LIBSSH2_FREE(session, secret);
+            }
+        }
+        _libssh2_debug(session, LIBSSH2_DBG_KEX,
+                       "Server to Client IV and Key calculated");
+
+        if (session->local.mac->dtor) {
+            session->local.mac->dtor(session, &session->local.mac_abstract);
+        }
+
+        if (session->local.mac->init) {
+            unsigned char *key = NULL;
+            int free_key = 0;
+
+            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key,
+                                                        session->local.mac->
+                                                        key_len, "E");
+            if (!key) {
+                ret = -1;
+                goto clean_exit;
+            }
+            session->local.mac->init(session, key, &free_key,
+                                     &session->local.mac_abstract);
+
+            if (free_key) {
+                memset(key, 0, session->local.mac->key_len);
+                LIBSSH2_FREE(session, key);
+            }
+        }
+        _libssh2_debug(session, LIBSSH2_DBG_KEX,
+                       "Client to Server HMAC Key calculated");
+
+        if (session->remote.mac->dtor) {
+            session->remote.mac->dtor(session, &session->remote.mac_abstract);
+        }
+
+        if (session->remote.mac->init) {
+            unsigned char *key = NULL;
+            int free_key = 0;
+
+            LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key,
+                                                        session->remote.mac->
+                                                        key_len, "F");
+            if (!key) {
+                ret = -1;
+                goto clean_exit;
+            }
+            session->remote.mac->init(session, key, &free_key,
+                                      &session->remote.mac_abstract);
+
+            if (free_key) {
+                memset(key, 0, session->remote.mac->key_len);
+                LIBSSH2_FREE(session, key);
+            }
+        }
+        _libssh2_debug(session, LIBSSH2_DBG_KEX,
+                       "Server to Client HMAC Key calculated");
+    }
+
+  clean_exit:
+    _libssh2_bn_free(exchange_state->x);
+    exchange_state->x = NULL;
+    _libssh2_bn_free(exchange_state->e);
+    exchange_state->e = NULL;
+    _libssh2_bn_free(exchange_state->f);
+    exchange_state->f = NULL;
+    _libssh2_bn_free(exchange_state->k);
+    exchange_state->k = NULL;
+    _libssh2_bn_ctx_free(exchange_state->ctx);
+    exchange_state->ctx = NULL;
+
+    if (exchange_state->e_packet) {
+        LIBSSH2_FREE(session, exchange_state->e_packet);
+        exchange_state->e_packet = NULL;
+    }
+
+    if (exchange_state->s_packet) {
+        LIBSSH2_FREE(session, exchange_state->s_packet);
+        exchange_state->s_packet = NULL;
+    }
+
+    if (exchange_state->k_value) {
+        LIBSSH2_FREE(session, exchange_state->k_value);
+        exchange_state->k_value = NULL;
+    }
+
+    if (session->server_hostkey) {
+        LIBSSH2_FREE(session, session->server_hostkey);
+        session->server_hostkey = NULL;
+    }
+
+    exchange_state->state = libssh2_NB_state_idle;
+
+    return ret;
+}
+
+/* }}} */
+
+/* {{{ libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange
+ * Diffie-Hellman Group1 (Actually Group2) Key Exchange using SHA1
+ */
+static int
+libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *
+                                                           session,
+                                                           key_exchange_state_low_t
+                                                           * key_state)
+{
+    static const unsigned char p_value[128] = {
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+        0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+        0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+        0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+        0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+        0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+        0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+        0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+        0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+        0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+    };
+
+    int ret;
+
+    if (key_state->state == libssh2_NB_state_idle) {
+        /* g == 2 */
+        key_state->p = _libssh2_bn_init();      /* SSH2 defined value (p_value) */
+        key_state->g = _libssh2_bn_init();      /* SSH2 defined value (2) */
+
+        /* Initialize P and G */
+        _libssh2_bn_set_word(key_state->g, 2);
+        _libssh2_bn_from_bin(key_state->p, 128, p_value);
+
+        _libssh2_debug(session, LIBSSH2_DBG_KEX,
+                       "Initiating Diffie-Hellman Group1 Key Exchange");
+
+        key_state->state = libssh2_NB_state_created;
+    }
+
+    ret =
+        libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session,
+                                                                    key_state->
+                                                                    g,
+                                                                    key_state->
+                                                                    p, 128,
+                                                                    SSH_MSG_KEXDH_INIT,
+                                                                    SSH_MSG_KEXDH_REPLY,
+                                                                    NULL, 0,
+                                                                    &key_state->
+                                                                    exchange_state);
+    if (ret == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    }
+
+    _libssh2_bn_free(key_state->p);
+    key_state->p = NULL;
+    _libssh2_bn_free(key_state->g);
+    key_state->g = NULL;
+    key_state->state = libssh2_NB_state_idle;
+
+    return ret;
+}
+
+/* }}} */
+
+/* {{{ libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange
+ * Diffie-Hellman Group14 Key Exchange using SHA1
+ */
+static int
+libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *
+                                                            session,
+                                                            key_exchange_state_low_t
+                                                            * key_state)
+{
+    static const unsigned char p_value[256] = {
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+        0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+        0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+        0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+        0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+        0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+        0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+        0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+        0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+        0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+        0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+        0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+        0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+        0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+        0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
+        0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
+        0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+        0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
+        0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
+        0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+        0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
+        0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
+        0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
+        0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
+        0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
+        0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
+        0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
+        0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
+        0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
+        0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+    };
+    int ret;
+
+    if (key_state->state == libssh2_NB_state_idle) {
+        key_state->p = _libssh2_bn_init();      /* SSH2 defined value (p_value) */
+        key_state->g = _libssh2_bn_init();      /* SSH2 defined value (2) */
+
+        /* g == 2 */
+        /* Initialize P and G */
+        _libssh2_bn_set_word(key_state->g, 2);
+        _libssh2_bn_from_bin(key_state->p, 256, p_value);
+
+        _libssh2_debug(session, LIBSSH2_DBG_KEX,
+                       "Initiating Diffie-Hellman Group14 Key Exchange");
+
+        key_state->state = libssh2_NB_state_created;
+    }
+    ret =
+        libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session,
+                                                                    key_state->
+                                                                    g,
+                                                                    key_state->
+                                                                    p, 256,
+                                                                    SSH_MSG_KEXDH_INIT,
+                                                                    SSH_MSG_KEXDH_REPLY,
+                                                                    NULL, 0,
+                                                                    &key_state->
+                                                                    exchange_state);
+    if (ret == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    }
+
+    key_state->state = libssh2_NB_state_idle;
+    _libssh2_bn_free(key_state->p);
+    key_state->p = NULL;
+    _libssh2_bn_free(key_state->g);
+    key_state->g = NULL;
+
+    return ret;
+}
+
+/* }}} */
+
+/* {{{ libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange
+ * Diffie-Hellman Group Exchange Key Exchange using SHA1
+ * Negotiates random(ish) group for secret derivation
+ */
+static int
+    libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange
+    (LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state)
+{
+    unsigned char *s;
+    unsigned long p_len, g_len;
+    int ret;
+    int rc;
+
+    if (key_state->state == libssh2_NB_state_idle) {
+        key_state->p = _libssh2_bn_init();
+        key_state->g = _libssh2_bn_init();
+        /* Ask for a P and G pair */
+#ifdef LIBSSH2_DH_GEX_NEW
+        key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST;
+        libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_MINGROUP);
+        libssh2_htonu32(key_state->request + 5, LIBSSH2_DH_GEX_OPTGROUP);
+        libssh2_htonu32(key_state->request + 9, LIBSSH2_DH_GEX_MAXGROUP);
+        key_state->request_len = 13;
+        _libssh2_debug(session, LIBSSH2_DBG_KEX,
+                       "Initiating Diffie-Hellman Group-Exchange (New Method)");
+#else
+        key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD;
+        libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_OPTGROUP);
+        key_state->request_len = 5;
+        _libssh2_debug(session, LIBSSH2_DBG_KEX,
+                       "Initiating Diffie-Hellman Group-Exchange (Old Method)");
+#endif
+
+        key_state->state = libssh2_NB_state_created;
+    }
+
+    if (key_state->state == libssh2_NB_state_created) {
+        rc = libssh2_packet_write(session, key_state->request,
+                                  key_state->request_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send Group Exchange Request", 0);
+            ret = -1;
+            goto dh_gex_clean_exit;
+        }
+
+        key_state->state = libssh2_NB_state_sent;
+    }
+
+    if (key_state->state == libssh2_NB_state_sent) {
+        rc = libssh2_packet_require_ex(session, SSH_MSG_KEX_DH_GEX_GROUP,
+                                       &key_state->data, &key_state->data_len,
+                                       0, NULL, 0, &key_state->req_state);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,
+                          "Timeout waiting for GEX_GROUP reply", 0);
+            ret = -1;
+            goto dh_gex_clean_exit;
+        }
+
+        key_state->state = libssh2_NB_state_sent1;
+    }
+
+    if (key_state->state == libssh2_NB_state_sent1) {
+        s = key_state->data + 1;
+        p_len = libssh2_ntohu32(s);
+        s += 4;
+        _libssh2_bn_from_bin(key_state->p, p_len, s);
+        s += p_len;
+
+        g_len = libssh2_ntohu32(s);
+        s += 4;
+        _libssh2_bn_from_bin(key_state->g, g_len, s);
+        s += g_len;
+
+        ret =
+            libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange
+            (session, key_state->g, key_state->p, p_len,
+             SSH_MSG_KEX_DH_GEX_INIT, SSH_MSG_KEX_DH_GEX_REPLY,
+             key_state->data + 1, key_state->data_len - 1,
+             &key_state->exchange_state);
+        if (ret == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        }
+
+        LIBSSH2_FREE(session, key_state->data);
+    }
+
+  dh_gex_clean_exit:
+    key_state->state = libssh2_NB_state_idle;
+    _libssh2_bn_free(key_state->g);
+    key_state->g = NULL;
+    _libssh2_bn_free(key_state->p);
+    key_state->p = NULL;
+
+    return ret;
+}
+
+/* }}} */
+
+#define LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY     0x0001
+#define LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY    0x0002
+
+static const LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group1_sha1 = {
+    "diffie-hellman-group1-sha1",
+    libssh2_kex_method_diffie_hellman_group1_sha1_key_exchange,
+    LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
+};
+
+static const LIBSSH2_KEX_METHOD libssh2_kex_method_diffie_helman_group14_sha1 = {
+    "diffie-hellman-group14-sha1",
+    libssh2_kex_method_diffie_hellman_group14_sha1_key_exchange,
+    LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
+};
+
+static const LIBSSH2_KEX_METHOD
+    libssh2_kex_method_diffie_helman_group_exchange_sha1 = {
+    "diffie-hellman-group-exchange-sha1",
+    libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange,
+    LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY,
+};
+
+static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = {
+    &libssh2_kex_method_diffie_helman_group14_sha1,
+    &libssh2_kex_method_diffie_helman_group_exchange_sha1,
+    &libssh2_kex_method_diffie_helman_group1_sha1,
+    NULL
+};
+
+typedef struct _LIBSSH2_COMMON_METHOD
+{
+    const char *name;
+} LIBSSH2_COMMON_METHOD;
+
+/* {{{ libssh2_kex_method_strlen
+ * Calculate the length of a particular method list's resulting string
+ * Includes SUM(strlen() of each individual method plus 1 (for coma)) - 1 (because the last coma isn't used)
+ * Another sign of bad coding practices gone mad.  Pretend you don't see this.
+ */
+static size_t
+libssh2_kex_method_strlen(LIBSSH2_COMMON_METHOD ** method)
+{
+    size_t len = 0;
+
+    if (!method || !*method) {
+        return 0;
+    }
+
+    while (*method && (*method)->name) {
+        len += strlen((*method)->name) + 1;
+        method++;
+    }
+
+    return len - 1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_kex_method_list
+ * Generate formatted preference list in buf
+ */
+static size_t
+libssh2_kex_method_list(unsigned char *buf, size_t list_strlen,
+                        LIBSSH2_COMMON_METHOD ** method)
+{
+    libssh2_htonu32(buf, list_strlen);
+    buf += 4;
+
+    if (!method || !*method) {
+        return 4;
+    }
+
+    while (*method && (*method)->name) {
+        int mlen = strlen((*method)->name);
+        memcpy(buf, (*method)->name, mlen);
+        buf += mlen;
+        *(buf++) = ',';
+        method++;
+    }
+
+    return list_strlen + 4;
+}
+
+/* }}} */
+
+#define LIBSSH2_METHOD_PREFS_LEN(prefvar, defaultvar)   ((prefvar) ? strlen(prefvar) : libssh2_kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar)))
+#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar)                              \
+    if (prefvar) {                                                                                  \
+        libssh2_htonu32((buf), (prefvarlen));                                                       \
+        buf += 4;                                                                                   \
+        memcpy((buf), (prefvar), (prefvarlen));                                                     \
+        buf += (prefvarlen);                                                                        \
+    } else {                                                                                        \
+        buf += libssh2_kex_method_list((buf), (prefvarlen), (LIBSSH2_COMMON_METHOD**)(defaultvar)); \
+    }
+
+/* {{{ libssh2_kexinit
+ * Send SSH_MSG_KEXINIT packet
+ */
+static int
+libssh2_kexinit(LIBSSH2_SESSION * session)
+{
+    /* 62 = packet_type(1) + cookie(16) + first_packet_follows(1) + 
+       reserved(4) + length longs(40) */
+    size_t data_len = 62;
+    size_t kex_len, hostkey_len = 0;
+    size_t crypt_cs_len, crypt_sc_len;
+    size_t comp_cs_len, comp_sc_len;
+    size_t mac_cs_len, mac_sc_len;
+    size_t lang_cs_len, lang_sc_len;
+    unsigned char *data, *s;
+    int rc;
+
+    if (session->kexinit_state == libssh2_NB_state_idle) {
+        kex_len =
+            LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods);
+        hostkey_len =
+            LIBSSH2_METHOD_PREFS_LEN(session->hostkey_prefs,
+                                     libssh2_hostkey_methods());
+        crypt_cs_len =
+            LIBSSH2_METHOD_PREFS_LEN(session->local.crypt_prefs,
+                                     libssh2_crypt_methods());
+        crypt_sc_len =
+            LIBSSH2_METHOD_PREFS_LEN(session->remote.crypt_prefs,
+                                     libssh2_crypt_methods());
+        mac_cs_len =
+            LIBSSH2_METHOD_PREFS_LEN(session->local.mac_prefs,
+                                     libssh2_mac_methods());
+        mac_sc_len =
+            LIBSSH2_METHOD_PREFS_LEN(session->remote.mac_prefs,
+                                     libssh2_mac_methods());
+        comp_cs_len =
+            LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs,
+                                     libssh2_comp_methods());
+        comp_sc_len =
+            LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs,
+                                     libssh2_comp_methods());
+        lang_cs_len =
+            LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL);
+        lang_sc_len =
+            LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL);
+
+        data_len += kex_len + hostkey_len + crypt_cs_len + crypt_sc_len +
+            comp_cs_len + comp_sc_len + mac_cs_len + mac_sc_len +
+            lang_cs_len + lang_sc_len;
+
+        s = data = LIBSSH2_ALLOC(session, data_len);
+        if (!data) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory", 0);
+            return -1;
+        }
+
+        *(s++) = SSH_MSG_KEXINIT;
+
+        libssh2_random(s, 16);
+        s += 16;
+
+        /* Ennumerating through these lists twice is probably (certainly?) 
+           inefficient from a CPU standpoint, but it saves multiple 
+           malloc/realloc calls */
+        LIBSSH2_METHOD_PREFS_STR(s, kex_len, session->kex_prefs,
+                                 libssh2_kex_methods);
+        LIBSSH2_METHOD_PREFS_STR(s, hostkey_len, session->hostkey_prefs,
+                                 libssh2_hostkey_methods());
+        LIBSSH2_METHOD_PREFS_STR(s, crypt_cs_len, session->local.crypt_prefs,
+                                 libssh2_crypt_methods());
+        LIBSSH2_METHOD_PREFS_STR(s, crypt_sc_len, session->remote.crypt_prefs,
+                                 libssh2_crypt_methods());
+        LIBSSH2_METHOD_PREFS_STR(s, mac_cs_len, session->local.mac_prefs,
+                                 libssh2_mac_methods());
+        LIBSSH2_METHOD_PREFS_STR(s, mac_sc_len, session->remote.mac_prefs,
+                                 libssh2_mac_methods());
+        LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len, session->local.comp_prefs,
+                                 libssh2_comp_methods());
+        LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len, session->remote.comp_prefs,
+                                 libssh2_comp_methods());
+        LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len, session->local.lang_prefs,
+                                 NULL);
+        LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs,
+                                 NULL);
+
+        /* No optimistic KEX packet follows */
+        /* Deal with optimistic packets
+         * session->flags |= KEXINIT_OPTIMISTIC
+         * session->flags |= KEXINIT_METHODSMATCH
+         */
+        *(s++) = 0;
+
+        /* Reserved == 0 */
+        *(s++) = 0;
+        *(s++) = 0;
+        *(s++) = 0;
+        *(s++) = 0;
+
+#ifdef LIBSSH2DEBUG
+        {
+            /* Funnily enough, they'll all "appear" to be '\0' terminated */
+            unsigned char *p = data + 21;       /* type(1) + cookie(16) + len(4) */
+
+            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent KEX: %s", p);
+            p += kex_len + 4;
+            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent HOSTKEY: %s", p);
+            p += hostkey_len + 4;
+            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_CS: %s", p);
+            p += crypt_cs_len + 4;
+            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent CRYPT_SC: %s", p);
+            p += crypt_sc_len + 4;
+            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_CS: %s", p);
+            p += mac_cs_len + 4;
+            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent MAC_SC: %s", p);
+            p += mac_sc_len + 4;
+            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_CS: %s", p);
+            p += comp_cs_len + 4;
+            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent COMP_SC: %s", p);
+            p += comp_sc_len + 4;
+            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_CS: %s", p);
+            p += lang_cs_len + 4;
+            _libssh2_debug(session, LIBSSH2_DBG_KEX, "Sent LANG_SC: %s", p);
+            p += lang_sc_len + 4;
+        }
+#endif /* LIBSSH2DEBUG */
+
+        session->kexinit_state = libssh2_NB_state_created;
+    } else {
+        data = session->kexinit_data;
+        data_len = session->kexinit_data_len;
+    }
+
+    if ((rc = libssh2_packet_write(session, data, data_len)) == PACKET_EAGAIN) {
+        session->kexinit_data = data;
+        session->kexinit_data_len = data_len;
+        return PACKET_EAGAIN;
+    } else if (rc) {
+        LIBSSH2_FREE(session, data);
+        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                      "Unable to send KEXINIT packet to remote host", 0);
+        session->kexinit_state = libssh2_NB_state_idle;
+        return -1;
+    }
+
+    if (session->local.kexinit) {
+        LIBSSH2_FREE(session, session->local.kexinit);
+    }
+
+    session->local.kexinit = data;
+    session->local.kexinit_len = data_len;
+
+    session->kexinit_state = libssh2_NB_state_idle;
+
+    return 0;
+}
+
+/* }}}  */
+
+/* {{{ libssh2_kex_agree_instr
+ * Kex specific variant of strstr()
+ * Needle must be preceed by BOL or ',', and followed by ',' or EOL
+ */
+static unsigned char *
+libssh2_kex_agree_instr(unsigned char *haystack, unsigned long haystack_len,
+                        const unsigned char *needle, unsigned long needle_len)
+{
+    unsigned char *s;
+
+    /* Haystack too short to bother trying */
+    if (haystack_len < needle_len) {
+        return NULL;
+    }
+
+    /* Needle at start of haystack */
+    if ((strncmp((char *) haystack, (char *) needle, needle_len) == 0) &&
+        (needle_len == haystack_len || haystack[needle_len] == ',')) {
+        return haystack;
+    }
+
+    s = haystack;
+    /* Search until we run out of comas or we run out of haystack,
+       whichever comes first */
+    while ((s = (unsigned char *) strchr((char *) s, ','))
+           && ((haystack_len - (s - haystack)) > needle_len)) {
+        s++;
+        /* Needle at X position */
+        if ((strncmp((char *) s, (char *) needle, needle_len) == 0) &&
+            (((s - haystack) + needle_len) == haystack_len
+             || s[needle_len] == ',')) {
+            return s;
+        }
+    }
+
+    return NULL;
+}
+
+/* }}} */
+
+/* {{{ libssh2_get_method_by_name
+ */
+static const LIBSSH2_COMMON_METHOD *
+libssh2_get_method_by_name(const char *name, int name_len,
+                           const LIBSSH2_COMMON_METHOD ** methodlist)
+{
+    while (*methodlist) {
+        if ((strlen((*methodlist)->name) == name_len) &&
+            (strncmp((*methodlist)->name, name, name_len) == 0)) {
+            return *methodlist;
+        }
+        methodlist++;
+    }
+    return NULL;
+}
+
+/* }}} */
+
+/* {{{ libssh2_kex_agree_hostkey
+ * Agree on a Hostkey which works with this kex
+ */
+static int
+libssh2_kex_agree_hostkey(LIBSSH2_SESSION * session, unsigned long kex_flags,
+                          unsigned char *hostkey, unsigned long hostkey_len)
+{
+    const LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods();
+    unsigned char *s;
+
+    if (session->hostkey_prefs) {
+        s = (unsigned char *) session->hostkey_prefs;
+
+        while (s && *s) {
+            unsigned char *p = (unsigned char *) strchr((char *) s, ',');
+            int method_len = (p ? (p - s) : strlen((char *) s));
+            if (libssh2_kex_agree_instr(hostkey, hostkey_len, s, method_len)) {
+                const LIBSSH2_HOSTKEY_METHOD *method =
+                    (const LIBSSH2_HOSTKEY_METHOD *)
+                    libssh2_get_method_by_name((char *) s, method_len,
+                                               (const LIBSSH2_COMMON_METHOD **)
+                                               hostkeyp);
+
+                if (!method) {
+                    /* Invalid method -- Should never be reached */
+                    return -1;
+                }
+
+                /* So far so good, but does it suit our purposes? (Encrypting vs Signing) */
+                if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) ==
+                     0) || (method->encrypt)) {
+                    /* Either this hostkey can do encryption or this kex just doesn't require it */
+                    if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY)
+                         == 0) || (method->sig_verify)) {
+                        /* Either this hostkey can do signing or this kex just doesn't require it */
+                        session->hostkey = method;
+                        return 0;
+                    }
+                }
+            }
+
+            s = p ? p + 1 : NULL;
+        }
+        return -1;
+    }
+
+    while (hostkeyp && (*hostkeyp)->name) {
+        s = libssh2_kex_agree_instr(hostkey, hostkey_len,
+                                    (unsigned char *) (*hostkeyp)->name,
+                                    strlen((*hostkeyp)->name));
+        if (s) {
+            /* So far so good, but does it suit our purposes? (Encrypting vs Signing) */
+            if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) == 0) ||
+                ((*hostkeyp)->encrypt)) {
+                /* Either this hostkey can do encryption or this kex just doesn't require it */
+                if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY) ==
+                     0) || ((*hostkeyp)->sig_verify)) {
+                    /* Either this hostkey can do signing or this kex just doesn't require it */
+                    session->hostkey = *hostkeyp;
+                    return 0;
+                }
+            }
+        }
+        hostkeyp++;
+    }
+
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_kex_agree_kex_hostkey
+ * Agree on a Key Exchange method and a hostkey encoding type
+ */
+static int
+libssh2_kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
+                              unsigned long kex_len, unsigned char *hostkey,
+                              unsigned long hostkey_len)
+{
+    const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods;
+    unsigned char *s;
+
+    if (session->kex_prefs) {
+        s = (unsigned char *) session->kex_prefs;
+
+        while (s && *s) {
+            unsigned char *q, *p = (unsigned char *) strchr((char *) s, ',');
+            int method_len = (p ? (p - s) : strlen((char *) s));
+            if ((q = libssh2_kex_agree_instr(kex, kex_len, s, method_len))) {
+                const LIBSSH2_KEX_METHOD *method = (const LIBSSH2_KEX_METHOD *)
+                    libssh2_get_method_by_name((char *) s, method_len,
+                                               (const LIBSSH2_COMMON_METHOD **)
+                                               kexp);
+
+                if (!method) {
+                    /* Invalid method -- Should never be reached */
+                    return -1;
+                }
+
+                /* We've agreed on a key exchange method,
+                 * Can we agree on a hostkey that works with this kex?
+                 */
+                if (libssh2_kex_agree_hostkey
+                    (session, method->flags, hostkey, hostkey_len) == 0) {
+                    session->kex = method;
+                    if (session->burn_optimistic_kexinit && (kex == q)) {
+                        /* Server sent an optimistic packet,
+                         * and client agrees with preference
+                         * cancel burning the first KEX_INIT packet that comes in */
+                        session->burn_optimistic_kexinit = 0;
+                    }
+                    return 0;
+                }
+            }
+
+            s = p ? p + 1 : NULL;
+        }
+        return -1;
+    }
+
+    while (*kexp && (*kexp)->name) {
+        s = libssh2_kex_agree_instr(kex, kex_len,
+                                    (unsigned char *) (*kexp)->name,
+                                    strlen((*kexp)->name));
+        if (s) {
+            /* We've agreed on a key exchange method,
+             * Can we agree on a hostkey that works with this kex?
+             */
+            if (libssh2_kex_agree_hostkey
+                (session, (*kexp)->flags, hostkey, hostkey_len) == 0) {
+                session->kex = *kexp;
+                if (session->burn_optimistic_kexinit && (kex == s)) {
+                    /* Server sent an optimistic packet,
+                     * and client agrees with preference
+                     * cancel burning the first KEX_INIT packet that comes in */
+                    session->burn_optimistic_kexinit = 0;
+                }
+                return 0;
+            }
+        }
+        kexp++;
+    }
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_kex_agree_crypt
+ * Agree on a cipher algo
+ */
+static int
+libssh2_kex_agree_crypt(LIBSSH2_SESSION * session,
+                        libssh2_endpoint_data * endpoint, unsigned char *crypt,
+                        unsigned long crypt_len)
+{
+    const LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods();
+    unsigned char *s;
+
+    (void) session;
+
+    if (endpoint->crypt_prefs) {
+        s = (unsigned char *) endpoint->crypt_prefs;
+
+        while (s && *s) {
+            unsigned char *p = (unsigned char *) strchr((char *) s, ',');
+            int method_len = (p ? (p - s) : strlen((char *) s));
+
+            if (libssh2_kex_agree_instr(crypt, crypt_len, s, method_len)) {
+                const LIBSSH2_CRYPT_METHOD *method =
+                    (const LIBSSH2_CRYPT_METHOD *)
+                    libssh2_get_method_by_name((char *) s, method_len,
+                                               (const LIBSSH2_COMMON_METHOD **)
+                                               cryptp);
+
+                if (!method) {
+                    /* Invalid method -- Should never be reached */
+                    return -1;
+                }
+
+                endpoint->crypt = method;
+                return 0;
+            }
+
+            s = p ? p + 1 : NULL;
+        }
+        return -1;
+    }
+
+    while (*cryptp && (*cryptp)->name) {
+        s = libssh2_kex_agree_instr(crypt, crypt_len,
+                                    (unsigned char *) (*cryptp)->name,
+                                    strlen((*cryptp)->name));
+        if (s) {
+            endpoint->crypt = *cryptp;
+            return 0;
+        }
+        cryptp++;
+    }
+
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_kex_agree_mac
+ * Agree on a message authentication hash
+ */
+static int
+libssh2_kex_agree_mac(LIBSSH2_SESSION * session,
+                      libssh2_endpoint_data * endpoint, unsigned char *mac,
+                      unsigned long mac_len)
+{
+    const LIBSSH2_MAC_METHOD **macp = libssh2_mac_methods();
+    unsigned char *s;
+    (void) session;
+
+    if (endpoint->mac_prefs) {
+        s = (unsigned char *) endpoint->mac_prefs;
+
+        while (s && *s) {
+            unsigned char *p = (unsigned char *) strchr((char *) s, ',');
+            int method_len = (p ? (p - s) : strlen((char *) s));
+
+            if (libssh2_kex_agree_instr(mac, mac_len, s, method_len)) {
+                const LIBSSH2_MAC_METHOD *method = (const LIBSSH2_MAC_METHOD *)
+                    libssh2_get_method_by_name((char *) s, method_len,
+                                               (const LIBSSH2_COMMON_METHOD **)
+                                               macp);
+
+                if (!method) {
+                    /* Invalid method -- Should never be reached */
+                    return -1;
+                }
+
+                endpoint->mac = method;
+                return 0;
+            }
+
+            s = p ? p + 1 : NULL;
+        }
+        return -1;
+    }
+
+    while (*macp && (*macp)->name) {
+        s = libssh2_kex_agree_instr(mac, mac_len,
+                                    (unsigned char *) (*macp)->name,
+                                    strlen((*macp)->name));
+        if (s) {
+            endpoint->mac = *macp;
+            return 0;
+        }
+        macp++;
+    }
+
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_kex_agree_comp
+ * Agree on a compression scheme
+ */
+static int
+libssh2_kex_agree_comp(LIBSSH2_SESSION * session,
+                       libssh2_endpoint_data * endpoint, unsigned char *comp,
+                       unsigned long comp_len)
+{
+    const LIBSSH2_COMP_METHOD **compp = libssh2_comp_methods();
+    unsigned char *s;
+    (void) session;
+
+    if (endpoint->comp_prefs) {
+        s = (unsigned char *) endpoint->comp_prefs;
+
+        while (s && *s) {
+            unsigned char *p = (unsigned char *) strchr((char *) s, ',');
+            int method_len = (p ? (p - s) : strlen((char *) s));
+
+            if (libssh2_kex_agree_instr(comp, comp_len, s, method_len)) {
+                const LIBSSH2_COMP_METHOD *method =
+                    (const LIBSSH2_COMP_METHOD *)
+                    libssh2_get_method_by_name((char *) s, method_len,
+                                               (const LIBSSH2_COMMON_METHOD **)
+                                               compp);
+
+                if (!method) {
+                    /* Invalid method -- Should never be reached */
+                    return -1;
+                }
+
+                endpoint->comp = method;
+                return 0;
+            }
+
+            s = p ? p + 1 : NULL;
+        }
+        return -1;
+    }
+
+    while (*compp && (*compp)->name) {
+        s = libssh2_kex_agree_instr(comp, comp_len,
+                                    (unsigned char *) (*compp)->name,
+                                    strlen((*compp)->name));
+        if (s) {
+            endpoint->comp = *compp;
+            return 0;
+        }
+        compp++;
+    }
+
+    return -1;
+}
+
+/* }}} */
+
+/* TODO: When in server mode we need to turn this logic on its head
+ * The Client gets to make the final call on "agreed methods"
+ */
+
+/* {{{ libssh2_kex_agree_methods
+ * Decide which specific method to use of the methods offered by each party
+ */
+static int
+libssh2_kex_agree_methods(LIBSSH2_SESSION * session, unsigned char *data,
+                          unsigned data_len)
+{
+    unsigned char *kex, *hostkey, *crypt_cs, *crypt_sc, *comp_cs, *comp_sc,
+        *mac_cs, *mac_sc, *lang_cs, *lang_sc;
+    size_t kex_len, hostkey_len, crypt_cs_len, crypt_sc_len, comp_cs_len;
+    size_t comp_sc_len, mac_cs_len, mac_sc_len, lang_cs_len, lang_sc_len;
+    unsigned char *s = data;
+
+    /* Skip packet_type, we know it already */
+    s++;
+
+    /* Skip cookie, don't worry, it's preserved in the kexinit field */
+    s += 16;
+
+    /* Locate each string */
+    kex_len = libssh2_ntohu32(s);
+    kex = s + 4;
+    s += 4 + kex_len;
+    hostkey_len = libssh2_ntohu32(s);
+    hostkey = s + 4;
+    s += 4 + hostkey_len;
+    crypt_cs_len = libssh2_ntohu32(s);
+    crypt_cs = s + 4;
+    s += 4 + crypt_cs_len;
+    crypt_sc_len = libssh2_ntohu32(s);
+    crypt_sc = s + 4;
+    s += 4 + crypt_sc_len;
+    mac_cs_len = libssh2_ntohu32(s);
+    mac_cs = s + 4;
+    s += 4 + mac_cs_len;
+    mac_sc_len = libssh2_ntohu32(s);
+    mac_sc = s + 4;
+    s += 4 + mac_sc_len;
+    comp_cs_len = libssh2_ntohu32(s);
+    comp_cs = s + 4;
+    s += 4 + comp_cs_len;
+    comp_sc_len = libssh2_ntohu32(s);
+    comp_sc = s + 4;
+    s += 4 + comp_sc_len;
+    lang_cs_len = libssh2_ntohu32(s);
+    lang_cs = s + 4;
+    s += 4 + lang_cs_len;
+    lang_sc_len = libssh2_ntohu32(s);
+    lang_sc = s + 4;
+    s += 4 + lang_sc_len;
+
+    /* If the server sent an optimistic packet, assume that it guessed wrong.
+     * If the guess is determined to be right (by libssh2_kex_agree_kex_hostkey)
+     * This flag will be reset to zero so that it's not ignored */
+    session->burn_optimistic_kexinit = *(s++);
+    /* Next uint32 in packet is all zeros (reserved) */
+
+    if (data_len < (unsigned) (s - data))
+        return -1;              /* short packet */
+
+    if (libssh2_kex_agree_kex_hostkey
+        (session, kex, kex_len, hostkey, hostkey_len)) {
+        return -1;
+    }
+
+    if (libssh2_kex_agree_crypt
+        (session, &session->local, crypt_cs, crypt_cs_len)
+        || libssh2_kex_agree_crypt(session, &session->remote, crypt_sc,
+                                   crypt_sc_len)) {
+        return -1;
+    }
+
+    if (libssh2_kex_agree_mac(session, &session->local, mac_cs, mac_cs_len) ||
+        libssh2_kex_agree_mac(session, &session->remote, mac_sc, mac_sc_len)) {
+        return -1;
+    }
+
+    if (libssh2_kex_agree_comp(session, &session->local, comp_cs, comp_cs_len)
+        || libssh2_kex_agree_comp(session, &session->remote, comp_sc,
+                                  comp_sc_len)) {
+        return -1;
+    }
+
+    if (libssh2_kex_agree_lang(session, &session->local, lang_cs, lang_cs_len)
+        || libssh2_kex_agree_lang(session, &session->remote, lang_sc,
+                                  lang_sc_len)) {
+        return -1;
+    }
+
+    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on KEX method: %s",
+                   session->kex->name);
+    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on HOSTKEY method: %s",
+                   session->hostkey->name);
+    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_CS method: %s",
+                   session->local.crypt->name);
+    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_SC method: %s",
+                   session->remote.crypt->name);
+    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_CS method: %s",
+                   session->local.mac->name);
+    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_SC method: %s",
+                   session->remote.mac->name);
+    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_CS method: %s",
+                   session->local.comp->name);
+    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_SC method: %s",
+                   session->remote.comp->name);
+    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_CS method:");      /* None yet */
+    _libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_SC method:");      /* None yet */
+
+    /* Initialize compression layer */
+    if (session->local.comp && session->local.comp->init &&
+        session->local.comp->init(session, 1, &session->local.comp_abstract)) {
+        return -1;
+    }
+
+    if (session->remote.comp && session->remote.comp->init &&
+        session->remote.comp->init(session, 0,
+                                   &session->remote.comp_abstract)) {
+        return -1;
+    }
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_kex_exchange
+ * Exchange keys
+ * Returns 0 on success, non-zero on failure
+ */
+int
+libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, /* session->flags |= SERVER */
+                     key_exchange_state_t * key_state)
+{
+    int rc = 0;
+    int retcode;
+
+    if (key_state->state == libssh2_NB_state_idle) {
+        /* Prevent loop in packet_add() */
+        session->state |= LIBSSH2_STATE_EXCHANGING_KEYS;
+
+        if (reexchange) {
+            session->kex = NULL;
+
+            if (session->hostkey && session->hostkey->dtor) {
+                session->hostkey->dtor(session,
+                                       &session->server_hostkey_abstract);
+            }
+            session->hostkey = NULL;
+        }
+
+        key_state->state = libssh2_NB_state_created;
+    }
+
+    if (!session->kex || !session->hostkey) {
+        if (key_state->state == libssh2_NB_state_created) {
+            /* Preserve in case of failure */
+            key_state->oldlocal = session->local.kexinit;
+            key_state->oldlocal_len = session->local.kexinit_len;
+
+            session->local.kexinit = NULL;
+
+            key_state->state = libssh2_NB_state_sent;
+        }
+
+        if (key_state->state == libssh2_NB_state_sent) {
+            retcode = libssh2_kexinit(session);
+            if (retcode == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            } else if (retcode) {
+                session->local.kexinit = key_state->oldlocal;
+                session->local.kexinit_len = key_state->oldlocal_len;
+                key_state->state = libssh2_NB_state_idle;
+                return -1;
+            }
+
+            key_state->state = libssh2_NB_state_sent1;
+        }
+
+        if (key_state->state == libssh2_NB_state_sent1) {
+            retcode =
+                libssh2_packet_require_ex(session, SSH_MSG_KEXINIT,
+                                          &key_state->data,
+                                          &key_state->data_len, 0, NULL, 0,
+                                          &key_state->req_state);
+            if (retcode == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            } else if (retcode) {
+                if (session->local.kexinit) {
+                    LIBSSH2_FREE(session, session->local.kexinit);
+                }
+                session->local.kexinit = key_state->oldlocal;
+                session->local.kexinit_len = key_state->oldlocal_len;
+                key_state->state = libssh2_NB_state_idle;
+                return -1;
+            }
+
+            if (session->remote.kexinit) {
+                LIBSSH2_FREE(session, session->remote.kexinit);
+            }
+            session->remote.kexinit = key_state->data;
+            session->remote.kexinit_len = key_state->data_len;
+
+            if (libssh2_kex_agree_methods
+                (session, key_state->data, key_state->data_len)) {
+                rc = -1;
+            }
+
+            key_state->state = libssh2_NB_state_sent2;
+        }
+    } else {
+        key_state->state = libssh2_NB_state_sent2;
+    }
+
+    if (rc == 0) {
+        if (key_state->state == libssh2_NB_state_sent2) {
+            retcode =
+                session->kex->exchange_keys(session,
+                                            &key_state->key_state_low);
+            if (retcode == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            } else if (retcode) {
+                libssh2_error(session, LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE,
+                              "Unrecoverable error exchanging keys", 0);
+                rc = -1;
+            }
+        }
+    }
+
+    /* Done with kexinit buffers */
+    if (session->local.kexinit) {
+        LIBSSH2_FREE(session, session->local.kexinit);
+        session->local.kexinit = NULL;
+    }
+    if (session->remote.kexinit) {
+        LIBSSH2_FREE(session, session->remote.kexinit);
+        session->remote.kexinit = NULL;
+    }
+
+    session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
+
+    key_state->state = libssh2_NB_state_idle;
+
+    return rc;
+}
+
+/* }}} */
+
+/* {{{ libssh2_session_method_pref
+ * Set preferred method
+ */
+LIBSSH2_API int
+libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type,
+                            const char *prefs)
+{
+    char **prefvar, *s, *newprefs;
+    int prefs_len = strlen(prefs);
+    const LIBSSH2_COMMON_METHOD **mlist;
+
+    switch (method_type) {
+    case LIBSSH2_METHOD_KEX:
+        prefvar = &session->kex_prefs;
+        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods;
+        break;
+
+    case LIBSSH2_METHOD_HOSTKEY:
+        prefvar = &session->hostkey_prefs;
+        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods();
+        break;
+
+    case LIBSSH2_METHOD_CRYPT_CS:
+        prefvar = &session->local.crypt_prefs;
+        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods();
+        break;
+
+    case LIBSSH2_METHOD_CRYPT_SC:
+        prefvar = &session->remote.crypt_prefs;
+        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods();
+        break;
+
+    case LIBSSH2_METHOD_MAC_CS:
+        prefvar = &session->local.mac_prefs;
+        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_mac_methods();
+        break;
+
+    case LIBSSH2_METHOD_MAC_SC:
+        prefvar = &session->remote.mac_prefs;
+        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_mac_methods();
+        break;
+
+    case LIBSSH2_METHOD_COMP_CS:
+        prefvar = &session->local.comp_prefs;
+        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_comp_methods();
+        break;
+
+    case LIBSSH2_METHOD_COMP_SC:
+        prefvar = &session->remote.comp_prefs;
+        mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_comp_methods();
+        break;
+
+    case LIBSSH2_METHOD_LANG_CS:
+        prefvar = &session->local.lang_prefs;
+        mlist = NULL;
+        break;
+
+    case LIBSSH2_METHOD_LANG_SC:
+        prefvar = &session->remote.lang_prefs;
+        mlist = NULL;
+        break;
+
+    default:
+        libssh2_error(session, LIBSSH2_ERROR_INVAL,
+                      "Invalid parameter specified for method_type", 0);
+        return -1;
+    }
+
+    s = newprefs = LIBSSH2_ALLOC(session, prefs_len + 1);
+    if (!newprefs) {
+        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                      "Error allocated space for method preferences", 0);
+        return -1;
+    }
+    memcpy(s, prefs, prefs_len + 1);
+
+    while (s && *s) {
+        char *p = strchr(s, ',');
+        int method_len = p ? (p - s) : (int) strlen(s);
+
+        if (!libssh2_get_method_by_name(s, method_len, mlist)) {
+            /* Strip out unsupported method */
+            if (p) {
+                memcpy(s, p + 1, strlen(s) - method_len);
+            } else {
+                if (s > newprefs) {
+                    *(--s) = '\0';
+                } else {
+                    *s = '\0';
+                }
+            }
+        }
+
+        s = p ? (p + 1) : NULL;
+    }
+
+    if (strlen(newprefs) == 0) {
+        libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
+                      "The requested method(s) are not currently supported",
+                      0);
+        LIBSSH2_FREE(session, newprefs);
+        return -1;
+    }
+
+    if (*prefvar) {
+        LIBSSH2_FREE(session, *prefvar);
+    }
+    *prefvar = newprefs;
+
+    return 0;
+}
+
+/* }}} */
diff --git a/Vendor/libssh2/Source/mac.c b/Vendor/libssh2/Source/mac.c
new file mode 100644 (file)
index 0000000..ed924d7
--- /dev/null
@@ -0,0 +1,311 @@
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+
+#ifdef LIBSSH2_MAC_NONE
+/* {{{ libssh2_mac_none_MAC
+ * Minimalist MAC: No MAC
+ */
+static int
+libssh2_mac_none_MAC(LIBSSH2_SESSION * session, unsigned char *buf,
+                     unsigned long seqno, const unsigned char *packet,
+                     unsigned long packet_len, const unsigned char *addtl,
+                     unsigned long addtl_len, void **abstract)
+{
+    return 0;
+}
+
+/* }}} */
+
+
+static LIBSSH2_MAC_METHOD libssh2_mac_method_none = {
+    "none",
+    0,
+    0,
+    NULL,
+    libssh2_mac_none_MAC,
+    NULL
+};
+#endif /* LIBSSH2_MAC_NONE */
+
+/* {{{ libssh2_mac_method_common_init
+ * Initialize simple mac methods
+ */
+static int
+libssh2_mac_method_common_init(LIBSSH2_SESSION * session, unsigned char *key,
+                               int *free_key, void **abstract)
+{
+    *abstract = key;
+    *free_key = 0;
+    (void) session;
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_mac_method_common_dtor
+ * Cleanup simple mac methods
+ */
+static int
+libssh2_mac_method_common_dtor(LIBSSH2_SESSION * session, void **abstract)
+{
+    if (*abstract) {
+        LIBSSH2_FREE(session, *abstract);
+    }
+    *abstract = NULL;
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_mac_method_hmac_sha1_hash
+ * Calculate hash using full sha1 value
+ */
+static int
+libssh2_mac_method_hmac_sha1_hash(LIBSSH2_SESSION * session,
+                                  unsigned char *buf, unsigned long seqno,
+                                  const unsigned char *packet,
+                                  unsigned long packet_len,
+                                  const unsigned char *addtl,
+                                  unsigned long addtl_len, void **abstract)
+{
+    libssh2_hmac_ctx ctx;
+    unsigned char seqno_buf[4];
+    (void) session;
+
+    libssh2_htonu32(seqno_buf, seqno);
+
+    libssh2_hmac_sha1_init(&ctx, *abstract, 20);
+    libssh2_hmac_update(ctx, seqno_buf, 4);
+    libssh2_hmac_update(ctx, packet, packet_len);
+    if (addtl && addtl_len) {
+        libssh2_hmac_update(ctx, addtl, addtl_len);
+    }
+    libssh2_hmac_final(ctx, buf);
+    libssh2_hmac_cleanup(&ctx);
+
+    return 0;
+}
+
+/* }}} */
+
+static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1 = {
+    "hmac-sha1",
+    20,
+    20,
+    libssh2_mac_method_common_init,
+    libssh2_mac_method_hmac_sha1_hash,
+    libssh2_mac_method_common_dtor,
+};
+
+/* {{{ libssh2_mac_method_hmac_sha1_96_hash
+ * Calculate hash using first 96 bits of sha1 value
+ */
+static int
+libssh2_mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION * session,
+                                     unsigned char *buf, unsigned long seqno,
+                                     const unsigned char *packet,
+                                     unsigned long packet_len,
+                                     const unsigned char *addtl,
+                                     unsigned long addtl_len, void **abstract)
+{
+    unsigned char temp[SHA_DIGEST_LENGTH];
+
+    libssh2_mac_method_hmac_sha1_hash(session, temp, seqno, packet, packet_len,
+                                      addtl, addtl_len, abstract);
+    memcpy(buf, (char *) temp, 96 / 8);
+
+    return 0;
+}
+
+/* }}} */
+
+static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1_96 = {
+    "hmac-sha1-96",
+    12,
+    20,
+    libssh2_mac_method_common_init,
+    libssh2_mac_method_hmac_sha1_96_hash,
+    libssh2_mac_method_common_dtor,
+};
+
+/* {{{ libssh2_mac_method_hmac_md5_hash
+ * Calculate hash using full md5 value
+ */
+static int
+libssh2_mac_method_hmac_md5_hash(LIBSSH2_SESSION * session, unsigned char *buf,
+                                 unsigned long seqno,
+                                 const unsigned char *packet,
+                                 unsigned long packet_len,
+                                 const unsigned char *addtl,
+                                 unsigned long addtl_len, void **abstract)
+{
+    libssh2_hmac_ctx ctx;
+    unsigned char seqno_buf[4];
+    (void) session;
+
+    libssh2_htonu32(seqno_buf, seqno);
+
+    libssh2_hmac_md5_init(&ctx, *abstract, 16);
+    libssh2_hmac_update(ctx, seqno_buf, 4);
+    libssh2_hmac_update(ctx, packet, packet_len);
+    if (addtl && addtl_len) {
+        libssh2_hmac_update(ctx, addtl, addtl_len);
+    }
+    libssh2_hmac_final(ctx, buf);
+    libssh2_hmac_cleanup(&ctx);
+
+    return 0;
+}
+
+/* }}} */
+
+static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5 = {
+    "hmac-md5",
+    16,
+    16,
+    libssh2_mac_method_common_init,
+    libssh2_mac_method_hmac_md5_hash,
+    libssh2_mac_method_common_dtor,
+};
+
+/* {{{ libssh2_mac_method_hmac_md5_96_hash
+ * Calculate hash using first 96 bits of md5 value
+ */
+static int
+libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION * session,
+                                    unsigned char *buf, unsigned long seqno,
+                                    const unsigned char *packet,
+                                    unsigned long packet_len,
+                                    const unsigned char *addtl,
+                                    unsigned long addtl_len, void **abstract)
+{
+    unsigned char temp[MD5_DIGEST_LENGTH];
+
+    libssh2_mac_method_hmac_md5_hash(session, temp, seqno, packet, packet_len,
+                                     addtl, addtl_len, abstract);
+    memcpy(buf, (char *) temp, 96 / 8);
+
+    return 0;
+}
+
+/* }}} */
+
+static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5_96 = {
+    "hmac-md5-96",
+    12,
+    16,
+    libssh2_mac_method_common_init,
+    libssh2_mac_method_hmac_md5_96_hash,
+    libssh2_mac_method_common_dtor,
+};
+
+#if LIBSSH2_HMAC_RIPEMD
+/* {{{ libssh2_mac_method_hmac_ripemd160_hash
+ * Calculate hash using ripemd160 value
+ */
+static int
+libssh2_mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION * session,
+                                       unsigned char *buf, unsigned long seqno,
+                                       const unsigned char *packet,
+                                       unsigned long packet_len,
+                                       const unsigned char *addtl,
+                                       unsigned long addtl_len,
+                                       void **abstract)
+{
+    libssh2_hmac_ctx ctx;
+    unsigned char seqno_buf[4];
+    (void) session;
+
+    libssh2_htonu32(seqno_buf, seqno);
+
+    libssh2_hmac_ripemd160_init(&ctx, *abstract, 20);
+    libssh2_hmac_update(ctx, seqno_buf, 4);
+    libssh2_hmac_update(ctx, packet, packet_len);
+    if (addtl && addtl_len) {
+        libssh2_hmac_update(ctx, addtl, addtl_len);
+    }
+    libssh2_hmac_final(ctx, buf);
+    libssh2_hmac_cleanup(&ctx);
+
+    return 0;
+}
+
+/* }}} */
+
+static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160 = {
+    "hmac-ripemd160",
+    20,
+    20,
+    libssh2_mac_method_common_init,
+    libssh2_mac_method_hmac_ripemd160_hash,
+    libssh2_mac_method_common_dtor,
+};
+
+static const LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160_openssh_com = {
+    "hmac-ripemd160@openssh.com",
+    20,
+    20,
+    libssh2_mac_method_common_init,
+    libssh2_mac_method_hmac_ripemd160_hash,
+    libssh2_mac_method_common_dtor,
+};
+#endif /* LIBSSH2_HMAC_RIPEMD */
+
+static const LIBSSH2_MAC_METHOD *_libssh2_mac_methods[] = {
+    &libssh2_mac_method_hmac_sha1,
+    &libssh2_mac_method_hmac_sha1_96,
+    &libssh2_mac_method_hmac_md5,
+    &libssh2_mac_method_hmac_md5_96,
+#ifdef LIBSSH2_HMAC_RIPEMD
+    &libssh2_mac_method_hmac_ripemd160,
+    &libssh2_mac_method_hmac_ripemd160_openssh_com,
+#endif /* LIBSSH2_HMAC_RIPEMD */
+#ifdef LIBSSH2_MAC_NONE
+    &libssh2_mac_method_none,
+#endif /* LIBSSH2_MAC_NONE */
+    NULL
+};
+
+const LIBSSH2_MAC_METHOD **
+libssh2_mac_methods(void)
+{
+    return _libssh2_mac_methods;
+}
diff --git a/Vendor/libssh2/Source/misc.c b/Vendor/libssh2/Source/misc.c
new file mode 100644 (file)
index 0000000..05f6329
--- /dev/null
@@ -0,0 +1,241 @@
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* {{{ libssh2_ntohu32
+ */
+unsigned long
+libssh2_ntohu32(const unsigned char *buf)
+{
+    return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+}
+
+/* }}} */
+
+/* {{{ libssh2_ntohu64
+ * Note: Some 32-bit platforms have issues with bitops on long longs
+ * Work around this by doing expensive (but safer) arithmetic ops with optimization defying parentheses
+ */
+libssh2_uint64_t
+libssh2_ntohu64(const unsigned char *buf)
+{
+    unsigned long msl, lsl;
+
+    msl = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+    lsl = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
+
+    return ((msl * 65536) * 65536) + lsl;
+}
+
+/* }}} */
+
+/* {{{ libssh2_htonu32
+ */
+void
+libssh2_htonu32(unsigned char *buf, unsigned long value)
+{
+    buf[0] = (value >> 24) & 0xFF;
+    buf[1] = (value >> 16) & 0xFF;
+    buf[2] = (value >> 8) & 0xFF;
+    buf[3] = value & 0xFF;
+}
+
+/* }}} */
+
+/* {{{ libssh2_htonu64
+ */
+void
+libssh2_htonu64(unsigned char *buf, libssh2_uint64_t value)
+{
+    unsigned long msl = (value / 65536) / 65536;
+
+    buf[0] = (msl >> 24) & 0xFF;
+    buf[1] = (msl >> 16) & 0xFF;
+    buf[2] = (msl >> 8) & 0xFF;
+    buf[3] = msl & 0xFF;
+
+    buf[4] = (value >> 24) & 0xFF;
+    buf[5] = (value >> 16) & 0xFF;
+    buf[6] = (value >> 8) & 0xFF;
+    buf[7] = value & 0xFF;
+}
+
+/* }}} */
+
+/* Base64 Conversion */
+
+/* {{{ */
+static const char libssh2_base64_table[] =
+    { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
+};
+
+static const char libssh2_base64_pad = '=';
+
+static const short libssh2_base64_reverse_table[256] = {
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+    -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+/* }}} */
+
+
+/* {{{ libssh2_base64_decode
+ * Decode a base64 chunk and store it into a newly alloc'd buffer
+ */
+LIBSSH2_API int
+libssh2_base64_decode(LIBSSH2_SESSION * session, char **data,
+                      unsigned int *datalen, const char *src,
+                      unsigned int src_len)
+{
+    unsigned char *s, *d;
+    short v;
+    int i = 0, len = 0;
+
+    *data = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1);
+    d = (unsigned char *) *data;
+    if (!d) {
+        return -1;
+    }
+
+    for(s = (unsigned char *) src; ((char *) s) < (src + src_len); s++) {
+        if ((v = libssh2_base64_reverse_table[*s]) < 0)
+            continue;
+        switch (i % 4) {
+        case 0:
+            d[len] = v << 2;
+            break;
+        case 1:
+            d[len++] |= v >> 4;
+            d[len] = v << 4;
+            break;
+        case 2:
+            d[len++] |= v >> 2;
+            d[len] = v << 6;
+            break;
+        case 3:
+            d[len++] |= v;
+            break;
+        }
+        i++;
+    }
+    if ((i % 4) == 1) {
+        /* Invalid -- We have a byte which belongs exclusively to a partial octet */
+        LIBSSH2_FREE(session, *data);
+        return -1;
+    }
+
+    *datalen = len;
+    return 0;
+}
+
+/* }}} */
+
+#ifdef LIBSSH2DEBUG
+LIBSSH2_API int
+libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
+{
+    session->showmask = bitmask;
+    return 0;
+}
+
+void
+_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
+{
+    char buffer[1536];
+    int len;
+    va_list vargs;
+    static const char *const contexts[9] = {
+        "Unknown",
+        "Transport",
+        "Key Exchange",
+        "Userauth",
+        "Connection",
+        "scp",
+        "SFTP Subsystem",
+        "Failure Event",
+        "Publickey Subsystem",
+    };
+
+    if (context < 1 || context > 8) {
+        context = 0;
+    }
+    if (!(session->showmask & (1 << context))) {
+        /* no such output asked for */
+        return;
+    }
+
+    len = snprintf(buffer, 1535, "[libssh2] %s: ", contexts[context]);
+
+    va_start(vargs, format);
+    len += vsnprintf(buffer + len, 1535 - len, format, vargs);
+    buffer[len] = '\n';
+    va_end(vargs);
+    write(2, buffer, len + 1);
+
+}
+
+#else
+LIBSSH2_API int
+libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
+{
+    (void) session;
+    (void) bitmask;
+    return 0;
+}
+#endif
diff --git a/Vendor/libssh2/Source/openssl.c b/Vendor/libssh2/Source/openssl.c
new file mode 100644 (file)
index 0000000..87e86dd
--- /dev/null
@@ -0,0 +1,316 @@
+/* Copyright (C) 2006, 2007 The Written Word, Inc.  All rights reserved.
+ * Author: Simon Josefsson
+ * Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+#include <string.h>
+
+#ifndef EVP_MAX_BLOCK_LENGTH
+#define EVP_MAX_BLOCK_LENGTH 32
+#endif
+
+int
+_libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
+                 const unsigned char *edata,
+                 unsigned long elen,
+                 const unsigned char *ndata,
+                 unsigned long nlen,
+                 const unsigned char *ddata,
+                 unsigned long dlen,
+                 const unsigned char *pdata,
+                 unsigned long plen,
+                 const unsigned char *qdata,
+                 unsigned long qlen,
+                 const unsigned char *e1data,
+                 unsigned long e1len,
+                 const unsigned char *e2data,
+                 unsigned long e2len,
+                 const unsigned char *coeffdata, unsigned long coefflen)
+{
+    *rsa = RSA_new();
+
+    (*rsa)->e = BN_new();
+    BN_bin2bn(edata, elen, (*rsa)->e);
+
+    (*rsa)->n = BN_new();
+    BN_bin2bn(ndata, nlen, (*rsa)->n);
+
+    if (ddata) {
+        (*rsa)->d = BN_new();
+        BN_bin2bn(ddata, dlen, (*rsa)->d);
+
+        (*rsa)->p = BN_new();
+        BN_bin2bn(pdata, plen, (*rsa)->p);
+
+        (*rsa)->q = BN_new();
+        BN_bin2bn(qdata, qlen, (*rsa)->q);
+
+        (*rsa)->dmp1 = BN_new();
+        BN_bin2bn(e1data, e1len, (*rsa)->dmp1);
+
+        (*rsa)->dmq1 = BN_new();
+        BN_bin2bn(e2data, e2len, (*rsa)->dmq1);
+
+        (*rsa)->iqmp = BN_new();
+        BN_bin2bn(coeffdata, coefflen, (*rsa)->iqmp);
+    }
+    return 0;
+}
+
+int
+_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx,
+                         const unsigned char *sig,
+                         unsigned long sig_len,
+                         const unsigned char *m, unsigned long m_len)
+{
+    unsigned char hash[SHA_DIGEST_LENGTH];
+    int ret;
+
+    SHA1(m, m_len, hash);
+    ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
+                     (unsigned char *) sig, sig_len, rsactx);
+    return (ret == 1) ? 0 : -1;
+}
+
+int
+_libssh2_dsa_new(libssh2_dsa_ctx ** dsactx,
+                 const unsigned char *p,
+                 unsigned long p_len,
+                 const unsigned char *q,
+                 unsigned long q_len,
+                 const unsigned char *g,
+                 unsigned long g_len,
+                 const unsigned char *y,
+                 unsigned long y_len,
+                 const unsigned char *x, unsigned long x_len)
+{
+    *dsactx = DSA_new();
+
+    (*dsactx)->p = BN_new();
+    BN_bin2bn(p, p_len, (*dsactx)->p);
+
+    (*dsactx)->q = BN_new();
+    BN_bin2bn(q, q_len, (*dsactx)->q);
+
+    (*dsactx)->g = BN_new();
+    BN_bin2bn(g, g_len, (*dsactx)->g);
+
+    (*dsactx)->pub_key = BN_new();
+    BN_bin2bn(y, y_len, (*dsactx)->pub_key);
+
+    if (x_len) {
+        (*dsactx)->priv_key = BN_new();
+        BN_bin2bn(x, x_len, (*dsactx)->priv_key);
+    }
+
+    return 0;
+}
+
+int
+_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
+                         const unsigned char *sig,
+                         const unsigned char *m, unsigned long m_len)
+{
+    unsigned char hash[SHA_DIGEST_LENGTH];
+    DSA_SIG dsasig;
+    int ret;
+
+    dsasig.r = BN_new();
+    BN_bin2bn(sig, 20, dsasig.r);
+    dsasig.s = BN_new();
+    BN_bin2bn(sig + 20, 20, dsasig.s);
+
+    libssh2_sha1(m, m_len, hash);
+    ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, &dsasig, dsactx);
+    BN_clear_free(dsasig.s);
+    BN_clear_free(dsasig.r);
+
+    return (ret == 1) ? 0 : -1;
+}
+
+int
+_libssh2_cipher_init(_libssh2_cipher_ctx * h,
+                     _libssh2_cipher_type(algo),
+                     unsigned char *iv, unsigned char *secret, int encrypt)
+{
+    EVP_CIPHER_CTX_init(h);
+    EVP_CipherInit(h, algo(), secret, iv, encrypt);
+    return 0;
+}
+
+int
+_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
+                      _libssh2_cipher_type(algo),
+                      int encrypt, unsigned char *block)
+{
+    int blocksize = ctx->cipher->block_size;
+    unsigned char buf[EVP_MAX_BLOCK_LENGTH];
+    int ret;
+    (void) algo;
+    (void) encrypt;
+
+    if (blocksize == 1) {
+/* Hack for arcfour. */
+        blocksize = 8;
+    }
+    ret = EVP_Cipher(ctx, buf, block, blocksize);
+    if (ret == 1) {
+        memcpy(block, buf, blocksize);
+    }
+    return ret == 1 ? 0 : 1;
+}
+
+/* TODO: Optionally call a passphrase callback specified by the
+ * calling program
+ */
+static int
+passphrase_cb(char *buf, int size, int rwflag, char *passphrase)
+{
+    int passphrase_len = strlen(passphrase);
+    (void) rwflag;
+
+    if (passphrase_len > (size - 1)) {
+        passphrase_len = size - 1;
+    }
+    memcpy(buf, passphrase, passphrase_len);
+    buf[passphrase_len] = '\0';
+
+    return passphrase_len;
+}
+
+int
+_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
+                         LIBSSH2_SESSION * session,
+                         FILE * fp, unsigned const char *passphrase)
+{
+    (void) session;
+    if (!EVP_get_cipherbyname("des")) {
+/* If this cipher isn't loaded it's a pretty good indication that none are.
+ * I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
+ * Someone buy me an OpenSSL manual and I'll read up on it.
+ */
+        OpenSSL_add_all_ciphers();
+    }
+    *rsa = PEM_read_RSAPrivateKey(fp, NULL, (void *) passphrase_cb,
+                                  (void *) passphrase);
+    if (!*rsa) {
+        return -1;
+    }
+    return 0;
+}
+
+int
+_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
+                         LIBSSH2_SESSION * session,
+                         FILE * fp, unsigned const char *passphrase)
+{
+    (void) session;
+    if (!EVP_get_cipherbyname("des")) {
+/* If this cipher isn't loaded it's a pretty good indication that none are.
+ * I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
+ * Someone buy me an OpenSSL manual and I'll read up on it.
+ */
+        OpenSSL_add_all_ciphers();
+    }
+    *dsa = PEM_read_DSAPrivateKey(fp, NULL, (void *) passphrase_cb,
+                                  (void *) passphrase);
+    if (!*dsa) {
+        return -1;
+    }
+    return 0;
+}
+
+int
+_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
+                       libssh2_rsa_ctx * rsactx,
+                       const unsigned char *hash,
+                       unsigned long hash_len,
+                       unsigned char **signature, unsigned long *signature_len)
+{
+    int ret;
+    unsigned char *sig;
+    unsigned int sig_len;
+
+    sig_len = RSA_size(rsactx);
+    sig = LIBSSH2_ALLOC(session, sig_len);
+
+    if (!sig) {
+        return -1;
+    }
+
+    ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx);
+
+    if (!ret) {
+        LIBSSH2_FREE(session, sig);
+        return -1;
+    }
+
+    *signature = sig;
+    *signature_len = sig_len;
+
+    return 0;
+}
+
+int
+_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
+                       const unsigned char *hash,
+                       unsigned long hash_len, unsigned char *signature)
+{
+    DSA_SIG *sig;
+    int r_len, s_len, rs_pad;
+    (void) hash_len;
+
+    sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
+    if (!sig) {
+        return -1;
+    }
+
+    r_len = BN_num_bytes(sig->r);
+    s_len = BN_num_bytes(sig->s);
+    rs_pad = (2 * SHA_DIGEST_LENGTH) - (r_len + s_len);
+    if (rs_pad < 0) {
+        DSA_SIG_free(sig);
+        return -1;
+    }
+
+    BN_bn2bin(sig->r, signature + rs_pad);
+    BN_bn2bin(sig->s, signature + rs_pad + r_len);
+
+    DSA_SIG_free(sig);
+
+    return 0;
+}
diff --git a/Vendor/libssh2/Source/packet.c b/Vendor/libssh2/Source/packet.c
new file mode 100644 (file)
index 0000000..fd17186
--- /dev/null
@@ -0,0 +1,1244 @@
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+/* Needed for struct iovec on some platforms */
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#include <sys/types.h>
+
+/* {{{ libssh2_packet_queue_listener
+ * Queue a connection request for a listener
+ */
+static inline int
+libssh2_packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
+                              unsigned long datalen,
+                              packet_queue_listener_state_t * listen_state)
+{
+    /*
+     * Look for a matching listener
+     */
+    unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5;
+    /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
+    unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1);
+    unsigned char *p;
+    LIBSSH2_LISTENER *listen = session->listeners;
+    char failure_code = 1;      /* SSH_OPEN_ADMINISTRATIVELY_PROHIBITED */
+    int rc;
+
+    (void) datalen;
+
+    if (listen_state->state == libssh2_NB_state_idle) {
+        listen_state->sender_channel = libssh2_ntohu32(s);
+        s += 4;
+
+        listen_state->initial_window_size = libssh2_ntohu32(s);
+        s += 4;
+        listen_state->packet_size = libssh2_ntohu32(s);
+        s += 4;
+
+        listen_state->host_len = libssh2_ntohu32(s);
+        s += 4;
+        listen_state->host = s;
+        s += listen_state->host_len;
+        listen_state->port = libssh2_ntohu32(s);
+        s += 4;
+
+        listen_state->shost_len = libssh2_ntohu32(s);
+        s += 4;
+        listen_state->shost = s;
+        s += listen_state->shost_len;
+        listen_state->sport = libssh2_ntohu32(s);
+        s += 4;
+
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "Remote received connection from %s:%ld to %s:%ld",
+                       listen_state->shost, listen_state->sport,
+                       listen_state->host, listen_state->port);
+
+        listen_state->state = libssh2_NB_state_allocated;
+    }
+
+    if (listen_state->state != libssh2_NB_state_sent) {
+        while (listen) {
+            if ((listen->port == (int) listen_state->port) &&
+                (strlen(listen->host) == listen_state->host_len) &&
+                (memcmp
+                 (listen->host, listen_state->host,
+                  listen_state->host_len) == 0)) {
+                /* This is our listener */
+                LIBSSH2_CHANNEL *channel, *last_queued = listen->queue;
+
+                last_queued = listen->queue;
+                if (listen_state->state == libssh2_NB_state_allocated) {
+                    if (listen->queue_maxsize &&
+                        (listen->queue_maxsize <= listen->queue_size)) {
+                        /* Queue is full */
+                        failure_code = 4;       /* SSH_OPEN_RESOURCE_SHORTAGE */
+                        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                                       "Listener queue full, ignoring");
+                        listen_state->state = libssh2_NB_state_sent;
+                        break;
+                    }
+
+                    channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
+                    if (!channel) {
+                        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                                      "Unable to allocate a channel for new connection",
+                                      0);
+                        failure_code = 4;       /* SSH_OPEN_RESOURCE_SHORTAGE */
+                        listen_state->state = libssh2_NB_state_sent;
+                        break;
+                    }
+                    memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
+
+                    channel->session = session;
+                    channel->channel_type_len = sizeof("forwarded-tcpip") - 1;
+                    channel->channel_type = LIBSSH2_ALLOC(session,
+                                                          channel->
+                                                          channel_type_len +
+                                                          1);
+                    if (!channel->channel_type) {
+                        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                                      "Unable to allocate a channel for new connection",
+                                      0);
+                        LIBSSH2_FREE(session, channel);
+                        failure_code = 4;       /* SSH_OPEN_RESOURCE_SHORTAGE */
+                        listen_state->state = libssh2_NB_state_sent;
+                        break;
+                    }
+                    memcpy(channel->channel_type, "forwarded-tcpip",
+                           channel->channel_type_len + 1);
+
+                    channel->remote.id = listen_state->sender_channel;
+                    channel->remote.window_size_initial =
+                        LIBSSH2_CHANNEL_WINDOW_DEFAULT;
+                    channel->remote.window_size =
+                        LIBSSH2_CHANNEL_WINDOW_DEFAULT;
+                    channel->remote.packet_size =
+                        LIBSSH2_CHANNEL_PACKET_DEFAULT;
+
+                    channel->local.id = libssh2_channel_nextid(session);
+                    channel->local.window_size_initial =
+                        listen_state->initial_window_size;
+                    channel->local.window_size =
+                        listen_state->initial_window_size;
+                    channel->local.packet_size = listen_state->packet_size;
+
+                    _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                                   "Connection queued: channel %lu/%lu win %lu/%lu packet %lu/%lu",
+                                   channel->local.id, channel->remote.id,
+                                   channel->local.window_size,
+                                   channel->remote.window_size,
+                                   channel->local.packet_size,
+                                   channel->remote.packet_size);
+
+                    p = listen_state->packet;
+                    *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
+                    libssh2_htonu32(p, channel->remote.id);
+                    p += 4;
+                    libssh2_htonu32(p, channel->local.id);
+                    p += 4;
+                    libssh2_htonu32(p, channel->remote.window_size_initial);
+                    p += 4;
+                    libssh2_htonu32(p, channel->remote.packet_size);
+                    p += 4;
+
+                    listen_state->state = libssh2_NB_state_created;
+                }
+
+                if (listen_state->state == libssh2_NB_state_created) {
+                    rc = libssh2_packet_write(session, listen_state->packet,
+                                              17);
+                    if (rc == PACKET_EAGAIN) {
+                        return PACKET_EAGAIN;
+                    } else if (rc) {
+                        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                                      "Unable to send channel open confirmation",
+                                      0);
+                        listen_state->state = libssh2_NB_state_idle;
+                        return -1;
+                    }
+
+                    /* Link the channel into the end of the queue list */
+
+                    if (!last_queued) {
+                        listen->queue = channel;
+                        listen_state->state = libssh2_NB_state_idle;
+                        return 0;
+                    }
+
+                    while (last_queued->next) {
+                        last_queued = last_queued->next;
+                    }
+
+                    last_queued->next = channel;
+                    channel->prev = last_queued;
+
+                    listen->queue_size++;
+
+                    listen_state->state = libssh2_NB_state_idle;
+                    return 0;
+                }
+            }
+
+            listen = listen->next;
+        }
+
+        listen_state->state = libssh2_NB_state_sent;
+    }
+
+    /* We're not listening to you */
+    {
+        p = listen_state->packet;
+        *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
+        libssh2_htonu32(p, listen_state->sender_channel);
+        p += 4;
+        libssh2_htonu32(p, failure_code);
+        p += 4;
+        libssh2_htonu32(p, sizeof(FwdNotReq) - 1);
+        p += 4;
+        memcpy(s, FwdNotReq, sizeof(FwdNotReq) - 1);
+        p += sizeof(FwdNotReq) - 1;
+        libssh2_htonu32(p, 0);
+
+        rc = libssh2_packet_write(session, listen_state->packet, packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send open failure", 0);
+            listen_state->state = libssh2_NB_state_idle;
+            return -1;
+        }
+        listen_state->state = libssh2_NB_state_idle;
+        return 0;
+    }
+}
+
+/* }}} */
+
+/* {{{ libssh2_packet_x11_open
+ * Accept a forwarded X11 connection
+ */
+static inline int
+libssh2_packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
+                        unsigned long datalen,
+                        packet_x11_open_state_t * x11open_state)
+{
+    int failure_code = 2;       /* SSH_OPEN_CONNECT_FAILED */
+    unsigned char *s = data + (sizeof("x11") - 1) + 5;
+    /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
+    unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1);
+    unsigned char *p;
+    LIBSSH2_CHANNEL *channel;
+    int rc;
+
+    (void) datalen;
+
+    if (x11open_state->state == libssh2_NB_state_idle) {
+        x11open_state->sender_channel = libssh2_ntohu32(s);
+        s += 4;
+        x11open_state->initial_window_size = libssh2_ntohu32(s);
+        s += 4;
+        x11open_state->packet_size = libssh2_ntohu32(s);
+        s += 4;
+        x11open_state->shost_len = libssh2_ntohu32(s);
+        s += 4;
+        x11open_state->shost = s;
+        s += x11open_state->shost_len;
+        x11open_state->sport = libssh2_ntohu32(s);
+        s += 4;
+
+        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                       "X11 Connection Received from %s:%ld on channel %lu",
+                       x11open_state->shost, x11open_state->sport,
+                       x11open_state->sender_channel);
+
+        x11open_state->state = libssh2_NB_state_allocated;
+    }
+
+    if (session->x11) {
+        if (x11open_state->state == libssh2_NB_state_allocated) {
+            channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
+            if (!channel) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                              "Unable to allocate a channel for new connection",
+                              0);
+                failure_code = 4;       /* SSH_OPEN_RESOURCE_SHORTAGE */
+                goto x11_exit;
+            }
+            memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
+
+            channel->session = session;
+            channel->channel_type_len = sizeof("x11") - 1;
+            channel->channel_type = LIBSSH2_ALLOC(session,
+                                                  channel->channel_type_len +
+                                                  1);
+            if (!channel->channel_type) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                              "Unable to allocate a channel for new connection",
+                              0);
+                LIBSSH2_FREE(session, channel);
+                failure_code = 4;       /* SSH_OPEN_RESOURCE_SHORTAGE */
+                goto x11_exit;
+            }
+            memcpy(channel->channel_type, "x11",
+                   channel->channel_type_len + 1);
+
+            channel->remote.id = x11open_state->sender_channel;
+            channel->remote.window_size_initial =
+                LIBSSH2_CHANNEL_WINDOW_DEFAULT;
+            channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
+            channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT;
+
+            channel->local.id = libssh2_channel_nextid(session);
+            channel->local.window_size_initial =
+                x11open_state->initial_window_size;
+            channel->local.window_size = x11open_state->initial_window_size;
+            channel->local.packet_size = x11open_state->packet_size;
+
+            _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                           "X11 Connection established: channel %lu/%lu win %lu/%lu packet %lu/%lu",
+                           channel->local.id, channel->remote.id,
+                           channel->local.window_size,
+                           channel->remote.window_size,
+                           channel->local.packet_size,
+                           channel->remote.packet_size);
+            p = x11open_state->packet;
+            *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
+            libssh2_htonu32(p, channel->remote.id);
+            p += 4;
+            libssh2_htonu32(p, channel->local.id);
+            p += 4;
+            libssh2_htonu32(p, channel->remote.window_size_initial);
+            p += 4;
+            libssh2_htonu32(p, channel->remote.packet_size);
+            p += 4;
+
+            x11open_state->state = libssh2_NB_state_created;
+        }
+
+        if (x11open_state->state == libssh2_NB_state_created) {
+            rc = libssh2_packet_write(session, x11open_state->packet, 17);
+            if (rc == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            } else if (rc) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                              "Unable to send channel open confirmation", 0);
+                x11open_state->state = libssh2_NB_state_idle;
+                return -1;
+            }
+
+            /* Link the channel into the session */
+            if (session->channels.tail) {
+                session->channels.tail->next = channel;
+                channel->prev = session->channels.tail;
+            } else {
+                session->channels.head = channel;
+                channel->prev = NULL;
+            }
+            channel->next = NULL;
+            session->channels.tail = channel;
+
+            /*
+             * Pass control to the callback, they may turn right around and
+             * free the channel, or actually use it
+             */
+            LIBSSH2_X11_OPEN(channel, (char *) x11open_state->shost,
+                             x11open_state->sport);
+
+            x11open_state->state = libssh2_NB_state_idle;
+            return 0;
+        }
+    } else {
+        failure_code = 4;       /* SSH_OPEN_RESOURCE_SHORTAGE */
+    }
+
+  x11_exit:
+    p = x11open_state->packet;
+    *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
+    libssh2_htonu32(p, x11open_state->sender_channel);
+    p += 4;
+    libssh2_htonu32(p, failure_code);
+    p += 4;
+    libssh2_htonu32(p, sizeof(X11FwdUnAvil) - 1);
+    p += 4;
+    memcpy(s, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1);
+    p += sizeof(X11FwdUnAvil) - 1;
+    libssh2_htonu32(p, 0);
+
+    rc = libssh2_packet_write(session, x11open_state->packet, packet_len);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    } else if (rc) {
+        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                      "Unable to send open failure", 0);
+        x11open_state->state = libssh2_NB_state_idle;
+        return -1;
+    }
+    x11open_state->state = libssh2_NB_state_idle;
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_packet_new
+ * Create a new packet and attach it to the brigade
+ */
+int
+libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
+                   size_t datalen, int macstate)
+{
+    int rc;
+
+    if (session->packAdd_state == libssh2_NB_state_idle) {
+        session->packAdd_data_head = 0;
+
+        /* Zero the whole thing out */
+        memset(&session->packAdd_key_state, 0,
+               sizeof(session->packAdd_key_state));
+
+        /* Zero the whole thing out */
+        memset(&session->packAdd_Qlstn_state, 0,
+               sizeof(session->packAdd_Qlstn_state));
+
+        /* Zero the whole thing out */
+        memset(&session->packAdd_x11open_state, 0,
+               sizeof(session->packAdd_x11open_state));
+
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
+                       "Packet type %d received, length=%d",
+                       (int) data[0], (int) datalen);
+        if (macstate == LIBSSH2_MAC_INVALID) {
+            if (session->macerror) {
+                if (LIBSSH2_MACERROR(session, (char *) data, datalen) == 0) {
+                    /* Calling app has given the OK, Process it anyway */
+                    macstate = LIBSSH2_MAC_CONFIRMED;
+                } else {
+                    libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
+                                  "Invalid Message Authentication Code received",
+                                  0);
+                    if (session->ssh_msg_disconnect) {
+                        LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR,
+                                           "Invalid MAC received",
+                                           sizeof("Invalid MAC received") - 1,
+                                           "", 0);
+                    }
+                    LIBSSH2_FREE(session, data);
+                    return -1;
+                }
+            } else {
+                libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
+                              "Invalid Message Authentication Code received",
+                              0);
+                if (session->ssh_msg_disconnect) {
+                    LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR,
+                                       "Invalid MAC received",
+                                       sizeof("Invalid MAC received") - 1,
+                                       "", 0);
+                }
+                LIBSSH2_FREE(session, data);
+                return -1;
+            }
+        }
+
+        session->packAdd_state = libssh2_NB_state_allocated;
+    }
+
+    /*
+     * =============================== NOTE ===============================
+     * I know this is very ugly and not a really good use of "goto", but
+     * this case statement would be even uglier to do it any other way
+     */
+    if (session->packAdd_state == libssh2_NB_state_jump1) {
+        goto libssh2_packet_add_jump_point1;
+    } else if (session->packAdd_state == libssh2_NB_state_jump2) {
+        goto libssh2_packet_add_jump_point2;
+    } else if (session->packAdd_state == libssh2_NB_state_jump3) {
+        goto libssh2_packet_add_jump_point3;
+    }
+
+    if (session->packAdd_state == libssh2_NB_state_allocated) {
+        /* A couple exceptions to the packet adding rule: */
+        switch (data[0]) {
+        case SSH_MSG_DISCONNECT:
+            {
+                char *message, *language;
+                int reason, message_len, language_len;
+
+                reason = libssh2_ntohu32(data + 1);
+                message_len = libssh2_ntohu32(data + 5);
+                /* 9 = packet_type(1) + reason(4) + message_len(4) */
+                message = (char *) data + 9;
+                language_len = libssh2_ntohu32(data + 9 + message_len);
+                /*
+                 * This is where we hack on the data a little,
+                 * Use the MSB of language_len to to a terminating NULL
+                 * (In all liklihood it is already)
+                 * Shift the language tag back a byte (In all likelihood
+                 * it's zero length anyway)
+                 * Store a NULL in the last byte of the packet to terminate
+                 * the language string
+                 * With the lengths passed this isn't *REALLY* necessary,
+                 * but it's "kind"
+                 */
+                message[message_len] = '\0';
+                language = (char *) data + 9 + message_len + 3;
+                if (language_len) {
+                    memcpy(language, language + 1, language_len);
+                }
+                language[language_len] = '\0';
+
+                if (session->ssh_msg_disconnect) {
+                    LIBSSH2_DISCONNECT(session, reason, message,
+                                       message_len, language, language_len);
+                }
+                _libssh2_debug(session, LIBSSH2_DBG_TRANS,
+                               "Disconnect(%d): %s(%s)", reason,
+                               message, language);
+                LIBSSH2_FREE(session, data);
+                session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
+                session->packAdd_state = libssh2_NB_state_idle;
+                return -1;
+            }
+            break;
+
+        case SSH_MSG_IGNORE:
+            /* As with disconnect, back it up one and add a trailing NULL */
+            memcpy(data + 4, data + 5, datalen - 5);
+            data[datalen] = '\0';
+            if (session->ssh_msg_ignore) {
+                LIBSSH2_IGNORE(session, (char *) data + 4, datalen - 5);
+            }
+            LIBSSH2_FREE(session, data);
+            session->packAdd_state = libssh2_NB_state_idle;
+            return 0;
+            break;
+
+        case SSH_MSG_DEBUG:
+            {
+                int always_display = data[0];
+                char *message, *language;
+                int message_len, language_len;
+
+                message_len = libssh2_ntohu32(data + 2);
+                /* 6 = packet_type(1) + display(1) + message_len(4) */
+                message = (char *) data + 6;
+                language_len = libssh2_ntohu32(data + 6 + message_len);
+                /*
+                 * This is where we hack on the data a little,
+                 * Use the MSB of language_len to to a terminating NULL
+                 * (In all liklihood it is already)
+                 * Shift the language tag back a byte (In all likelihood
+                 * it's zero length anyway)
+                 * Store a NULL in the last byte of the packet to terminate
+                 * the language string
+                 * With the lengths passed this isn't *REALLY* necessary,
+                 * but it's "kind"
+                 */
+                message[message_len] = '\0';
+                language = (char *) data + 6 + message_len + 3;
+                if (language_len) {
+                    memcpy(language, language + 1, language_len);
+                }
+                language[language_len] = '\0';
+
+                if (session->ssh_msg_debug) {
+                    LIBSSH2_DEBUG(session, always_display, message,
+                                  message_len, language, language_len);
+                }
+                /*
+                 * _libssh2_debug will actually truncate this for us so
+                 * that it's not an inordinate about of data
+                 */
+                _libssh2_debug(session, LIBSSH2_DBG_TRANS,
+                               "Debug Packet: %s", message);
+                LIBSSH2_FREE(session, data);
+                session->packAdd_state = libssh2_NB_state_idle;
+                return 0;
+            }
+            break;
+
+        case SSH_MSG_CHANNEL_EXTENDED_DATA:
+            /* streamid(4) */
+            session->packAdd_data_head += 4;
+        case SSH_MSG_CHANNEL_DATA:
+            /* packet_type(1) + channelno(4) + datalen(4) */
+            session->packAdd_data_head += 9;
+            {
+                session->packAdd_channel = libssh2_channel_locate(session,
+                                                                  libssh2_ntohu32
+                                                                  (data + 1));
+
+                if (!session->packAdd_channel) {
+                    libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN,
+                                  "Packet received for unknown channel, ignoring",
+                                  0);
+                    LIBSSH2_FREE(session, data);
+                    session->packAdd_state = libssh2_NB_state_idle;
+                    return 0;
+                }
+#ifdef LIBSSH2DEBUG
+                {
+                    unsigned long stream_id = 0;
+
+                    if (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) {
+                        stream_id = libssh2_ntohu32(data + 5);
+                    }
+
+                    _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                                   "%d bytes received for channel %lu/%lu stream #%lu",
+                                   (int) (datalen -
+                                          session->packAdd_data_head),
+                                   session->packAdd_channel->local.id,
+                                   session->packAdd_channel->remote.id,
+                                   stream_id);
+                }
+#endif
+                if ((session->packAdd_channel->remote.
+                     extended_data_ignore_mode ==
+                     LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE)
+                    && (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) {
+                    /* Pretend we didn't receive this */
+                    LIBSSH2_FREE(session, data);
+
+                    _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                                   "Ignoring extended data and refunding %d bytes",
+                                   (int) (datalen - 13));
+                    /* Adjust the window based on the block we just freed */
+                  libssh2_packet_add_jump_point1:
+                    session->packAdd_state = libssh2_NB_state_jump1;
+                    rc = libssh2_channel_receive_window_adjust(session->
+                                                               packAdd_channel,
+                                                               datalen - 13,
+                                                               0);
+                    if (rc == PACKET_EAGAIN) {
+                        return PACKET_EAGAIN;
+                    }
+                    session->packAdd_state = libssh2_NB_state_idle;
+                    return 0;
+                }
+
+                /*
+                 * REMEMBER! remote means remote as source of data,
+                 * NOT remote window!
+                 */
+                if (session->packAdd_channel->remote.packet_size <
+                    (datalen - session->packAdd_data_head)) {
+                    /*
+                     * Spec says we MAY ignore bytes sent beyond 
+                     * packet_size
+                     */
+                    libssh2_error(session,
+                                  LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
+                                  "Packet contains more data than we offered to receive, truncating",
+                                  0);
+                    datalen =
+                        session->packAdd_channel->remote.packet_size +
+                        session->packAdd_data_head;
+                }
+                if (session->packAdd_channel->remote.window_size <= 0) {
+                    /*
+                     * Spec says we MAY ignore bytes sent beyond
+                     * window_size
+                     */
+                    libssh2_error(session,
+                                  LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
+                                  "The current receive window is full, data ignored",
+                                  0);
+                    LIBSSH2_FREE(session, data);
+                    session->packAdd_state = libssh2_NB_state_idle;
+                    return 0;
+                }
+                /* Reset EOF status */
+                session->packAdd_channel->remote.eof = 0;
+
+                if ((datalen - session->packAdd_data_head) >
+                    session->packAdd_channel->remote.window_size) {
+                    libssh2_error(session,
+                                  LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
+                                  "Remote sent more data than current window allows, truncating",
+                                  0);
+                    datalen =
+                        session->packAdd_channel->remote.window_size +
+                        session->packAdd_data_head;
+                } else {
+                    /* Now that we've received it, shrink our window */
+                    session->packAdd_channel->remote.window_size -=
+                        datalen - session->packAdd_data_head;
+                }
+            }
+            break;
+
+        case SSH_MSG_CHANNEL_EOF:
+            {
+                session->packAdd_channel = libssh2_channel_locate(session,
+                                                                  libssh2_ntohu32
+                                                                  (data + 1));
+
+                if (!session->packAdd_channel) {
+                    /* We may have freed already, just quietly ignore this... */
+                    LIBSSH2_FREE(session, data);
+                    session->packAdd_state = libssh2_NB_state_idle;
+                    return 0;
+                }
+
+                _libssh2_debug(session,
+                               LIBSSH2_DBG_CONN,
+                               "EOF received for channel %lu/%lu",
+                               session->packAdd_channel->local.id,
+                               session->packAdd_channel->remote.id);
+                session->packAdd_channel->remote.eof = 1;
+
+                LIBSSH2_FREE(session, data);
+                session->packAdd_state = libssh2_NB_state_idle;
+                return 0;
+            }
+            break;
+
+        case SSH_MSG_CHANNEL_REQUEST:
+            {
+                if (libssh2_ntohu32(data + 5) == sizeof("exit-status") - 1
+                    && !memcmp("exit-status", data + 9,
+                               sizeof("exit-status") - 1)) {
+
+                    /* we've got "exit-status" packet. Set the session value */
+                    session->packAdd_channel =
+                        libssh2_channel_locate(session,
+                                               libssh2_ntohu32(data + 1));
+
+                    if (session->packAdd_channel) {
+                        session->packAdd_channel->exit_status =
+                            libssh2_ntohu32(data + 9 + sizeof("exit-status"));
+                        _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                                       "Exit status %lu received for channel %lu/%lu",
+                                       session->packAdd_channel->exit_status,
+                                       session->packAdd_channel->local.id,
+                                       session->packAdd_channel->remote.id);
+                    }
+
+                    LIBSSH2_FREE(session, data);
+                    session->packAdd_state = libssh2_NB_state_idle;
+                    return 0;
+                }
+            }
+            break;
+
+        case SSH_MSG_CHANNEL_CLOSE:
+            {
+                session->packAdd_channel = libssh2_channel_locate(session,
+                                                                  libssh2_ntohu32
+                                                                  (data + 1));
+
+                if (!session->packAdd_channel) {
+                    /* We may have freed already, just quietly ignore this... */
+                    LIBSSH2_FREE(session, data);
+                    session->packAdd_state = libssh2_NB_state_idle;
+                    return 0;
+                }
+                _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                               "Close received for channel %lu/%lu",
+                               session->packAdd_channel->local.id,
+                               session->packAdd_channel->remote.id);
+
+                session->packAdd_channel->remote.close = 1;
+                session->packAdd_channel->remote.eof = 1;
+                /* TODO: Add a callback for this */
+
+                LIBSSH2_FREE(session, data);
+                session->packAdd_state = libssh2_NB_state_idle;
+                return 0;
+            }
+            break;
+
+        case SSH_MSG_CHANNEL_OPEN:
+            if ((datalen >= (sizeof("forwarded-tcpip") + 4)) &&
+                ((sizeof("forwarded-tcpip") - 1) == libssh2_ntohu32(data + 1))
+                &&
+                (memcmp
+                 (data + 5, "forwarded-tcpip",
+                  sizeof("forwarded-tcpip") - 1) == 0)) {
+
+              libssh2_packet_add_jump_point2:
+                session->packAdd_state = libssh2_NB_state_jump2;
+                rc = libssh2_packet_queue_listener(session, data, datalen,
+                                                   &session->
+                                                   packAdd_Qlstn_state);
+                if (rc == PACKET_EAGAIN) {
+                    return PACKET_EAGAIN;
+                }
+
+                LIBSSH2_FREE(session, data);
+                session->packAdd_state = libssh2_NB_state_idle;
+                return rc;
+            }
+            if ((datalen >= (sizeof("x11") + 4)) &&
+                ((sizeof("x11") - 1) == libssh2_ntohu32(data + 1)) &&
+                (memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {
+
+              libssh2_packet_add_jump_point3:
+                session->packAdd_state = libssh2_NB_state_jump3;
+                rc = libssh2_packet_x11_open(session, data, datalen,
+                                             &session->packAdd_x11open_state);
+                if (rc == PACKET_EAGAIN) {
+                    return PACKET_EAGAIN;
+                }
+
+                LIBSSH2_FREE(session, data);
+                session->packAdd_state = libssh2_NB_state_idle;
+                return rc;
+            }
+            break;
+
+        case SSH_MSG_CHANNEL_WINDOW_ADJUST:
+            {
+                unsigned long bytestoadd = libssh2_ntohu32(data + 5);
+                session->packAdd_channel = libssh2_channel_locate(session,
+                                                                  libssh2_ntohu32
+                                                                  (data + 1));
+
+                if (session->packAdd_channel && bytestoadd) {
+                    session->packAdd_channel->local.window_size += bytestoadd;
+                }
+                _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                               "Window adjust received for channel %lu/%lu, adding %lu bytes, new window_size=%lu",
+                               session->packAdd_channel->local.id,
+                               session->packAdd_channel->remote.id,
+                               bytestoadd,
+                               session->packAdd_channel->local.window_size);
+
+                LIBSSH2_FREE(session, data);
+                session->packAdd_state = libssh2_NB_state_idle;
+                return 0;
+            }
+            break;
+        }
+
+        session->packAdd_state = libssh2_NB_state_sent;
+    }
+
+    if (session->packAdd_state == libssh2_NB_state_sent) {
+        session->packAdd_packet =
+            LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
+        if (!session->packAdd_packet) {
+            _libssh2_debug(session, LIBSSH2_ERROR_ALLOC,
+                           "Unable to allocate memory for LIBSSH2_PACKET");
+            LIBSSH2_FREE(session, data);
+            session->packAdd_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        memset(session->packAdd_packet, 0, sizeof(LIBSSH2_PACKET));
+
+        session->packAdd_packet->data = data;
+        session->packAdd_packet->data_len = datalen;
+        session->packAdd_packet->data_head = session->packAdd_data_head;
+        session->packAdd_packet->mac = macstate;
+        session->packAdd_packet->brigade = &session->packets;
+        session->packAdd_packet->next = NULL;
+
+        if (session->packets.tail) {
+            session->packAdd_packet->prev = session->packets.tail;
+            session->packAdd_packet->prev->next = session->packAdd_packet;
+            session->packets.tail = session->packAdd_packet;
+        } else {
+            session->packets.head = session->packAdd_packet;
+            session->packets.tail = session->packAdd_packet;
+            session->packAdd_packet->prev = NULL;
+        }
+
+        session->packAdd_state = libssh2_NB_state_sent1;
+    }
+
+    if ((data[0] == SSH_MSG_KEXINIT &&
+         !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) ||
+        (session->packAdd_state == libssh2_NB_state_sent2)) {
+        if (session->packAdd_state == libssh2_NB_state_sent1) {
+            /*
+             * Remote wants new keys
+             * Well, it's already in the brigade,
+             * let's just call back into ourselves
+             */
+            _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Renegotiating Keys");
+
+            session->packAdd_state = libssh2_NB_state_sent2;
+        }
+        /*
+         * If there was a key reexchange failure, let's just hope we didn't
+         * send NEWKEYS yet, otherwise remote will drop us like a rock
+         */
+        rc = libssh2_kex_exchange(session, 1, &session->packAdd_key_state);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        }
+    }
+
+    session->packAdd_state = libssh2_NB_state_idle;
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_packet_ask
+ * Scan the brigade for a matching packet type, optionally poll the socket for
+ * a packet first
+ */
+int
+libssh2_packet_ask_ex(LIBSSH2_SESSION * session, unsigned char packet_type,
+                      unsigned char **data, unsigned long *data_len,
+                      unsigned long match_ofs, const unsigned char *match_buf,
+                      unsigned long match_len, int poll_socket)
+{
+    LIBSSH2_PACKET *packet = session->packets.head;
+
+    if (poll_socket) {
+        /*
+         * XXX CHECK ***
+         * When "poll_socket" is "1" libhss2_packet_read() can return
+         * PACKET_EAGAIN.  I am not sure what should happen, but internally
+         * there is only one location that might do so, libssh2_packet_askv_ex()
+         */
+        libssh2pack_t rc = libssh2_packet_read(session);
+        if ((rc < 0) && !packet) {
+            return rc;
+        }
+    }
+    _libssh2_debug(session, LIBSSH2_DBG_TRANS,
+                   "Looking for packet of type: %d", (int) packet_type);
+
+    while (packet) {
+        if (packet->data[0] == packet_type
+            && (packet->data_len >= (match_ofs + match_len)) && (!match_buf
+                                                                 ||
+                                                                 (memcmp
+                                                                  (packet->
+                                                                   data +
+                                                                   match_ofs,
+                                                                   match_buf,
+                                                                   match_len)
+                                                                  == 0))) {
+            *data = packet->data;
+            *data_len = packet->data_len;
+
+            if (packet->prev) {
+                packet->prev->next = packet->next;
+            } else {
+                session->packets.head = packet->next;
+            }
+
+            if (packet->next) {
+                packet->next->prev = packet->prev;
+            } else {
+                session->packets.tail = packet->prev;
+            }
+
+            LIBSSH2_FREE(session, packet);
+
+            return 0;
+        }
+        packet = packet->next;
+    }
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_packet_askv
+ * Scan for any of a list of packet types in the brigade, optionally poll the
+ * socket for a packet first
+ */
+int
+libssh2_packet_askv_ex(LIBSSH2_SESSION * session,
+                       const unsigned char *packet_types,
+                       unsigned char **data, unsigned long *data_len,
+                       unsigned long match_ofs,
+                       const unsigned char *match_buf,
+                       unsigned long match_len, int poll_socket)
+{
+    int i, packet_types_len = strlen((char *) packet_types);
+
+    for(i = 0; i < packet_types_len; i++) {
+        /*
+         * XXX CHECK XXX
+         * When "poll_socket" is "1" libssh2_packet_ask_ex() could
+         * return PACKET_EAGAIN.  Not sure the correct action, I 
+         * think it is right as is.
+         */
+        if (0 == libssh2_packet_ask_ex(session, packet_types[i], data,
+                                       data_len, match_ofs, match_buf,
+                                       match_len, i ? 0 : poll_socket)) {
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ waitsocket
+ * Returns
+ * negative on error
+ * >0 on incoming data
+ * 0 on timeout
+ *
+ * FIXME: convert to use poll on systems that have it.
+ */
+int
+libssh2_waitsocket(LIBSSH2_SESSION * session, long seconds)
+{
+    struct timeval timeout;
+    int rc;
+    fd_set fd;
+
+    timeout.tv_sec = seconds;
+    timeout.tv_usec = 0;
+
+    FD_ZERO(&fd);
+
+    FD_SET(session->socket_fd, &fd);
+
+    rc = select(session->socket_fd + 1, &fd, NULL, NULL, &timeout);
+
+    return rc;
+}
+
+/* {{{ libssh2_packet_require
+ * Loops libssh2_packet_read() until the packet requested is available
+ * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
+ *
+ * Returns negative on error
+ * Returns 0 when it has taken care of the requested packet.
+ */
+int
+libssh2_packet_require_ex(LIBSSH2_SESSION * session, unsigned char packet_type,
+                          unsigned char **data, unsigned long *data_len,
+                          unsigned long match_ofs,
+                          const unsigned char *match_buf,
+                          unsigned long match_len,
+                          packet_require_state_t * state)
+{
+    if (state->start == 0) {
+        if (libssh2_packet_ask_ex
+            (session, packet_type, data, data_len, match_ofs, match_buf,
+             match_len, 0) == 0) {
+            /* A packet was available in the packet brigade */
+            return 0;
+        }
+
+        state->start = time(NULL);
+
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
+                       "May block until packet of type %d becomes available",
+                       (int) packet_type);
+    }
+
+    while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
+        libssh2pack_t ret = libssh2_packet_read(session);
+        if (ret == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if ((ret == 0) && (!session->socket_block)) {
+            /* If we are in non-blocking and there is no data, return that */
+            return PACKET_EAGAIN;
+        } else if (ret < 0) {
+            state->start = 0;
+            /* an error which is not just because of blocking */
+            return ret;
+        } else if (ret == packet_type) {
+            /* Be lazy, let packet_ask pull it out of the brigade */
+            ret =
+                libssh2_packet_ask_ex(session, packet_type, data, data_len,
+                                      match_ofs, match_buf, match_len, 0);
+            state->start = 0;
+            return ret;
+        } else if (ret == 0) {
+            /* nothing available, wait until data arrives or we time out */
+            long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start);
+
+            if ((left <= 0) || (libssh2_waitsocket(session, left) <= 0)) {
+                state->start = 0;
+                return PACKET_TIMEOUT;
+            }
+        }
+    }
+
+    /* Only reached if the socket died */
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_packet_burn
+ * Loops libssh2_packet_read() until any packet is available and promptly 
+ * discards it
+ * Used during KEX exchange to discard badly guessed KEX_INIT packets
+ */
+int
+libssh2_packet_burn(LIBSSH2_SESSION * session,
+                    libssh2_nonblocking_states * state)
+{
+    unsigned char *data;
+    unsigned long data_len;
+    unsigned char all_packets[255];
+    int i;
+    int ret;
+
+    if (*state == libssh2_NB_state_idle) {
+        for(i = 1; i < 256; i++) {
+            all_packets[i - 1] = i;
+        }
+
+        if (libssh2_packet_askv_ex
+            (session, all_packets, &data, &data_len, 0, NULL, 0, 0) == 0) {
+            i = data[0];
+            /* A packet was available in the packet brigade, burn it */
+            LIBSSH2_FREE(session, data);
+            return i;
+        }
+
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
+                       "Blocking until packet becomes available to burn");
+        *state = libssh2_NB_state_created;
+    }
+
+    while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
+        if ((ret = libssh2_packet_read(session)) == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (ret < 0) {
+            *state = libssh2_NB_state_idle;
+            return ret;
+        } else if (ret == 0) {
+            /* FIXME: this might busyloop */
+            continue;
+        }
+
+        /* Be lazy, let packet_ask pull it out of the brigade */
+        if (0 ==
+            libssh2_packet_ask_ex(session, ret, &data, &data_len, 0, NULL, 0,
+                                  0)) {
+            /* Smoke 'em if you got 'em */
+            LIBSSH2_FREE(session, data);
+            *state = libssh2_NB_state_idle;
+            return ret;
+        }
+    }
+
+    /* Only reached if the socket died */
+    return -1;
+}
+
+/* }}} */
+
+/*
+ * {{{ libssh2_packet_requirev
+ *
+ * Loops libssh2_packet_read() until one of a list of packet types requested is
+ * available
+ * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
+ * packet_types is a null terminated list of packet_type numbers
+ */
+
+int
+libssh2_packet_requirev_ex(LIBSSH2_SESSION * session,
+                           const unsigned char *packet_types,
+                           unsigned char **data, unsigned long *data_len,
+                           unsigned long match_ofs,
+                           const unsigned char *match_buf,
+                           unsigned long match_len,
+                           packet_requirev_state_t * state)
+{
+    if (libssh2_packet_askv_ex
+        (session, packet_types, data, data_len, match_ofs, match_buf,
+         match_len, 0) == 0) {
+        /* One of the packets listed was available in the packet
+           brigade */
+        state->start = 0;
+        return 0;
+    }
+
+    if (state->start == 0) {
+        state->start = time(NULL);
+    }
+
+    while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
+        int ret = libssh2_packet_read(session);
+        if ((ret < 0) && (ret != PACKET_EAGAIN)) {
+            state->start = 0;
+            return ret;
+        }
+        if (ret <= 0) {
+            long left = LIBSSH2_READ_TIMEOUT - (time(NULL) - state->start);
+
+            if ((left <= 0) || (libssh2_waitsocket(session, left) <= 0)) {
+                state->start = 0;
+                return PACKET_TIMEOUT;
+            } else if (ret == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            }
+        }
+
+        if (strchr((char *) packet_types, ret)) {
+            /* Be lazy, let packet_ask pull it out of the brigade */
+            return libssh2_packet_askv_ex(session, packet_types, data,
+                                          data_len, match_ofs, match_buf,
+                                          match_len, 0);
+        }
+    }
+
+    /* Only reached if the socket died */
+    state->start = 0;
+    return -1;
+}
+
+/* }}} */
diff --git a/Vendor/libssh2/Source/pem.c b/Vendor/libssh2/Source/pem.c
new file mode 100644 (file)
index 0000000..58c01e8
--- /dev/null
@@ -0,0 +1,207 @@
+/* Copyright (C) 2007 The Written Word, Inc.  All rights reserved.
+ * Author: Simon Josefsson
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+
+static int
+readline(char *line, int line_size, FILE * fp)
+{
+    if (!fgets(line, line_size, fp)) {
+        return -1;
+    }
+    if (*line && line[strlen(line) - 1] == '\n') {
+        line[strlen(line) - 1] = '\0';
+    }
+    if (*line && line[strlen(line) - 1] == '\r') {
+        line[strlen(line) - 1] = '\0';
+    }
+    return 0;
+}
+
+#define LINE_SIZE 128
+
+int
+_libssh2_pem_parse(LIBSSH2_SESSION * session,
+                   const char *headerbegin,
+                   const char *headerend,
+                   FILE * fp, char **data, unsigned int *datalen)
+{
+    char line[LINE_SIZE];
+    char *b64data = NULL;
+    unsigned int b64datalen = 0;
+    int ret;
+
+    do {
+        if (readline(line, LINE_SIZE, fp)) {
+            return -1;
+        }
+    }
+    while (strcmp(line, headerbegin) != 0);
+
+    *line = '\0';
+
+    do {
+        if (*line) {
+            char *tmp;
+            size_t linelen;
+
+            linelen = strlen(line);
+            tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
+            if (!tmp) {
+                ret = -1;
+                goto out;
+            }
+            memcpy(tmp + b64datalen, line, linelen);
+            b64data = tmp;
+            b64datalen += linelen;
+        }
+
+        if (readline(line, LINE_SIZE, fp)) {
+            ret = -1;
+            goto out;
+        }
+    } while (strcmp(line, headerend) != 0);
+
+    if (libssh2_base64_decode(session, data, datalen, b64data, b64datalen)) {
+        ret = -1;
+        goto out;
+    }
+
+    ret = 0;
+  out:
+    if (b64data) {
+        LIBSSH2_FREE(session, b64data);
+    }
+    return ret;
+}
+
+static int
+read_asn1_length(const unsigned char *data,
+                 unsigned int datalen, unsigned int *len)
+{
+    unsigned int lenlen;
+    int nextpos;
+
+    if (datalen < 1) {
+        return -1;
+    }
+    *len = data[0];
+
+    if (*len >= 0x80) {
+        lenlen = *len & 0x7F;
+        *len = data[1];
+        if (1 + lenlen > datalen) {
+            return -1;
+        }
+        if (lenlen > 1) {
+            *len <<= 8;
+            *len |= data[2];
+        }
+    } else {
+        lenlen = 0;
+    }
+
+    nextpos = 1 + lenlen;
+    if (lenlen > 2 || 1 + lenlen + *len > datalen) {
+        return -1;
+    }
+
+    return nextpos;
+}
+
+int
+_libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen)
+{
+    unsigned int len;
+    int lenlen;
+
+    if (*datalen < 1) {
+        return -1;
+    }
+
+    if ((*data)[0] != '\x30') {
+        return -1;
+    }
+
+    (*data)++;
+    (*datalen)--;
+
+    lenlen = read_asn1_length(*data, *datalen, &len);
+    if (lenlen < 0 || lenlen + len != *datalen) {
+        return -1;
+    }
+
+    *data += lenlen;
+    *datalen -= lenlen;
+
+    return 0;
+}
+
+int
+_libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
+                            unsigned char **i, unsigned int *ilen)
+{
+    unsigned int len;
+    int lenlen;
+
+    if (*datalen < 1) {
+        return -1;
+    }
+
+    if ((*data)[0] != '\x02') {
+        return -1;
+    }
+
+    (*data)++;
+    (*datalen)--;
+
+    lenlen = read_asn1_length(*data, *datalen, &len);
+    if (lenlen < 0 || lenlen + len > *datalen) {
+        return -1;
+    }
+
+    *data += lenlen;
+    *datalen -= lenlen;
+
+    *i = *data;
+    *ilen = len;
+
+    *data += len;
+    *datalen -= len;
+
+    return 0;
+}
diff --git a/Vendor/libssh2/Source/publickey.c b/Vendor/libssh2/Source/publickey.c
new file mode 100644 (file)
index 0000000..075db8a
--- /dev/null
@@ -0,0 +1,1094 @@
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+#include "libssh2_publickey.h"
+
+#define LIBSSH2_PUBLICKEY_VERSION               2
+
+/* Numericised response codes -- Not IETF standard, just a local representation */
+#define LIBSSH2_PUBLICKEY_RESPONSE_STATUS       0
+#define LIBSSH2_PUBLICKEY_RESPONSE_VERSION      1
+#define LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY    2
+
+typedef struct _LIBSSH2_PUBLICKEY_CODE_LIST
+{
+    int code;
+    const char *name;
+    int name_len;
+} LIBSSH2_PUBLICKEY_CODE_LIST;
+
+static const LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_response_codes[] = {
+    {LIBSSH2_PUBLICKEY_RESPONSE_STATUS, "status", sizeof("status") - 1}
+    ,
+    {LIBSSH2_PUBLICKEY_RESPONSE_VERSION, "version", sizeof("version") - 1}
+    ,
+    {LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY, "publickey", sizeof("publickey") - 1}
+    ,
+    {0, NULL, 0}
+};
+
+/* PUBLICKEY status codes -- IETF defined */
+#define LIBSSH2_PUBLICKEY_SUCCESS               0
+#define LIBSSH2_PUBLICKEY_ACCESS_DENIED         1
+#define LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED      2
+#define LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED 3
+#define LIBSSH2_PUBLICKEY_KEY_NOT_FOUND         4
+#define LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED     5
+#define LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT   6
+#define LIBSSH2_PUBLICKEY_GENERAL_FAILURE       7
+#define LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED 8
+
+#define LIBSSH2_PUBLICKEY_STATUS_CODE_MAX       8
+
+static const LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_status_codes[] = {
+    {LIBSSH2_PUBLICKEY_SUCCESS, "success", sizeof("success") - 1}
+    ,
+    {LIBSSH2_PUBLICKEY_ACCESS_DENIED, "access denied",
+     sizeof("access denied") - 1}
+    ,
+    {LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED, "storage exceeded",
+     sizeof("storage exceeded") - 1}
+    ,
+    {LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED, "version not supported",
+     sizeof("version not supported") - 1}
+    ,
+    {LIBSSH2_PUBLICKEY_KEY_NOT_FOUND, "key not found",
+     sizeof("key not found") - 1}
+    ,
+    {LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED, "key not supported",
+     sizeof("key not supported") - 1}
+    ,
+    {LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT, "key already present",
+     sizeof("key already present") - 1}
+    ,
+    {LIBSSH2_PUBLICKEY_GENERAL_FAILURE, "general failure",
+     sizeof("general failure") - 1}
+    ,
+    {LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED, "request not supported",
+     sizeof("request not supported") - 1}
+    ,
+    {0, NULL, 0}
+};
+
+/* {{{ libssh2_publickey_status_error
+ * Format an error message from a status code
+ */
+#define LIBSSH2_PUBLICKEY_STATUS_TEXT_START     "Publickey Subsystem Error: \""
+#define LIBSSH2_PUBLICKEY_STATUS_TEXT_MID       "\" Server Resports: \""
+#define LIBSSH2_PUBLICKEY_STATUS_TEXT_END       "\""
+static void
+libssh2_publickey_status_error(const LIBSSH2_PUBLICKEY * pkey,
+                               LIBSSH2_SESSION * session, int status,
+                               const unsigned char *message, int message_len)
+{
+    const char *status_text;
+    int status_text_len;
+    char *m, *s;
+    int m_len;
+
+    /* GENERAL_FAILURE got remapped between version 1 and 2 */
+    if (status == 6 && pkey && pkey->version == 1) {
+        status = 7;
+    }
+
+    if (status < 0 || status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) {
+        status_text = "unknown";
+        status_text_len = sizeof("unknown") - 1;
+    } else {
+        status_text = libssh2_publickey_status_codes[status].name;
+        status_text_len = libssh2_publickey_status_codes[status].name_len;
+    }
+
+    m_len =
+        (sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1) + status_text_len +
+        (sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1) + message_len +
+        (sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
+    m = LIBSSH2_ALLOC(session, m_len + 1);
+    if (!m) {
+        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                      "Unable to allocate memory for status message", 0);
+        return;
+    }
+    s = m;
+    memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_START,
+           sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1);
+    s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1;
+    memcpy(s, status_text, status_text_len);
+    s += status_text_len;
+    memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_MID,
+           sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1);
+    s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1;
+    memcpy(s, message, message_len);
+    s += message_len;
+    memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_END,
+           sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
+    s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END);
+    libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, m, 1);
+}
+
+/* }}} */
+
+/* {{{ libssh2_publickey_packet_receive
+ * Read a packet from the subsystem
+ */
+static int
+libssh2_publickey_packet_receive(LIBSSH2_PUBLICKEY * pkey,
+                                 unsigned char **data, unsigned long *data_len)
+{
+    LIBSSH2_CHANNEL *channel = pkey->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned char buffer[4];
+    int rc;
+
+    if (pkey->receive_state == libssh2_NB_state_idle) {
+        rc = libssh2_channel_read_ex(channel, 0, (char *) buffer, 4);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc != 4) {
+            libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
+                          "Invalid response from publickey subsystem", 0);
+            return -1;
+        }
+
+        pkey->receive_packet_len = libssh2_ntohu32(buffer);
+        pkey->receive_packet =
+            LIBSSH2_ALLOC(session, pkey->receive_packet_len);
+        if (!pkey->receive_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate publickey response buffer", 0);
+            return -1;
+        }
+
+        pkey->receive_state = libssh2_NB_state_sent;
+    }
+
+    if (pkey->receive_state == libssh2_NB_state_sent) {
+        rc = libssh2_channel_read_ex(channel, 0, (char *) pkey->receive_packet,
+                                     pkey->receive_packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc != (int)pkey->receive_packet_len) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                          "Timeout waiting for publickey subsystem response packet",
+                          0);
+            LIBSSH2_FREE(session, pkey->receive_packet);
+            pkey->receive_packet = NULL;
+            pkey->receive_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        *data = pkey->receive_packet;
+        *data_len = pkey->receive_packet_len;
+    }
+
+    pkey->receive_state = libssh2_NB_state_idle;
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_publickey_response_id
+ * Translate a string response name to a numeric code
+ * Data will be incremented by 4 + response_len on success only
+ */
+static int
+libssh2_publickey_response_id(unsigned char **pdata, int data_len)
+{
+    unsigned long response_len;
+    unsigned char *data = *pdata;
+    const LIBSSH2_PUBLICKEY_CODE_LIST *codes =
+        libssh2_publickey_response_codes;
+
+    if (data_len < 4) {
+        /* Malformed response */
+        return -1;
+    }
+    response_len = libssh2_ntohu32(data);
+    data += 4;
+    data_len -= 4;
+    if (data_len < (int)response_len) {
+        /* Malformed response */
+        return -1;
+    }
+
+    while (codes->name) {
+        if ((unsigned long)codes->name_len == response_len &&
+            strncmp(codes->name, (char *) data, response_len) == 0) {
+            *pdata = data + response_len;
+            return codes->code;
+        }
+        codes++;
+    }
+
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_publickey_response_success
+ * Generic helper routine to wait for success response and nothing else
+ */
+static int
+libssh2_publickey_response_success(LIBSSH2_PUBLICKEY * pkey)
+{
+    LIBSSH2_SESSION *session = pkey->channel->session;
+    unsigned char *data, *s;
+    unsigned long data_len;
+    int response;
+    int rc;
+
+    while (1) {
+        rc = libssh2_publickey_packet_receive(pkey, &data, &data_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                          "Timeout waiting for response from publickey subsystem",
+                          0);
+            return -1;
+        }
+
+        s = data;
+        if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
+            libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
+                          "Invalid publickey subsystem response code", 0);
+            LIBSSH2_FREE(session, data);
+            return -1;
+        }
+
+        switch (response) {
+        case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
+            /* Error, or processing complete */
+            {
+                unsigned long status, descr_len, lang_len;
+                unsigned char *descr, *lang;
+
+                status = libssh2_ntohu32(s);
+                s += 4;
+                descr_len = libssh2_ntohu32(s);
+                s += 4;
+                descr = s;
+                s += descr_len;
+                lang_len = libssh2_ntohu32(s);
+                s += 4;
+                lang = s;
+                s += lang_len;
+
+                if (s > data + data_len) {
+                    libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
+                                  "Malformed publickey subsystem packet", 0);
+                    LIBSSH2_FREE(session, data);
+                    return -1;
+                }
+
+                if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
+                    LIBSSH2_FREE(session, data);
+                    return 0;
+                }
+
+                libssh2_publickey_status_error(pkey, session, status, descr,
+                                               descr_len);
+                LIBSSH2_FREE(session, data);
+                return -1;
+            }
+        default:
+            /* Unknown/Unexpected */
+            libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
+                          "Unexpected publickey subsystem response, ignoring",
+                          0);
+            LIBSSH2_FREE(session, data);
+            data = NULL;
+        }
+    }
+    /* never reached, but include `return` to silence compiler warnings */
+    return -1;
+}
+
+/* }}} */
+
+
+/* *****************
+   * Publickey API *
+   ***************** */
+
+/* {{{ libssh2_publickey_init
+ * Startup the publickey subsystem
+ */
+LIBSSH2_API LIBSSH2_PUBLICKEY *
+libssh2_publickey_init(LIBSSH2_SESSION * session)
+{
+    /* 19 = packet_len(4) + version_len(4) + "version"(7) + version_num(4) */
+    unsigned char buffer[19];
+    unsigned char *s;
+    int response;
+    int rc;
+
+    if (session->pkeyInit_state == libssh2_NB_state_idle) {
+        session->pkeyInit_data = NULL;
+        session->pkeyInit_pkey = NULL;
+        session->pkeyInit_channel = NULL;
+
+        _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
+                       "Initializing publickey subsystem");
+
+        session->pkeyInit_state = libssh2_NB_state_allocated;
+    }
+
+    if (session->pkeyInit_state == libssh2_NB_state_allocated) {
+        do {
+            session->pkeyInit_channel =
+                libssh2_channel_open_ex(session, "session",
+                                        sizeof("session") - 1,
+                                        LIBSSH2_CHANNEL_WINDOW_DEFAULT,
+                                        LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL,
+                                        0);
+            if (!session->pkeyInit_channel
+                && (libssh2_session_last_errno(session) ==
+                    LIBSSH2_ERROR_EAGAIN)) {
+                /* The error state is already set, so leave it */
+                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                              "Would block to startup channel", 0);
+                return NULL;
+            } else if (!session->pkeyInit_channel
+                       && (libssh2_session_last_errno(session) !=
+                           LIBSSH2_ERROR_EAGAIN)) {
+                libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
+                              "Unable to startup channel", 0);
+                goto err_exit;
+            }
+        } while (!session->pkeyInit_channel);
+
+        session->pkeyInit_state = libssh2_NB_state_sent;
+    }
+
+    if (session->pkeyInit_state == libssh2_NB_state_sent) {
+        rc = libssh2_channel_process_startup(session->pkeyInit_channel,
+                                             "subsystem",
+                                             sizeof("subsystem") - 1,
+                                             "publickey", strlen("publickey"));
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block starting publickkey subsystem", 0);
+            return NULL;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
+                          "Unable to request publickey subsystem", 0);
+            goto err_exit;
+        }
+
+        session->pkeyInit_state = libssh2_NB_state_sent1;
+    }
+
+    if (session->pkeyInit_state == libssh2_NB_state_sent1) {
+        rc = libssh2_channel_handle_extended_data2(session->pkeyInit_channel,
+                                                   LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block starting publickkey subsystem", 0);
+            return NULL;
+        }
+
+        session->pkeyInit_pkey =
+            LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PUBLICKEY));
+        if (!session->pkeyInit_pkey) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate a new publickey structure", 0);
+            goto err_exit;
+        }
+        memset(session->pkeyInit_pkey, 0, sizeof(LIBSSH2_PUBLICKEY));
+        session->pkeyInit_pkey->channel = session->pkeyInit_channel;
+        session->pkeyInit_pkey->version = 0;
+
+        s = buffer;
+        libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4);
+        s += 4;
+        libssh2_htonu32(s, sizeof("version") - 1);
+        s += 4;
+        memcpy(s, "version", sizeof("version") - 1);
+        s += sizeof("version") - 1;
+        libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION);
+        s += 4;
+
+        _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
+                       "Sending publickey version packet advertising version %d support",
+                       (int) LIBSSH2_PUBLICKEY_VERSION);
+
+        session->pkeyInit_state = libssh2_NB_state_sent2;
+    }
+
+    if (session->pkeyInit_state == libssh2_NB_state_sent2) {
+        rc = libssh2_channel_write_ex(session->pkeyInit_channel, 0,
+                                      (char *) buffer, (s - buffer));
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block sending publickkey version packet", 0);
+            return NULL;
+        } else if ((s - buffer) != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send publickey version packet", 0);
+            goto err_exit;
+        }
+
+        session->pkeyInit_state = libssh2_NB_state_sent3;
+    }
+
+    if (session->pkeyInit_state == libssh2_NB_state_sent3) {
+        while (1) {
+            rc = libssh2_publickey_packet_receive(session->pkeyInit_pkey,
+                                                  &session->pkeyInit_data,
+                                                  &session->pkeyInit_data_len);
+            if (rc == PACKET_EAGAIN) {
+                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                              "Would block waiting for response from publickey subsystem",
+                              0);
+                return NULL;
+            } else if (rc) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                              "Timeout waiting for response from publickey subsystem",
+                              0);
+                goto err_exit;
+            }
+
+            s = session->pkeyInit_data;
+            if ((response =
+                 libssh2_publickey_response_id(&s,
+                                               session->pkeyInit_data_len)) <
+                0) {
+                libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
+                              "Invalid publickey subsystem response code", 0);
+                goto err_exit;
+            }
+
+            switch (response) {
+            case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
+                /* Error */
+                {
+                    unsigned long status, descr_len, lang_len;
+                    unsigned char *descr, *lang;
+
+                    status = libssh2_ntohu32(s);
+                    s += 4;
+                    descr_len = libssh2_ntohu32(s);
+                    s += 4;
+                    descr = s;
+                    s += descr_len;
+                    lang_len = libssh2_ntohu32(s);
+                    s += 4;
+                    lang = s;
+                    s += lang_len;
+
+                    if (s >
+                        session->pkeyInit_data + session->pkeyInit_data_len) {
+                        libssh2_error(session,
+                                      LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
+                                      "Malformed publickey subsystem packet",
+                                      0);
+                        goto err_exit;
+                    }
+
+                    libssh2_publickey_status_error(NULL, session, status,
+                                                   descr, descr_len);
+                    goto err_exit;
+                }
+
+            case LIBSSH2_PUBLICKEY_RESPONSE_VERSION:
+                /* What we want */
+                session->pkeyInit_pkey->version = libssh2_ntohu32(s);
+                if (session->pkeyInit_pkey->version >
+                    LIBSSH2_PUBLICKEY_VERSION) {
+                    _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
+                                   "Truncating remote publickey version from %lu",
+                                   session->pkeyInit_pkey->version);
+                    session->pkeyInit_pkey->version =
+                        LIBSSH2_PUBLICKEY_VERSION;
+                }
+                _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
+                               "Enabling publickey subsystem version %lu",
+                               session->pkeyInit_pkey->version);
+                LIBSSH2_FREE(session, session->pkeyInit_data);
+                session->pkeyInit_data = NULL;
+                session->pkeyInit_state = libssh2_NB_state_idle;
+                return session->pkeyInit_pkey;
+
+            default:
+                /* Unknown/Unexpected */
+                libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
+                              "Unexpected publickey subsystem response, ignoring",
+                              0);
+                LIBSSH2_FREE(session, session->pkeyInit_data);
+                session->pkeyInit_data = NULL;
+            }
+        }
+    }
+
+    /* Never reached except by direct goto */
+  err_exit:
+    session->pkeyInit_state = libssh2_NB_state_sent4;
+    if (session->pkeyInit_channel) {
+        rc = libssh2_channel_close(session->pkeyInit_channel);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block closing channel", 0);
+            return NULL;
+        }
+    }
+    if (session->pkeyInit_pkey) {
+        LIBSSH2_FREE(session, session->pkeyInit_pkey);
+        session->pkeyInit_pkey = NULL;
+    }
+    if (session->pkeyInit_data) {
+        LIBSSH2_FREE(session, session->pkeyInit_data);
+        session->pkeyInit_data = NULL;
+    }
+    session->pkeyInit_state = libssh2_NB_state_idle;
+    return NULL;
+}
+
+/* }}} */
+
+/* {{{ libssh2_publickey_add_ex
+ * Add a new public key entry
+ */
+LIBSSH2_API int
+libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY * pkey, const unsigned char *name,
+                         unsigned long name_len, const unsigned char *blob,
+                         unsigned long blob_len, char overwrite,
+                         unsigned long num_attrs,
+                         const libssh2_publickey_attribute attrs[])
+{
+    LIBSSH2_CHANNEL *channel = pkey->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    /*  19 = packet_len(4) + add_len(4) + "add"(3) + name_len(4) + {name} blob_len(4) + {blob} */
+    unsigned long i, packet_len = 19 + name_len + blob_len;
+    unsigned char *comment = NULL;
+    unsigned long comment_len = 0;
+    int rc;
+
+    if (pkey->add_state == libssh2_NB_state_idle) {
+        pkey->add_packet = NULL;
+
+        _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Adding %s publickey",
+                       name);
+
+        if (pkey->version == 1) {
+            for(i = 0; i < num_attrs; i++) {
+                /* Search for a comment attribute */
+                if (attrs[i].name_len == (sizeof("comment") - 1) &&
+                    strncmp(attrs[i].name, "comment",
+                            sizeof("comment") - 1) == 0) {
+                    comment = (unsigned char *) attrs[i].value;
+                    comment_len = attrs[i].value_len;
+                    break;
+                }
+            }
+            packet_len += 4 + comment_len;
+        } else {
+            packet_len += 5;    /* overwrite(1) + attribute_count(4) */
+            for(i = 0; i < num_attrs; i++) {
+                packet_len += 9 + attrs[i].name_len + attrs[i].value_len;
+                /* name_len(4) + value_len(4) + mandatory(1) */
+            }
+        }
+
+        pkey->add_packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!pkey->add_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for publickey \"add\" packet",
+                          0);
+            return -1;
+        }
+
+        pkey->add_s = pkey->add_packet;
+        libssh2_htonu32(pkey->add_s, packet_len - 4);
+        pkey->add_s += 4;
+        libssh2_htonu32(pkey->add_s, sizeof("add") - 1);
+        pkey->add_s += 4;
+        memcpy(pkey->add_s, "add", sizeof("add") - 1);
+        pkey->add_s += sizeof("add") - 1;
+        if (pkey->version == 1) {
+            libssh2_htonu32(pkey->add_s, comment_len);
+            pkey->add_s += 4;
+            if (comment) {
+                memcpy(pkey->add_s, comment, comment_len);
+                pkey->add_s += comment_len;
+            }
+
+            libssh2_htonu32(pkey->add_s, name_len);
+            pkey->add_s += 4;
+            memcpy(pkey->add_s, name, name_len);
+            pkey->add_s += name_len;
+            libssh2_htonu32(pkey->add_s, blob_len);
+            pkey->add_s += 4;
+            memcpy(pkey->add_s, blob, blob_len);
+            pkey->add_s += blob_len;
+        } else {
+            /* Version == 2 */
+
+            libssh2_htonu32(pkey->add_s, name_len);
+            pkey->add_s += 4;
+            memcpy(pkey->add_s, name, name_len);
+            pkey->add_s += name_len;
+            libssh2_htonu32(pkey->add_s, blob_len);
+            pkey->add_s += 4;
+            memcpy(pkey->add_s, blob, blob_len);
+            pkey->add_s += blob_len;
+            *(pkey->add_s++) = overwrite ? 0x01 : 0;
+            libssh2_htonu32(pkey->add_s, num_attrs);
+            pkey->add_s += 4;
+            for(i = 0; i < num_attrs; i++) {
+                libssh2_htonu32(pkey->add_s, attrs[i].name_len);
+                pkey->add_s += 4;
+                memcpy(pkey->add_s, attrs[i].name, attrs[i].name_len);
+                pkey->add_s += attrs[i].name_len;
+                libssh2_htonu32(pkey->add_s, attrs[i].value_len);
+                pkey->add_s += 4;
+                memcpy(pkey->add_s, attrs[i].value, attrs[i].value_len);
+                pkey->add_s += attrs[i].value_len;
+                *(pkey->add_s++) = attrs[i].mandatory ? 0x01 : 0;
+            }
+        }
+
+        _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
+                       "Sending publickey \"add\" packet: type=%s blob_len=%ld num_attrs=%ld",
+                       name, blob_len, num_attrs);
+
+        pkey->add_state = libssh2_NB_state_created;
+    }
+
+    if (pkey->add_state == libssh2_NB_state_created) {
+        rc = libssh2_channel_write_ex(channel, 0, (char *) pkey->add_packet,
+                                      (pkey->add_s - pkey->add_packet));
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if ((pkey->add_s - pkey->add_packet) != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send publickey add packet", 0);
+            LIBSSH2_FREE(session, pkey->add_packet);
+            pkey->add_packet = NULL;
+            return -1;
+        }
+        LIBSSH2_FREE(session, pkey->add_packet);
+        pkey->add_packet = NULL;
+
+        pkey->add_state = libssh2_NB_state_sent;
+    }
+
+    rc = libssh2_publickey_response_success(pkey);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    }
+
+    pkey->add_state = libssh2_NB_state_idle;
+
+    return rc;
+}
+
+/* }}} */
+
+/* {{{ libssh2_publickey_remove_ex
+ * Remove an existing publickey so that authentication can no longer be performed using it
+ */
+LIBSSH2_API int
+libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY * pkey,
+                            const unsigned char *name, unsigned long name_len,
+                            const unsigned char *blob, unsigned long blob_len)
+{
+    LIBSSH2_CHANNEL *channel = pkey->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    /* 22 = packet_len(4) + remove_len(4) + "remove"(6) + name_len(4) + {name} + blob_len(4) + {blob} */
+    unsigned long packet_len = 22 + name_len + blob_len;
+    int rc;
+
+    if (pkey->remove_state == libssh2_NB_state_idle) {
+        pkey->remove_packet = NULL;
+
+        pkey->remove_packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!pkey->remove_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for publickey \"remove\" packet",
+                          0);
+            return -1;
+        }
+
+        pkey->remove_s = pkey->remove_packet;
+        libssh2_htonu32(pkey->remove_s, packet_len - 4);
+        pkey->remove_s += 4;
+        libssh2_htonu32(pkey->remove_s, sizeof("remove") - 1);
+        pkey->remove_s += 4;
+        memcpy(pkey->remove_s, "remove", sizeof("remove") - 1);
+        pkey->remove_s += sizeof("remove") - 1;
+        libssh2_htonu32(pkey->remove_s, name_len);
+        pkey->remove_s += 4;
+        memcpy(pkey->remove_s, name, name_len);
+        pkey->remove_s += name_len;
+        libssh2_htonu32(pkey->remove_s, blob_len);
+        pkey->remove_s += 4;
+        memcpy(pkey->remove_s, blob, blob_len);
+        pkey->remove_s += blob_len;
+
+        _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
+                       "Sending publickey \"remove\" packet: type=%s blob_len=%ld",
+                       name, blob_len);
+
+        pkey->remove_state = libssh2_NB_state_created;
+    }
+
+    if (pkey->remove_state == libssh2_NB_state_created) {
+        rc = libssh2_channel_write_ex(channel, 0, (char *) pkey->remove_packet,
+                                      (pkey->remove_s - pkey->remove_packet));
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if ((pkey->remove_s - pkey->remove_packet) != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send publickey remove packet", 0);
+            LIBSSH2_FREE(session, pkey->remove_packet);
+            pkey->remove_packet = NULL;
+            pkey->remove_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, pkey->remove_packet);
+        pkey->remove_packet = NULL;
+
+        pkey->remove_state = libssh2_NB_state_sent;
+    }
+
+    rc = libssh2_publickey_response_success(pkey);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    }
+
+    pkey->remove_state = libssh2_NB_state_idle;
+
+    return rc;
+}
+
+/* }}} */
+
+/* {{{ libssh2_publickey_list_fetch
+ * Fetch a list of supported public key from a server
+ */
+LIBSSH2_API int
+libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys,
+                             libssh2_publickey_list ** pkey_list)
+{
+    LIBSSH2_CHANNEL *channel = pkey->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    libssh2_publickey_list *list = NULL;
+    unsigned long buffer_len = 12, keys = 0, max_keys = 0, i;
+    /* 12 = packet_len(4) + list_len(4) + "list"(4) */
+    int response;
+    int rc;
+
+    if (pkey->listFetch_state == libssh2_NB_state_idle) {
+        pkey->listFetch_data = NULL;
+
+        pkey->listFetch_s = pkey->listFetch_buffer;
+        libssh2_htonu32(pkey->listFetch_s, buffer_len - 4);
+        pkey->listFetch_s += 4;
+        libssh2_htonu32(pkey->listFetch_s, sizeof("list") - 1);
+        pkey->listFetch_s += 4;
+        memcpy(pkey->listFetch_s, "list", sizeof("list") - 1);
+        pkey->listFetch_s += sizeof("list") - 1;
+
+        _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY,
+                       "Sending publickey \"list\" packet");
+
+        pkey->listFetch_state = libssh2_NB_state_created;
+    }
+
+    if (pkey->listFetch_state == libssh2_NB_state_created) {
+        rc = libssh2_channel_write_ex(channel, 0,
+                                      (char *) pkey->listFetch_buffer,
+                                      (pkey->listFetch_s -
+                                       pkey->listFetch_buffer));
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if ((pkey->listFetch_s - pkey->listFetch_buffer) != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send publickey list packet", 0);
+            pkey->listFetch_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        pkey->listFetch_state = libssh2_NB_state_sent;
+    }
+
+    while (1) {
+        rc = libssh2_publickey_packet_receive(pkey, &pkey->listFetch_data,
+                                              &pkey->listFetch_data_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                          "Timeout waiting for response from publickey subsystem",
+                          0);
+            goto err_exit;
+        }
+
+        pkey->listFetch_s = pkey->listFetch_data;
+        if ((response =
+             libssh2_publickey_response_id(&pkey->listFetch_s,
+                                           pkey->listFetch_data_len)) < 0) {
+            libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
+                          "Invalid publickey subsystem response code", 0);
+            goto err_exit;
+        }
+
+        switch (response) {
+        case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
+            /* Error, or processing complete */
+            {
+                unsigned long status, descr_len, lang_len;
+                unsigned char *descr, *lang;
+
+                status = libssh2_ntohu32(pkey->listFetch_s);
+                pkey->listFetch_s += 4;
+                descr_len = libssh2_ntohu32(pkey->listFetch_s);
+                pkey->listFetch_s += 4;
+                descr = pkey->listFetch_s;
+                pkey->listFetch_s += descr_len;
+                lang_len = libssh2_ntohu32(pkey->listFetch_s);
+                pkey->listFetch_s += 4;
+                lang = pkey->listFetch_s;
+                pkey->listFetch_s += lang_len;
+
+                if (pkey->listFetch_s >
+                    pkey->listFetch_data + pkey->listFetch_data_len) {
+                    libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
+                                  "Malformed publickey subsystem packet", 0);
+                    goto err_exit;
+                }
+
+                if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
+                    LIBSSH2_FREE(session, pkey->listFetch_data);
+                    pkey->listFetch_data = NULL;
+                    *pkey_list = list;
+                    *num_keys = keys;
+                    pkey->listFetch_state = libssh2_NB_state_idle;
+                    return 0;
+                }
+
+                libssh2_publickey_status_error(pkey, session, status, descr,
+                                               descr_len);
+                goto err_exit;
+            }
+        case LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY:
+            /* What we want */
+            if (keys >= max_keys) {
+                libssh2_publickey_list *newlist;
+                /* Grow the key list if necessary */
+                max_keys += 8;
+                newlist =
+                    LIBSSH2_REALLOC(session, list,
+                                    (max_keys +
+                                     1) * sizeof(libssh2_publickey_list));
+                if (!newlist) {
+                    libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                                  "Unable to allocate memory for publickey list",
+                                  0);
+                    goto err_exit;
+                }
+                list = newlist;
+            }
+            if (pkey->version == 1) {
+                unsigned long comment_len;
+
+                comment_len = libssh2_ntohu32(pkey->listFetch_s);
+                pkey->listFetch_s += 4;
+                if (comment_len) {
+                    list[keys].num_attrs = 1;
+                    list[keys].attrs =
+                        LIBSSH2_ALLOC(session,
+                                      sizeof(libssh2_publickey_attribute));
+                    if (!list[keys].attrs) {
+                        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                                      "Unable to allocate memory for publickey attributes",
+                                      0);
+                        goto err_exit;
+                    }
+                    list[keys].attrs[0].name = "comment";
+                    list[keys].attrs[0].name_len = sizeof("comment") - 1;
+                    list[keys].attrs[0].value = (char *) pkey->listFetch_s;
+                    list[keys].attrs[0].value_len = comment_len;
+                    list[keys].attrs[0].mandatory = 0;
+
+                    pkey->listFetch_s += comment_len;
+                } else {
+                    list[keys].num_attrs = 0;
+                    list[keys].attrs = NULL;
+                }
+                list[keys].name_len = libssh2_ntohu32(pkey->listFetch_s);
+                pkey->listFetch_s += 4;
+                list[keys].name = pkey->listFetch_s;
+                pkey->listFetch_s += list[keys].name_len;
+                list[keys].blob_len = libssh2_ntohu32(pkey->listFetch_s);
+                pkey->listFetch_s += 4;
+                list[keys].blob = pkey->listFetch_s;
+                pkey->listFetch_s += list[keys].blob_len;
+            } else {
+                /* Version == 2 */
+                list[keys].name_len = libssh2_ntohu32(pkey->listFetch_s);
+                pkey->listFetch_s += 4;
+                list[keys].name = pkey->listFetch_s;
+                pkey->listFetch_s += list[keys].name_len;
+                list[keys].blob_len = libssh2_ntohu32(pkey->listFetch_s);
+                pkey->listFetch_s += 4;
+                list[keys].blob = pkey->listFetch_s;
+                pkey->listFetch_s += list[keys].blob_len;
+                list[keys].num_attrs = libssh2_ntohu32(pkey->listFetch_s);
+                pkey->listFetch_s += 4;
+                if (list[keys].num_attrs) {
+                    list[keys].attrs =
+                        LIBSSH2_ALLOC(session,
+                                      list[keys].num_attrs *
+                                      sizeof(libssh2_publickey_attribute));
+                    if (!list[keys].attrs) {
+                        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                                      "Unable to allocate memory for publickey attributes",
+                                      0);
+                        goto err_exit;
+                    }
+                    for(i = 0; i < list[keys].num_attrs; i++) {
+                        list[keys].attrs[i].name_len =
+                            libssh2_ntohu32(pkey->listFetch_s);
+                        pkey->listFetch_s += 4;
+                        list[keys].attrs[i].name = (char *) pkey->listFetch_s;
+                        pkey->listFetch_s += list[keys].attrs[i].name_len;
+                        list[keys].attrs[i].value_len =
+                            libssh2_ntohu32(pkey->listFetch_s);
+                        pkey->listFetch_s += 4;
+                        list[keys].attrs[i].value = (char *) pkey->listFetch_s;
+                        pkey->listFetch_s += list[keys].attrs[i].value_len;
+                        list[keys].attrs[i].mandatory = 0;      /* actually an ignored value */
+                    }
+                } else {
+                    list[keys].attrs = NULL;
+                }
+            }
+            list[keys].packet = pkey->listFetch_data;   /* To be FREEd in libssh2_publickey_list_free() */
+            keys++;
+
+            list[keys].packet = NULL;   /* Terminate the list */
+            pkey->listFetch_data = NULL;
+            break;
+        default:
+            /* Unknown/Unexpected */
+            libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL,
+                          "Unexpected publickey subsystem response, ignoring",
+                          0);
+            LIBSSH2_FREE(session, pkey->listFetch_data);
+            pkey->listFetch_data = NULL;
+        }
+    }
+
+    /* Only reached via explicit goto */
+  err_exit:
+    if (pkey->listFetch_data) {
+        LIBSSH2_FREE(session, pkey->listFetch_data);
+        pkey->listFetch_data = NULL;
+    }
+    if (list) {
+        libssh2_publickey_list_free(pkey, list);
+    }
+    pkey->listFetch_state = libssh2_NB_state_idle;
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_publickey_list_free
+ * Free a previously fetched list of public keys
+ */
+LIBSSH2_API void
+libssh2_publickey_list_free(LIBSSH2_PUBLICKEY * pkey,
+                            libssh2_publickey_list * pkey_list)
+{
+    LIBSSH2_SESSION *session = pkey->channel->session;
+    libssh2_publickey_list *p = pkey_list;
+
+    while (p->packet) {
+        if (p->attrs) {
+            LIBSSH2_FREE(session, p->attrs);
+        }
+        LIBSSH2_FREE(session, p->packet);
+        p++;
+    }
+
+    LIBSSH2_FREE(session, pkey_list);
+}
+
+/* }}} */
+
+/* {{{ libssh2_publickey_shutdown
+ * Shutdown the publickey subsystem
+ */
+LIBSSH2_API int
+libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY * pkey)
+{
+    LIBSSH2_SESSION *session = pkey->channel->session;
+
+    /*
+     * Make sure all memory used in the state variables are free
+     */
+    if (pkey->receive_packet) {
+        LIBSSH2_FREE(session, pkey->receive_packet);
+        pkey->receive_packet = NULL;
+    }
+    if (pkey->add_packet) {
+        LIBSSH2_FREE(session, pkey->add_packet);
+        pkey->add_packet = NULL;
+    }
+    if (pkey->remove_packet) {
+        LIBSSH2_FREE(session, pkey->remove_packet);
+        pkey->remove_packet = NULL;
+    }
+    if (pkey->listFetch_data) {
+        LIBSSH2_FREE(session, pkey->listFetch_data);
+        pkey->listFetch_data = NULL;
+    }
+
+    if (libssh2_channel_free(pkey->channel) == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    }
+
+    LIBSSH2_FREE(session, pkey);
+    return 0;
+}
+
+/* }}} */
diff --git a/Vendor/libssh2/Source/scp.c b/Vendor/libssh2/Source/scp.c
new file mode 100644 (file)
index 0000000..28eef5d
--- /dev/null
@@ -0,0 +1,811 @@
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+#include <errno.h>
+#include <stdlib.h>
+
+/* {{{ libssh2_scp_recv
+ * Open a channel and request a remote file via SCP
+ *
+ * NOTE:  Will block in a busy loop on error.  This has to be done,
+ *        otherwise the blocking error code would erase the true
+ *        cause of the error.
+ */
+LIBSSH2_API LIBSSH2_CHANNEL *
+libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
+{
+    int path_len = strlen(path);
+    int rc;
+
+    if (session->scpRecv_state == libssh2_NB_state_idle) {
+        session->scpRecv_mode = 0;
+        session->scpRecv_size = 0;
+        session->scpRecv_mtime = 0;
+        session->scpRecv_atime = 0;
+
+        session->scpRecv_command_len = path_len + sizeof("scp -f ");
+
+        if (sb) {
+            session->scpRecv_command_len++;
+        }
+
+        session->scpRecv_command =
+            LIBSSH2_ALLOC(session, session->scpRecv_command_len);
+        if (!session->scpRecv_command) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate a command buffer for SCP session",
+                          0);
+            return NULL;
+        }
+        if (sb) {
+            memcpy(session->scpRecv_command, "scp -pf ",
+                   sizeof("scp -pf ") - 1);
+            memcpy(session->scpRecv_command + sizeof("scp -pf ") - 1, path,
+                   path_len);
+        } else {
+            memcpy(session->scpRecv_command, "scp -f ", sizeof("scp -f ") - 1);
+            memcpy(session->scpRecv_command + sizeof("scp -f ") - 1, path,
+                   path_len);
+        }
+        session->scpRecv_command[session->scpRecv_command_len - 1] = '\0';
+
+        _libssh2_debug(session, LIBSSH2_DBG_SCP,
+                       "Opening channel for SCP receive");
+
+        session->scpRecv_state = libssh2_NB_state_created;
+    }
+
+    if (session->scpRecv_state == libssh2_NB_state_created) {
+        /* Allocate a channel */
+        do {
+            session->scpRecv_channel =
+                libssh2_channel_open_ex(session, "session",
+                                        sizeof("session") - 1,
+                                        LIBSSH2_CHANNEL_WINDOW_DEFAULT,
+                                        LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL,
+                                        0);
+            if (!session->scpRecv_channel) {
+                if (libssh2_session_last_errno(session) !=
+                    LIBSSH2_ERROR_EAGAIN) {
+                    LIBSSH2_FREE(session, session->scpRecv_command);
+                    session->scpRecv_command = NULL;
+                    session->scpRecv_state = libssh2_NB_state_idle;
+                    return NULL;
+                } else if (libssh2_session_last_errno(session) ==
+                           LIBSSH2_ERROR_EAGAIN) {
+                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                                  "Would block starting up channel", 0);
+                    return NULL;
+                }
+            }
+        } while (!session->scpRecv_channel);
+
+        session->scpRecv_state = libssh2_NB_state_sent;
+    }
+
+    if (session->scpRecv_state == libssh2_NB_state_sent) {
+        /* Request SCP for the desired file */
+        rc = libssh2_channel_process_startup(session->scpRecv_channel, "exec",
+                                             sizeof("exec") - 1,
+                                             (char *) session->scpRecv_command,
+                                             session->scpRecv_command_len);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block requesting SCP startup", 0);
+            return NULL;
+        } else if (rc) {
+            LIBSSH2_FREE(session, session->scpRecv_command);
+            session->scpRecv_command = NULL;
+            goto scp_recv_error;
+        }
+        LIBSSH2_FREE(session, session->scpRecv_command);
+        session->scpRecv_command = NULL;
+
+        _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup");
+        /* SCP ACK */
+        session->scpRecv_response[0] = '\0';
+
+        session->scpRecv_state = libssh2_NB_state_sent1;
+    }
+
+    if (session->scpRecv_state == libssh2_NB_state_sent1) {
+        rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
+                                      (char *) session->scpRecv_response, 1);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block sending initial wakeup", 0);
+            return NULL;
+        } else if (rc != 1) {
+            goto scp_recv_error;
+        }
+
+        /* Parse SCP response */
+        session->scpRecv_response_len = 0;
+
+        session->scpRecv_state = libssh2_NB_state_sent2;
+    }
+
+    if ((session->scpRecv_state == libssh2_NB_state_sent2)
+        || (session->scpRecv_state == libssh2_NB_state_sent3)) {
+        while (sb
+               && (session->scpRecv_response_len <
+                   LIBSSH2_SCP_RESPONSE_BUFLEN)) {
+            unsigned char *s, *p;
+
+            if (session->scpRecv_state == libssh2_NB_state_sent2) {
+                rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
+                                             (char *) session->
+                                             scpRecv_response +
+                                             session->scpRecv_response_len, 1);
+                if (rc == PACKET_EAGAIN) {
+                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                                  "Would block waiting for SCP response", 0);
+                    return NULL;
+                } else if (rc <= 0) {
+                    /* Timeout, give up */
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Timed out waiting for SCP response", 0);
+                    goto scp_recv_error;
+                }
+                session->scpRecv_response_len++;
+
+                if (session->scpRecv_response[0] != 'T') {
+                    /*
+                     * Set this as the default error for here, if
+                     * we are successful it will be replaced
+                     */
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid data in SCP response, missing Time data",
+                                  0);
+
+                    session->scpRecv_err_len =
+                        libssh2_channel_packet_data_len(session->
+                                                        scpRecv_channel, 0);
+                    session->scpRecv_err_msg =
+                        LIBSSH2_ALLOC(session, session->scpRecv_err_len + 1);
+                    if (!session->scpRecv_err_msg) {
+                        goto scp_recv_error;
+                    }
+                    memset(session->scpRecv_err_msg, 0,
+                           session->scpRecv_err_len + 1);
+
+                    /* Read the remote error message */
+                    rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
+                                                 session->scpRecv_err_msg,
+                                                 session->scpRecv_err_len);
+                    if (rc <= 0) {
+                        /*
+                         * Since we have alread started reading this packet, it is
+                         * already in the systems so it can't return PACKET_EAGAIN
+                         */
+                        LIBSSH2_FREE(session, session->scpRecv_err_msg);
+                        session->scpRecv_err_msg = NULL;
+                        libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                      "Unknown error while getting error string",
+                                      0);
+                        goto scp_recv_error;
+                    }
+
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  session->scpRecv_err_msg, 1);
+                    session->scpRecv_err_msg = NULL;
+                    goto scp_recv_error;
+                }
+
+                if ((session->scpRecv_response_len > 1) &&
+                    ((session->
+                      scpRecv_response[session->scpRecv_response_len - 1] <
+                      '0')
+                     || (session->
+                         scpRecv_response[session->scpRecv_response_len - 1] >
+                         '9'))
+                    && (session->
+                        scpRecv_response[session->scpRecv_response_len - 1] !=
+                        ' ')
+                    && (session->
+                        scpRecv_response[session->scpRecv_response_len - 1] !=
+                        '\r')
+                    && (session->
+                        scpRecv_response[session->scpRecv_response_len - 1] !=
+                        '\n')) {
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid data in SCP response", 0);
+                    goto scp_recv_error;
+                }
+
+                if ((session->scpRecv_response_len < 9)
+                    || (session->
+                        scpRecv_response[session->scpRecv_response_len - 1] !=
+                        '\n')) {
+                    if (session->scpRecv_response_len ==
+                        LIBSSH2_SCP_RESPONSE_BUFLEN) {
+                        /* You had your chance */
+                        libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                      "Unterminated response from SCP server",
+                                      0);
+                        goto scp_recv_error;
+                    }
+                    /* Way too short to be an SCP response,  or not done yet, short circuit */
+                    continue;
+                }
+
+                /* We're guaranteed not to go under response_len == 0 by the logic above */
+                while ((session->
+                        scpRecv_response[session->scpRecv_response_len - 1] ==
+                        '\r')
+                       || (session->
+                           scpRecv_response[session->scpRecv_response_len -
+                                            1] == '\n'))
+                    session->scpRecv_response_len--;
+                session->scpRecv_response[session->scpRecv_response_len] =
+                    '\0';
+
+                if (session->scpRecv_response_len < 8) {
+                    /* EOL came too soon */
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid response from SCP server, too short",
+                                  0);
+                    goto scp_recv_error;
+                }
+
+                s = session->scpRecv_response + 1;
+
+                p = (unsigned char *) strchr((char *) s, ' ');
+                if (!p || ((p - s) <= 0)) {
+                    /* No spaces or space in the wrong spot */
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid response from SCP server, malformed mtime",
+                                  0);
+                    goto scp_recv_error;
+                }
+
+                *(p++) = '\0';
+                /* Make sure we don't get fooled by leftover values */
+                errno = 0;
+                session->scpRecv_mtime = strtol((char *) s, NULL, 10);
+                if (errno) {
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid response from SCP server, invalid mtime",
+                                  0);
+                    goto scp_recv_error;
+                }
+                s = (unsigned char *) strchr((char *) p, ' ');
+                if (!s || ((s - p) <= 0)) {
+                    /* No spaces or space in the wrong spot */
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid response from SCP server, malformed mtime.usec",
+                                  0);
+                    goto scp_recv_error;
+                }
+
+                /* Ignore mtime.usec */
+                s++;
+                p = (unsigned char *) strchr((char *) s, ' ');
+                if (!p || ((p - s) <= 0)) {
+                    /* No spaces or space in the wrong spot */
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid response from SCP server, too short or malformed",
+                                  0);
+                    goto scp_recv_error;
+                }
+
+                *(p++) = '\0';
+                /* Make sure we don't get fooled by leftover values */
+                errno = 0;
+                session->scpRecv_atime = strtol((char *) s, NULL, 10);
+                if (errno) {
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid response from SCP server, invalid atime",
+                                  0);
+                    goto scp_recv_error;
+                }
+
+                /* SCP ACK */
+                session->scpRecv_response[0] = '\0';
+
+                session->scpRecv_state = libssh2_NB_state_sent3;
+            }
+
+            if (session->scpRecv_state == libssh2_NB_state_sent3) {
+                rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
+                                              (char *) session->
+                                              scpRecv_response, 1);
+                if (rc == PACKET_EAGAIN) {
+                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                                  "Would block waiting to send SCP ACK", 0);
+                    return NULL;
+                } else if (rc != 1) {
+                    goto scp_recv_error;
+                }
+
+                _libssh2_debug(session, LIBSSH2_DBG_SCP,
+                               "mtime = %ld, atime = %ld",
+                               session->scpRecv_mtime, session->scpRecv_atime);
+
+                /* We *should* check that atime.usec is valid, but why let that stop use? */
+                break;
+            }
+        }
+
+        session->scpRecv_state = libssh2_NB_state_sent4;
+    }
+
+    if (session->scpRecv_state == libssh2_NB_state_sent4) {
+        session->scpRecv_response_len = 0;
+
+        session->scpRecv_state = libssh2_NB_state_sent5;
+    }
+
+    if ((session->scpRecv_state == libssh2_NB_state_sent5)
+        || (session->scpRecv_state == libssh2_NB_state_sent6)) {
+        while (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) {
+            char *s, *p, *e = NULL;
+
+            if (session->scpRecv_state == libssh2_NB_state_sent5) {
+                rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
+                                             (char *) session->
+                                             scpRecv_response +
+                                             session->scpRecv_response_len, 1);
+                if (rc == PACKET_EAGAIN) {
+                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                                  "Would block waiting for SCP response", 0);
+                    return NULL;
+                } else if (rc <= 0) {
+                    /* Timeout, give up */
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Timed out waiting for SCP response", 0);
+                    goto scp_recv_error;
+                }
+                session->scpRecv_response_len++;
+
+                if (session->scpRecv_response[0] != 'C') {
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid response from SCP server", 0);
+                    goto scp_recv_error;
+                }
+
+                if ((session->scpRecv_response_len > 1) &&
+                    (session->
+                     scpRecv_response[session->scpRecv_response_len - 1] !=
+                     '\r')
+                    && (session->
+                        scpRecv_response[session->scpRecv_response_len - 1] !=
+                        '\n')
+                    &&
+                    ((session->
+                      scpRecv_response[session->scpRecv_response_len - 1] < 32)
+                     || (session->
+                         scpRecv_response[session->scpRecv_response_len - 1] >
+                         126))) {
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid data in SCP response", 0);
+                    goto scp_recv_error;
+                }
+
+                if ((session->scpRecv_response_len < 7)
+                    || (session->
+                        scpRecv_response[session->scpRecv_response_len - 1] !=
+                        '\n')) {
+                    if (session->scpRecv_response_len ==
+                        LIBSSH2_SCP_RESPONSE_BUFLEN) {
+                        /* You had your chance */
+                        libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                      "Unterminated response from SCP server",
+                                      0);
+                        goto scp_recv_error;
+                    }
+                    /* Way too short to be an SCP response,  or not done yet, short circuit */
+                    continue;
+                }
+
+                /* We're guaranteed not to go under response_len == 0 by the logic above */
+                while ((session->
+                        scpRecv_response[session->scpRecv_response_len - 1] ==
+                        '\r')
+                       || (session->
+                           scpRecv_response[session->scpRecv_response_len -
+                                            1] == '\n')) {
+                    session->scpRecv_response_len--;
+                }
+                session->scpRecv_response[session->scpRecv_response_len] =
+                    '\0';
+
+                if (session->scpRecv_response_len < 6) {
+                    /* EOL came too soon */
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid response from SCP server, too short",
+                                  0);
+                    goto scp_recv_error;
+                }
+
+                s = (char *) session->scpRecv_response + 1;
+
+                p = strchr(s, ' ');
+                if (!p || ((p - s) <= 0)) {
+                    /* No spaces or space in the wrong spot */
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid response from SCP server, malformed mode",
+                                  0);
+                    goto scp_recv_error;
+                }
+
+                *(p++) = '\0';
+                /* Make sure we don't get fooled by leftover values */
+                errno = 0;
+                session->scpRecv_mode = strtol(s, &e, 8);
+                if ((e && *e) || errno) {
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid response from SCP server, invalid mode",
+                                  0);
+                    goto scp_recv_error;
+                }
+
+                s = strchr(p, ' ');
+                if (!s || ((s - p) <= 0)) {
+                    /* No spaces or space in the wrong spot */
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid response from SCP server, too short or malformed",
+                                  0);
+                    goto scp_recv_error;
+                }
+
+                *(s++) = '\0';
+                /* Make sure we don't get fooled by leftover values */
+                errno = 0;
+                session->scpRecv_size = strtol(p, &e, 10);
+                if ((e && *e) || errno) {
+                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                                  "Invalid response from SCP server, invalid size",
+                                  0);
+                    goto scp_recv_error;
+                }
+
+                /* SCP ACK */
+                session->scpRecv_response[0] = '\0';
+
+                session->scpRecv_state = libssh2_NB_state_sent6;
+            }
+
+            if (session->scpRecv_state == libssh2_NB_state_sent6) {
+                rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
+                                              (char *) session->
+                                              scpRecv_response, 1);
+                if (rc == PACKET_EAGAIN) {
+                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                                  "Would block sending SCP ACK", 0);
+                    return NULL;
+                } else if (rc != 1) {
+                    goto scp_recv_error;
+                }
+                _libssh2_debug(session, LIBSSH2_DBG_SCP,
+                               "mode = 0%lo size = %ld", session->scpRecv_mode,
+                               session->scpRecv_size);
+
+                /* We *should* check that basename is valid, but why let that stop us? */
+                break;
+            }
+        }
+
+        session->scpRecv_state = libssh2_NB_state_sent7;
+    }
+
+    if (sb) {
+        memset(sb, 0, sizeof(struct stat));
+
+        sb->st_mtime = session->scpRecv_mtime;
+        sb->st_atime = session->scpRecv_atime;
+        sb->st_size = session->scpRecv_size;
+        sb->st_mode = session->scpRecv_mode;
+    }
+
+    session->scpRecv_state = libssh2_NB_state_idle;
+    return session->scpRecv_channel;
+
+  scp_recv_error:
+    while (libssh2_channel_free(session->scpRecv_channel) == PACKET_EAGAIN);
+    session->scpRecv_channel = NULL;
+    session->scpRecv_state = libssh2_NB_state_idle;
+    return NULL;
+}
+
+/* }}} */
+
+/* {{{ libssh2_scp_send_ex
+ * Send a file using SCP
+ *
+ * NOTE:  Will block in a busy loop on error.  This has to be done,
+ *        otherwise the blocking error code would erase the true
+ *        cause of the error.
+ */
+LIBSSH2_API LIBSSH2_CHANNEL *
+libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
+                    size_t size, long mtime, long atime)
+{
+    int path_len = strlen(path);
+    unsigned const char *base;
+    int rc;
+
+    if (session->scpSend_state == libssh2_NB_state_idle) {
+        session->scpSend_command_len = path_len + sizeof("scp -t ");
+
+        if (mtime || atime) {
+            session->scpSend_command_len++;
+        }
+
+        session->scpSend_command =
+            LIBSSH2_ALLOC(session, session->scpSend_command_len);
+        if (!session->scpSend_command) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate a command buffer for scp session",
+                          0);
+            return NULL;
+        }
+
+        if (mtime || atime) {
+            memcpy(session->scpSend_command, "scp -pt ",
+                   sizeof("scp -pt ") - 1);
+            memcpy(session->scpSend_command + sizeof("scp -pt ") - 1, path,
+                   path_len);
+        } else {
+            memcpy(session->scpSend_command, "scp -t ", sizeof("scp -t ") - 1);
+            memcpy(session->scpSend_command + sizeof("scp -t ") - 1, path,
+                   path_len);
+        }
+        session->scpSend_command[session->scpSend_command_len - 1] = '\0';
+
+        _libssh2_debug(session, LIBSSH2_DBG_SCP,
+                       "Opening channel for SCP send");
+        /* Allocate a channel */
+
+        session->scpSend_state = libssh2_NB_state_created;
+    }
+
+    if (session->scpSend_state == libssh2_NB_state_created) {
+        session->scpSend_channel =
+            libssh2_channel_open_ex(session, "session", sizeof("session") - 1,
+                                    LIBSSH2_CHANNEL_WINDOW_DEFAULT,
+                                    LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0);
+        if (!session->scpSend_channel) {
+            if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
+                /* previous call set libssh2_session_last_error(), pass it through */
+                LIBSSH2_FREE(session, session->scpSend_command);
+                session->scpSend_command = NULL;
+                session->scpSend_state = libssh2_NB_state_idle;
+                return NULL;
+            } else if (libssh2_session_last_errno(session) ==
+                       LIBSSH2_ERROR_EAGAIN) {
+                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                              "Would block starting up channel", 0);
+                return NULL;
+            }
+        }
+
+        session->scpSend_state = libssh2_NB_state_sent;
+    }
+
+    if (session->scpSend_state == libssh2_NB_state_sent) {
+        /* Request SCP for the desired file */
+        rc = libssh2_channel_process_startup(session->scpSend_channel, "exec",
+                                             sizeof("exec") - 1,
+                                             (char *) session->scpSend_command,
+                                             session->scpSend_command_len);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block requesting SCP startup", 0);
+            return NULL;
+        } else if (rc) {
+            /* previous call set libssh2_session_last_error(), pass it through */
+            LIBSSH2_FREE(session, session->scpSend_command);
+            session->scpSend_command = NULL;
+            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                          "Unknown error while getting error string", 0);
+            goto scp_send_error;
+        }
+        LIBSSH2_FREE(session, session->scpSend_command);
+        session->scpSend_command = NULL;
+
+        session->scpSend_state = libssh2_NB_state_sent1;
+    }
+
+    if (session->scpSend_state == libssh2_NB_state_sent1) {
+        /* Wait for ACK */
+        rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
+                                     (char *) session->scpSend_response, 1);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block waiting for response from remote", 0);
+            return NULL;
+        } else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
+            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                          "Invalid ACK response from remote", 0);
+            goto scp_send_error;
+        }
+
+        if (mtime || atime) {
+            /* Send mtime and atime to be used for file */
+            session->scpSend_response_len =
+                snprintf((char *) session->scpSend_response,
+                         LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", mtime,
+                         atime);
+            _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
+                           session->scpSend_response);
+        }
+
+        session->scpSend_state = libssh2_NB_state_sent2;
+    }
+
+    /* Send mtime and atime to be used for file */
+    if (mtime || atime) {
+        if (session->scpSend_state == libssh2_NB_state_sent2) {
+            rc = libssh2_channel_write_ex(session->scpSend_channel, 0,
+                                          (char *) session->scpSend_response,
+                                          session->scpSend_response_len);
+            if (rc == PACKET_EAGAIN) {
+                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                              "Would block sending time data for SCP file", 0);
+                return NULL;
+            } else if (rc != session->scpSend_response_len) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                              "Unable to send time data for SCP file", 0);
+                goto scp_send_error;
+            }
+
+            session->scpSend_state = libssh2_NB_state_sent3;
+        }
+
+        if (session->scpSend_state == libssh2_NB_state_sent3) {
+            /* Wait for ACK */
+            rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
+                                         (char *) session->scpSend_response,
+                                         1);
+            if (rc == PACKET_EAGAIN) {
+                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                              "Would block waiting for response", 0);
+                return NULL;
+            } else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
+                libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                              "Invalid ACK response from remote", 0);
+                goto scp_send_error;
+            }
+
+            session->scpSend_state = libssh2_NB_state_sent4;
+        }
+    } else {
+        if (session->scpSend_state == libssh2_NB_state_sent2) {
+            session->scpSend_state = libssh2_NB_state_sent4;
+        }
+    }
+
+    if (session->scpSend_state == libssh2_NB_state_sent4) {
+        /* Send mode, size, and basename */
+        base = (unsigned char *) strrchr(path, '/');
+        if (base) {
+            base++;
+        } else {
+            base = (unsigned char *) path;
+        }
+
+        session->scpSend_response_len =
+            snprintf((char *) session->scpSend_response,
+                     LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %lu %s\n", mode,
+                     (unsigned long) size, base);
+        _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
+                       session->scpSend_response);
+
+        session->scpSend_state = libssh2_NB_state_sent5;
+    }
+
+    if (session->scpSend_state == libssh2_NB_state_sent5) {
+        rc = libssh2_channel_write_ex(session->scpSend_channel, 0,
+                                      (char *) session->scpSend_response,
+                                      session->scpSend_response_len);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block send core file data for SCP file", 0);
+            return NULL;
+        } else if (rc != session->scpSend_response_len) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send core file data for SCP file", 0);
+            goto scp_send_error;
+        }
+
+        session->scpSend_state = libssh2_NB_state_sent6;
+    }
+
+    if (session->scpSend_state == libssh2_NB_state_sent6) {
+        /* Wait for ACK */
+        rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
+                                     (char *) session->scpSend_response, 1);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block waiting for response", 0);
+            return NULL;
+        } else if (rc <= 0) {
+            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                          "Invalid ACK response from remote", 0);
+            goto scp_send_error;
+        } else if (session->scpSend_response[0] != 0) {
+            /*
+             * Set this as the default error for here, if
+             * we are successful it will be replaced
+             */
+            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                          "Invalid ACK response from remote", 0);
+
+            session->scpSend_err_len =
+                libssh2_channel_packet_data_len(session->scpSend_channel, 0);
+            session->scpSend_err_msg =
+                LIBSSH2_ALLOC(session, session->scpSend_err_len + 1);
+            if (!session->scpSend_err_msg) {
+                goto scp_send_error;
+            }
+            memset(session->scpSend_err_msg, 0, session->scpSend_err_len + 1);
+
+            /* Read the remote error message */
+            rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
+                                         session->scpSend_err_msg,
+                                         session->scpSend_err_len);
+            if (rc <= 0) {
+                /*
+                 * Since we have alread started reading this packet, it is
+                 * already in the systems so it can't return PACKET_EAGAIN
+                 */
+                LIBSSH2_FREE(session, session->scpSend_err_msg);
+                session->scpSend_err_msg = NULL;
+                goto scp_send_error;
+            }
+
+            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
+                          session->scpSend_err_msg, 1);
+            session->scpSend_err_msg = NULL;
+            goto scp_send_error;
+        }
+    }
+
+    session->scpSend_state = libssh2_NB_state_idle;
+
+    return session->scpSend_channel;
+
+  scp_send_error:
+    while (libssh2_channel_free(session->scpSend_channel) == PACKET_EAGAIN);
+    session->scpSend_channel = NULL;
+    session->scpSend_state = libssh2_NB_state_idle;
+    return NULL;
+}
+
+/* }}} */
diff --git a/Vendor/libssh2/Source/session.c b/Vendor/libssh2/Source/session.c
new file mode 100644 (file)
index 0000000..3d33b63
--- /dev/null
@@ -0,0 +1,1535 @@
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <fcntl.h>
+
+#ifdef HAVE_GETTIMEOFDAY
+#include <sys/time.h>
+#endif
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+/* {{{ libssh2_default_alloc
+ */
+static
+LIBSSH2_ALLOC_FUNC(libssh2_default_alloc)
+{
+    (void) abstract;
+    return malloc(count);
+}
+
+/* }}} */
+
+/* {{{ libssh2_default_free
+ */
+static
+LIBSSH2_FREE_FUNC(libssh2_default_free)
+{
+    (void) abstract;
+    free(ptr);
+}
+
+/* }}} */
+
+/* {{{ libssh2_default_realloc
+ */
+static
+LIBSSH2_REALLOC_FUNC(libssh2_default_realloc)
+{
+    (void) abstract;
+    return realloc(ptr, count);
+}
+
+/* }}} */
+
+/* {{{ libssh2_banner_receive
+ * Wait for a hello from the remote host
+ * Allocate a buffer and store the banner in session->remote.banner
+ * Returns: 0 on success, PACKET_EAGAIN if read would block, 1 on failure
+ */
+static int
+libssh2_banner_receive(LIBSSH2_SESSION * session)
+{
+    int ret;
+    int banner_len;
+
+    if (session->banner_TxRx_state == libssh2_NB_state_idle) {
+        banner_len = 0;
+
+        session->banner_TxRx_state = libssh2_NB_state_created;
+    } else {
+        banner_len = session->banner_TxRx_total_send;
+    }
+
+    while ((banner_len < (int) sizeof(session->banner_TxRx_banner)) &&
+           ((banner_len == 0)
+            || (session->banner_TxRx_banner[banner_len - 1] != '\n'))) {
+        char c = '\0';
+
+        ret =
+            recv(session->socket_fd, &c, 1,
+                 LIBSSH2_SOCKET_RECV_FLAGS(session));
+
+        if (ret < 0) {
+#ifdef WIN32
+            switch (WSAGetLastError()) {
+            case WSAEWOULDBLOCK:
+                errno = EAGAIN;
+                break;
+
+            case WSAENOTSOCK:
+                errno = EBADF;
+                break;
+
+            case WSAENOTCONN:
+            case WSAECONNABORTED:
+                errno = WSAENOTCONN;
+                break;
+
+            case WSAEINTR:
+                errno = EINTR;
+                break;
+            }
+#endif /* WIN32 */
+            if (errno == EAGAIN) {
+                session->banner_TxRx_total_send = banner_len;
+                return PACKET_EAGAIN;
+            }
+
+            /* Some kinda error */
+            session->banner_TxRx_state = libssh2_NB_state_idle;
+            session->banner_TxRx_total_send = 0;
+            return 1;
+        }
+
+        if (ret == 0) {
+            session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
+            return PACKET_FAIL;
+        }
+
+        if (c == '\0') {
+            /* NULLs are not allowed in SSH banners */
+            session->banner_TxRx_state = libssh2_NB_state_idle;
+            session->banner_TxRx_total_send = 0;
+            return 1;
+        }
+
+        session->banner_TxRx_banner[banner_len++] = c;
+    }
+
+    while (banner_len &&
+           ((session->banner_TxRx_banner[banner_len - 1] == '\n') ||
+            (session->banner_TxRx_banner[banner_len - 1] == '\r'))) {
+        banner_len--;
+    }
+
+    /* From this point on, we are done here */
+    session->banner_TxRx_state = libssh2_NB_state_idle;
+    session->banner_TxRx_total_send = 0;
+
+    if (!banner_len)
+        return 1;
+
+    session->remote.banner = LIBSSH2_ALLOC(session, banner_len + 1);
+    if (!session->remote.banner) {
+        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                      "Error allocating space for remote banner", 0);
+        return 1;
+    }
+    memcpy(session->remote.banner, session->banner_TxRx_banner, banner_len);
+    session->remote.banner[banner_len] = '\0';
+    _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Received Banner: %s",
+                   session->remote.banner);
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_banner_send
+ * Send the default banner, or the one set via libssh2_setopt_string
+ *
+ * Returns PACKET_EAGAIN if it would block - and if it does so, you should
+ * call this function again as soon as it is likely that more data can be
+ * sent, and this function should then be called with the same argument set
+ * (same data pointer and same data_len) until zero or failure is returned.
+ */
+static int
+libssh2_banner_send(LIBSSH2_SESSION * session)
+{
+    char *banner = (char *) LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF;
+    int banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1;
+    ssize_t ret;
+#ifdef LIBSSH2DEBUG
+    char banner_dup[256];
+#endif
+
+    if (session->banner_TxRx_state == libssh2_NB_state_idle) {
+        if (session->local.banner) {
+            /* setopt_string will have given us our \r\n characters */
+            banner_len = strlen((char *) session->local.banner);
+            banner = (char *) session->local.banner;
+        }
+#ifdef LIBSSH2DEBUG
+        /* Hack and slash to avoid sending CRLF in debug output */
+        if (banner_len < 256) {
+            memcpy(banner_dup, banner, banner_len - 2);
+            banner_dup[banner_len - 2] = '\0';
+        } else {
+            memcpy(banner_dup, banner, 255);
+            banner[255] = '\0';
+        }
+
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending Banner: %s",
+                       banner_dup);
+#endif
+
+        session->banner_TxRx_state = libssh2_NB_state_created;
+    }
+
+    ret =
+        send(session->socket_fd, banner + session->banner_TxRx_total_send,
+             banner_len - session->banner_TxRx_total_send,
+             LIBSSH2_SOCKET_SEND_FLAGS(session));
+
+    if (ret != (banner_len - session->banner_TxRx_total_send)) {
+        if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
+            /* the whole packet could not be sent, save the what was */
+            session->banner_TxRx_total_send += ret;
+            return PACKET_EAGAIN;
+        }
+        session->banner_TxRx_state = libssh2_NB_state_idle;
+        session->banner_TxRx_total_send = 0;
+        return PACKET_FAIL;
+    }
+
+    /* Set the state back to idle */
+    session->banner_TxRx_state = libssh2_NB_state_idle;
+    session->banner_TxRx_total_send = 0;
+
+    return 0;
+}
+
+/* }}} */
+
+/*
+ * _libssh2_nonblock() sets the given socket to either blocking or
+ * non-blocking mode based on the 'nonblock' boolean argument. This function
+ * is copied from the libcurl sources with permission.
+ */
+static int
+_libssh2_nonblock(int sockfd,   /* operate on this */
+                  int nonblock /* TRUE or FALSE */ )
+{
+#undef SETBLOCK
+#define SETBLOCK 0
+#ifdef HAVE_O_NONBLOCK
+    /* most recent unix versions */
+    int flags;
+
+    flags = fcntl(sockfd, F_GETFL, 0);
+    if (nonblock)
+        return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
+    else
+        return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
+#undef SETBLOCK
+#define SETBLOCK 1
+#endif
+
+#if defined(HAVE_FIONBIO) && (SETBLOCK == 0)
+    /* older unix versions */
+    int flags;
+
+    flags = nonblock;
+    return ioctl(sockfd, FIONBIO, &flags);
+#undef SETBLOCK
+#define SETBLOCK 2
+#endif
+
+#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0)
+    /* Windows? */
+    unsigned long flags;
+    flags = nonblock;
+
+    return ioctlsocket(sockfd, FIONBIO, &flags);
+#undef SETBLOCK
+#define SETBLOCK 3
+#endif
+
+#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0)
+    /* presumably for Amiga */
+    return IoctlSocket(sockfd, FIONBIO, (long) nonblock);
+#undef SETBLOCK
+#define SETBLOCK 4
+#endif
+
+#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0)
+    /* BeOS */
+    long b = nonblock ? 1 : 0;
+    return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
+#undef SETBLOCK
+#define SETBLOCK 5
+#endif
+
+#ifdef HAVE_DISABLED_NONBLOCKING
+    return 0;                   /* returns success */
+#undef SETBLOCK
+#define SETBLOCK 6
+#endif
+
+#if (SETBLOCK == 0)
+#error "no non-blocking method was found/used/set"
+#endif
+}
+
+/*
+ * _libssh2_get_socket_nonblocking() gets the given blocking or non-blocking
+ * state of the socket.
+ */
+static int
+_libssh2_get_socket_nonblocking(int sockfd)
+{                               /* operate on this */
+#undef GETBLOCK
+#define GETBLOCK 0
+#ifdef HAVE_O_NONBLOCK
+    /* most recent unix versions */
+    int flags;
+
+    if ((flags = fcntl(sockfd, F_GETFL, 0)) == -1) {
+        /* Assume blocking on error */
+        return 1;
+    }
+    return (flags & O_NONBLOCK);
+#undef GETBLOCK
+#define GETBLOCK 1
+#endif
+
+#if defined(WSAEWOULDBLOCK) && (GETBLOCK == 0)
+    /* Windows? */
+    unsigned int option_value;
+    socklen_t option_len = sizeof(option_value);
+
+    if (getsockopt
+        (sockfd, SOL_SOCKET, SO_ERROR, (void *) &option_value, &option_len)) {
+        /* Assume blocking on error */
+        return 1;
+    }
+    return (int) option_value;
+#undef GETBLOCK
+#define GETBLOCK 2
+#endif
+
+#if defined(HAVE_SO_NONBLOCK) && (GETBLOCK == 0)
+    /* BeOS */
+    long b;
+    if (getsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b))) {
+        /* Assume blocking on error */
+        return 1;
+    }
+    return (int) b;
+#undef GETBLOCK
+#define GETBLOCK 5
+#endif
+
+#ifdef HAVE_DISABLED_NONBLOCKING
+    return 1;                   /* returns blocking */
+#undef GETBLOCK
+#define GETBLOCK 6
+#endif
+
+#if (GETBLOCK == 0)
+#error "no non-blocking method was found/used/get"
+#endif
+}
+
+/* {{{ libssh2_banner_set
+ * Set the local banner
+ */
+LIBSSH2_API int
+libssh2_banner_set(LIBSSH2_SESSION * session, const char *banner)
+{
+    int banner_len = banner ? strlen(banner) : 0;
+
+    if (session->local.banner) {
+        LIBSSH2_FREE(session, session->local.banner);
+        session->local.banner = NULL;
+    }
+
+    if (!banner_len) {
+        return 0;
+    }
+
+    session->local.banner = LIBSSH2_ALLOC(session, banner_len + 3);
+    if (!session->local.banner) {
+        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                      "Unable to allocate memory for local banner", 0);
+        return -1;
+    }
+
+    memcpy(session->local.banner, banner, banner_len);
+    session->local.banner[banner_len] = '\0';
+    _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting local Banner: %s",
+                   session->local.banner);
+    session->local.banner[banner_len++] = '\r';
+    session->local.banner[banner_len++] = '\n';
+    session->local.banner[banner_len++] = '\0';
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ proto libssh2_session_init
+ * Allocate and initialize a libssh2 session structure
+ * Allows for malloc callbacks in case the calling program has its own memory manager
+ * It's allowable (but unadvisable) to define some but not all of the malloc callbacks
+ * An additional pointer value may be optionally passed to be sent to the callbacks (so they know who's asking)
+ */
+LIBSSH2_API LIBSSH2_SESSION *
+libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)),
+                        LIBSSH2_FREE_FUNC((*my_free)),
+                        LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract)
+{
+    LIBSSH2_ALLOC_FUNC((*local_alloc)) = libssh2_default_alloc;
+    LIBSSH2_FREE_FUNC((*local_free)) = libssh2_default_free;
+    LIBSSH2_REALLOC_FUNC((*local_realloc)) = libssh2_default_realloc;
+    LIBSSH2_SESSION *session;
+
+    if (my_alloc) {
+        local_alloc = my_alloc;
+    }
+    if (my_free) {
+        local_free = my_free;
+    }
+    if (my_realloc) {
+        local_realloc = my_realloc;
+    }
+
+    session = local_alloc(sizeof(LIBSSH2_SESSION), abstract);
+    if (session) {
+        memset(session, 0, sizeof(LIBSSH2_SESSION));
+        session->alloc = local_alloc;
+        session->free = local_free;
+        session->realloc = local_realloc;
+        session->abstract = abstract;
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
+                       "New session resource allocated");
+        libssh2_crypto_init();
+    }
+    return session;
+}
+
+/* }}} */
+
+/* {{{ libssh2_session_callback_set
+ * Set (or reset) a callback function
+ * Returns the prior address
+ *
+ * FIXME: this function relies on that we can typecast function pointers
+ * to void pointers, which isn't allowed in ISO C!
+ */
+LIBSSH2_API void *
+libssh2_session_callback_set(LIBSSH2_SESSION * session,
+                             int cbtype, void *callback)
+{
+    void *oldcb;
+
+    switch (cbtype) {
+    case LIBSSH2_CALLBACK_IGNORE:
+        oldcb = session->ssh_msg_ignore;
+        session->ssh_msg_ignore = callback;
+        return oldcb;
+
+    case LIBSSH2_CALLBACK_DEBUG:
+        oldcb = session->ssh_msg_debug;
+        session->ssh_msg_debug = callback;
+        return oldcb;
+
+    case LIBSSH2_CALLBACK_DISCONNECT:
+        oldcb = session->ssh_msg_disconnect;
+        session->ssh_msg_disconnect = callback;
+        return oldcb;
+
+    case LIBSSH2_CALLBACK_MACERROR:
+        oldcb = session->macerror;
+        session->macerror = callback;
+        return oldcb;
+
+    case LIBSSH2_CALLBACK_X11:
+        oldcb = session->x11;
+        session->x11 = callback;
+        return oldcb;
+
+    }
+    _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting Callback %d", cbtype);
+
+    return NULL;
+}
+
+/* }}} */
+
+/* {{{ proto libssh2_session_startup
+ * session: LIBSSH2_SESSION struct allocated and owned by the calling program
+ * Returns: 0 on success, or non-zero on failure
+ * Any memory allocated by libssh2 will use alloc/realloc/free
+ * callbacks in session
+ * socket *must* be populated with an opened and connected socket.
+ */
+LIBSSH2_API int
+libssh2_session_startup(LIBSSH2_SESSION * session, int sock)
+{
+    int rc;
+
+    if (session->startup_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
+                       "session_startup for socket %d", sock);
+        /* FIXME: on some platforms (like win32) sockets are unsigned */
+        if (sock < 0) {
+            /* Did we forget something? */
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE,
+                          "Bad socket provided", 0);
+            return LIBSSH2_ERROR_SOCKET_NONE;
+        }
+        session->socket_fd = sock;
+
+        session->socket_block =
+            !_libssh2_get_socket_nonblocking(session->socket_fd);
+        if (session->socket_block) {
+            /*
+             * Since we can't be sure that we are in blocking or there
+             * was an error detecting the state, so set to blocking to
+             * be sure
+             */
+            _libssh2_nonblock(session->socket_fd, 0);
+        }
+
+        session->startup_state = libssh2_NB_state_created;
+    }
+
+    /* TODO: Liveness check */
+
+    if (session->startup_state == libssh2_NB_state_created) {
+        rc = libssh2_banner_send(session);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block sending banner to remote host", 0);
+            return LIBSSH2_ERROR_EAGAIN;
+        } else if (rc) {
+            /* Unable to send banner? */
+            libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND,
+                          "Error sending banner to remote host", 0);
+            return LIBSSH2_ERROR_BANNER_SEND;
+        }
+
+        session->startup_state = libssh2_NB_state_sent;
+    }
+
+    if (session->startup_state == libssh2_NB_state_sent) {
+        rc = libssh2_banner_receive(session);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block waiting for banner", 0);
+            return LIBSSH2_ERROR_EAGAIN;
+        } else if (rc) {
+            /* Unable to receive banner from remote */
+            libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE,
+                          "Timeout waiting for banner", 0);
+            return LIBSSH2_ERROR_BANNER_NONE;
+        }
+
+        session->startup_state = libssh2_NB_state_sent1;
+    }
+
+    if (session->startup_state == libssh2_NB_state_sent1) {
+        rc = libssh2_kex_exchange(session, 0, &session->startup_key_state);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block exchanging encryption keys", 0);
+            return LIBSSH2_ERROR_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
+                          "Unable to exchange encryption keys", 0);
+            return LIBSSH2_ERROR_KEX_FAILURE;
+        }
+
+        session->startup_state = libssh2_NB_state_sent2;
+    }
+
+    if (session->startup_state == libssh2_NB_state_sent2) {
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
+                       "Requesting userauth service");
+
+        /* Request the userauth service */
+        session->startup_service[0] = SSH_MSG_SERVICE_REQUEST;
+        libssh2_htonu32(session->startup_service + 1,
+                        sizeof("ssh-userauth") - 1);
+        memcpy(session->startup_service + 5, "ssh-userauth",
+               sizeof("ssh-userauth") - 1);
+
+        session->startup_state = libssh2_NB_state_sent3;
+    }
+
+    if (session->startup_state == libssh2_NB_state_sent3) {
+        rc = libssh2_packet_write(session, session->startup_service,
+                                  sizeof("ssh-userauth") + 5 - 1);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block asking for ssh-userauth service", 0);
+            return LIBSSH2_ERROR_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to ask for ssh-userauth service", 0);
+            return LIBSSH2_ERROR_SOCKET_SEND;
+        }
+
+        session->startup_state = libssh2_NB_state_sent4;
+    }
+
+    if (session->startup_state == libssh2_NB_state_sent4) {
+        rc = libssh2_packet_require_ex(session, SSH_MSG_SERVICE_ACCEPT,
+                                       &session->startup_data,
+                                       &session->startup_data_len, 0, NULL, 0,
+                                       &session->startup_req_state);
+        if (rc == PACKET_EAGAIN) {
+            return LIBSSH2_ERROR_EAGAIN;
+        } else if (rc) {
+            return LIBSSH2_ERROR_SOCKET_DISCONNECT;
+        }
+        session->startup_service_length =
+            libssh2_ntohu32(session->startup_data + 1);
+
+        if ((session->startup_service_length != (sizeof("ssh-userauth") - 1))
+            || strncmp("ssh-userauth", (char *) session->startup_data + 5,
+                       session->startup_service_length)) {
+            LIBSSH2_FREE(session, session->startup_data);
+            session->startup_data = NULL;
+            libssh2_error(session, LIBSSH2_ERROR_PROTO,
+                          "Invalid response received from server", 0);
+            return LIBSSH2_ERROR_PROTO;
+        }
+        LIBSSH2_FREE(session, session->startup_data);
+        session->startup_data = NULL;
+
+        session->startup_state = libssh2_NB_state_idle;
+
+        return 0;
+    }
+
+    /* just for safety return some error */
+    return LIBSSH2_ERROR_INVAL;
+}
+
+/* }}} */
+
+/* {{{ proto libssh2_session_free
+ * Frees the memory allocated to the session
+ * Also closes and frees any channels attached to this session
+ */
+LIBSSH2_API int
+libssh2_session_free(LIBSSH2_SESSION * session)
+{
+    int rc;
+
+    if (session->free_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS, "Freeing session resource",
+                       session->remote.banner);
+
+        session->state = libssh2_NB_state_created;
+    }
+
+    if (session->free_state == libssh2_NB_state_created) {
+        while (session->channels.head) {
+            LIBSSH2_CHANNEL *tmp = session->channels.head;
+
+            rc = libssh2_channel_free(session->channels.head);
+            if (rc == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            }
+            if (tmp == session->channels.head) {
+                /* channel_free couldn't do it's job, perform a messy cleanup */
+                tmp = session->channels.head;
+
+                /* unlink */
+                session->channels.head = tmp->next;
+
+                /* free */
+                LIBSSH2_FREE(session, tmp);
+
+                /* reverse linking isn't important here, we're killing the structure */
+            }
+        }
+
+        session->state = libssh2_NB_state_sent;
+    }
+
+    if (session->state == libssh2_NB_state_sent) {
+        while (session->listeners) {
+            rc = libssh2_channel_forward_cancel(session->listeners);
+            if (rc == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            }
+        }
+
+        session->state = libssh2_NB_state_sent1;
+    }
+
+    if (session->state & LIBSSH2_STATE_NEWKEYS) {
+        /* hostkey */
+        if (session->hostkey && session->hostkey->dtor) {
+            session->hostkey->dtor(session, &session->server_hostkey_abstract);
+        }
+
+        /* Client to Server */
+        /* crypt */
+        if (session->local.crypt && session->local.crypt->dtor) {
+            session->local.crypt->dtor(session,
+                                       &session->local.crypt_abstract);
+        }
+        /* comp */
+        if (session->local.comp && session->local.comp->dtor) {
+            session->local.comp->dtor(session, 1,
+                                      &session->local.comp_abstract);
+        }
+        /* mac */
+        if (session->local.mac && session->local.mac->dtor) {
+            session->local.mac->dtor(session, &session->local.mac_abstract);
+        }
+
+        /* Server to Client */
+        /* crypt */
+        if (session->remote.crypt && session->remote.crypt->dtor) {
+            session->remote.crypt->dtor(session,
+                                        &session->remote.crypt_abstract);
+        }
+        /* comp */
+        if (session->remote.comp && session->remote.comp->dtor) {
+            session->remote.comp->dtor(session, 0,
+                                       &session->remote.comp_abstract);
+        }
+        /* mac */
+        if (session->remote.mac && session->remote.mac->dtor) {
+            session->remote.mac->dtor(session, &session->remote.mac_abstract);
+        }
+
+        /* session_id */
+        if (session->session_id) {
+            LIBSSH2_FREE(session, session->session_id);
+        }
+    }
+
+    /* Free banner(s) */
+    if (session->remote.banner) {
+        LIBSSH2_FREE(session, session->remote.banner);
+    }
+    if (session->local.banner) {
+        LIBSSH2_FREE(session, session->local.banner);
+    }
+
+    /* Free preference(s) */
+    if (session->kex_prefs) {
+        LIBSSH2_FREE(session, session->kex_prefs);
+    }
+    if (session->hostkey_prefs) {
+        LIBSSH2_FREE(session, session->hostkey_prefs);
+    }
+
+    if (session->local.crypt_prefs) {
+        LIBSSH2_FREE(session, session->local.crypt_prefs);
+    }
+    if (session->local.mac_prefs) {
+        LIBSSH2_FREE(session, session->local.mac_prefs);
+    }
+    if (session->local.comp_prefs) {
+        LIBSSH2_FREE(session, session->local.comp_prefs);
+    }
+    if (session->local.lang_prefs) {
+        LIBSSH2_FREE(session, session->local.lang_prefs);
+    }
+
+    if (session->remote.crypt_prefs) {
+        LIBSSH2_FREE(session, session->remote.crypt_prefs);
+    }
+    if (session->remote.mac_prefs) {
+        LIBSSH2_FREE(session, session->remote.mac_prefs);
+    }
+    if (session->remote.comp_prefs) {
+        LIBSSH2_FREE(session, session->remote.comp_prefs);
+    }
+    if (session->remote.lang_prefs) {
+        LIBSSH2_FREE(session, session->remote.lang_prefs);
+    }
+
+    /*
+     * Make sure all memory used in the state variables are free
+     */
+    if (session->startup_data) {
+        LIBSSH2_FREE(session, session->startup_data);
+    }
+    if (session->disconnect_data) {
+        LIBSSH2_FREE(session, session->disconnect_data);
+    }
+    if (session->userauth_list_data) {
+        LIBSSH2_FREE(session, session->userauth_list_data);
+    }
+    if (session->userauth_pswd_data) {
+        LIBSSH2_FREE(session, session->userauth_pswd_data);
+    }
+    if (session->userauth_pswd_newpw) {
+        LIBSSH2_FREE(session, session->userauth_pswd_newpw);
+    }
+    if (session->userauth_host_packet) {
+        LIBSSH2_FREE(session, session->userauth_host_packet);
+    }
+    if (session->userauth_host_method) {
+        LIBSSH2_FREE(session, session->userauth_host_method);
+    }
+    if (session->userauth_host_data) {
+        LIBSSH2_FREE(session, session->userauth_host_data);
+    }
+    if (session->userauth_pblc_data) {
+        LIBSSH2_FREE(session, session->userauth_pblc_data);
+    }
+    if (session->userauth_pblc_packet) {
+        LIBSSH2_FREE(session, session->userauth_pblc_packet);
+    }
+    if (session->userauth_pblc_method) {
+        LIBSSH2_FREE(session, session->userauth_pblc_method);
+    }
+    if (session->userauth_kybd_data) {
+        LIBSSH2_FREE(session, session->userauth_kybd_data);
+    }
+    if (session->userauth_kybd_packet) {
+        LIBSSH2_FREE(session, session->userauth_kybd_packet);
+    }
+    if (session->userauth_kybd_auth_instruction) {
+        LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction);
+    }
+    if (session->open_packet) {
+        LIBSSH2_FREE(session, session->open_packet);
+    }
+    if (session->open_data) {
+        LIBSSH2_FREE(session, session->open_data);
+    }
+    if (session->direct_message) {
+        LIBSSH2_FREE(session, session->direct_message);
+    }
+    if (session->fwdLstn_packet) {
+        LIBSSH2_FREE(session, session->fwdLstn_packet);
+    }
+    if (session->pkeyInit_data) {
+        LIBSSH2_FREE(session, session->pkeyInit_data);
+    }
+    if (session->scpRecv_command) {
+        LIBSSH2_FREE(session, session->scpRecv_command);
+    }
+    if (session->scpSend_command) {
+        LIBSSH2_FREE(session, session->scpSend_command);
+    }
+    if (session->scpRecv_err_msg) {
+        LIBSSH2_FREE(session, session->scpRecv_err_msg);
+    }
+    if (session->scpSend_err_msg) {
+        LIBSSH2_FREE(session, session->scpSend_err_msg);
+    }
+
+    /* Free the error message, if we ar supposed to */
+    if (session->err_msg && session->err_should_free) {
+        LIBSSH2_FREE(session, session->err_msg);
+    }
+
+    /* Cleanup any remaining packets */
+    while (session->packets.head) {
+        LIBSSH2_PACKET *tmp = session->packets.head;
+
+        /* unlink */
+        session->packets.head = tmp->next;
+
+        /* free */
+        LIBSSH2_FREE(session, tmp->data);
+        LIBSSH2_FREE(session, tmp);
+    }
+
+    LIBSSH2_FREE(session, session);
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_session_disconnect_ex
+ */
+LIBSSH2_API int
+libssh2_session_disconnect_ex(LIBSSH2_SESSION * session, int reason,
+                              const char *description, const char *lang)
+{
+    unsigned char *s;
+    unsigned long descr_len = 0, lang_len = 0;
+    int rc;
+
+    if (session->disconnect_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
+                       "Disconnecting: reason=%d, desc=%s, lang=%s", reason,
+                       description, lang);
+        if (description) {
+            descr_len = strlen(description);
+        }
+        if (lang) {
+            lang_len = strlen(lang);
+        }
+        /* 13 = packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */
+        session->disconnect_data_len = descr_len + lang_len + 13;
+
+        s = session->disconnect_data =
+            LIBSSH2_ALLOC(session, session->disconnect_data_len);
+        if (!session->disconnect_data) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for disconnect packet",
+                          0);
+            session->disconnect_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        *(s++) = SSH_MSG_DISCONNECT;
+        libssh2_htonu32(s, reason);
+        s += 4;
+
+        libssh2_htonu32(s, descr_len);
+        s += 4;
+        if (description) {
+            memcpy(s, description, descr_len);
+            s += descr_len;
+        }
+
+        libssh2_htonu32(s, lang_len);
+        s += 4;
+        if (lang) {
+            memcpy(s, lang, lang_len);
+            s += lang_len;
+        }
+
+        session->disconnect_state = libssh2_NB_state_created;
+    }
+
+    rc = libssh2_packet_write(session, session->disconnect_data,
+                              session->disconnect_data_len);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    }
+
+    LIBSSH2_FREE(session, session->disconnect_data);
+    session->disconnect_data = NULL;
+    session->disconnect_state = libssh2_NB_state_idle;
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_session_methods
+ * Return the currently active methods for method_type
+ * NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string regardless of actual negotiation
+ * Strings should NOT be freed
+ */
+LIBSSH2_API const char *
+libssh2_session_methods(LIBSSH2_SESSION * session, int method_type)
+{
+    /* All methods have char *name as their first element */
+    const LIBSSH2_KEX_METHOD *method = NULL;
+
+    switch (method_type) {
+    case LIBSSH2_METHOD_KEX:
+        method = session->kex;
+        break;
+
+    case LIBSSH2_METHOD_HOSTKEY:
+        method = (LIBSSH2_KEX_METHOD *) session->hostkey;
+        break;
+
+    case LIBSSH2_METHOD_CRYPT_CS:
+        method = (LIBSSH2_KEX_METHOD *) session->local.crypt;
+        break;
+
+    case LIBSSH2_METHOD_CRYPT_SC:
+        method = (LIBSSH2_KEX_METHOD *) session->remote.crypt;
+        break;
+
+    case LIBSSH2_METHOD_MAC_CS:
+        method = (LIBSSH2_KEX_METHOD *) session->local.mac;
+        break;
+
+    case LIBSSH2_METHOD_MAC_SC:
+        method = (LIBSSH2_KEX_METHOD *) session->remote.mac;
+        break;
+
+    case LIBSSH2_METHOD_COMP_CS:
+        method = (LIBSSH2_KEX_METHOD *) session->local.comp;
+        break;
+
+    case LIBSSH2_METHOD_COMP_SC:
+        method = (LIBSSH2_KEX_METHOD *) session->remote.comp;
+        break;
+
+    case LIBSSH2_METHOD_LANG_CS:
+        return "";
+        break;
+
+    case LIBSSH2_METHOD_LANG_SC:
+        return "";
+        break;
+
+    default:
+        libssh2_error(session, LIBSSH2_ERROR_INVAL,
+                      "Invalid parameter specified for method_type", 0);
+        return NULL;
+        break;
+    }
+
+    if (!method) {
+        libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
+                      "No method negotiated", 0);
+        return NULL;
+    }
+
+    return method->name;
+}
+
+/* }}} */
+
+/* {{{ libssh2_session_abstract
+ * Retrieve a pointer to the abstract property
+ */
+LIBSSH2_API void **
+libssh2_session_abstract(LIBSSH2_SESSION * session)
+{
+    return &session->abstract;
+}
+
+/* }}} */
+
+/* {{{ libssh2_session_last_error
+ * Returns error code and populates an error string into errmsg
+ * If want_buf is non-zero then the string placed into errmsg must be freed by the calling program
+ * Otherwise it is assumed to be owned by libssh2
+ */
+LIBSSH2_API int
+libssh2_session_last_error(LIBSSH2_SESSION * session, char **errmsg,
+                           int *errmsg_len, int want_buf)
+{
+    /* No error to report */
+    if (!session->err_code) {
+        if (errmsg) {
+            if (want_buf) {
+                *errmsg = LIBSSH2_ALLOC(session, 1);
+                if (*errmsg) {
+                    **errmsg = 0;
+                }
+            } else {
+                *errmsg = (char *) "";
+            }
+        }
+        if (errmsg_len) {
+            *errmsg_len = 0;
+        }
+        return 0;
+    }
+
+    if (errmsg) {
+        char *serrmsg = session->err_msg ? session->err_msg : (char *) "";
+        int ownbuf = session->err_msg ? session->err_should_free : 0;
+
+        if (want_buf) {
+            if (ownbuf) {
+                /* Just give the calling program the buffer */
+                *errmsg = serrmsg;
+                session->err_should_free = 0;
+            } else {
+                /* Make a copy so the calling program can own it */
+                *errmsg = LIBSSH2_ALLOC(session, session->err_msglen + 1);
+                if (*errmsg) {
+                    memcpy(*errmsg, session->err_msg, session->err_msglen);
+                    (*errmsg)[session->err_msglen] = 0;
+                }
+            }
+        } else {
+            *errmsg = serrmsg;
+        }
+    }
+
+    if (errmsg_len) {
+        *errmsg_len = session->err_msglen;
+    }
+
+    return session->err_code;
+}
+
+/* }}} */
+
+/* {{{ libssh2_session_last_error
+* Returns error code
+*/
+LIBSSH2_API int
+libssh2_session_last_errno(LIBSSH2_SESSION * session)
+{
+    return session->err_code;
+}
+
+/* }}} */
+
+/* {{{ libssh2_session_flag
+ * Set/Get session flags
+ * Passing flag==0 will avoid changing session->flags while still returning its current value
+ */
+LIBSSH2_API int
+libssh2_session_flag(LIBSSH2_SESSION * session, int flag, int value)
+{
+    if (value) {
+        session->flags |= flag;
+    } else {
+        session->flags &= ~flag;
+    }
+
+    return session->flags;
+}
+
+/* }}} */
+
+/* {{{ _libssh2_session_set_blocking
+ * Set a session's blocking mode on or off, return the previous status
+ * when this function is called.
+ */
+int
+_libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking)
+{
+    int bl = session->socket_block;
+    _libssh2_debug(session, LIBSSH2_DBG_CONN,
+                   "Setting blocking mode on session %d", blocking);
+    if (blocking == session->socket_block) {
+        /* avoid if already correct */
+        return bl;
+    }
+    session->socket_block = blocking;
+
+    _libssh2_nonblock(session->socket_fd, !blocking);
+
+    return bl;
+}
+
+/* }}} */
+
+/* {{{ libssh2_session_set_blocking
+ * Set a channel's blocking mode on or off, similar to a socket's
+ * fcntl(fd, F_SETFL, O_NONBLOCK); type command
+ */
+LIBSSH2_API void
+libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking)
+{
+    (void) _libssh2_session_set_blocking(session, blocking);
+}
+
+/* }}} */
+
+/* {{{ libssh2_session_get_blocking
+* Returns a session's blocking mode on or off
+*/
+LIBSSH2_API int
+libssh2_session_get_blocking(LIBSSH2_SESSION * session)
+{
+    return session->socket_block;
+}
+
+/* }}} */
+
+/* {{{ libssh2_poll_channel_read
+ * Returns 0 if no data is waiting on channel,
+ * non-0 if data is available
+ */
+LIBSSH2_API int
+libssh2_poll_channel_read(LIBSSH2_CHANNEL * channel, int extended)
+{
+    LIBSSH2_SESSION *session = channel->session;
+    LIBSSH2_PACKET *packet = session->packets.head;
+
+    while (packet) {
+        if (((packet->data[0] == SSH_MSG_CHANNEL_DATA) && (extended == 0) &&
+             (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
+            ((packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)
+             && (extended != 0)
+             && (channel->local.id == libssh2_ntohu32(packet->data + 1)))) {
+            /* Found data waiting to be read */
+            return 1;
+        }
+        packet = packet->next;
+    }
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_poll_channel_write
+ * Returns 0 if writing to channel would block,
+ * non-0 if data can be written without blocking
+ */
+static inline int
+libssh2_poll_channel_write(LIBSSH2_CHANNEL * channel)
+{
+    return channel->local.window_size ? 1 : 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_poll_listener_queued
+ * Returns 0 if no connections are waiting to be accepted
+ * non-0 if one or more connections are available
+ */
+static inline int
+libssh2_poll_listener_queued(LIBSSH2_LISTENER * listener)
+{
+    return listener->queue ? 1 : 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_poll
+ * Poll sockets, channels, and listeners for activity
+ */
+LIBSSH2_API int
+libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout)
+{
+    long timeout_remaining;
+    unsigned int i, active_fds;
+#ifdef HAVE_POLL
+    LIBSSH2_SESSION *session = NULL;
+#ifdef HAVE_ALLOCA
+    struct pollfd *sockets = alloca(sizeof(struct pollfd) * nfds);
+#else
+    struct pollfd sockets[256];
+
+    if (nfds > 256)
+        /* systems without alloca use a fixed-size array, this can be fixed
+           if we really want to, at least if the compiler is a C99 capable one */
+        return -1;
+#endif
+    /* Setup sockets for polling */
+    for(i = 0; i < nfds; i++) {
+        fds[i].revents = 0;
+        switch (fds[i].type) {
+        case LIBSSH2_POLLFD_SOCKET:
+            sockets[i].fd = fds[i].fd.socket;
+            sockets[i].events = fds[i].events;
+            sockets[i].revents = 0;
+            break;
+
+        case LIBSSH2_POLLFD_CHANNEL:
+            sockets[i].fd = fds[i].fd.channel->session->socket_fd;
+            sockets[i].events = POLLIN;
+            sockets[i].revents = 0;
+            if (!session)
+                session = fds[i].fd.channel->session;
+            break;
+
+        case LIBSSH2_POLLFD_LISTENER:
+            sockets[i].fd = fds[i].fd.listener->session->socket_fd;
+            sockets[i].events = POLLIN;
+            sockets[i].revents = 0;
+            if (!session)
+                session = fds[i].fd.listener->session;
+            break;
+
+        default:
+            if (session)
+                libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
+                              "Invalid descriptor passed to libssh2_poll()",
+                              0);
+            return -1;
+        }
+    }
+#elif defined(HAVE_SELECT)
+    LIBSSH2_SESSION *session = NULL;
+    int maxfd = 0;
+    fd_set rfds, wfds;
+    struct timeval tv;
+
+    FD_ZERO(&rfds);
+    FD_ZERO(&wfds);
+    for(i = 0; i < nfds; i++) {
+        fds[i].revents = 0;
+        switch (fds[i].type) {
+        case LIBSSH2_POLLFD_SOCKET:
+            if (fds[i].events & LIBSSH2_POLLFD_POLLIN) {
+                FD_SET(fds[i].fd.socket, &rfds);
+                if (fds[i].fd.socket > maxfd)
+                    maxfd = fds[i].fd.socket;
+            }
+            if (fds[i].events & LIBSSH2_POLLFD_POLLOUT) {
+                FD_SET(fds[i].fd.socket, &wfds);
+                if (fds[i].fd.socket > maxfd)
+                    maxfd = fds[i].fd.socket;
+            }
+            break;
+
+        case LIBSSH2_POLLFD_CHANNEL:
+            FD_SET(fds[i].fd.channel->session->socket_fd, &rfds);
+            if (fds[i].fd.channel->session->socket_fd > maxfd)
+                maxfd = fds[i].fd.channel->session->socket_fd;
+            if (!session)
+                session = fds[i].fd.channel->session;
+            break;
+
+        case LIBSSH2_POLLFD_LISTENER:
+            FD_SET(fds[i].fd.listener->session->socket_fd, &rfds);
+            if (fds[i].fd.listener->session->socket_fd > maxfd)
+                maxfd = fds[i].fd.listener->session->socket_fd;
+            if (!session)
+                session = fds[i].fd.listener->session;
+            break;
+
+        default:
+            if (session)
+                libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE,
+                              "Invalid descriptor passed to libssh2_poll()",
+                              0);
+            return -1;
+        }
+    }
+#else
+    /* No select() or poll()
+     * no sockets sturcture to setup
+     */
+
+    timeout = 0;
+#endif /* HAVE_POLL or HAVE_SELECT */
+
+    timeout_remaining = timeout;
+    do {
+#if defined(HAVE_POLL) || defined(HAVE_SELECT)
+        int sysret;
+#endif
+
+        active_fds = 0;
+
+        for(i = 0; i < nfds; i++) {
+            if (fds[i].events != fds[i].revents) {
+                switch (fds[i].type) {
+                case LIBSSH2_POLLFD_CHANNEL:
+                    if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) &&      /* Want to be ready for read */
+                        ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) {      /* Not yet known to be ready for read */
+                        fds[i].revents |=
+                            libssh2_poll_channel_read(fds[i].fd.channel,
+                                                      0) ?
+                            LIBSSH2_POLLFD_POLLIN : 0;
+                    }
+                    if ((fds[i].events & LIBSSH2_POLLFD_POLLEXT) &&     /* Want to be ready for extended read */
+                        ((fds[i].revents & LIBSSH2_POLLFD_POLLEXT) == 0)) {     /* Not yet known to be ready for extended read */
+                        fds[i].revents |=
+                            libssh2_poll_channel_read(fds[i].fd.channel,
+                                                      1) ?
+                            LIBSSH2_POLLFD_POLLEXT : 0;
+                    }
+                    if ((fds[i].events & LIBSSH2_POLLFD_POLLOUT) &&     /* Want to be ready for write */
+                        ((fds[i].revents & LIBSSH2_POLLFD_POLLOUT) == 0)) {     /* Not yet known to be ready for write */
+                        fds[i].revents |=
+                            libssh2_poll_channel_write(fds[i].fd.
+                                                       channel) ?
+                            LIBSSH2_POLLFD_POLLOUT : 0;
+                    }
+                    if (fds[i].fd.channel->remote.close
+                        || fds[i].fd.channel->local.close) {
+                        fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED;
+                    }
+                    if (fds[i].fd.channel->session->socket_state ==
+                        LIBSSH2_SOCKET_DISCONNECTED) {
+                        fds[i].revents |=
+                            LIBSSH2_POLLFD_CHANNEL_CLOSED |
+                            LIBSSH2_POLLFD_SESSION_CLOSED;
+                    }
+                    break;
+
+                case LIBSSH2_POLLFD_LISTENER:
+                    if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) &&      /* Want a connection */
+                        ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) {      /* No connections known of yet */
+                        fds[i].revents |=
+                            libssh2_poll_listener_queued(fds[i].fd.
+                                                         listener) ?
+                            LIBSSH2_POLLFD_POLLIN : 0;
+                    }
+                    if (fds[i].fd.listener->session->socket_state ==
+                        LIBSSH2_SOCKET_DISCONNECTED) {
+                        fds[i].revents |=
+                            LIBSSH2_POLLFD_LISTENER_CLOSED |
+                            LIBSSH2_POLLFD_SESSION_CLOSED;
+                    }
+                    break;
+                }
+            }
+            if (fds[i].revents) {
+                active_fds++;
+            }
+        }
+
+        if (active_fds) {
+            /* Don't block on the sockets if we have channels/listeners which are ready */
+            timeout_remaining = 0;
+        }
+#ifdef HAVE_POLL
+
+#ifdef HAVE_GETTIMEOFDAY
+        {
+            struct timeval tv_begin, tv_end;
+
+            gettimeofday((struct timeval *) &tv_begin, NULL);
+            sysret = poll(sockets, nfds, timeout_remaining);
+            gettimeofday((struct timeval *) &tv_end, NULL);
+            timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
+            timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
+        }
+#else
+        /* If the platform doesn't support gettimeofday,
+         * then just make the call non-blocking and walk away
+         */
+        sysret = poll(sockets, nfds, timeout_remaining);
+        timeout_remaining = 0;
+#endif /* HAVE_GETTIMEOFDAY */
+
+        if (sysret > 0) {
+            for(i = 0; i < nfds; i++) {
+                switch (fds[i].type) {
+                case LIBSSH2_POLLFD_SOCKET:
+                    fds[i].revents = sockets[i].revents;
+                    sockets[i].revents = 0;     /* In case we loop again, be nice */
+                    if (fds[i].revents) {
+                        active_fds++;
+                    }
+                    break;
+                case LIBSSH2_POLLFD_CHANNEL:
+                    if (sockets[i].events & POLLIN) {
+                        /* Spin session until no data available */
+                        while (libssh2_packet_read(fds[i].fd.channel->session)
+                               > 0);
+                    }
+                    if (sockets[i].revents & POLLHUP) {
+                        fds[i].revents |=
+                            LIBSSH2_POLLFD_CHANNEL_CLOSED |
+                            LIBSSH2_POLLFD_SESSION_CLOSED;
+                    }
+                    sockets[i].revents = 0;
+                    break;
+                case LIBSSH2_POLLFD_LISTENER:
+                    if (sockets[i].events & POLLIN) {
+                        /* Spin session until no data available */
+                        while (libssh2_packet_read(fds[i].fd.listener->session)
+                               > 0);
+                    }
+                    if (sockets[i].revents & POLLHUP) {
+                        fds[i].revents |=
+                            LIBSSH2_POLLFD_LISTENER_CLOSED |
+                            LIBSSH2_POLLFD_SESSION_CLOSED;
+                    }
+                    sockets[i].revents = 0;
+                    break;
+                }
+            }
+        }
+#elif defined(HAVE_SELECT)
+        tv.tv_sec = timeout_remaining / 1000;
+        tv.tv_usec = (timeout_remaining % 1000) * 1000;
+#ifdef HAVE_GETTIMEOFDAY
+        {
+            struct timeval tv_begin, tv_end;
+
+            gettimeofday((struct timeval *) &tv_begin, NULL);
+            sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
+            gettimeofday((struct timeval *) &tv_end, NULL);
+
+            timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
+            timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
+        }
+#else
+        /* If the platform doesn't support gettimeofday,
+         * then just make the call non-blocking and walk away
+         */
+        sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
+        timeout_remaining = 0;
+#endif
+
+        if (sysret > 0) {
+            for(i = 0; i < nfds; i++) {
+                switch (fds[i].type) {
+                case LIBSSH2_POLLFD_SOCKET:
+                    if (FD_ISSET(fds[i].fd.socket, &rfds)) {
+                        fds[i].revents |= LIBSSH2_POLLFD_POLLIN;
+                    }
+                    if (FD_ISSET(fds[i].fd.socket, &wfds)) {
+                        fds[i].revents |= LIBSSH2_POLLFD_POLLOUT;
+                    }
+                    if (fds[i].revents) {
+                        active_fds++;
+                    }
+                    break;
+
+                case LIBSSH2_POLLFD_CHANNEL:
+                    if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) {
+                        /* Spin session until no data available */
+                        while (libssh2_packet_read(fds[i].fd.channel->session)
+                               > 0);
+                    }
+                    break;
+
+                case LIBSSH2_POLLFD_LISTENER:
+                    if (FD_ISSET
+                        (fds[i].fd.listener->session->socket_fd, &rfds)) {
+                        /* Spin session until no data available */
+                        while (libssh2_packet_read(fds[i].fd.listener->session)
+                               > 0);
+                    }
+                    break;
+                }
+            }
+        }
+#endif /* else no select() or poll() -- timeout (and by extension timeout_remaining) will be equal to 0 */
+    } while ((timeout_remaining > 0) && !active_fds);
+
+    return active_fds;
+}
+
+/* }}} */
diff --git a/Vendor/libssh2/Source/sftp.c b/Vendor/libssh2/Source/sftp.c
new file mode 100644 (file)
index 0000000..fd4e5e6
--- /dev/null
@@ -0,0 +1,2325 @@
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+#include "libssh2_sftp.h"
+
+/* Note: Version 6 was documented at the time of writing
+ * However it was marked as "DO NOT IMPLEMENT" due to pending changes
+ *
+ * This release of libssh2 implements Version 5 with automatic downgrade
+ * based on server's declaration
+ */
+
+/* SFTP packet types */
+#define SSH_FXP_INIT                            1
+#define SSH_FXP_VERSION                         2
+#define SSH_FXP_OPEN                            3
+#define SSH_FXP_CLOSE                           4
+#define SSH_FXP_READ                            5
+#define SSH_FXP_WRITE                           6
+#define SSH_FXP_LSTAT                           7
+#define SSH_FXP_FSTAT                           8
+#define SSH_FXP_SETSTAT                         9
+#define SSH_FXP_FSETSTAT                        10
+#define SSH_FXP_OPENDIR                         11
+#define SSH_FXP_READDIR                         12
+#define SSH_FXP_REMOVE                          13
+#define SSH_FXP_MKDIR                           14
+#define SSH_FXP_RMDIR                           15
+#define SSH_FXP_REALPATH                        16
+#define SSH_FXP_STAT                            17
+#define SSH_FXP_RENAME                          18
+#define SSH_FXP_READLINK                        19
+#define SSH_FXP_SYMLINK                         20
+#define SSH_FXP_STATUS                          101
+#define SSH_FXP_HANDLE                          102
+#define SSH_FXP_DATA                            103
+#define SSH_FXP_NAME                            104
+#define SSH_FXP_ATTRS                           105
+#define SSH_FXP_EXTENDED                        200
+#define SSH_FXP_EXTENDED_REPLY                  201
+
+#define LIBSSH2_SFTP_HANDLE_FILE        0
+#define LIBSSH2_SFTP_HANDLE_DIR         1
+
+/* S_IFREG */
+#define LIBSSH2_SFTP_ATTR_PFILETYPE_FILE        0100000
+/* S_IFDIR */
+#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR         0040000
+
+/* {{{ libssh2_sftp_packet_add
+ * Add a packet to the SFTP packet brigade
+ */
+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_debug(session, LIBSSH2_DBG_SFTP, "Received packet %d",
+                   (int) data[0]);
+    packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
+    if (!packet) {
+        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                      "Unable to allocate datablock for SFTP packet", 0);
+        return -1;
+    }
+    memset(packet, 0, sizeof(LIBSSH2_PACKET));
+
+    packet->data = data;
+    packet->data_len = data_len;
+    packet->data_head = 5;
+    packet->brigade = &sftp->packets;
+    packet->next = NULL;
+    packet->prev = sftp->packets.tail;
+    if (packet->prev) {
+        packet->prev->next = packet;
+    } else {
+        sftp->packets.head = packet;
+    }
+    sftp->packets.tail = packet;
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_packet_read
+ * Frame an SFTP packet off the channel
+ */
+static int
+libssh2_sftp_packet_read(LIBSSH2_SFTP * sftp, int flush)
+{
+    LIBSSH2_CHANNEL *channel = sftp->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned char buffer[4];    /* To store the packet length */
+    unsigned char *packet;
+    unsigned long packet_len, packet_received;
+    ssize_t bytes_received;
+    int rc;
+
+    _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Waiting for packet");
+
+    if (flush && sftp->partial_packet) {
+        /* When flushing, remove previous partial */
+        LIBSSH2_FREE(session, sftp->partial_packet);
+        sftp->partial_packet = NULL;
+    }
+
+    /* If there was a previous partial, start using it */
+    if (sftp->partial_packet) {
+        packet = sftp->partial_packet;
+        packet_len = sftp->partial_len;
+        packet_received = sftp->partial_received;
+        sftp->partial_packet = NULL;
+    } else {
+        if (flush && session->socket_block && !libssh2_waitsocket(session, 0)) {
+            /* While flushing in blocking mode, check before reading */
+            return -1;
+        }
+        rc = libssh2_channel_read_ex(channel, 0, (char *) buffer, 4);
+        if (flush && (rc < 0)) {
+            /* When flushing, exit quickly */
+            return -1;
+        } else if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (4 != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                          "Timeout waiting for FXP packet", 0);
+            return -1;
+        }
+
+        packet_len = libssh2_ntohu32(buffer);
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
+                       "Data begin - Packet Length: %lu", packet_len);
+        if (packet_len > LIBSSH2_SFTP_PACKET_MAXLEN) {
+            libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
+                          "SFTP packet too large", 0);
+            return -1;
+        }
+
+        packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate SFTP packet", 0);
+            return -1;
+        }
+
+        packet_received = 0;
+    }
+
+    /* Read as much of the packet as we can */
+    while (packet_len > packet_received) {
+        bytes_received =
+            libssh2_channel_read_ex(channel, 0,
+                                    (char *) packet + packet_received,
+                                    packet_len - packet_received);
+
+        if (flush && (bytes_received < 0)) {
+            if (packet) {
+                /* When flushing, remove packet if existing */
+                LIBSSH2_FREE(session, packet);
+            }
+            /* When flushing, exit quickly */
+            return -1;
+        } else if (bytes_received == PACKET_EAGAIN) {
+            /*
+             * We received EAGAIN, save what we have and
+             * return to EAGAIN to the caller
+             */
+            sftp->partial_packet = packet;
+            sftp->partial_len = packet_len;
+            sftp->partial_received = packet_received;
+            packet = NULL;
+
+            return PACKET_EAGAIN;
+        } else if (bytes_received < 0) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                          "Receive error waiting for SFTP packet", 0);
+            LIBSSH2_FREE(session, packet);
+            return -1;
+        }
+        packet_received += bytes_received;
+    }
+
+    if (libssh2_sftp_packet_add(sftp, packet, packet_len)) {
+        LIBSSH2_FREE(session, packet);
+        return -1;
+    }
+
+    return packet[0];
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_packet_ask
+ * A la libssh2_packet_ask()
+ */
+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_debug(session, LIBSSH2_DBG_SFTP, "Asking for %d packet",
+                   (int) packet_type);
+    if (poll_channel) {
+        int ret = libssh2_sftp_packet_read(sftp, 0);
+        if (ret == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (ret < 0) {
+            return -1;
+        }
+    }
+
+    match_buf[0] = packet_type;
+    if (packet_type == SSH_FXP_VERSION) {
+        /* Special consideration when matching VERSION packet */
+        match_len = 1;
+    } else {
+        libssh2_htonu32(match_buf + 1, request_id);
+    }
+
+    while (packet) {
+        if (strncmp((char *) packet->data, (char *) match_buf, match_len) == 0) {
+            *data = packet->data;
+            *data_len = packet->data_len;
+
+            if (packet->prev) {
+                packet->prev->next = packet->next;
+            } else {
+                sftp->packets.head = packet->next;
+            }
+
+            if (packet->next) {
+                packet->next->prev = packet->prev;
+            } else {
+                sftp->packets.tail = packet->prev;
+            }
+
+            LIBSSH2_FREE(session, packet);
+
+            return 0;
+        }
+        packet = packet->next;
+    }
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_packet_require
+ * A la libssh2_packet_require
+ */
+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;
+    int ret;
+
+    _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Requiring %d packet",
+                   (int) packet_type);
+
+    if (libssh2_sftp_packet_ask
+        (sftp, packet_type, request_id, data, data_len, 0) == 0) {
+        /* The right packet was available in the packet brigade */
+        return 0;
+    }
+
+    while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
+        ret = libssh2_sftp_packet_read(sftp, 0);
+        if (ret == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (ret <= 0) {
+            return -1;
+        }
+
+        if (packet_type == ret) {
+            /* Be lazy, let packet_ask pull it out of the brigade */
+            return libssh2_sftp_packet_ask(sftp, packet_type, request_id, data,
+                                           data_len, 0);
+        }
+    }
+
+    /* 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,
+                             const unsigned char *valid_responses,
+                             unsigned long request_id, unsigned char **data,
+                             unsigned long *data_len)
+{
+    int i;
+    int ret;
+
+    /*
+     * If no timeout is active, start a new one and flush
+     * any pending packets
+     */
+    if (sftp->requirev_start == 0) {
+        _libssh2_debug(sftp->channel->session, LIBSSH2_DBG_SFTP,
+                       "_requirev(): Initialize timeout");
+        sftp->requirev_start = time(NULL);
+
+        /* Flush */
+        while (libssh2_sftp_packet_read(sftp, 1) > 0);
+    }
+
+    while (sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
+        for(i = 0; i < num_valid_responses; i++) {
+            if (libssh2_sftp_packet_ask
+                (sftp, valid_responses[i], request_id, data, data_len,
+                 0) == 0) {
+                /*
+                 * Set to zero before all returns to say
+                 * the timeout is not active
+                 */
+                sftp->requirev_start = 0;
+                return 0;
+            }
+        }
+
+        ret = libssh2_sftp_packet_read(sftp, 0);
+        if ((ret < 0) && (ret != PACKET_EAGAIN)) {
+            sftp->requirev_start = 0;
+            return -1;
+        } else if (ret <= 0) {
+            /* prevent busy-looping */
+            long left =
+                LIBSSH2_READ_TIMEOUT - (time(NULL) - sftp->requirev_start);
+
+            if (left <= 0) {
+                sftp->requirev_start = 0;
+                return PACKET_TIMEOUT;
+            } else if (sftp->channel->session->socket_block
+                       && (libssh2_waitsocket(sftp->channel->session, left) <=
+                           0)) {
+                sftp->requirev_start = 0;
+                return PACKET_TIMEOUT;
+            } else if (ret == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            }
+        }
+    }
+
+    sftp->requirev_start = 0;
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_attrsize
+ * Size that attr will occupy when turned into a bin struct
+ */
+static int
+libssh2_sftp_attrsize(const LIBSSH2_SFTP_ATTRIBUTES * attrs)
+{
+    int attrsize = 4;           /* flags(4) */
+
+    if (!attrs) {
+        return attrsize;
+    }
+
+    if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE)
+        attrsize += 8;
+    if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID)
+        attrsize += 8;
+    if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS)
+        attrsize += 4;
+    if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME)
+        attrsize += 8;          /* atime + mtime as u32 */
+
+    return attrsize;
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_attr2bin
+ * Populate attributes into an SFTP block
+ */
+static int
+libssh2_sftp_attr2bin(unsigned char *p, const LIBSSH2_SFTP_ATTRIBUTES * attrs)
+{
+    unsigned char *s = p;
+    unsigned long flag_mask =
+        LIBSSH2_SFTP_ATTR_SIZE | LIBSSH2_SFTP_ATTR_UIDGID |
+        LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME;
+
+    /* TODO: When we add SFTP4+ functionality flag_mask can get additional bits */
+
+    if (!attrs) {
+        libssh2_htonu32(s, 0);
+        return 4;
+    }
+
+    libssh2_htonu32(s, attrs->flags & flag_mask);
+    s += 4;
+
+    if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
+        libssh2_htonu64(s, attrs->filesize);
+        s += 8;
+    }
+
+    if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) {
+        libssh2_htonu32(s, attrs->uid);
+        s += 4;
+        libssh2_htonu32(s, attrs->gid);
+        s += 4;
+    }
+
+    if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
+        libssh2_htonu32(s, attrs->permissions);
+        s += 4;
+    }
+
+    if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
+        libssh2_htonu32(s, attrs->atime);
+        s += 4;
+        libssh2_htonu32(s, attrs->mtime);
+        s += 4;
+    }
+
+    return (s - p);
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_bin2attr
+ */
+static int
+libssh2_sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES * attrs, const unsigned char *p)
+{
+    const unsigned char *s = p;
+
+    memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+    attrs->flags = libssh2_ntohu32(s);
+    s += 4;
+
+    if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) {
+        attrs->filesize = libssh2_ntohu64(s);
+        s += 8;
+    }
+
+    if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) {
+        attrs->uid = libssh2_ntohu32(s);
+        s += 4;
+        attrs->gid = libssh2_ntohu32(s);
+        s += 4;
+    }
+
+    if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
+        attrs->permissions = libssh2_ntohu32(s);
+        s += 4;
+    }
+
+    if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
+        attrs->atime = libssh2_ntohu32(s);
+        s += 4;
+        attrs->mtime = libssh2_ntohu32(s);
+        s += 4;
+    }
+
+    return (s - p);
+}
+
+/* }}} */
+
+/* ************
+   * SFTP API *
+   ************ */
+
+LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor);
+
+/* {{{ libssh2_sftp_dtor
+ * Shutdown an SFTP stream when the channel closes
+ */
+LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor)
+{
+    LIBSSH2_SFTP *sftp = (LIBSSH2_SFTP *) (*channel_abstract);
+
+    (void) session_abstract;
+    (void) channel;
+
+    /* Loop through handles closing them */
+    while (sftp->handles) {
+        libssh2_sftp_close_handle(sftp->handles);
+    }
+
+    /* Free the partial packet storage for libssh2_sftp_packet_read */
+    if (sftp->partial_packet) {
+        LIBSSH2_FREE(session, sftp->partial_packet);
+    }
+
+    /* Free the packet storage for _libssh2_sftp_packet_readdir */
+    if (sftp->readdir_packet) {
+        LIBSSH2_FREE(session, sftp->readdir_packet);
+    }
+
+    LIBSSH2_FREE(session, sftp);
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_init
+ * Startup an SFTP session
+ *
+ * NOTE:  Will block in a busy loop on error.  This has to be done,
+ *        otherwise the blocking error code would erase the true
+ *        cause of the error.
+ */
+LIBSSH2_API LIBSSH2_SFTP *
+libssh2_sftp_init(LIBSSH2_SESSION * session)
+{
+    unsigned char *data, *s;
+    unsigned long data_len;
+    int rc;
+
+    if (session->sftpInit_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
+                       "Initializing SFTP subsystem");
+
+        session->sftpInit_sftp = NULL;
+
+        session->sftpInit_state = libssh2_NB_state_created;
+    }
+
+    if (session->sftpInit_state == libssh2_NB_state_created) {
+        session->sftpInit_channel =
+            libssh2_channel_open_ex(session, "session", sizeof("session") - 1,
+                                    LIBSSH2_CHANNEL_WINDOW_DEFAULT,
+                                    LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0);
+        if (!session->sftpInit_channel) {
+            if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
+                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                              "Would block starting up channel", 0);
+                return NULL;
+            } else if (libssh2_session_last_errno(session) !=
+                       LIBSSH2_ERROR_EAGAIN) {
+                libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
+                              "Unable to startup channel", 0);
+                session->sftpInit_state = libssh2_NB_state_idle;
+                return NULL;
+            }
+        }
+
+        session->sftpInit_state = libssh2_NB_state_sent;
+    }
+
+    if (session->sftpInit_state == libssh2_NB_state_sent) {
+        rc = libssh2_channel_process_startup(session->sftpInit_channel,
+                                             "subsystem",
+                                             sizeof("subsystem") - 1, "sftp",
+                                             strlen("sftp"));
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block to request SFTP subsystem", 0);
+            return NULL;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
+                          "Unable to request SFTP subsystem", 0);
+            goto sftp_init_error;
+        }
+
+        session->sftpInit_state = libssh2_NB_state_sent1;
+    }
+
+    if (session->sftpInit_state == libssh2_NB_state_sent1) {
+        rc = libssh2_channel_handle_extended_data2(session->sftpInit_channel,
+                                                   LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block requesting handle extended data", 0);
+            return NULL;
+        }
+
+        session->sftpInit_sftp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP));
+        if (!session->sftpInit_sftp) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate a new SFTP structure", 0);
+            goto sftp_init_error;
+        }
+        memset(session->sftpInit_sftp, 0, sizeof(LIBSSH2_SFTP));
+        session->sftpInit_sftp->channel = session->sftpInit_channel;
+        session->sftpInit_sftp->request_id = 0;
+
+        libssh2_htonu32(session->sftpInit_buffer, 5);
+        session->sftpInit_buffer[4] = SSH_FXP_INIT;
+        libssh2_htonu32(session->sftpInit_buffer + 5, LIBSSH2_SFTP_VERSION);
+
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
+                       "Sending FXP_INIT packet advertising version %d support",
+                       (int) LIBSSH2_SFTP_VERSION);
+
+        session->sftpInit_state = libssh2_NB_state_sent2;
+    }
+
+    if (session->sftpInit_state == libssh2_NB_state_sent2) {
+        rc = libssh2_channel_write_ex(session->sftpInit_channel, 0,
+                                      (char *) session->sftpInit_buffer, 9);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block sending SSH_FXP_INIT", 0);
+            return NULL;
+        } else if (9 != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send SSH_FXP_INIT", 0);
+            goto sftp_init_error;
+        }
+
+        session->sftpInit_state = libssh2_NB_state_sent3;
+    }
+
+    /* For initiallization we are requiring blocking, probably reasonable */
+    rc = libssh2_sftp_packet_require(session->sftpInit_sftp, SSH_FXP_VERSION,
+                                     0, &data, &data_len);
+    if (rc == PACKET_EAGAIN) {
+        libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                      "Would block waiting for response from SFTP subsystem",
+                      0);
+        return NULL;
+    } else if (rc) {
+        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                      "Timeout waiting for response from SFTP subsystem", 0);
+        goto sftp_init_error;
+    }
+    if (data_len < 5) {
+        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                      "Invalid SSH_FXP_VERSION response", 0);
+        goto sftp_init_error;
+    }
+
+    s = data + 1;
+    session->sftpInit_sftp->version = libssh2_ntohu32(s);
+    s += 4;
+    if (session->sftpInit_sftp->version > LIBSSH2_SFTP_VERSION) {
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
+                       "Truncating remote SFTP version from %lu",
+                       session->sftpInit_sftp->version);
+        session->sftpInit_sftp->version = LIBSSH2_SFTP_VERSION;
+    }
+    _libssh2_debug(session, LIBSSH2_DBG_SFTP,
+                   "Enabling SFTP version %lu compatability",
+                   session->sftpInit_sftp->version);
+    while (s < (data + data_len)) {
+        unsigned char *extension_name, *extension_data;
+        unsigned long extname_len, extdata_len;
+
+        extname_len = libssh2_ntohu32(s);
+        s += 4;
+        extension_name = s;
+        s += extname_len;
+
+        extdata_len = libssh2_ntohu32(s);
+        s += 4;
+        extension_data = s;
+        s += extdata_len;
+
+        /* TODO: Actually process extensions */
+    }
+    LIBSSH2_FREE(session, data);
+
+    /* Make sure that when the channel gets closed, the SFTP service is shut down too */
+    session->sftpInit_sftp->channel->abstract = session->sftpInit_sftp;
+    session->sftpInit_sftp->channel->close_cb = libssh2_sftp_dtor;
+
+    session->sftpInit_state = libssh2_NB_state_idle;
+    return session->sftpInit_sftp;
+
+  sftp_init_error:
+    while (libssh2_channel_free(session->sftpInit_channel) == PACKET_EAGAIN);
+    session->sftpInit_channel = NULL;
+    if (session->sftpInit_sftp) {
+        LIBSSH2_FREE(session, session->sftpInit_sftp);
+        session->sftpInit_sftp = NULL;
+    }
+    session->sftpInit_state = libssh2_NB_state_idle;
+    return NULL;
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_shutdown
+ * Shutsdown the SFTP subsystem
+ */
+LIBSSH2_API int
+libssh2_sftp_shutdown(LIBSSH2_SFTP * sftp)
+{
+    /*
+     * Make sure all memory used in the state variables are free
+     */
+    if (sftp->partial_packet) {
+        LIBSSH2_FREE(sftp->channel->session, sftp->partial_packet);
+        sftp->partial_packet = NULL;
+    }
+    if (sftp->open_packet) {
+        LIBSSH2_FREE(sftp->channel->session, sftp->open_packet);
+        sftp->open_packet = NULL;
+    }
+    if (sftp->read_packet) {
+        LIBSSH2_FREE(sftp->channel->session, sftp->read_packet);
+        sftp->read_packet = NULL;
+    }
+    if (sftp->readdir_packet) {
+        LIBSSH2_FREE(sftp->channel->session, sftp->readdir_packet);
+        sftp->readdir_packet = NULL;
+    }
+    if (sftp->write_packet) {
+        LIBSSH2_FREE(sftp->channel->session, sftp->write_packet);
+        sftp->write_packet = NULL;
+    }
+    if (sftp->fstat_packet) {
+        LIBSSH2_FREE(sftp->channel->session, sftp->fstat_packet);
+        sftp->fstat_packet = NULL;
+    }
+    if (sftp->unlink_packet) {
+        LIBSSH2_FREE(sftp->channel->session, sftp->unlink_packet);
+        sftp->unlink_packet = NULL;
+    }
+    if (sftp->rename_packet) {
+        LIBSSH2_FREE(sftp->channel->session, sftp->rename_packet);
+        sftp->rename_packet = NULL;
+    }
+    if (sftp->mkdir_packet) {
+        LIBSSH2_FREE(sftp->channel->session, sftp->mkdir_packet);
+        sftp->mkdir_packet = NULL;
+    }
+    if (sftp->rmdir_packet) {
+        LIBSSH2_FREE(sftp->channel->session, sftp->rmdir_packet);
+        sftp->rmdir_packet = NULL;
+    }
+    if (sftp->stat_packet) {
+        LIBSSH2_FREE(sftp->channel->session, sftp->stat_packet);
+        sftp->stat_packet = NULL;
+    }
+    if (sftp->symlink_packet) {
+        LIBSSH2_FREE(sftp->channel->session, sftp->symlink_packet);
+        sftp->symlink_packet = NULL;
+    }
+
+    return libssh2_channel_free(sftp->channel);
+}
+
+/* }}} */
+
+/* *******************************
+   * SFTP File and Directory Ops *
+   ******************************* */
+
+/* {{{ libssh2_sftp_open_ex
+ */
+LIBSSH2_API LIBSSH2_SFTP_HANDLE *
+libssh2_sftp_open_ex(LIBSSH2_SFTP * sftp, const char *filename,
+                     unsigned int filename_len, unsigned long flags, long mode,
+                     int open_type)
+{
+    LIBSSH2_CHANNEL *channel = sftp->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    LIBSSH2_SFTP_HANDLE *fp;
+    LIBSSH2_SFTP_ATTRIBUTES attrs = {
+        LIBSSH2_SFTP_ATTR_PERMISSIONS, 0, 0, 0, 0, 0, 0
+    };
+    unsigned long data_len;
+    unsigned char *data, *s;
+    static const unsigned char fopen_responses[2] =
+        { SSH_FXP_HANDLE, SSH_FXP_STATUS };
+    int rc;
+
+    if (sftp->open_state == libssh2_NB_state_idle) {
+        /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) + flags(4) */
+        sftp->open_packet_len = filename_len + 13 +
+            ((open_type ==
+              LIBSSH2_SFTP_OPENFILE) ? (4 +
+                                        libssh2_sftp_attrsize(&attrs)) : 0);
+
+        s = sftp->open_packet = LIBSSH2_ALLOC(session, sftp->open_packet_len);
+        if (!sftp->open_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for FXP_OPEN or FXP_OPENDIR packet",
+                          0);
+            return NULL;
+        }
+        /* Filetype in SFTP 3 and earlier */
+        attrs.permissions = mode |
+            ((open_type ==
+              LIBSSH2_SFTP_OPENFILE) ? LIBSSH2_SFTP_ATTR_PFILETYPE_FILE :
+             LIBSSH2_SFTP_ATTR_PFILETYPE_DIR);
+
+        libssh2_htonu32(s, sftp->open_packet_len - 4);
+        s += 4;
+        *(s++) =
+            (open_type ==
+             LIBSSH2_SFTP_OPENFILE) ? SSH_FXP_OPEN : SSH_FXP_OPENDIR;
+        sftp->open_request_id = sftp->request_id++;
+        libssh2_htonu32(s, sftp->open_request_id);
+        s += 4;
+        libssh2_htonu32(s, filename_len);
+        s += 4;
+        memcpy(s, filename, filename_len);
+        s += filename_len;
+        if (open_type == LIBSSH2_SFTP_OPENFILE) {
+            libssh2_htonu32(s, flags);
+            s += 4;
+            s += libssh2_sftp_attr2bin(s, &attrs);
+        }
+
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Sending %s open request",
+                       (open_type ==
+                        LIBSSH2_SFTP_OPENFILE) ? "file" : "directory");
+
+        sftp->open_state = libssh2_NB_state_created;
+    }
+
+    if (sftp->open_state == libssh2_NB_state_created) {
+        rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->open_packet,
+                                      sftp->open_packet_len);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block sending FXP_OPEN or FXP_OPENDIR command",
+                          0);
+            return NULL;
+        } else if (sftp->open_packet_len != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send FXP_OPEN or FXP_OPENDIR command", 0);
+            LIBSSH2_FREE(session, sftp->open_packet);
+            sftp->open_packet = NULL;
+            sftp->open_state = libssh2_NB_state_idle;
+            return NULL;
+        }
+        LIBSSH2_FREE(session, sftp->open_packet);
+        sftp->open_packet = NULL;
+
+        sftp->open_state = libssh2_NB_state_sent;
+    }
+
+    if (sftp->open_state == libssh2_NB_state_sent) {
+        rc = libssh2_sftp_packet_requirev(sftp, 2, fopen_responses,
+                                          sftp->open_request_id, &data,
+                                          &data_len);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block waiting for status message", 0);
+            return NULL;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                          "Timeout waiting for status message", 0);
+            sftp->open_state = libssh2_NB_state_idle;
+            return NULL;
+        }
+    }
+
+    sftp->open_state = libssh2_NB_state_idle;
+
+    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->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;
+
+    fp->u.file.offset = 0;
+
+    _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Open command successful");
+    return fp;
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_read
+ * Read from an SFTP file handle
+ */
+LIBSSH2_API ssize_t
+libssh2_sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
+                  size_t buffer_maxlen)
+{
+    LIBSSH2_SFTP *sftp = handle->sftp;
+    LIBSSH2_CHANNEL *channel = sftp->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned long data_len, request_id;
+    /* 25 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) + offset(8) + length(4) */
+    ssize_t packet_len = handle->handle_len + 25;
+    unsigned char *packet, *s, *data;
+    static const unsigned char read_responses[2] =
+        { SSH_FXP_DATA, SSH_FXP_STATUS };
+    size_t bytes_read = 0;
+    size_t bytes_requested = 0;
+    size_t total_read = 0;
+    int retcode;
+
+    if (sftp->read_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
+                       "Reading %lu bytes from SFTP handle",
+                       (unsigned long) buffer_maxlen);
+        packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for FXP_CLOSE packet", 0);
+            return -1;
+        }
+        sftp->read_state = libssh2_NB_state_allocated;
+    } else {
+        packet = sftp->read_packet;
+        request_id = sftp->read_request_id;
+        total_read = sftp->read_total_read;
+    }
+
+    while (total_read < buffer_maxlen) {
+        s = packet;
+        /*
+         * If buffer_maxlen bytes will be requested, server may return all
+         * with one packet.  But libssh2 have packet length limit.
+         * So we request data by pieces.
+         */
+        bytes_requested = buffer_maxlen - total_read;
+        /* 10 = packet_type(1)+request_id(4)+data_length(4)+end_of_line_flag(1) */
+        if (bytes_requested > LIBSSH2_SFTP_PACKET_MAXLEN - 10) {
+            bytes_requested = LIBSSH2_SFTP_PACKET_MAXLEN - 10;
+        }
+#ifdef LIBSSH2_DEBUG_SFTP
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
+                       "Requesting %lu bytes from SFTP handle",
+                       (unsigned long) bytes_requested);
+#endif
+
+        if (sftp->read_state == libssh2_NB_state_allocated) {
+            libssh2_htonu32(s, packet_len - 4);
+            s += 4;
+            *(s++) = SSH_FXP_READ;
+            request_id = sftp->request_id++;
+            libssh2_htonu32(s, request_id);
+            s += 4;
+            libssh2_htonu32(s, handle->handle_len);
+            s += 4;
+
+            memcpy(s, handle->handle, handle->handle_len);
+            s += handle->handle_len;
+
+            libssh2_htonu64(s, handle->u.file.offset);
+            s += 8;
+
+            libssh2_htonu32(s, buffer_maxlen);
+            s += 4;
+
+            sftp->read_state = libssh2_NB_state_created;
+        }
+
+        if (sftp->read_state == libssh2_NB_state_created) {
+            retcode =
+                libssh2_channel_write_ex(channel, 0, (char *) packet,
+                                         packet_len);
+            if (retcode == PACKET_EAGAIN) {
+                sftp->read_packet = packet;
+                sftp->read_request_id = request_id;
+                sftp->read_total_read = total_read;
+                return PACKET_EAGAIN;
+            } else if (packet_len != retcode) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                              "Unable to send FXP_READ command", 0);
+                LIBSSH2_FREE(session, packet);
+                sftp->read_packet = NULL;
+                sftp->read_state = libssh2_NB_state_idle;
+                return -1;
+            }
+            sftp->read_packet = packet;
+            sftp->read_request_id = request_id;
+            sftp->read_total_read = total_read;
+            sftp->read_state = libssh2_NB_state_sent;
+        }
+
+        if (sftp->read_state == libssh2_NB_state_sent) {
+            retcode =
+                libssh2_sftp_packet_requirev(sftp, 2, read_responses,
+                                             request_id, &data, &data_len);
+            if (retcode == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            } else if (retcode) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                              "Timeout waiting for status message", 0);
+                LIBSSH2_FREE(session, packet);
+                sftp->read_packet = NULL;
+                sftp->read_state = libssh2_NB_state_idle;
+                return -1;
+            }
+
+            sftp->read_state = libssh2_NB_state_sent1;
+        }
+
+        switch (data[0]) {
+        case SSH_FXP_STATUS:
+            retcode = libssh2_ntohu32(data + 5);
+            LIBSSH2_FREE(session, packet);
+            LIBSSH2_FREE(session, data);
+            sftp->read_packet = NULL;
+            sftp->read_state = libssh2_NB_state_idle;
+
+            if (retcode == LIBSSH2_FX_EOF) {
+                return total_read;
+            } else {
+                sftp->last_errno = retcode;
+                libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                              "SFTP Protocol Error", 0);
+                return -1;
+            }
+
+        case SSH_FXP_DATA:
+            bytes_read = libssh2_ntohu32(data + 5);
+            if (bytes_read > (data_len - 9)) {
+                LIBSSH2_FREE(session, packet);
+                sftp->read_packet = NULL;
+                sftp->read_state = libssh2_NB_state_idle;
+                return -1;
+            }
+#ifdef LIBSSH2_DEBUG_SFTP
+            _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu bytes returned",
+                           (unsigned long) bytes_read);
+#endif
+            memcpy(buffer + total_read, data + 9, bytes_read);
+            handle->u.file.offset += bytes_read;
+            total_read += bytes_read;
+            LIBSSH2_FREE(session, data);
+            /*
+             * Set the state back to allocated, so a new one will be
+             * created to either request more data or get EOF
+             */
+            sftp->read_state = libssh2_NB_state_allocated;
+        }
+    }
+
+    LIBSSH2_FREE(session, packet);
+    sftp->read_packet = NULL;
+    sftp->read_state = libssh2_NB_state_idle;
+    return total_read;
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_readdir
+ * Read from an SFTP directory handle
+ */
+LIBSSH2_API int
+libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE * handle, char *buffer,
+                        size_t buffer_maxlen, char *longentry,
+                        size_t longentry_maxlen,
+                        LIBSSH2_SFTP_ATTRIBUTES * attrs)
+{
+    LIBSSH2_SFTP *sftp = handle->sftp;
+    LIBSSH2_CHANNEL *channel = sftp->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    LIBSSH2_SFTP_ATTRIBUTES attrs_dummy;
+    unsigned long data_len, filename_len, longentry_len, num_names;
+    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
+    ssize_t packet_len = handle->handle_len + 13;
+    unsigned char *s, *data;
+    unsigned char read_responses[2] = { SSH_FXP_NAME, SSH_FXP_STATUS };
+    int retcode;
+
+    if (sftp->readdir_state == libssh2_NB_state_idle) {
+        if (handle->u.dir.names_left) {
+            /*
+             * A prior request returned more than one directory entry,
+             * feed it back from the buffer
+             */
+            unsigned char *s = (unsigned char *) handle->u.dir.next_name;
+            unsigned long real_filename_len = libssh2_ntohu32(s);
+
+            filename_len = real_filename_len;
+            s += 4;
+            if (filename_len > buffer_maxlen) {
+                filename_len = buffer_maxlen;
+            }
+            memcpy(buffer, s, filename_len);
+            s += real_filename_len;
+
+            /* The filename is not null terminated, make it so if possible */
+            if (filename_len < buffer_maxlen) {
+                buffer[filename_len] = '\0';
+            }
+
+            if ((longentry == NULL) || (longentry_maxlen == 0)) {
+                /* Skip longname */
+                s += 4 + libssh2_ntohu32(s);
+            } else {
+                unsigned long real_longentry_len = libssh2_ntohu32(s);
+
+                longentry_len = real_longentry_len;
+                s += 4;
+                if (longentry_len > longentry_maxlen) {
+                    longentry_len = longentry_maxlen;
+                }
+                memcpy(longentry, s, longentry_len);
+                s += real_longentry_len;
+
+                /* The longentry is not null terminated, make it so if possible */
+                if (longentry_len < longentry_maxlen) {
+                    longentry[longentry_len] = '\0';
+                }
+            }
+
+            if (attrs) {
+                memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+            }
+            s += libssh2_sftp_bin2attr(attrs ? attrs : &attrs_dummy, s);
+
+            handle->u.dir.next_name = (char *) s;
+            if ((--handle->u.dir.names_left) == 0) {
+                LIBSSH2_FREE(session, handle->u.dir.names_packet);
+            }
+
+            _libssh2_debug(session, LIBSSH2_DBG_SFTP,
+                           "libssh2_sftp_readdir_ex() return %d",
+                           filename_len);
+            return filename_len;
+        }
+
+        /* Request another entry(entries?) */
+
+        s = sftp->readdir_packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!sftp->readdir_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for FXP_READDIR packet",
+                          0);
+            return -1;
+        }
+
+        libssh2_htonu32(s, packet_len - 4);
+        s += 4;
+        *(s++) = SSH_FXP_READDIR;
+        sftp->readdir_request_id = sftp->request_id++;
+        libssh2_htonu32(s, sftp->readdir_request_id);
+        s += 4;
+        libssh2_htonu32(s, handle->handle_len);
+        s += 4;
+        memcpy(s, handle->handle, handle->handle_len);
+        s += handle->handle_len;
+
+        sftp->readdir_state = libssh2_NB_state_created;
+    }
+
+    if (sftp->readdir_state == libssh2_NB_state_created) {
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
+                       "Reading entries from directory handle");
+        if ((retcode =
+             libssh2_channel_write_ex(channel, 0,
+                                      (char *) sftp->readdir_packet,
+                                      packet_len)) == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (packet_len != retcode) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send FXP_READ command", 0);
+            LIBSSH2_FREE(session, sftp->readdir_packet);
+            sftp->readdir_packet = NULL;
+            sftp->readdir_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        LIBSSH2_FREE(session, sftp->readdir_packet);
+        sftp->readdir_packet = NULL;
+
+        sftp->readdir_state = libssh2_NB_state_sent;
+    }
+
+    retcode =
+        libssh2_sftp_packet_requirev(sftp, 2, read_responses,
+                                     sftp->readdir_request_id, &data,
+                                     &data_len);
+    if (retcode == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    } else if (retcode) {
+        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                      "Timeout waiting for status message", 0);
+        sftp->readdir_state = libssh2_NB_state_idle;
+        return -1;
+    }
+
+    if (data[0] == SSH_FXP_STATUS) {
+        retcode = libssh2_ntohu32(data + 5);
+        LIBSSH2_FREE(session, data);
+        if (retcode == LIBSSH2_FX_EOF) {
+            sftp->readdir_state = libssh2_NB_state_idle;
+            return 0;
+        } else {
+            sftp->last_errno = retcode;
+            libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                          "SFTP Protocol Error", 0);
+            sftp->readdir_state = libssh2_NB_state_idle;
+            return -1;
+        }
+    }
+
+    num_names = libssh2_ntohu32(data + 5);
+    _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu entries returned",
+                   num_names);
+    if (num_names <= 0) {
+        LIBSSH2_FREE(session, data);
+        sftp->readdir_state = libssh2_NB_state_idle;
+        return (num_names == 0) ? 0 : -1;
+    }
+
+    if (num_names == 1) {
+        unsigned long real_filename_len = libssh2_ntohu32(data + 9);
+
+        filename_len = real_filename_len;
+        if (filename_len > buffer_maxlen) {
+            filename_len = buffer_maxlen;
+        }
+        memcpy(buffer, data + 13, filename_len);
+
+        /* The filename is not null terminated, make it so if possible */
+        if (filename_len < buffer_maxlen) {
+            buffer[filename_len] = '\0';
+        }
+
+        if (attrs) {
+            memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+            libssh2_sftp_bin2attr(attrs, data + 13 + real_filename_len +
+                                  (4 +
+                                   libssh2_ntohu32(data + 13 +
+                                                   real_filename_len)));
+        }
+        LIBSSH2_FREE(session, data);
+
+        sftp->readdir_state = libssh2_NB_state_idle;
+        return filename_len;
+    }
+
+    handle->u.dir.names_left = num_names;
+    handle->u.dir.names_packet = data;
+    handle->u.dir.next_name = (char *) data + 9;
+
+    sftp->readdir_state = libssh2_NB_state_idle;
+
+    /* Be lazy, just use the name popping mechanism from the start of the function */
+    return libssh2_sftp_readdir_ex(handle, buffer, buffer_maxlen, longentry,
+                                   longentry_maxlen, attrs);
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_write
+ * Write data to a file handle
+ */
+LIBSSH2_API ssize_t
+libssh2_sftp_write(LIBSSH2_SFTP_HANDLE * handle, const char *buffer,
+                   size_t count)
+{
+    LIBSSH2_SFTP *sftp = handle->sftp;
+    LIBSSH2_CHANNEL *channel = sftp->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned long data_len, retcode;
+    /* 25 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) + offset(8) + count(4) */
+    ssize_t packet_len = handle->handle_len + count + 25;
+    unsigned char *s, *data;
+    int rc;
+
+    if (sftp->write_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Writing %lu bytes",
+                       (unsigned long) count);
+        s = sftp->write_packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!sftp->write_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for FXP_WRITE packet", 0);
+            return -1;
+        }
+
+        libssh2_htonu32(s, packet_len - 4);
+        s += 4;
+        *(s++) = SSH_FXP_WRITE;
+        sftp->write_request_id = sftp->request_id++;
+        libssh2_htonu32(s, sftp->write_request_id);
+        s += 4;
+        libssh2_htonu32(s, handle->handle_len);
+        s += 4;
+        memcpy(s, handle->handle, handle->handle_len);
+        s += handle->handle_len;
+        libssh2_htonu64(s, handle->u.file.offset);
+        s += 8;
+        libssh2_htonu32(s, count);
+        s += 4;
+        memcpy(s, buffer, count);
+        s += count;
+
+        sftp->write_state = libssh2_NB_state_created;
+    }
+
+    if (sftp->write_state == libssh2_NB_state_created) {
+        if ((rc =
+             libssh2_channel_write_ex(channel, 0, (char *) sftp->write_packet,
+                                      packet_len)) == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        }
+        if (packet_len != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send FXP_READ command", 0);
+            LIBSSH2_FREE(session, sftp->write_packet);
+            sftp->write_packet = NULL;
+            sftp->write_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, sftp->write_packet);
+        sftp->write_packet = NULL;
+        sftp->write_state = libssh2_NB_state_sent;
+    }
+
+    rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
+                                     sftp->write_request_id, &data, &data_len);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    } else if (rc) {
+        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                      "Timeout waiting for status message", 0);
+        sftp->write_state = libssh2_NB_state_idle;
+        return -1;
+    }
+
+    sftp->write_state = libssh2_NB_state_idle;
+
+    retcode = libssh2_ntohu32(data + 5);
+    LIBSSH2_FREE(session, data);
+
+    if (retcode == LIBSSH2_FX_OK) {
+        handle->u.file.offset += count;
+        return count;
+    }
+    libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error",
+                  0);
+    sftp->last_errno = retcode;
+
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_fstat_ex
+ * Get or Set stat on a file
+ */
+LIBSSH2_API int
+libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE * handle,
+                      LIBSSH2_SFTP_ATTRIBUTES * attrs, int setstat)
+{
+    LIBSSH2_SFTP *sftp = handle->sftp;
+    LIBSSH2_CHANNEL *channel = sftp->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned long data_len;
+    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
+    ssize_t packet_len =
+        handle->handle_len + 13 + (setstat ? libssh2_sftp_attrsize(attrs) : 0);
+    unsigned char *s, *data;
+    static const unsigned char fstat_responses[2] =
+        { SSH_FXP_ATTRS, SSH_FXP_STATUS };
+    int rc;
+
+    if (sftp->fstat_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Issuing %s command",
+                       setstat ? "set-stat" : "stat");
+        s = sftp->fstat_packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!sftp->fstat_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for FSTAT/FSETSTAT packet",
+                          0);
+            return -1;
+        }
+
+        libssh2_htonu32(s, packet_len - 4);
+        s += 4;
+        *(s++) = setstat ? SSH_FXP_FSETSTAT : SSH_FXP_FSTAT;
+        sftp->fstat_request_id = sftp->request_id++;
+        libssh2_htonu32(s, sftp->fstat_request_id);
+        s += 4;
+        libssh2_htonu32(s, handle->handle_len);
+        s += 4;
+        memcpy(s, handle->handle, handle->handle_len);
+        s += handle->handle_len;
+        if (setstat) {
+            s += libssh2_sftp_attr2bin(s, attrs);
+        }
+
+        sftp->fstat_state = libssh2_NB_state_created;
+    }
+
+    if (sftp->fstat_state == libssh2_NB_state_created) {
+        rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->fstat_packet,
+                                      packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (packet_len != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          setstat ? (char *) "Unable to send FXP_FSETSTAT"
+                          : (char *) "Unable to send FXP_FSTAT command", 0);
+            LIBSSH2_FREE(session, sftp->fstat_packet);
+            sftp->fstat_packet = NULL;
+            sftp->fstat_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, sftp->fstat_packet);
+        sftp->fstat_packet = NULL;
+
+        sftp->fstat_state = libssh2_NB_state_sent;
+    }
+
+    rc = libssh2_sftp_packet_requirev(sftp, 2, fstat_responses,
+                                      sftp->fstat_request_id, &data,
+                                      &data_len);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    } else if (rc) {
+        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                      "Timeout waiting for status message", 0);
+        sftp->fstat_state = libssh2_NB_state_idle;
+        return -1;
+    }
+
+    sftp->fstat_state = libssh2_NB_state_idle;
+
+    if (data[0] == SSH_FXP_STATUS) {
+        int retcode;
+
+        retcode = libssh2_ntohu32(data + 5);
+        LIBSSH2_FREE(session, data);
+        if (retcode == LIBSSH2_FX_OK) {
+            return 0;
+        } else {
+            sftp->last_errno = retcode;
+            libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                          "SFTP Protocol Error", 0);
+            return -1;
+        }
+    }
+
+    libssh2_sftp_bin2attr(attrs, data + 5);
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_seek
+ * Set the read/write pointer to an arbitrary position within the file
+ */
+LIBSSH2_API void
+libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE * handle, size_t offset)
+{
+    handle->u.file.offset = offset;
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_tell
+ * Return the current read/write pointer's offset
+ */
+LIBSSH2_API size_t
+libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE * handle)
+{
+    return handle->u.file.offset;
+}
+
+/* }}} */
+
+
+/* {{{ libssh2_sftp_close_handle
+ * Close a file or directory handle
+ * Also frees handle resource and unlinks it from the SFTP structure
+ */
+LIBSSH2_API int
+libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE * handle)
+{
+    LIBSSH2_SFTP *sftp = handle->sftp;
+    LIBSSH2_CHANNEL *channel = sftp->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned long data_len, retcode;
+    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
+    ssize_t packet_len = handle->handle_len + 13;
+    unsigned char *s, *data;
+    int rc;
+
+    if (handle->close_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Closing handle");
+        s = handle->close_packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!handle->close_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for FXP_CLOSE packet", 0);
+            return -1;
+        }
+
+        libssh2_htonu32(s, packet_len - 4);
+        s += 4;
+        *(s++) = SSH_FXP_CLOSE;
+        handle->close_request_id = sftp->request_id++;
+        libssh2_htonu32(s, handle->close_request_id);
+        s += 4;
+        libssh2_htonu32(s, handle->handle_len);
+        s += 4;
+        memcpy(s, handle->handle, handle->handle_len);
+        s += handle->handle_len;
+
+        handle->close_state = libssh2_NB_state_created;
+    }
+
+    if (handle->close_state == libssh2_NB_state_created) {
+        rc = libssh2_channel_write_ex(channel, 0,
+                                      (char *) handle->close_packet,
+                                      packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (packet_len != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send FXP_CLOSE command", 0);
+            LIBSSH2_FREE(session, handle->close_packet);
+            handle->close_packet = NULL;
+            handle->close_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, handle->close_packet);
+        handle->close_packet = NULL;
+
+        handle->close_state = libssh2_NB_state_sent;
+    }
+
+    if (handle->close_state == libssh2_NB_state_sent) {
+        rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
+                                         handle->close_request_id, &data,
+                                         &data_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                          "Timeout waiting for status message", 0);
+            handle->close_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        handle->close_state = libssh2_NB_state_sent1;
+    }
+
+    retcode = libssh2_ntohu32(data + 5);
+    LIBSSH2_FREE(session, data);
+
+    if (retcode != LIBSSH2_FX_OK) {
+        sftp->last_errno = retcode;
+        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                      "SFTP Protocol Error", 0);
+        handle->close_state = libssh2_NB_state_idle;
+        return -1;
+    }
+
+    if (handle == sftp->handles) {
+        sftp->handles = handle->next;
+    }
+    if (handle->next) {
+        handle->next->prev = NULL;
+    }
+
+    if ((handle->handle_type == LIBSSH2_SFTP_HANDLE_DIR)
+        && handle->u.dir.names_left) {
+        LIBSSH2_FREE(session, handle->u.dir.names_packet);
+    }
+
+    handle->close_state = libssh2_NB_state_idle;
+
+    LIBSSH2_FREE(session, handle->handle);
+    LIBSSH2_FREE(session, handle);
+
+    return 0;
+}
+
+/* }}} */
+
+/* **********************
+   * SFTP Miscellaneous *
+   ********************** */
+
+/* {{{ libssh2_sftp_unlink_ex
+ * Delete a file from the remote server
+ */
+/* libssh2_sftp_unlink_ex - NB-UNSAFE?? */
+LIBSSH2_API int
+libssh2_sftp_unlink_ex(LIBSSH2_SFTP * sftp, const char *filename,
+                       unsigned int filename_len)
+{
+    LIBSSH2_CHANNEL *channel = sftp->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned long data_len, retcode;
+    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */
+    ssize_t packet_len = filename_len + 13;
+    unsigned char *s, *data;
+    int rc;
+
+    if (sftp->unlink_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Unlinking %s", filename);
+        s = sftp->unlink_packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!sftp->unlink_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for FXP_REMOVE packet",
+                          0);
+            return -1;
+        }
+
+        libssh2_htonu32(s, packet_len - 4);
+        s += 4;
+        *(s++) = SSH_FXP_REMOVE;
+        sftp->unlink_request_id = sftp->request_id++;
+        libssh2_htonu32(s, sftp->unlink_request_id);
+        s += 4;
+        libssh2_htonu32(s, filename_len);
+        s += 4;
+        memcpy(s, filename, filename_len);
+        s += filename_len;
+
+        sftp->unlink_state = libssh2_NB_state_created;
+    }
+
+    if (sftp->unlink_state == libssh2_NB_state_created) {
+        rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->unlink_packet,
+                                      packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (packet_len != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send FXP_REMOVE command", 0);
+            LIBSSH2_FREE(session, sftp->unlink_packet);
+            sftp->unlink_packet = NULL;
+            sftp->unlink_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, sftp->unlink_packet);
+        sftp->unlink_packet = NULL;
+
+        sftp->unlink_state = libssh2_NB_state_sent;
+    }
+
+    rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
+                                     sftp->unlink_request_id, &data,
+                                     &data_len);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    } else if (rc) {
+        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                      "Timeout waiting for status message", 0);
+        sftp->unlink_state = libssh2_NB_state_idle;
+        return -1;
+    }
+
+    sftp->unlink_state = libssh2_NB_state_idle;
+
+    retcode = libssh2_ntohu32(data + 5);
+    LIBSSH2_FREE(session, data);
+
+    if (retcode == LIBSSH2_FX_OK) {
+        return 0;
+    } else {
+        sftp->last_errno = retcode;
+        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                      "SFTP Protocol Error", 0);
+        return -1;
+    }
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_rename_ex
+ * Rename a file on the remote server
+ */
+LIBSSH2_API int
+libssh2_sftp_rename_ex(LIBSSH2_SFTP * sftp, const char *source_filename,
+                       unsigned int source_filename_len,
+                       const char *dest_filename,
+                       unsigned int dest_filename_len, long flags)
+{
+    LIBSSH2_CHANNEL *channel = sftp->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned long data_len, retcode;
+    ssize_t packet_len =
+        source_filename_len + dest_filename_len + 17 + (sftp->version >=
+                                                        5 ? 4 : 0);
+    /* packet_len(4) + packet_type(1) + request_id(4) +
+       source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */
+    unsigned char *data;
+    int rc;
+
+    if (sftp->version < 2) {
+        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                      "Server does not support RENAME", 0);
+        return -1;
+    }
+
+    if (sftp->rename_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Renaming %s to %s",
+                       source_filename, dest_filename);
+        sftp->rename_s = sftp->rename_packet =
+            LIBSSH2_ALLOC(session, packet_len);
+        if (!sftp->rename_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for FXP_RENAME packet",
+                          0);
+            return -1;
+        }
+
+        libssh2_htonu32(sftp->rename_s, packet_len - 4);
+        sftp->rename_s += 4;
+        *(sftp->rename_s++) = SSH_FXP_RENAME;
+        sftp->rename_request_id = sftp->request_id++;
+        libssh2_htonu32(sftp->rename_s, sftp->rename_request_id);
+        sftp->rename_s += 4;
+        libssh2_htonu32(sftp->rename_s, source_filename_len);
+        sftp->rename_s += 4;
+        memcpy(sftp->rename_s, source_filename, source_filename_len);
+        sftp->rename_s += source_filename_len;
+        libssh2_htonu32(sftp->rename_s, dest_filename_len);
+        sftp->rename_s += 4;
+        memcpy(sftp->rename_s, dest_filename, dest_filename_len);
+        sftp->rename_s += dest_filename_len;
+
+        if (sftp->version >= 5) {
+            libssh2_htonu32(sftp->rename_s, flags);
+            sftp->rename_s += 4;
+        }
+
+        sftp->rename_state = libssh2_NB_state_created;
+    }
+
+    if (sftp->rename_state == libssh2_NB_state_created) {
+        rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->rename_packet,
+                                      sftp->rename_s - sftp->rename_packet);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (packet_len != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send FXP_RENAME command", 0);
+            LIBSSH2_FREE(session, sftp->rename_packet);
+            sftp->rename_packet = NULL;
+            sftp->rename_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, sftp->rename_packet);
+        sftp->rename_packet = NULL;
+
+        sftp->rename_state = libssh2_NB_state_sent;
+    }
+
+    rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
+                                     sftp->rename_request_id, &data,
+                                     &data_len);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    } else if (rc) {
+        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                      "Timeout waiting for status message", 0);
+        sftp->rename_state = libssh2_NB_state_idle;
+        return -1;
+    }
+
+    sftp->rename_state = libssh2_NB_state_idle;
+
+    retcode = libssh2_ntohu32(data + 5);
+    LIBSSH2_FREE(session, data);
+
+    switch (retcode) {
+    case LIBSSH2_FX_OK:
+        retcode = 0;
+        break;
+
+    case LIBSSH2_FX_FILE_ALREADY_EXISTS:
+        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                      "File already exists and SSH_FXP_RENAME_OVERWRITE not specified",
+                      0);
+        sftp->last_errno = retcode;
+        retcode = -1;
+        break;
+
+    case LIBSSH2_FX_OP_UNSUPPORTED:
+        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                      "Operation Not Supported", 0);
+        sftp->last_errno = retcode;
+        retcode = -1;
+        break;
+
+    default:
+        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                      "SFTP Protocol Error", 0);
+        sftp->last_errno = retcode;
+        retcode = -1;
+    }
+
+    return retcode;
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_mkdir_ex
+ * Create an SFTP directory
+ */
+LIBSSH2_API int
+libssh2_sftp_mkdir_ex(LIBSSH2_SFTP * sftp, const char *path,
+                      unsigned int path_len, long mode)
+{
+    LIBSSH2_CHANNEL *channel = sftp->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    LIBSSH2_SFTP_ATTRIBUTES attrs = {
+        LIBSSH2_SFTP_ATTR_PERMISSIONS, 0, 0, 0, 0, 0, 0
+    };
+    unsigned long data_len, retcode, request_id;
+    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
+    ssize_t packet_len = path_len + 13 + libssh2_sftp_attrsize(&attrs);
+    unsigned char *packet, *s, *data;
+    int rc;
+
+    if (sftp->mkdir_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP,
+                       "Creating directory %s with mode 0%lo", path, mode);
+        s = packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for FXP_MKDIR packet", 0);
+            return -1;
+        }
+        /* Filetype in SFTP 3 and earlier */
+        attrs.permissions = mode | LIBSSH2_SFTP_ATTR_PFILETYPE_DIR;
+
+        libssh2_htonu32(s, packet_len - 4);
+        s += 4;
+        *(s++) = SSH_FXP_MKDIR;
+        request_id = sftp->request_id++;
+        libssh2_htonu32(s, request_id);
+        s += 4;
+        libssh2_htonu32(s, path_len);
+        s += 4;
+        memcpy(s, path, path_len);
+        s += path_len;
+        s += libssh2_sftp_attr2bin(s, &attrs);
+
+        sftp->mkdir_state = libssh2_NB_state_created;
+    } else {
+        packet = sftp->mkdir_packet;
+        request_id = sftp->mkdir_request_id;
+    }
+
+    if (sftp->mkdir_state == libssh2_NB_state_created) {
+        rc = libssh2_channel_write_ex(channel, 0, (char *) packet, packet_len);
+        if (rc == PACKET_EAGAIN) {
+            sftp->mkdir_packet = packet;
+            sftp->mkdir_request_id = request_id;
+            return PACKET_EAGAIN;
+        }
+        if (packet_len != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send FXP_READ command", 0);
+            LIBSSH2_FREE(session, packet);
+            sftp->mkdir_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, packet);
+        sftp->mkdir_state = libssh2_NB_state_sent;
+        sftp->mkdir_packet = NULL;
+    }
+
+    rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data,
+                                     &data_len);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    } else if (rc) {
+        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                      "Timeout waiting for status message", 0);
+        sftp->mkdir_state = libssh2_NB_state_idle;
+        return -1;
+    }
+
+    sftp->mkdir_state = libssh2_NB_state_idle;
+
+    retcode = libssh2_ntohu32(data + 5);
+    LIBSSH2_FREE(session, data);
+
+    if (retcode == LIBSSH2_FX_OK) {
+        return 0;
+    } else {
+        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                      "SFTP Protocol Error", 0);
+        sftp->last_errno = retcode;
+        return -1;
+    }
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_rmdir_ex
+ * Remove a directory
+ */
+/* libssh2_sftp_rmdir_ex - NB-UNSAFE?? */
+LIBSSH2_API int
+libssh2_sftp_rmdir_ex(LIBSSH2_SFTP * sftp, const char *path,
+                      unsigned int path_len)
+{
+    LIBSSH2_CHANNEL *channel = sftp->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned long data_len, retcode;
+    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
+    ssize_t packet_len = path_len + 13;
+    unsigned char *s, *data;
+    int rc;
+
+    if (sftp->rmdir_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Removing directory: %s",
+                       path);
+        s = sftp->rmdir_packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!sftp->rmdir_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for FXP_MKDIR packet", 0);
+            return -1;
+        }
+
+        libssh2_htonu32(s, packet_len - 4);
+        s += 4;
+        *(s++) = SSH_FXP_RMDIR;
+        sftp->rmdir_request_id = sftp->request_id++;
+        libssh2_htonu32(s, sftp->rmdir_request_id);
+        s += 4;
+        libssh2_htonu32(s, path_len);
+        s += 4;
+        memcpy(s, path, path_len);
+        s += path_len;
+
+        sftp->rmdir_state = libssh2_NB_state_created;
+    }
+
+    if (sftp->rmdir_state == libssh2_NB_state_created) {
+        rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->rmdir_packet,
+                                      packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (packet_len != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send FXP_MKDIR command", 0);
+            LIBSSH2_FREE(session, sftp->rmdir_packet);
+            sftp->rmdir_packet = NULL;
+            sftp->rmdir_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, sftp->rmdir_packet);
+        sftp->rmdir_packet = NULL;
+
+        sftp->rmdir_state = libssh2_NB_state_sent;
+    }
+
+    rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
+                                     sftp->rmdir_request_id, &data, &data_len);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    } else if (rc) {
+        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                      "Timeout waiting for status message", 0);
+        sftp->rmdir_state = libssh2_NB_state_idle;
+        return -1;
+    }
+
+    sftp->rmdir_state = libssh2_NB_state_idle;
+
+    retcode = libssh2_ntohu32(data + 5);
+    LIBSSH2_FREE(session, data);
+
+    if (retcode == LIBSSH2_FX_OK) {
+        return 0;
+    } else {
+        sftp->last_errno = retcode;
+        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                      "SFTP Protocol Error", 0);
+        return -1;
+    }
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_stat_ex
+ * Stat a file or symbolic link
+ */
+/* libssh2_sftp_stat_ex - NB-UNSAFE?? */
+LIBSSH2_API int
+libssh2_sftp_stat_ex(LIBSSH2_SFTP * sftp, const char *path,
+                     unsigned int path_len, int stat_type,
+                     LIBSSH2_SFTP_ATTRIBUTES * attrs)
+{
+    LIBSSH2_CHANNEL *channel = sftp->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned long data_len;
+    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
+    ssize_t packet_len =
+        path_len + 13 +
+        ((stat_type ==
+          LIBSSH2_SFTP_SETSTAT) ? libssh2_sftp_attrsize(attrs) : 0);
+    unsigned char *s, *data;
+    static const unsigned char stat_responses[2] =
+        { SSH_FXP_ATTRS, SSH_FXP_STATUS };
+    int rc;
+
+    if (sftp->stat_state == libssh2_NB_state_idle) {
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s",
+                       (stat_type == LIBSSH2_SFTP_SETSTAT) ? "Set-statting" :
+                       (stat_type ==
+                        LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path);
+        s = sftp->stat_packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!sftp->stat_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for FXP_MKDIR packet", 0);
+            return -1;
+        }
+
+        libssh2_htonu32(s, packet_len - 4);
+        s += 4;
+        switch (stat_type) {
+        case LIBSSH2_SFTP_SETSTAT:
+            *(s++) = SSH_FXP_SETSTAT;
+            break;
+
+        case LIBSSH2_SFTP_LSTAT:
+            *(s++) = SSH_FXP_LSTAT;
+            break;
+
+        case LIBSSH2_SFTP_STAT:
+        default:
+            *(s++) = SSH_FXP_STAT;
+        }
+        sftp->stat_request_id = sftp->request_id++;
+        libssh2_htonu32(s, sftp->stat_request_id);
+        s += 4;
+        libssh2_htonu32(s, path_len);
+        s += 4;
+        memcpy(s, path, path_len);
+        s += path_len;
+        if (stat_type == LIBSSH2_SFTP_SETSTAT) {
+            s += libssh2_sftp_attr2bin(s, attrs);
+        }
+
+        sftp->stat_state = libssh2_NB_state_created;
+    }
+
+    if (sftp->stat_state == libssh2_NB_state_created) {
+        rc = libssh2_channel_write_ex(channel, 0, (char *) sftp->stat_packet,
+                                      packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (packet_len != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send STAT/LSTAT/SETSTAT command", 0);
+            LIBSSH2_FREE(session, sftp->stat_packet);
+            sftp->stat_packet = NULL;
+            sftp->stat_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, sftp->stat_packet);
+        sftp->stat_packet = NULL;
+
+        sftp->stat_state = libssh2_NB_state_sent;
+    }
+
+    rc = libssh2_sftp_packet_requirev(sftp, 2, stat_responses,
+                                      sftp->stat_request_id, &data, &data_len);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    } else if (rc) {
+        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                      "Timeout waiting for status message", 0);
+        sftp->stat_state = libssh2_NB_state_idle;
+        return -1;
+    }
+
+    sftp->stat_state = libssh2_NB_state_idle;
+
+    if (data[0] == SSH_FXP_STATUS) {
+        int retcode;
+
+        retcode = libssh2_ntohu32(data + 5);
+        LIBSSH2_FREE(session, data);
+        if (retcode == LIBSSH2_FX_OK) {
+            return 0;
+        } else {
+            sftp->last_errno = retcode;
+            libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                          "SFTP Protocol Error", 0);
+            return -1;
+        }
+    }
+
+    memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+    libssh2_sftp_bin2attr(attrs, data + 5);
+    LIBSSH2_FREE(session, data);
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_symlink_ex
+ * Read or set a symlink
+ */
+LIBSSH2_API int
+libssh2_sftp_symlink_ex(LIBSSH2_SFTP * sftp, const char *path,
+                        unsigned int path_len, char *target,
+                        unsigned int target_len, int link_type)
+{
+    LIBSSH2_CHANNEL *channel = sftp->channel;
+    LIBSSH2_SESSION *session = channel->session;
+    unsigned long data_len, link_len;
+    /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
+    ssize_t packet_len =
+        path_len + 13 +
+        ((link_type == LIBSSH2_SFTP_SYMLINK) ? (4 + target_len) : 0);
+    unsigned char *s, *data;
+    static const unsigned char link_responses[2] =
+        { SSH_FXP_NAME, SSH_FXP_STATUS };
+    int rc;
+
+    if ((sftp->version < 3) && (link_type != LIBSSH2_SFTP_REALPATH)) {
+        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                      "Server does not support SYMLINK or READLINK", 0);
+        return -1;
+    }
+
+    if (sftp->symlink_state == libssh2_NB_state_idle) {
+        s = sftp->symlink_packet = LIBSSH2_ALLOC(session, packet_len);
+        if (!sftp->symlink_packet) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for SYMLINK/READLINK/REALPATH packet",
+                          0);
+            return -1;
+        }
+
+        _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s on %s",
+                       (link_type ==
+                        LIBSSH2_SFTP_SYMLINK) ? "Creating" : "Reading",
+                       (link_type ==
+                        LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", path);
+
+        libssh2_htonu32(s, packet_len - 4);
+        s += 4;
+        switch (link_type) {
+        case LIBSSH2_SFTP_REALPATH:
+            *(s++) = SSH_FXP_REALPATH;
+            break;
+
+        case LIBSSH2_SFTP_SYMLINK:
+            *(s++) = SSH_FXP_SYMLINK;
+            break;
+
+        case LIBSSH2_SFTP_READLINK:
+        default:
+            *(s++) = SSH_FXP_READLINK;
+        }
+        sftp->symlink_request_id = sftp->request_id++;
+        libssh2_htonu32(s, sftp->symlink_request_id);
+        s += 4;
+        libssh2_htonu32(s, path_len);
+        s += 4;
+        memcpy(s, path, path_len);
+        s += path_len;
+        if (link_type == LIBSSH2_SFTP_SYMLINK) {
+            libssh2_htonu32(s, target_len);
+            s += 4;
+            memcpy(s, target, target_len);
+            s += target_len;
+        }
+
+        sftp->symlink_state = libssh2_NB_state_created;
+    }
+
+    if (sftp->symlink_state == libssh2_NB_state_created) {
+        rc = libssh2_channel_write_ex(channel, 0,
+                                      (char *) sftp->symlink_packet,
+                                      packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (packet_len != rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send SYMLINK/READLINK command", 0);
+            LIBSSH2_FREE(session, sftp->symlink_packet);
+            sftp->symlink_packet = NULL;
+            sftp->symlink_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, sftp->symlink_packet);
+        sftp->symlink_packet = NULL;
+
+        sftp->symlink_state = libssh2_NB_state_sent;
+    }
+
+    rc = libssh2_sftp_packet_requirev(sftp, 2, link_responses,
+                                      sftp->symlink_request_id, &data,
+                                      &data_len);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    } else if (rc) {
+        libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
+                      "Timeout waiting for status message", 0);
+        sftp->symlink_state = libssh2_NB_state_idle;
+        return -1;
+    }
+
+    sftp->symlink_state = libssh2_NB_state_idle;
+
+    if (data[0] == SSH_FXP_STATUS) {
+        int retcode;
+
+        retcode = libssh2_ntohu32(data + 5);
+        LIBSSH2_FREE(session, data);
+        if (retcode == LIBSSH2_FX_OK) {
+            return 0;
+        } else {
+            sftp->last_errno = retcode;
+            libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                          "SFTP Protocol Error", 0);
+            return -1;
+        }
+    }
+
+    if (libssh2_ntohu32(data + 5) < 1) {
+        libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+                      "Invalid READLINK/REALPATH response, no name entries",
+                      0);
+        LIBSSH2_FREE(session, data);
+        return -1;
+    }
+
+    link_len = libssh2_ntohu32(data + 9);
+    if (link_len >= target_len) {
+        link_len = target_len - 1;
+    }
+    memcpy(target, data + 13, link_len);
+    target[link_len] = 0;
+    LIBSSH2_FREE(session, data);
+
+    return link_len;
+}
+
+/* }}} */
+
+/* {{{ libssh2_sftp_last_error
+ * Returns the last error code reported by SFTP
+ */
+LIBSSH2_API unsigned long
+libssh2_sftp_last_error(LIBSSH2_SFTP * sftp)
+{
+    return sftp->last_errno;
+}
+
+/* }}} */
diff --git a/Vendor/libssh2/Source/transport.c b/Vendor/libssh2/Source/transport.c
new file mode 100644 (file)
index 0000000..13f5130
--- /dev/null
@@ -0,0 +1,761 @@
+/* Copyright (C) 2007 The Written Word, Inc.  All rights reserved.
+ * Author: Daniel Stenberg <daniel@haxx.se>
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file handles reading and writing to the SECSH transport layer. RFC4253.
+ */
+
+#include "libssh2_priv.h"
+#include <errno.h>
+#include <fcntl.h>
+
+#include <assert.h>
+
+#define MAX_BLOCKSIZE 32        /* MUST fit biggest crypto block size we use/get */
+#define MAX_MACSIZE 20          /* MUST fit biggest MAC length we support */
+
+#ifdef LIBSSH2DEBUG
+#define UNPRINTABLE_CHAR '.'
+static void
+debugdump(LIBSSH2_SESSION * session,
+          const char *desc, unsigned char *ptr, unsigned long size)
+{
+    size_t i;
+    size_t c;
+    FILE *stream = stdout;
+    unsigned int width = 0x10;
+
+    if (!(session->showmask & (1 << LIBSSH2_DBG_TRANS))) {
+        /* not asked for, bail out */
+        return;
+    }
+
+    fprintf(stream, "=> %s (%d bytes)\n", desc, (int) size);
+
+    for(i = 0; i < size; i += width) {
+
+        fprintf(stream, "%04lx: ", (long)i);
+
+        /* hex not disabled, show it */
+        for(c = 0; c < width; c++) {
+            if (i + c < size)
+                fprintf(stream, "%02x ", ptr[i + c]);
+            else
+                fputs("   ", stream);
+        }
+
+        for(c = 0; (c < width) && (i + c < size); c++) {
+            fprintf(stream, "%c",
+                    (ptr[i + c] >= 0x20) &&
+                    (ptr[i + c] < 0x80) ? ptr[i + c] : UNPRINTABLE_CHAR);
+        }
+        fputc('\n', stream);    /* newline */
+    }
+    fflush(stream);
+}
+#else
+#define debugdump(a,x,y,z)
+#endif
+
+
+/* decrypt() decrypts 'len' bytes from 'source' to 'dest'.
+ *
+ * returns PACKET_NONE on success and PACKET_FAIL on failure
+ */
+
+static libssh2pack_t
+decrypt(LIBSSH2_SESSION * session, unsigned char *source,
+        unsigned char *dest, int len)
+{
+    struct transportpacket *p = &session->packet;
+    int blocksize = session->remote.crypt->blocksize;
+
+    /* if we get called with a len that isn't an even number of blocksizes
+       we risk losing those extra bytes */
+    assert((len % blocksize) == 0);
+
+    while (len >= blocksize) {
+        if (session->remote.crypt->crypt(session, source,
+                                         &session->remote.crypt_abstract)) {
+            libssh2_error(session, LIBSSH2_ERROR_DECRYPT,
+                          (char *) "Error decrypting packet", 0);
+            LIBSSH2_FREE(session, p->payload);
+            return PACKET_FAIL;
+        }
+
+        /* if the crypt() function would write to a given address it
+           wouldn't have to memcpy() and we could avoid this memcpy()
+           too */
+        memcpy(dest, source, blocksize);
+
+        len -= blocksize;       /* less bytes left */
+        dest += blocksize;      /* advance write pointer */
+        source += blocksize;    /* advance read pointer */
+    }
+    return PACKET_NONE;         /* all is fine */
+}
+
+/*
+ * fullpacket() gets called when a full packet has been received and properly
+ * collected.
+ */
+static libssh2pack_t
+fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
+{
+    unsigned char macbuf[MAX_MACSIZE];
+    struct transportpacket *p = &session->packet;
+    int rc;
+
+    if (session->fullpacket_state == libssh2_NB_state_idle) {
+        session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED;
+        session->fullpacket_payload_len = p->packet_length - 1;
+
+        if (encrypted) {
+
+            /* Calculate MAC hash */
+            session->remote.mac->hash(session, macbuf,  /* store hash here */
+                                      session->remote.seqno,
+                                      p->init, 5,
+                                      p->payload,
+                                      session->fullpacket_payload_len,
+                                      &session->remote.mac_abstract);
+
+            /* Compare the calculated hash with the MAC we just read from
+             * the network. The read one is at the very end of the payload
+             * buffer. Note that 'payload_len' here is the packet_length
+             * field which includes the padding but not the MAC.
+             */
+            if (memcmp(macbuf, p->payload + session->fullpacket_payload_len,
+                       session->remote.mac->mac_len)) {
+                session->fullpacket_macstate = LIBSSH2_MAC_INVALID;
+            }
+        }
+
+        session->remote.seqno++;
+
+        /* ignore the padding */
+        session->fullpacket_payload_len -= p->padding_length;
+
+        /* Check for and deal with decompression */
+        if (session->remote.comp && strcmp(session->remote.comp->name, "none")) {
+            unsigned char *data;
+            unsigned long data_len;
+            int free_payload = 1;
+
+            if (session->remote.comp->comp(session, 0,
+                                           &data, &data_len,
+                                           LIBSSH2_PACKET_MAXDECOMP,
+                                           &free_payload,
+                                           p->payload,
+                                           session->fullpacket_payload_len,
+                                           &session->remote.comp_abstract)) {
+                LIBSSH2_FREE(session, p->payload);
+                return PACKET_FAIL;
+            }
+
+            if (free_payload) {
+                LIBSSH2_FREE(session, p->payload);
+                p->payload = data;
+                session->fullpacket_payload_len = data_len;
+            } else {
+                if (data == p->payload) {
+                    /* It's not to be freed, because the
+                     * compression layer reused payload, So let's
+                     * do the same!
+                     */
+                    session->fullpacket_payload_len = data_len;
+                } else {
+                    /* No comp_method actually lets this happen,
+                     * but let's prepare for the future */
+
+                    LIBSSH2_FREE(session, p->payload);
+
+                    /* We need a freeable struct otherwise the
+                     * brigade won't know what to do with it */
+                    p->payload = LIBSSH2_ALLOC(session, data_len);
+                    if (!p->payload) {
+                        libssh2_error(session, LIBSSH2_ERROR_ALLOC, (char *)
+                                      "Unable to allocate memory for copy of uncompressed data",
+                                      0);
+                        return PACKET_ENOMEM;
+                    }
+                    memcpy(p->payload, data, data_len);
+                    session->fullpacket_payload_len = data_len;
+                }
+            }
+        }
+
+        session->fullpacket_packet_type = p->payload[0];
+
+        debugdump(session, "libssh2_packet_read() plain",
+                  p->payload, session->fullpacket_payload_len);
+
+        session->fullpacket_state = libssh2_NB_state_created;
+    }
+
+    if (session->fullpacket_state == libssh2_NB_state_created) {
+        rc = libssh2_packet_add(session, p->payload,
+                                session->fullpacket_payload_len,
+                                session->fullpacket_macstate);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc < 0) {
+            return PACKET_FAIL;
+        }
+    }
+
+    session->fullpacket_state = libssh2_NB_state_idle;
+
+    return session->fullpacket_packet_type;
+}
+
+
+/* {{{ libssh2_packet_read
+ * Collect a packet into the input brigade
+ * block only controls whether or not to wait for a packet to start,
+ * Once a packet starts, libssh2 will block until it is complete
+ *
+ * Returns packet type added to input brigade (PACKET_NONE if nothing added),
+ * or PACKET_FAIL on failure and PACKET_EAGAIN if it couldn't process a full
+ * packet.
+ */
+
+/*
+ * This function reads the binary stream as specified in chapter 6 of RFC4253
+ * "The Secure Shell (SSH) Transport Layer Protocol"
+ */
+libssh2pack_t
+libssh2_packet_read(LIBSSH2_SESSION * session)
+{
+    libssh2pack_t rc;
+    struct transportpacket *p = &session->packet;
+    int remainbuf;
+    int remainpack;
+    int numbytes;
+    int numdecrypt;
+    unsigned char block[MAX_BLOCKSIZE];
+    int blocksize;
+    int encrypted = 1;
+
+    /*
+     * =============================== NOTE ===============================
+     * I know this is very ugly and not a really good use of "goto", but
+     * this case statement would be even uglier to do it any other way
+     */
+    if (session->readPack_state == libssh2_NB_state_jump1) {
+        session->readPack_state = libssh2_NB_state_idle;
+        encrypted = session->readPack_encrypted;
+        goto libssh2_packet_read_point1;
+    }
+
+    do {
+        if (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
+            return PACKET_NONE;
+        }
+
+        if (session->state & LIBSSH2_STATE_NEWKEYS) {
+            blocksize = session->remote.crypt->blocksize;
+        } else {
+            encrypted = 0;      /* not encrypted */
+            blocksize = 5;      /* not strictly true, but we can use 5 here to
+                                   make the checks below work fine still */
+        }
+
+        /* read/use a whole big chunk into a temporary area stored in
+           the LIBSSH2_SESSION struct. We will decrypt data from that
+           buffer into the packet buffer so this temp one doesn't have
+           to be able to keep a whole SSH packet, just be large enough
+           so that we can read big chunks from the network layer. */
+
+        /* how much data there is remaining in the buffer to deal with
+           before we should read more from the network */
+        remainbuf = p->writeidx - p->readidx;
+
+        /* if remainbuf turns negative we have a bad internal error */
+        assert(remainbuf >= 0);
+
+        if (remainbuf < blocksize) {
+            /* If we have less than a blocksize left, it is too
+               little data to deal with, read more */
+            ssize_t nread;
+
+            /* move any remainder to the start of the buffer so
+               that we can do a full refill */
+            if (remainbuf) {
+                memmove(p->buf, &p->buf[p->readidx], remainbuf);
+                p->readidx = 0;
+                p->writeidx = remainbuf;
+            } else {
+                /* nothing to move, just zero the indexes */
+                p->readidx = p->writeidx = 0;
+            }
+
+            /* now read a big chunk from the network into the temp buffer */
+            nread =
+                recv(session->socket_fd, &p->buf[remainbuf],
+                     PACKETBUFSIZE - remainbuf,
+                     LIBSSH2_SOCKET_RECV_FLAGS(session));
+            if (nread <= 0) {
+                /* check if this is due to EAGAIN and return the special
+                   return code if so, error out normally otherwise */
+#ifdef WIN32
+                switch (WSAGetLastError()) {
+                case WSAEWOULDBLOCK:
+                    errno = EAGAIN;
+                    break;
+
+                case WSAENOTSOCK:
+                    errno = EBADF;
+                    break;
+
+                case WSAENOTCONN:
+                case WSAECONNABORTED:
+                    errno = WSAENOTCONN;
+                    break;
+
+                case WSAEINTR:
+                    errno = EINTR;
+                    break;
+                }
+#endif /* WIN32 */
+                if ((nread < 0) && (errno == EAGAIN)) {
+                    return PACKET_EAGAIN;
+                }
+                return PACKET_FAIL;
+            }
+            debugdump(session, "libssh2_packet_read() raw",
+                      &p->buf[remainbuf], nread);
+            /* advance write pointer */
+            p->writeidx += nread;
+
+            /* update remainbuf counter */
+            remainbuf = p->writeidx - p->readidx;
+        }
+
+        /* how much data to deal with from the buffer */
+        numbytes = remainbuf;
+
+        if (!p->total_num) {
+            /* No payload package area allocated yet. To know the
+               size of this payload, we need to decrypt the first
+               blocksize data. */
+
+            if (numbytes < blocksize) {
+                /* we can't act on anything less than blocksize, but this
+                   check is only done for the initial block since once we have
+                   got the start of a block we can in fact deal with fractions
+                */
+                return PACKET_EAGAIN;
+            }
+
+            if (encrypted) {
+                rc = decrypt(session, &p->buf[p->readidx], block, blocksize);
+                if (rc != PACKET_NONE) {
+                    return rc;
+                }
+                /* save the first 5 bytes of the decrypted package, to be
+                   used in the hash calculation later down. */
+                memcpy(p->init, &p->buf[p->readidx], 5);
+            } else {
+                /* the data is plain, just copy it verbatim to
+                   the working block buffer */
+                memcpy(block, &p->buf[p->readidx], blocksize);
+            }
+
+            /* advance the read pointer */
+            p->readidx += blocksize;
+
+            /* we now have the initial blocksize bytes decrypted,
+             * and we can extract packet and padding length from it
+             */
+            p->packet_length = libssh2_ntohu32(block);
+            p->padding_length = block[4];
+
+            /* total_num is the number of bytes following the initial
+               (5 bytes) packet length and padding length fields */
+            p->total_num =
+                p->packet_length - 1 +
+                (encrypted ? session->remote.mac->mac_len : 0);
+
+            /* RFC4253 section 6.1 Maximum Packet Length says:
+             *
+             * "All implementations MUST be able to process
+             * packets with uncompressed payload length of 32768
+             * bytes or less and total packet size of 35000 bytes
+             * or less (including length, padding length, payload,
+             * padding, and MAC.)."
+             */
+            if (p->total_num > LIBSSH2_PACKET_MAXPAYLOAD) {
+                return PACKET_TOOBIG;
+            }
+
+            /* Get a packet handle put data into. We get one to
+               hold all data, including padding and MAC. */
+            p->payload = LIBSSH2_ALLOC(session, p->total_num);
+            if (!p->payload) {
+                return PACKET_ENOMEM;
+            }
+            /* init write pointer to start of payload buffer */
+            p->wptr = p->payload;
+
+            if (blocksize > 5) {
+                /* copy the data from index 5 to the end of
+                   the blocksize from the temporary buffer to
+                   the start of the decrypted buffer */
+                memcpy(p->wptr, &block[5], blocksize - 5);
+                p->wptr += blocksize - 5;       /* advance write pointer */
+            }
+
+            /* init the data_num field to the number of bytes of
+               the package read so far */
+            p->data_num = p->wptr - p->payload;
+
+            /* we already dealt with a blocksize worth of data */
+            numbytes -= blocksize;
+        }
+
+        /* how much there is left to add to the current payload
+           package */
+        remainpack = p->total_num - p->data_num;
+
+        if (numbytes > remainpack) {
+            /* if we have more data in the buffer than what is going into this
+               particular packet, we limit this round to this packet only */
+            numbytes = remainpack;
+        }
+
+        if (encrypted) {
+            /* At the end of the incoming stream, there is a MAC,
+               and we don't want to decrypt that since we need it
+               "raw". We MUST however decrypt the padding data
+               since it is used for the hash later on. */
+            int skip = session->remote.mac->mac_len;
+
+            /* if what we have plus numbytes is bigger than the
+               total minus the skip margin, we should lower the
+               amount to decrypt even more */
+            if ((p->data_num + numbytes) > (p->total_num - skip)) {
+                numdecrypt = (p->total_num - skip) - p->data_num;
+            } else {
+                int frac;
+                numdecrypt = numbytes;
+                frac = numdecrypt % blocksize;
+                if (frac) {
+                    /* not an aligned amount of blocks,
+                       align it */
+                    numdecrypt -= frac;
+                    /* and make it no unencrypted data
+                       after it */
+                    numbytes = 0;
+                }
+            }
+        } else {
+            /* unencrypted data should not be decrypted at all */
+            numdecrypt = 0;
+        }
+
+        /* if there are bytes to decrypt, do that */
+        if (numdecrypt > 0) {
+            /* now decrypt the lot */
+            rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt);
+            if (rc != PACKET_NONE) {
+                return rc;
+            }
+
+            /* advance the read pointer */
+            p->readidx += numdecrypt;
+            /* advance write pointer */
+            p->wptr += numdecrypt;
+            /* increse data_num */
+            p->data_num += numdecrypt;
+
+            /* bytes left to take care of without decryption */
+            numbytes -= numdecrypt;
+        }
+
+        /* if there are bytes to copy that aren't decrypted, simply
+           copy them as-is to the target buffer */
+        if (numbytes > 0) {
+            memcpy(p->wptr, &p->buf[p->readidx], numbytes);
+
+            /* advance the read pointer */
+            p->readidx += numbytes;
+            /* advance write pointer */
+            p->wptr += numbytes;
+            /* increse data_num */
+            p->data_num += numbytes;
+        }
+
+        /* now check how much data there's left to read to finish the
+           current packet */
+        remainpack = p->total_num - p->data_num;
+
+        if (!remainpack) {
+            /* we have a full packet */
+          libssh2_packet_read_point1:
+            rc = fullpacket(session, encrypted);
+            if (rc == PACKET_EAGAIN) {
+                session->readPack_encrypted = encrypted;
+                session->readPack_state = libssh2_NB_state_jump1;
+                return PACKET_EAGAIN;
+            }
+
+            p->total_num = 0;   /* no packet buffer available */
+
+            return rc;
+        }
+    } while (1);                /* loop */
+
+    return PACKET_FAIL;         /* we never reach this point */
+}
+
+/* }}} */
+
+#ifndef OLDSEND
+
+static libssh2pack_t
+send_existing(LIBSSH2_SESSION * session, unsigned char *data,
+              unsigned long data_len, ssize_t * ret)
+{
+    ssize_t rc;
+    ssize_t length;
+    struct transportpacket *p = &session->packet;
+
+    if (!p->outbuf) {
+        *ret = 0;
+        return PACKET_NONE;
+    }
+
+    /* send as much as possible of the existing packet */
+    if ((data != p->odata) || (data_len != p->olen)) {
+        /* When we are about to complete the sending of a packet, it is vital
+           that the caller doesn't try to send a new/different packet since
+           we don't add this one up until the previous one has been sent. To
+           make the caller really notice his/hers flaw, we return error for
+           this case */
+        return PACKET_BADUSE;
+    }
+
+    *ret = 1;                   /* set to make our parent return */
+
+    /* number of bytes left to send */
+    length = p->ototal_num - p->osent;
+
+    rc = send(session->socket_fd, &p->outbuf[p->osent], length,
+              LIBSSH2_SOCKET_SEND_FLAGS(session));
+
+    if (rc == length) {
+        /* the remainder of the package was sent */
+        LIBSSH2_FREE(session, p->outbuf);
+        p->outbuf = NULL;
+        p->ototal_num = 0;
+    } else if (rc < 0) {
+        /* nothing was sent */
+        if (errno != EAGAIN) {
+            /* send failure! */
+            return PACKET_FAIL;
+        }
+        return PACKET_EAGAIN;
+    }
+
+    debugdump(session, "libssh2_packet_write send()", &p->outbuf[p->osent],
+              length);
+    p->osent += length;         /* we sent away this much data */
+
+    return PACKET_NONE;
+}
+
+/* {{{ libssh2_packet_write
+ * Send a packet, encrypting it and adding a MAC code if necessary
+ * Returns 0 on success, non-zero on failure.
+ *
+ * Returns PACKET_EAGAIN if it would block - and if it does so, you should
+ * call this function again as soon as it is likely that more data can be
+ * sent, and this function should then be called with the same argument set
+ * (same data pointer and same data_len) until zero or failure is returned.
+ */
+int
+libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
+                     unsigned long data_len)
+{
+    int blocksize =
+        (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->
+        blocksize : 8;
+    int padding_length;
+    int packet_length;
+    int total_length;
+    int free_data = 0;
+#ifdef RANDOM_PADDING
+    int rand_max;
+    int seed = data[0];         /* FIXME: make this random */
+#endif
+    struct transportpacket *p = &session->packet;
+    int encrypted;
+    int i;
+    ssize_t ret;
+    libssh2pack_t rc;
+    unsigned char *orgdata = data;
+    unsigned long orgdata_len = data_len;
+
+    debugdump(session, "libssh2_packet_write plain", data, data_len);
+
+    /* FIRST, check if we have a pending write to complete */
+    rc = send_existing(session, data, data_len, &ret);
+    if (rc || ret) {
+        return rc;
+    }
+
+    encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0;
+
+    /* check if we should compress */
+    if (encrypted && strcmp(session->local.comp->name, "none")) {
+        if (session->local.comp->
+            comp(session, 1, &data, &data_len, LIBSSH2_PACKET_MAXCOMP,
+                 &free_data, data, data_len, &session->local.comp_abstract)) {
+            return PACKET_COMPRESS;     /* compression failure */
+        }
+    }
+
+    /* RFC4253 says: Note that the length of the concatenation of
+       'packet_length', 'padding_length', 'payload', and 'random padding'
+       MUST be a multiple of the cipher block size or 8, whichever is
+       larger. */
+
+    /* Plain math: (4 + 1 + packet_length + padding_length) % blocksize == 0 */
+
+    packet_length = data_len + 1 + 4;   /* 1 is for padding_length field
+                                           4 for the packet_length field */
+
+    /* at this point we have it all except the padding */
+
+    /* first figure out our minimum padding amount to make it an even
+       block size */
+    padding_length = blocksize - (packet_length % blocksize);
+
+    /* if the padding becomes too small we add another blocksize worth
+       of it (taken from the original libssh2 where it didn't have any
+       real explanation) */
+    if (padding_length < 4) {
+        padding_length += blocksize;
+    }
+#ifdef RANDOM_PADDING
+    /* FIXME: we can add padding here, but that also makes the packets
+       bigger etc */
+
+    /* now we can add 'blocksize' to the padding_length N number of times
+       (to "help thwart traffic analysis") but it must be less than 255 in
+       total */
+    rand_max = (255 - padding_length) / blocksize + 1;
+    padding_length += blocksize * (seed % rand_max);
+#endif
+
+    packet_length += padding_length;
+
+    /* append the MAC length to the total_length size */
+    total_length =
+        packet_length + (encrypted ? session->local.mac->mac_len : 0);
+
+    /* allocate memory to store the outgoing packet in, in case we can't
+       send the whole one and thus need to keep it after this function
+       returns. */
+    p->outbuf = LIBSSH2_ALLOC(session, total_length);
+    if (!p->outbuf) {
+        return PACKET_ENOMEM;
+    }
+
+    /* store packet_length, which is the size of the whole packet except
+       the MAC and the packet_length field itself */
+    libssh2_htonu32(p->outbuf, packet_length - 4);
+    /* store padding_length */
+    p->outbuf[4] = padding_length;
+    /* copy the payload data */
+    memcpy(p->outbuf + 5, data, data_len);
+    /* fill the padding area with random junk */
+    libssh2_random(p->outbuf + 5 + data_len, padding_length);
+    if (free_data) {
+        LIBSSH2_FREE(session, data);
+    }
+
+    if (encrypted) {
+        /* Calculate MAC hash. Put the output at index packet_length,
+           since that size includes the whole packet. The MAC is
+           calculated on the entire unencrypted packet, including all
+           fields except the MAC field itself. */
+        session->local.mac->hash(session, p->outbuf + packet_length,
+                                 session->local.seqno, p->outbuf,
+                                 packet_length, NULL, 0,
+                                 &session->local.mac_abstract);
+
+        /* Encrypt the whole packet data, one block size at a time.
+           The MAC field is not encrypted. */
+        for(i = 0; i < packet_length; i += session->local.crypt->blocksize) {
+            unsigned char *ptr = &p->outbuf[i];
+            if (session->local.crypt->
+                crypt(session, ptr, &session->local.crypt_abstract))
+                return PACKET_FAIL;     /* encryption failure */
+        }
+    }
+
+    session->local.seqno++;
+
+    ret = send(session->socket_fd, p->outbuf, total_length,
+               LIBSSH2_SOCKET_SEND_FLAGS(session));
+
+    if (ret != -1) {
+        debugdump(session, "libssh2_packet_write send()", p->outbuf, ret);
+    }
+    if (ret != total_length) {
+        if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
+            /* the whole packet could not be sent, save the rest */
+            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/Vendor/libssh2/Source/userauth.c b/Vendor/libssh2/Source/userauth.c
new file mode 100644 (file)
index 0000000..91151f6
--- /dev/null
@@ -0,0 +1,1459 @@
+/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ *   Redistributions of source code must retain the above
+ *   copyright notice, this list of conditions and the
+ *   following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials
+ *   provided with the distribution.
+ *
+ *   Neither the name of the copyright holder nor the names
+ *   of any other contributors may be used to endorse or
+ *   promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+
+#include <ctype.h>
+#include <stdio.h>
+
+/* Needed for struct iovec on some platforms */
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+
+/* {{{ proto libssh2_userauth_list
+ * List authentication methods
+ * Will yield successful login if "none" happens to be allowable for this user
+ * Not a common configuration for any SSH server though
+ * username should be NULL, or a null terminated string
+ */
+LIBSSH2_API char *
+libssh2_userauth_list(LIBSSH2_SESSION * session, const char *username,
+                      unsigned int username_len)
+{
+    static const unsigned char reply_codes[3] =
+        { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
+    /* packet_type(1) + username_len(4) + service_len(4) +
+       service(14)"ssh-connection" + method_len(4) + method(4)"none" */
+    unsigned long methods_len;
+    unsigned char *s;
+    int rc;
+
+    if (session->userauth_list_state == libssh2_NB_state_idle) {
+        /* Zero the whole thing out */
+        memset(&session->userauth_list_packet_requirev_state, 0,
+               sizeof(session->userauth_list_packet_requirev_state));
+
+        session->userauth_list_data_len = username_len + 31;
+
+        s = session->userauth_list_data =
+            LIBSSH2_ALLOC(session, session->userauth_list_data_len);
+        if (!session->userauth_list_data) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for userauth_list", 0);
+            return NULL;
+        }
+
+        *(s++) = SSH_MSG_USERAUTH_REQUEST;
+        libssh2_htonu32(s, username_len);
+        s += 4;
+        if (username) {
+            memcpy(s, username, username_len);
+            s += username_len;
+        }
+
+        libssh2_htonu32(s, 14);
+        s += 4;
+        memcpy(s, "ssh-connection", 14);
+        s += 14;
+
+        libssh2_htonu32(s, 4);
+        s += 4;
+        memcpy(s, "none", 4);
+        s += 4;
+
+        session->userauth_list_state = libssh2_NB_state_created;
+    }
+
+    if (session->userauth_list_state == libssh2_NB_state_created) {
+        rc = libssh2_packet_write(session, session->userauth_list_data,
+                                  session->userauth_list_data_len);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block requesting userauth list", 0);
+            return NULL;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send userauth-none request", 0);
+            LIBSSH2_FREE(session, session->userauth_list_data);
+            session->userauth_list_data = NULL;
+            session->userauth_list_state = libssh2_NB_state_idle;
+            return NULL;
+        }
+        LIBSSH2_FREE(session, session->userauth_list_data);
+        session->userauth_list_data = NULL;
+
+        session->userauth_list_state = libssh2_NB_state_sent;
+    }
+
+    if (session->userauth_list_state == libssh2_NB_state_sent) {
+        rc = libssh2_packet_requirev_ex(session, reply_codes,
+                                        &session->userauth_list_data,
+                                        &session->userauth_list_data_len, 0,
+                                        NULL, 0,
+                                        &session->
+                                        userauth_list_packet_requirev_state);
+        if (rc == PACKET_EAGAIN) {
+            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
+                          "Would block requesting userauth list", 0);
+            return NULL;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_NONE, "No error", 0);
+            session->userauth_list_state = libssh2_NB_state_idle;
+            return NULL;
+        }
+
+        if (session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
+            /* Wow, who'dve thought... */
+            libssh2_error(session, LIBSSH2_ERROR_NONE, "No error", 0);
+            LIBSSH2_FREE(session, session->userauth_list_data);
+            session->userauth_list_data = NULL;
+            session->state |= LIBSSH2_STATE_AUTHENTICATED;
+            session->userauth_list_state = libssh2_NB_state_idle;
+            return NULL;
+        }
+
+        methods_len = libssh2_ntohu32(session->userauth_list_data + 1);
+        memcpy(session->userauth_list_data, session->userauth_list_data + 5,
+               methods_len);
+        session->userauth_list_data[methods_len] = '\0';
+        _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Permitted auth methods: %s",
+                       session->userauth_list_data);
+    }
+
+    session->userauth_list_state = libssh2_NB_state_idle;
+    return (char *) session->userauth_list_data;
+}
+
+/* }}} */
+
+/* {{{ libssh2_userauth_authenticated
+ * 0 if not yet authenticated
+ * non-zero is already authenticated
+ */
+LIBSSH2_API int
+libssh2_userauth_authenticated(LIBSSH2_SESSION * session)
+{
+    return session->state & LIBSSH2_STATE_AUTHENTICATED;
+}
+
+/* }}} */
+
+/* {{{ libssh2_userauth_password
+ * Plain ol' login
+ */
+LIBSSH2_API int
+libssh2_userauth_password_ex(LIBSSH2_SESSION * session, const char *username,
+                             unsigned int username_len, const char *password,
+                             unsigned int password_len,
+                             LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
+{
+    unsigned char *s;
+    static const unsigned char reply_codes[4] =
+        { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
+        SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0
+    };
+    int rc;
+
+    if (session->userauth_pswd_state == libssh2_NB_state_idle) {
+        /* Zero the whole thing out */
+        memset(&session->userauth_pswd_packet_requirev_state, 0,
+               sizeof(session->userauth_pswd_packet_requirev_state));
+
+        /*
+         * 40 = acket_type(1) + username_len(4) + service_len(4) + 
+         * service(14)"ssh-connection" + method_len(4) + method(8)"password" +
+         * chgpwdbool(1) + password_len(4) */
+        session->userauth_pswd_data_len = username_len + password_len + 40;
+
+        session->userauth_pswd_data0 = ~SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
+
+        s = session->userauth_pswd_data =
+            LIBSSH2_ALLOC(session, session->userauth_pswd_data_len);
+        if (!session->userauth_pswd_data) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for userauth-password request",
+                          0);
+            return -1;
+        }
+
+        *(s++) = SSH_MSG_USERAUTH_REQUEST;
+        libssh2_htonu32(s, username_len);
+        s += 4;
+        memcpy(s, username, username_len);
+        s += username_len;
+
+        libssh2_htonu32(s, sizeof("ssh-connection") - 1);
+        s += 4;
+        memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1);
+        s += sizeof("ssh-connection") - 1;
+
+        libssh2_htonu32(s, sizeof("password") - 1);
+        s += 4;
+        memcpy(s, "password", sizeof("password") - 1);
+        s += sizeof("password") - 1;
+
+        *s = '\0';
+        s++;
+
+        libssh2_htonu32(s, password_len);
+        s += 4;
+        memcpy(s, password, password_len);
+        s += password_len;
+
+        _libssh2_debug(session, LIBSSH2_DBG_AUTH,
+                       "Attempting to login using password authentication");
+
+        session->userauth_pswd_state = libssh2_NB_state_created;
+    }
+
+    if (session->userauth_pswd_state == libssh2_NB_state_created) {
+        rc = libssh2_packet_write(session, session->userauth_pswd_data,
+                                  session->userauth_pswd_data_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send userauth-password request", 0);
+            LIBSSH2_FREE(session, session->userauth_pswd_data);
+            session->userauth_pswd_data = NULL;
+            session->userauth_pswd_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, session->userauth_pswd_data);
+        session->userauth_pswd_data = NULL;
+
+        session->userauth_pswd_state = libssh2_NB_state_sent;
+    }
+
+  password_response:
+
+    if ((session->userauth_pswd_state == libssh2_NB_state_sent)
+        || (session->userauth_pswd_state == libssh2_NB_state_sent1)
+        || (session->userauth_pswd_state == libssh2_NB_state_sent2)) {
+        if (session->userauth_pswd_state == libssh2_NB_state_sent) {
+            rc = libssh2_packet_requirev_ex(session, reply_codes,
+                                            &session->userauth_pswd_data,
+                                            &session->userauth_pswd_data_len,
+                                            0, NULL, 0,
+                                            &session->
+                                            userauth_pswd_packet_requirev_state);
+            if (rc == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            } else if (rc) {
+                session->userauth_pswd_state = libssh2_NB_state_idle;
+                return -1;
+            }
+
+            if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
+                _libssh2_debug(session, LIBSSH2_DBG_AUTH,
+                               "Password authentication successful");
+                LIBSSH2_FREE(session, session->userauth_pswd_data);
+                session->userauth_pswd_data = NULL;
+                session->state |= LIBSSH2_STATE_AUTHENTICATED;
+                session->userauth_pswd_state = libssh2_NB_state_idle;
+                return 0;
+            }
+
+            session->userauth_pswd_newpw = NULL;
+            session->userauth_pswd_newpw_len = 0;
+
+            session->userauth_pswd_state = libssh2_NB_state_sent1;
+        }
+
+        if ((session->userauth_pswd_data[0] ==
+             SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)
+            || (session->userauth_pswd_data0 ==
+                SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)) {
+            session->userauth_pswd_data0 = SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
+
+            if ((session->userauth_pswd_state == libssh2_NB_state_sent1) ||
+                (session->userauth_pswd_state == libssh2_NB_state_sent2)) {
+                if (session->userauth_pswd_state == libssh2_NB_state_sent1) {
+                    _libssh2_debug(session, LIBSSH2_DBG_AUTH,
+                                   "Password change required");
+                    LIBSSH2_FREE(session, session->userauth_pswd_data);
+                    session->userauth_pswd_data = NULL;
+                }
+                if (passwd_change_cb) {
+                    if (session->userauth_pswd_state == libssh2_NB_state_sent1) {
+                        passwd_change_cb(session,
+                                         &session->userauth_pswd_newpw,
+                                         &session->userauth_pswd_newpw_len,
+                                         &session->abstract);
+                        if (!session->userauth_pswd_newpw) {
+                            libssh2_error(session,
+                                          LIBSSH2_ERROR_PASSWORD_EXPIRED,
+                                          "Password expired, and callback failed",
+                                          0);
+                            return -1;
+                        }
+
+                        /* basic data_len + newpw_len(4) */
+                        session->userauth_pswd_data_len =
+                            username_len + password_len + 44 +
+                            session->userauth_pswd_newpw_len;
+
+                        s = session->userauth_pswd_data =
+                            LIBSSH2_ALLOC(session,
+                                          session->userauth_pswd_data_len);
+                        if (!session->userauth_pswd_data) {
+                            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                                          "Unable to allocate memory for userauth-password-change request",
+                                          0);
+                            LIBSSH2_FREE(session,
+                                         session->userauth_pswd_newpw);
+                            session->userauth_pswd_newpw = NULL;
+                            return -1;
+                        }
+
+                        *(s++) = SSH_MSG_USERAUTH_REQUEST;
+                        libssh2_htonu32(s, username_len);
+                        s += 4;
+                        memcpy(s, username, username_len);
+                        s += username_len;
+
+                        libssh2_htonu32(s, sizeof("ssh-connection") - 1);
+                        s += 4;
+                        memcpy(s, "ssh-connection",
+                               sizeof("ssh-connection") - 1);
+                        s += sizeof("ssh-connection") - 1;
+
+                        libssh2_htonu32(s, sizeof("password") - 1);
+                        s += 4;
+                        memcpy(s, "password", sizeof("password") - 1);
+                        s += sizeof("password") - 1;
+
+                        *s = 0x01;
+                        s++;
+
+                        libssh2_htonu32(s, password_len);
+                        s += 4;
+                        memcpy(s, password, password_len);
+                        s += password_len;
+
+                        libssh2_htonu32(s, session->userauth_pswd_newpw_len);
+                        s += 4;
+                        memcpy(s, session->userauth_pswd_newpw,
+                               session->userauth_pswd_newpw_len);
+                        s += session->userauth_pswd_newpw_len;
+
+                        session->userauth_pswd_state = libssh2_NB_state_sent2;
+                    }
+
+                    if (session->userauth_pswd_state == libssh2_NB_state_sent2) {
+                        rc = libssh2_packet_write(session,
+                                                  session->userauth_pswd_data,
+                                                  session->
+                                                  userauth_pswd_data_len);
+                        if (rc == PACKET_EAGAIN) {
+                            return PACKET_EAGAIN;
+                        } else if (rc) {
+                            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                                          "Unable to send userauth-password-change request",
+                                          0);
+                            LIBSSH2_FREE(session, session->userauth_pswd_data);
+                            session->userauth_pswd_data = NULL;
+                            LIBSSH2_FREE(session,
+                                         session->userauth_pswd_newpw);
+                            session->userauth_pswd_newpw = NULL;
+                            return -1;
+                        }
+                        LIBSSH2_FREE(session, session->userauth_pswd_data);
+                        session->userauth_pswd_data = NULL;
+                        LIBSSH2_FREE(session, session->userauth_pswd_newpw);
+                        session->userauth_pswd_newpw = NULL;
+
+                        /*
+                         * Ugliest use of goto ever.  Blame it on the
+                         * askN => requirev migration.
+                         */
+                        session->userauth_pswd_state = libssh2_NB_state_sent;
+                        goto password_response;
+                    }
+                }
+            } else {
+                libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED,
+                              "Password Expired, and no callback specified",
+                              0);
+                session->userauth_pswd_state = libssh2_NB_state_idle;
+                return -1;
+            }
+        }
+    }
+
+    /* FAILURE */
+    LIBSSH2_FREE(session, session->userauth_pswd_data);
+    session->userauth_pswd_data = NULL;
+    session->userauth_pswd_state = libssh2_NB_state_idle;
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_file_read_publickey
+ * Read a public key from an id_???.pub style file
+ */
+static int
+libssh2_file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
+                            unsigned long *method_len,
+                            unsigned char **pubkeydata,
+                            unsigned long *pubkeydata_len,
+                            const char *pubkeyfile)
+{
+    FILE *fd;
+    char c;
+    unsigned char *pubkey = NULL, *sp1, *sp2, *tmp;
+    size_t pubkey_len = 0;
+    unsigned int tmp_len;
+
+    _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading public key file: %s",
+                   pubkeyfile);
+    /* Read Public Key */
+    fd = fopen(pubkeyfile, "r");
+    if (!fd) {
+        libssh2_error(session, LIBSSH2_ERROR_FILE,
+                      "Unable to open public key file", 0);
+        return -1;
+    }
+    while (!feof(fd) && (c = fgetc(fd)) != '\r' && c != '\n')
+        pubkey_len++;
+    if (feof(fd)) {
+        /* the last character was EOF */
+        pubkey_len--;
+    }
+    rewind(fd);
+
+    if (pubkey_len <= 1) {
+        libssh2_error(session, LIBSSH2_ERROR_FILE,
+                      "Invalid data in public key file", 0);
+        fclose(fd);
+        return -1;
+    }
+
+    pubkey = LIBSSH2_ALLOC(session, pubkey_len);
+    if (!pubkey) {
+        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                      "Unable to allocate memory for public key data", 0);
+        fclose(fd);
+        return -1;
+    }
+    if (fread(pubkey, 1, pubkey_len, fd) != pubkey_len) {
+        libssh2_error(session, LIBSSH2_ERROR_FILE,
+                      "Unable to read public key from file", 0);
+        LIBSSH2_FREE(session, pubkey);
+        fclose(fd);
+        return -1;
+    }
+    fclose(fd);
+    /*
+     * Remove trailing whitespace
+     */
+    while (pubkey_len && isspace(pubkey[pubkey_len - 1]))
+        pubkey_len--;
+
+    if (!pubkey_len) {
+        libssh2_error(session, LIBSSH2_ERROR_FILE, "Missing public key data",
+                      0);
+        LIBSSH2_FREE(session, pubkey);
+        return -1;
+    }
+
+    if ((sp1 = memchr(pubkey, ' ', pubkey_len)) == NULL) {
+        libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid public key data",
+                      0);
+        LIBSSH2_FREE(session, pubkey);
+        return -1;
+    }
+    /* Wasting some bytes here (okay, more than some),
+     * but since it's likely to be freed soon anyway, 
+     * we'll just avoid the extra free/alloc and call it a wash */
+    *method = pubkey;
+    *method_len = sp1 - pubkey;
+
+    sp1++;
+
+    if ((sp2 = memchr(sp1, ' ', pubkey_len - *method_len)) == NULL) {
+        /* Assume that the id string is missing, but that it's okay */
+        sp2 = pubkey + pubkey_len;
+    }
+
+    if (libssh2_base64_decode
+        (session, (char **) &tmp, &tmp_len, (char *) sp1, sp2 - sp1)) {
+        libssh2_error(session, LIBSSH2_ERROR_FILE,
+                      "Invalid key data, not base64 encoded", 0);
+        LIBSSH2_FREE(session, pubkey);
+        return -1;
+    }
+    *pubkeydata = tmp;
+    *pubkeydata_len = tmp_len;
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_file_read_privatekey
+ * Read a PEM encoded private key from an id_??? style file
+ */
+static int
+libssh2_file_read_privatekey(LIBSSH2_SESSION * session,
+                             const LIBSSH2_HOSTKEY_METHOD ** hostkey_method,
+                             void **hostkey_abstract,
+                             const unsigned char *method, int method_len,
+                             const char *privkeyfile, const char *passphrase)
+{
+    const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail =
+        libssh2_hostkey_methods();
+
+    _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading private key file: %s",
+                   privkeyfile);
+    *hostkey_method = NULL;
+    *hostkey_abstract = NULL;
+    while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) {
+        if ((*hostkey_methods_avail)->initPEM
+            && strncmp((*hostkey_methods_avail)->name, (const char *) method,
+                       method_len) == 0) {
+            *hostkey_method = *hostkey_methods_avail;
+            break;
+        }
+        hostkey_methods_avail++;
+    }
+    if (!*hostkey_method) {
+        libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
+                      "No handler for specified private key", 0);
+        return -1;
+    }
+
+    if ((*hostkey_method)->
+        initPEM(session, privkeyfile, (unsigned char *) passphrase,
+                hostkey_abstract)) {
+        libssh2_error(session, LIBSSH2_ERROR_FILE,
+                      "Unable to initialize private key from file", 0);
+        return -1;
+    }
+
+    return 0;
+}
+
+/* }}} */
+
+/* {{{ libssh2_userauth_hostbased_fromfile_ex
+ * Authenticate using a keypair found in the named files
+ */
+LIBSSH2_API int
+libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION * session,
+                                       const char *username,
+                                       unsigned int username_len,
+                                       const char *publickey,
+                                       const char *privatekey,
+                                       const char *passphrase,
+                                       const char *hostname,
+                                       unsigned int hostname_len,
+                                       const char *local_username,
+                                       unsigned int local_username_len)
+{
+    const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
+    void *abstract;
+    unsigned char buf[5];
+    struct iovec datavec[4];
+    unsigned char *pubkeydata, *sig;
+    static const unsigned char reply_codes[3] =
+        { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
+    unsigned long pubkeydata_len, sig_len, data_len;
+    int rc;
+
+    if (session->userauth_host_state == libssh2_NB_state_idle) {
+        /* Zero the whole thing out */
+        memset(&session->userauth_host_packet_requirev_state, 0,
+               sizeof(session->userauth_host_packet_requirev_state));
+
+        if (libssh2_file_read_publickey
+            (session, &session->userauth_host_method,
+             &session->userauth_host_method_len, &pubkeydata, &pubkeydata_len,
+             publickey)) {
+            return -1;
+        }
+
+        /*
+         * 48 = packet_type(1) + username_len(4) + servicename_len(4) + 
+         * service_name(14)"ssh-connection" + authmethod_len(4) +
+         * authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) + 
+         * local_username_len(4)
+         */
+        session->userauth_host_packet_len =
+            username_len + session->userauth_host_method_len + hostname_len +
+            local_username_len + pubkeydata_len + 48;
+
+        /*
+         * Preallocate space for an overall length,  method name again,
+         * and the signature, which won't be any larger than the size of 
+         * the publickeydata itself
+         */
+        session->userauth_host_s = session->userauth_host_packet =
+            LIBSSH2_ALLOC(session,
+                          session->userauth_host_packet_len + 4 + (4 +
+                                                                   session->
+                                                                   userauth_host_method_len)
+                          + (4 + pubkeydata_len));
+        if (!session->userauth_host_packet) {
+            LIBSSH2_FREE(session, session->userauth_host_method);
+            session->userauth_host_method = NULL;
+            return -1;
+        }
+
+        *(session->userauth_host_s++) = SSH_MSG_USERAUTH_REQUEST;
+        libssh2_htonu32(session->userauth_host_s, username_len);
+        session->userauth_host_s += 4;
+        memcpy(session->userauth_host_s, username, username_len);
+        session->userauth_host_s += username_len;
+
+        libssh2_htonu32(session->userauth_host_s, 14);
+        session->userauth_host_s += 4;
+        memcpy(session->userauth_host_s, "ssh-connection", 14);
+        session->userauth_host_s += 14;
+
+        libssh2_htonu32(session->userauth_host_s, 9);
+        session->userauth_host_s += 4;
+        memcpy(session->userauth_host_s, "hostbased", 9);
+        session->userauth_host_s += 9;
+
+        libssh2_htonu32(session->userauth_host_s,
+                        session->userauth_host_method_len);
+        session->userauth_host_s += 4;
+        memcpy(session->userauth_host_s, session->userauth_host_method,
+               session->userauth_host_method_len);
+        session->userauth_host_s += session->userauth_host_method_len;
+
+        libssh2_htonu32(session->userauth_host_s, pubkeydata_len);
+        session->userauth_host_s += 4;
+        memcpy(session->userauth_host_s, pubkeydata, pubkeydata_len);
+        session->userauth_host_s += pubkeydata_len;
+
+        libssh2_htonu32(session->userauth_host_s, hostname_len);
+        session->userauth_host_s += 4;
+        memcpy(session->userauth_host_s, hostname, hostname_len);
+        session->userauth_host_s += hostname_len;
+
+        libssh2_htonu32(session->userauth_host_s, local_username_len);
+        session->userauth_host_s += 4;
+        memcpy(session->userauth_host_s, local_username, local_username_len);
+        session->userauth_host_s += local_username_len;
+
+        if (libssh2_file_read_privatekey
+            (session, &privkeyobj, &abstract, session->userauth_host_method,
+             session->userauth_host_method_len, privatekey, passphrase)) {
+            LIBSSH2_FREE(session, session->userauth_host_method);
+            session->userauth_host_method = NULL;
+            LIBSSH2_FREE(session, session->userauth_host_packet);
+            session->userauth_host_packet = NULL;
+            return -1;
+        }
+
+        libssh2_htonu32(buf, session->session_id_len);
+        datavec[0].iov_base = buf;
+        datavec[0].iov_len = 4;
+        datavec[1].iov_base = session->session_id;
+        datavec[1].iov_len = session->session_id_len;
+        datavec[2].iov_base = session->userauth_host_packet;
+        datavec[2].iov_len = session->userauth_host_packet_len;
+
+        if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
+            LIBSSH2_FREE(session, session->userauth_host_method);
+            session->userauth_host_method = NULL;
+            LIBSSH2_FREE(session, session->userauth_host_packet);
+            session->userauth_host_packet = NULL;
+            if (privkeyobj->dtor) {
+                privkeyobj->dtor(session, &abstract);
+            }
+            return -1;
+        }
+
+        if (privkeyobj->dtor) {
+            privkeyobj->dtor(session, &abstract);
+        }
+
+        if (sig_len > pubkeydata_len) {
+            unsigned char *newpacket;
+            /* Should *NEVER* happen, but...well.. better safe than sorry */
+            newpacket = LIBSSH2_REALLOC(session, session->userauth_host_packet, session->userauth_host_packet_len + 4 + (4 + session->userauth_host_method_len) + (4 + sig_len));       /* PK sigblob */
+            if (!newpacket) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                              "Failed allocating additional space for userauth-hostbased packet",
+                              0);
+                LIBSSH2_FREE(session, sig);
+                LIBSSH2_FREE(session, session->userauth_host_packet);
+                session->userauth_host_packet = NULL;
+                LIBSSH2_FREE(session, session->userauth_host_method);
+                session->userauth_host_method = NULL;
+                return -1;
+            }
+            session->userauth_host_packet = newpacket;
+        }
+
+        session->userauth_host_s =
+            session->userauth_host_packet + session->userauth_host_packet_len;
+
+        libssh2_htonu32(session->userauth_host_s,
+                        4 + session->userauth_host_method_len + 4 + sig_len);
+        session->userauth_host_s += 4;
+
+        libssh2_htonu32(session->userauth_host_s,
+                        session->userauth_host_method_len);
+        session->userauth_host_s += 4;
+        memcpy(session->userauth_host_s, session->userauth_host_method,
+               session->userauth_host_method_len);
+        session->userauth_host_s += session->userauth_host_method_len;
+        LIBSSH2_FREE(session, session->userauth_host_method);
+        session->userauth_host_method = NULL;
+
+        libssh2_htonu32(session->userauth_host_s, sig_len);
+        session->userauth_host_s += 4;
+        memcpy(session->userauth_host_s, sig, sig_len);
+        session->userauth_host_s += sig_len;
+        LIBSSH2_FREE(session, sig);
+
+        _libssh2_debug(session, LIBSSH2_DBG_AUTH,
+                       "Attempting hostbased authentication");
+
+        session->userauth_host_state = libssh2_NB_state_created;
+    }
+
+    if (session->userauth_host_state == libssh2_NB_state_created) {
+        rc = libssh2_packet_write(session, session->userauth_host_packet,
+                                  session->userauth_host_s -
+                                  session->userauth_host_packet);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send userauth-hostbased request", 0);
+            LIBSSH2_FREE(session, session->userauth_host_packet);
+            session->userauth_host_packet = NULL;
+            session->userauth_host_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, session->userauth_host_packet);
+        session->userauth_host_packet = NULL;
+
+        session->userauth_host_state = libssh2_NB_state_sent;
+    }
+
+    if (session->userauth_host_state == libssh2_NB_state_sent) {
+        rc = libssh2_packet_requirev_ex(session, reply_codes,
+                                        &session->userauth_host_data,
+                                        &data_len, 0, NULL, 0,
+                                        &session->
+                                        userauth_host_packet_requirev_state);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            session->userauth_host_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        if (session->userauth_host_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
+            _libssh2_debug(session, LIBSSH2_DBG_AUTH,
+                           "Hostbased authentication successful");
+            /* We are us and we've proved it. */
+            LIBSSH2_FREE(session, session->userauth_host_data);
+            session->userauth_host_data = NULL;
+            session->state |= LIBSSH2_STATE_AUTHENTICATED;
+            session->userauth_host_state = libssh2_NB_state_idle;
+            return 0;
+        }
+    }
+
+    /* This public key is not allowed for this user on this server */
+    LIBSSH2_FREE(session, session->userauth_host_data);
+    session->userauth_host_data = NULL;
+    libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
+                  "Invalid signature for supplied public key, or bad username/public key combination",
+                  0);
+    session->userauth_host_state = libssh2_NB_state_idle;
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_userauth_publickey_fromfile_ex
+ * Authenticate using a keypair found in the named files
+ */
+LIBSSH2_API int
+libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION * session,
+                                       const char *username,
+                                       unsigned int username_len,
+                                       const char *publickey,
+                                       const char *privatekey,
+                                       const char *passphrase)
+{
+    const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
+    void *abstract;
+    unsigned char buf[5];
+    struct iovec datavec[4];
+    unsigned char *pubkeydata, *sig;
+    unsigned char reply_codes[4] =
+        { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
+        SSH_MSG_USERAUTH_PK_OK, 0
+    };
+    unsigned long pubkeydata_len, sig_len;
+    int rc;
+
+    if (session->userauth_pblc_state == libssh2_NB_state_idle) {
+        /* Zero the whole thing out */
+        memset(&session->userauth_pblc_packet_requirev_state, 0,
+               sizeof(session->userauth_pblc_packet_requirev_state));
+
+        if (libssh2_file_read_publickey
+            (session, &session->userauth_pblc_method,
+             &session->userauth_pblc_method_len, &pubkeydata, &pubkeydata_len,
+             publickey)) {
+            return -1;
+        }
+
+        /*
+         * 45 = packet_type(1) + username_len(4) + servicename_len(4) + 
+         * service_name(14)"ssh-connection" + authmethod_len(4) + 
+         * authmethod(9)"publickey" + sig_included(1)'\0' + algmethod_len(4) +
+         * publickey_len(4)
+         */
+        session->userauth_pblc_packet_len =
+            username_len + session->userauth_pblc_method_len + pubkeydata_len +
+            45;
+
+        /*
+         * Preallocate space for an overall length,  method name again, and
+         * the signature, which won't be any larger than the size of the 
+         * publickeydata itself
+         */
+        session->userauth_pblc_s = session->userauth_pblc_packet =
+            LIBSSH2_ALLOC(session,
+                          session->userauth_pblc_packet_len + 4 + (4 +
+                                                                   session->
+                                                                   userauth_pblc_method_len)
+                          + (4 + pubkeydata_len));
+        if (!session->userauth_pblc_packet) {
+            LIBSSH2_FREE(session, session->userauth_pblc_method);
+            session->userauth_pblc_method = NULL;
+            LIBSSH2_FREE(session, pubkeydata);
+            return -1;
+        }
+
+        *(session->userauth_pblc_s++) = SSH_MSG_USERAUTH_REQUEST;
+        libssh2_htonu32(session->userauth_pblc_s, username_len);
+        session->userauth_pblc_s += 4;
+        memcpy(session->userauth_pblc_s, username, username_len);
+        session->userauth_pblc_s += username_len;
+
+        libssh2_htonu32(session->userauth_pblc_s, 14);
+        session->userauth_pblc_s += 4;
+        memcpy(session->userauth_pblc_s, "ssh-connection", 14);
+        session->userauth_pblc_s += 14;
+
+        libssh2_htonu32(session->userauth_pblc_s, 9);
+        session->userauth_pblc_s += 4;
+        memcpy(session->userauth_pblc_s, "publickey", 9);
+        session->userauth_pblc_s += 9;
+
+        session->userauth_pblc_b = session->userauth_pblc_s;
+        /* Not sending signature with *this* packet */
+        *(session->userauth_pblc_s++) = 0;
+
+        libssh2_htonu32(session->userauth_pblc_s,
+                        session->userauth_pblc_method_len);
+        session->userauth_pblc_s += 4;
+        memcpy(session->userauth_pblc_s, session->userauth_pblc_method,
+               session->userauth_pblc_method_len);
+        session->userauth_pblc_s += session->userauth_pblc_method_len;
+
+        libssh2_htonu32(session->userauth_pblc_s, pubkeydata_len);
+        session->userauth_pblc_s += 4;
+        memcpy(session->userauth_pblc_s, pubkeydata, pubkeydata_len);
+        session->userauth_pblc_s += pubkeydata_len;
+        LIBSSH2_FREE(session, pubkeydata);
+
+        _libssh2_debug(session, LIBSSH2_DBG_AUTH,
+                       "Attempting publickey authentication");
+
+        session->userauth_pblc_state = libssh2_NB_state_created;
+    }
+
+    if (session->userauth_pblc_state == libssh2_NB_state_created) {
+        rc = libssh2_packet_write(session, session->userauth_pblc_packet,
+                                  session->userauth_pblc_packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send userauth-publickey request", 0);
+            LIBSSH2_FREE(session, session->userauth_pblc_packet);
+            session->userauth_pblc_packet = NULL;
+            LIBSSH2_FREE(session, session->userauth_pblc_method);
+            session->userauth_pblc_method = NULL;
+            session->userauth_pblc_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        session->userauth_pblc_state = libssh2_NB_state_sent;
+    }
+
+    if (session->userauth_pblc_state == libssh2_NB_state_sent) {
+        rc = libssh2_packet_requirev_ex(session, reply_codes,
+                                        &session->userauth_pblc_data,
+                                        &session->userauth_pblc_data_len, 0,
+                                        NULL, 0,
+                                        &session->
+                                        userauth_pblc_packet_requirev_state);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            LIBSSH2_FREE(session, session->userauth_pblc_packet);
+            session->userauth_pblc_packet = NULL;
+            LIBSSH2_FREE(session, session->userauth_pblc_method);
+            session->userauth_pblc_method = NULL;
+            session->userauth_pblc_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
+            _libssh2_debug(session, LIBSSH2_DBG_AUTH,
+                           "Pubkey authentication prematurely successful");
+            /*
+             * God help any SSH server that allows an UNVERIFIED
+             * public key to validate the user
+             */
+            LIBSSH2_FREE(session, session->userauth_pblc_data);
+            session->userauth_pblc_data = NULL;
+            LIBSSH2_FREE(session, session->userauth_pblc_packet);
+            session->userauth_pblc_packet = NULL;
+            LIBSSH2_FREE(session, session->userauth_pblc_method);
+            session->userauth_pblc_method = NULL;
+            session->state |= LIBSSH2_STATE_AUTHENTICATED;
+            session->userauth_pblc_state = libssh2_NB_state_idle;
+            return 0;
+        }
+
+        if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_FAILURE) {
+            /* This public key is not allowed for this user on this server */
+            LIBSSH2_FREE(session, session->userauth_pblc_data);
+            session->userauth_pblc_data = NULL;
+            LIBSSH2_FREE(session, session->userauth_pblc_packet);
+            session->userauth_pblc_packet = NULL;
+            LIBSSH2_FREE(session, session->userauth_pblc_method);
+            session->userauth_pblc_method = NULL;
+            libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED,
+                          "Username/PublicKey combination invalid", 0);
+            session->userauth_pblc_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        /* Semi-Success! */
+        LIBSSH2_FREE(session, session->userauth_pblc_data);
+        session->userauth_pblc_data = NULL;
+
+        if (libssh2_file_read_privatekey
+            (session, &privkeyobj, &abstract, session->userauth_pblc_method,
+             session->userauth_pblc_method_len, privatekey, passphrase)) {
+            LIBSSH2_FREE(session, session->userauth_pblc_method);
+            session->userauth_pblc_method = NULL;
+            LIBSSH2_FREE(session, session->userauth_pblc_packet);
+            session->userauth_pblc_packet = NULL;
+            session->userauth_pblc_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        *session->userauth_pblc_b = 0x01;
+
+        libssh2_htonu32(buf, session->session_id_len);
+        datavec[0].iov_base = buf;
+        datavec[0].iov_len = 4;
+        datavec[1].iov_base = session->session_id;
+        datavec[1].iov_len = session->session_id_len;
+        datavec[2].iov_base = session->userauth_pblc_packet;
+        datavec[2].iov_len = session->userauth_pblc_packet_len;
+
+        if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
+            LIBSSH2_FREE(session, session->userauth_pblc_method);
+            session->userauth_pblc_method = NULL;
+            LIBSSH2_FREE(session, session->userauth_pblc_packet);
+            session->userauth_pblc_packet = NULL;
+            if (privkeyobj->dtor) {
+                privkeyobj->dtor(session, &abstract);
+            }
+            session->userauth_pblc_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        if (privkeyobj->dtor) {
+            privkeyobj->dtor(session, &abstract);
+        }
+
+        if (sig_len > pubkeydata_len) {
+            unsigned char *newpacket;
+            /* Should *NEVER* happen, but...well.. better safe than sorry */
+            newpacket = LIBSSH2_REALLOC(session, session->userauth_pblc_packet, session->userauth_pblc_packet_len + 4 + (4 + session->userauth_pblc_method_len) + (4 + sig_len));       /* PK sigblob */
+            if (!newpacket) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                              "Failed allocating additional space for userauth-publickey packet",
+                              0);
+                LIBSSH2_FREE(session, sig);
+                LIBSSH2_FREE(session, session->userauth_pblc_packet);
+                session->userauth_pblc_packet = NULL;
+                LIBSSH2_FREE(session, session->userauth_pblc_method);
+                session->userauth_pblc_method = NULL;
+                session->userauth_pblc_state = libssh2_NB_state_idle;
+                return -1;
+            }
+            session->userauth_pblc_packet = newpacket;
+        }
+
+        session->userauth_pblc_s =
+            session->userauth_pblc_packet + session->userauth_pblc_packet_len;
+
+        libssh2_htonu32(session->userauth_pblc_s,
+                        4 + session->userauth_pblc_method_len + 4 + sig_len);
+        session->userauth_pblc_s += 4;
+
+        libssh2_htonu32(session->userauth_pblc_s,
+                        session->userauth_pblc_method_len);
+        session->userauth_pblc_s += 4;
+        memcpy(session->userauth_pblc_s, session->userauth_pblc_method,
+               session->userauth_pblc_method_len);
+        session->userauth_pblc_s += session->userauth_pblc_method_len;
+        LIBSSH2_FREE(session, session->userauth_pblc_method);
+        session->userauth_pblc_method = NULL;
+
+        libssh2_htonu32(session->userauth_pblc_s, sig_len);
+        session->userauth_pblc_s += 4;
+        memcpy(session->userauth_pblc_s, sig, sig_len);
+        session->userauth_pblc_s += sig_len;
+        LIBSSH2_FREE(session, sig);
+
+        _libssh2_debug(session, LIBSSH2_DBG_AUTH,
+                       "Attempting publickey authentication -- phase 2");
+
+        session->userauth_pblc_state = libssh2_NB_state_sent1;
+    }
+
+    if (session->userauth_pblc_state == libssh2_NB_state_sent1) {
+        rc = libssh2_packet_write(session, session->userauth_pblc_packet,
+                                  session->userauth_pblc_s -
+                                  session->userauth_pblc_packet);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send userauth-publickey request", 0);
+            LIBSSH2_FREE(session, session->userauth_pblc_packet);
+            session->userauth_pblc_packet = NULL;
+            session->userauth_pblc_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, session->userauth_pblc_packet);
+        session->userauth_pblc_packet = NULL;
+
+        session->userauth_pblc_state = libssh2_NB_state_sent2;
+    }
+
+    /* PK_OK is no longer valid */
+    reply_codes[2] = 0;
+
+    rc = libssh2_packet_requirev_ex(session, reply_codes,
+                                    &session->userauth_pblc_data,
+                                    &session->userauth_pblc_data_len, 0, NULL,
+                                    0,
+                                    &session->
+                                    userauth_pblc_packet_requirev_state);
+    if (rc == PACKET_EAGAIN) {
+        return PACKET_EAGAIN;
+    } else if (rc) {
+        session->userauth_pblc_state = libssh2_NB_state_idle;
+        return -1;
+    }
+
+    if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
+        _libssh2_debug(session, LIBSSH2_DBG_AUTH,
+                       "Publickey authentication successful");
+        /* We are us and we've proved it. */
+        LIBSSH2_FREE(session, session->userauth_pblc_data);
+        session->userauth_pblc_data = NULL;
+        session->state |= LIBSSH2_STATE_AUTHENTICATED;
+        session->userauth_pblc_state = libssh2_NB_state_idle;
+        return 0;
+    }
+
+    /* This public key is not allowed for this user on this server */
+    LIBSSH2_FREE(session, session->userauth_pblc_data);
+    session->userauth_pblc_data = NULL;
+    libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
+                  "Invalid signature for supplied public key, or bad username/public key combination",
+                  0);
+    session->userauth_pblc_state = libssh2_NB_state_idle;
+    return -1;
+}
+
+/* }}} */
+
+/* {{{ libssh2_userauth_keyboard_interactive
+ * Authenticate using a challenge-response authentication
+ */
+LIBSSH2_API int
+libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
+                                         const char *username,
+                                         unsigned int username_len,
+                                         LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
+{
+    unsigned char *s;
+    int rc;
+
+    static const unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS,
+        SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0
+    };
+    unsigned int language_tag_len;
+    unsigned int i;
+
+    if (session->userauth_kybd_state == libssh2_NB_state_idle) {
+        session->userauth_kybd_auth_name = NULL;
+        session->userauth_kybd_auth_instruction = NULL;
+        session->userauth_kybd_num_prompts = 0;
+        session->userauth_kybd_auth_failure = 1;
+        session->userauth_kybd_prompts = NULL;
+        session->userauth_kybd_responses = NULL;
+
+        /* Zero the whole thing out */
+        memset(&session->userauth_kybd_packet_requirev_state, 0,
+               sizeof(session->userauth_kybd_packet_requirev_state));
+
+        session->userauth_kybd_packet_len = 1   /* byte      SSH_MSG_USERAUTH_REQUEST */
+            + 4 + username_len  /* string    user name (ISO-10646 UTF-8, as defined in [RFC-3629]) */
+            + 4 + 14            /* string    service name (US-ASCII) */
+            + 4 + 20            /* string    "keyboard-interactive" (US-ASCII) */
+            + 4 + 0             /* string    language tag (as defined in [RFC-3066]) */
+            + 4 + 0             /* string    submethods (ISO-10646 UTF-8) */
+            ;
+
+        session->userauth_kybd_data = s =
+            LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
+        if (!s) {
+            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                          "Unable to allocate memory for keyboard-interactive authentication",
+                          0);
+            return -1;
+        }
+
+        *s++ = SSH_MSG_USERAUTH_REQUEST;
+
+        /* user name */
+        libssh2_htonu32(s, username_len);
+        s += 4;
+        memcpy(s, username, username_len);
+        s += username_len;
+
+        /* service name */
+        libssh2_htonu32(s, sizeof("ssh-connection") - 1);
+        s += 4;
+        memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1);
+        s += sizeof("ssh-connection") - 1;
+
+        /* "keyboard-interactive" */
+        libssh2_htonu32(s, sizeof("keyboard-interactive") - 1);
+        s += 4;
+        memcpy(s, "keyboard-interactive", sizeof("keyboard-interactive") - 1);
+        s += sizeof("keyboard-interactive") - 1;
+
+        /* language tag */
+        libssh2_htonu32(s, 0);
+        s += 4;
+
+        /* submethods */
+        libssh2_htonu32(s, 0);
+        s += 4;
+
+        _libssh2_debug(session, LIBSSH2_DBG_AUTH,
+                       "Attempting keyboard-interactive authentication");
+
+        session->userauth_kybd_state = libssh2_NB_state_created;
+    }
+
+    if (session->userauth_kybd_state == libssh2_NB_state_created) {
+        rc = libssh2_packet_write(session, session->userauth_kybd_data,
+                                  session->userauth_kybd_packet_len);
+        if (rc == PACKET_EAGAIN) {
+            return PACKET_EAGAIN;
+        } else if (rc) {
+            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                          "Unable to send keyboard-interactive request", 0);
+            LIBSSH2_FREE(session, session->userauth_kybd_data);
+            session->userauth_kybd_data = NULL;
+            session->userauth_kybd_state = libssh2_NB_state_idle;
+            return -1;
+        }
+        LIBSSH2_FREE(session, session->userauth_kybd_data);
+        session->userauth_kybd_data = NULL;
+
+        session->userauth_kybd_state = libssh2_NB_state_sent;
+    }
+
+    for(;;) {
+        if (session->userauth_kybd_state == libssh2_NB_state_sent) {
+            rc = libssh2_packet_requirev_ex(session, reply_codes,
+                                            &session->userauth_kybd_data,
+                                            &session->userauth_kybd_data_len,
+                                            0, NULL, 0,
+                                            &session->
+                                            userauth_kybd_packet_requirev_state);
+            if (rc == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            } else if (rc) {
+                session->userauth_kybd_state = libssh2_NB_state_idle;
+                return -1;
+            }
+
+            if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
+                _libssh2_debug(session, LIBSSH2_DBG_AUTH,
+                               "Keyboard-interactive authentication successful");
+                LIBSSH2_FREE(session, session->userauth_kybd_data);
+                session->userauth_kybd_data = NULL;
+                session->state |= LIBSSH2_STATE_AUTHENTICATED;
+                session->userauth_kybd_state = libssh2_NB_state_idle;
+                return 0;
+            }
+
+            if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) {
+                LIBSSH2_FREE(session, session->userauth_kybd_data);
+                session->userauth_kybd_data = NULL;
+                session->userauth_kybd_state = libssh2_NB_state_idle;
+                return -1;
+            }
+
+            /* server requested PAM-like conversation */
+
+            s = session->userauth_kybd_data + 1;
+
+            /* string    name (ISO-10646 UTF-8) */
+            session->userauth_kybd_auth_name_len = libssh2_ntohu32(s);
+            s += 4;
+            session->userauth_kybd_auth_name =
+                LIBSSH2_ALLOC(session, session->userauth_kybd_auth_name_len);
+            if (!session->userauth_kybd_auth_name) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                              "Unable to allocate memory for keyboard-interactive 'name' request field",
+                              0);
+                goto cleanup;
+            }
+            memcpy(session->userauth_kybd_auth_name, s,
+                   session->userauth_kybd_auth_name_len);
+            s += session->userauth_kybd_auth_name_len;
+
+            /* string    instruction (ISO-10646 UTF-8) */
+            session->userauth_kybd_auth_instruction_len = libssh2_ntohu32(s);
+            s += 4;
+            session->userauth_kybd_auth_instruction =
+                LIBSSH2_ALLOC(session,
+                              session->userauth_kybd_auth_instruction_len);
+            if (!session->userauth_kybd_auth_instruction) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                              "Unable to allocate memory for keyboard-interactive 'instruction' request field",
+                              0);
+                goto cleanup;
+            }
+            memcpy(session->userauth_kybd_auth_instruction, s,
+                   session->userauth_kybd_auth_instruction_len);
+            s += session->userauth_kybd_auth_instruction_len;
+
+            /* string    language tag (as defined in [RFC-3066]) */
+            language_tag_len = libssh2_ntohu32(s);
+            s += 4;
+            /* ignoring this field as deprecated */
+            s += language_tag_len;
+
+            /* int       num-prompts */
+            session->userauth_kybd_num_prompts = libssh2_ntohu32(s);
+            s += 4;
+
+            session->userauth_kybd_prompts =
+                LIBSSH2_ALLOC(session,
+                              sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
+                              session->userauth_kybd_num_prompts);
+            if (!session->userauth_kybd_prompts) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                              "Unable to allocate memory for keyboard-interactive prompts array",
+                              0);
+                goto cleanup;
+            }
+            memset(session->userauth_kybd_prompts, 0,
+                   sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
+                   session->userauth_kybd_num_prompts);
+
+            session->userauth_kybd_responses =
+                LIBSSH2_ALLOC(session,
+                              sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
+                              session->userauth_kybd_num_prompts);
+            if (!session->userauth_kybd_responses) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                              "Unable to allocate memory for keyboard-interactive responses array",
+                              0);
+                goto cleanup;
+            }
+            memset(session->userauth_kybd_responses, 0,
+                   sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
+                   session->userauth_kybd_num_prompts);
+
+            for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
+                /* string    prompt[1] (ISO-10646 UTF-8) */
+                session->userauth_kybd_prompts[i].length = libssh2_ntohu32(s);
+                s += 4;
+                session->userauth_kybd_prompts[i].text =
+                    LIBSSH2_ALLOC(session,
+                                  session->userauth_kybd_prompts[i].length);
+                if (!session->userauth_kybd_prompts[i].text) {
+                    libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                                  "Unable to allocate memory for keyboard-interactive prompt message",
+                                  0);
+                    goto cleanup;
+                }
+                memcpy(session->userauth_kybd_prompts[i].text, s,
+                       session->userauth_kybd_prompts[i].length);
+                s += session->userauth_kybd_prompts[i].length;
+
+                /* boolean   echo[1] */
+                session->userauth_kybd_prompts[i].echo = *s++;
+            }
+
+            response_callback(session->userauth_kybd_auth_name,
+                              session->userauth_kybd_auth_name_len,
+                              session->userauth_kybd_auth_instruction,
+                              session->userauth_kybd_auth_instruction_len,
+                              session->userauth_kybd_num_prompts,
+                              session->userauth_kybd_prompts,
+                              session->userauth_kybd_responses,
+                              &session->abstract);
+
+            _libssh2_debug(session, LIBSSH2_DBG_AUTH,
+                           "Keyboard-interactive response callback function invoked");
+
+            session->userauth_kybd_packet_len = 1       /* byte      SSH_MSG_USERAUTH_INFO_RESPONSE */
+                + 4             /* int       num-responses */
+                ;
+
+            for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
+                /* string    response[1] (ISO-10646 UTF-8) */
+                session->userauth_kybd_packet_len +=
+                    4 + session->userauth_kybd_responses[i].length;
+            }
+
+            session->userauth_kybd_data = s =
+                LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
+            if (!s) {
+                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                              "Unable to allocate memory for keyboard-interactive response packet",
+                              0);
+                goto cleanup;
+            }
+
+            *s = SSH_MSG_USERAUTH_INFO_RESPONSE;
+            s++;
+            libssh2_htonu32(s, session->userauth_kybd_num_prompts);
+            s += 4;
+
+            for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
+                libssh2_htonu32(s, session->userauth_kybd_responses[i].length);
+                s += 4;
+                memcpy(s, session->userauth_kybd_responses[i].text,
+                       session->userauth_kybd_responses[i].length);
+                s += session->userauth_kybd_responses[i].length;
+            }
+
+            session->userauth_kybd_state = libssh2_NB_state_sent1;
+        }
+
+        if (session->userauth_kybd_state == libssh2_NB_state_sent1) {
+            rc = libssh2_packet_write(session, session->userauth_kybd_data,
+                                      session->userauth_kybd_packet_len);
+            if (rc == PACKET_EAGAIN) {
+                return PACKET_EAGAIN;
+            }
+            if (rc) {
+                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
+                              "Unable to send userauth-keyboard-interactive request",
+                              0);
+                goto cleanup;
+            }
+
+            session->userauth_kybd_auth_failure = 0;
+        }
+
+      cleanup:
+        /*
+         * It's safe to clean all the data here, because unallocated pointers
+         * are filled by zeroes
+         */
+
+        LIBSSH2_FREE(session, session->userauth_kybd_data);
+        session->userauth_kybd_data = NULL;
+
+        if (session->userauth_kybd_prompts) {
+            for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
+                LIBSSH2_FREE(session, session->userauth_kybd_prompts[i].text);
+                session->userauth_kybd_prompts[i].text = NULL;
+            }
+        }
+
+        if (session->userauth_kybd_responses) {
+            for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
+                LIBSSH2_FREE(session,
+                             session->userauth_kybd_responses[i].text);
+                session->userauth_kybd_responses[i].text = NULL;
+            }
+        }
+
+        LIBSSH2_FREE(session, session->userauth_kybd_prompts);
+        session->userauth_kybd_prompts = NULL;
+        LIBSSH2_FREE(session, session->userauth_kybd_responses);
+        session->userauth_kybd_responses = NULL;
+
+        if (session->userauth_kybd_auth_failure) {
+            session->userauth_kybd_state = libssh2_NB_state_idle;
+            return -1;
+        }
+
+        session->userauth_kybd_state = libssh2_NB_state_sent;
+    }
+}
+
+/* }}} */
diff --git a/libssh2/lib/libssh2.a b/libssh2/lib/libssh2.a
deleted file mode 100644 (file)
index 1235448..0000000
Binary files a/libssh2/lib/libssh2.a and /dev/null differ
diff --git a/libssh2/lib/libssh2.la b/libssh2/lib/libssh2.la
deleted file mode 100755 (executable)
index 8c97f0d..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-# libssh2.la - a libtool library file
-# Generated by ltmain.sh - GNU libtool 1.5.24 Debian 1.5.24-1 (1.1220.2.456 2007/06/24 02:25:32)
-#
-# Please DO NOT delete this file!
-# It is necessary for linking the library.
-
-# The name that we can dlopen(3).
-dlname=''
-
-# Names of this library.
-library_names=''
-
-# The name of the static archive.
-old_library='libssh2.a'
-
-# Libraries that this one depends upon.
-dependency_libs=' -L/usr/lib -lcrypto -lz'
-
-# Version information for libssh2.
-current=1
-age=0
-revision=0
-
-# Is this an already installed library?
-installed=yes
-
-# Should we warn about portability when linking against -modules?
-shouldnotlink=no
-
-# Files to dlopen/dlpreopen
-dlopen=''
-dlpreopen=''
-
-# Directory that this library needs to be installed in:
-libdir='/Users/rsesek/Projects/PrintDrop/libssh2/lib'
diff --git a/libssh2/share/man/man3/libssh2_banner_set.3 b/libssh2/share/man/man3/libssh2_banner_set.3
deleted file mode 100644 (file)
index e5c286f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-.\" $Id: libssh2_banner_set.3,v 1.1 2007/06/13 17:03:38 jehousley Exp $
-.\"
-.TH libssh2_banner_set 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_banner_set - set the SSH prococol banner for the local client
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_banner_set(LIBSSH2_SESSION *session, const char *banner);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fIbanner\fP - A pointer to a user defined banner
-
-Set the banner that will be sent to the remote host when the SSH session is 
-started with 
-.BR libssh2_session_startup(3)
-.  This is optional; a banner corresponding to the protocol and libssh2 version will be sent by default.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-.SH SEE ALSO
-.BR libssh2_session_startup(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_close.3 b/libssh2/share/man/man3/libssh2_channel_close.3
deleted file mode 100644 (file)
index f12d25f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-.\" $Id: libssh2_channel_close.3,v 1.1 2007/06/13 17:03:38 jehousley Exp $
-.\"
-.TH libssh2_channel_close 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_close - close a channel<
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_channel_close(LIBSSH2_CHANNEL *channel);
-
-.SH DESCRIPTION
-\fIchannel\fP - active channel stream to set closed status on.
-
-Close an active data channel. In practice this means sending an SSH_MSG_CLOSE 
-packet to the remote host which serves as instruction that no further data 
-will be sent to it. The remote host may still send data back until it sends 
-its own close message in response. To wait for the remote end to close its 
-connection as well, follow this command with 
-.BR libssh2_channel_wait_closed(3)
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-.SH SEE ALSO
-.BR libssh2_channel_open(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_direct_tcpip_ex.3 b/libssh2/share/man/man3/libssh2_channel_direct_tcpip_ex.3
deleted file mode 100644 (file)
index 09e6077..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-.\" $Id: libssh2_channel_direct_tcpip_ex.3,v 1.1 2007/06/13 17:22:15 jehousley Exp $
-.\"
-.TH libssh2_channel_direct_tcpip_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_direct_tcpip_ex - Tunnel a TCP connection through an SSH session
-.SH SYNOPSIS
-#include <libssh2.h>
-
-LIBSSH2_CHANNEL * 
-libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, int port, const char *shost, int sport);
-
-LIBSSH2_CHANNEL * 
-libssh2_channel_direct_tcpip(LIBSSH2_SESSION *session, const char *host, int port);
-
-.SH DESCRIPTION
-/fIsession/fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-/fIhost/fP - Third party host to connect to using the SSH host as a proxy.
-
-/fIport/fP - Port on third party host to connect to.
-
-/fIshost/fP - Host to tell the SSH server the connection originated on.
-
-/fIsport/fP - Port to tell the SSH server the connection originated from.
-
-Tunnel a TCP/IP connection through the SSH transport via the remote host to 
-a third party. Communication from the client to the SSH server remains 
-encrypted, communication from the server to the 3rd party host travels 
-in cleartext.
-
-.SH RETURN VALUE
-Pointer to a newly allocated LIBSSH2_CHANNEL instance, or NULL on errors.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-.SH SEE ALSO
-.BR libssh2_session_init(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_eof.3 b/libssh2/share/man/man3/libssh2_channel_eof.3
deleted file mode 100644 (file)
index 5066731..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-.\" $Id: libssh2_channel_eof.3,v 1.1 2007/06/13 17:22:15 jehousley Exp $
-.\"
-.TH libssh2_channel_eof 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_eof - check a channel's EOF status
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_channel_eof(LIBSSH2_CHANNEL *channel);
-
-.SH DESCRIPTION
-\fIchannel\fP - active channel stream to set closed status on.
-
-Check if the remote host has sent an EOF status for the selected stream.
-
-.SH RETURN VALUE
-Returns 1 if the remote host has sent EOF, otherwise 0.
diff --git a/libssh2/share/man/man3/libssh2_channel_flush_ex.3 b/libssh2/share/man/man3/libssh2_channel_flush_ex.3
deleted file mode 100644 (file)
index 67de921..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-.\" $Id: libssh2_channel_flush_ex.3,v 1.1 2007/06/13 19:53:09 jehousley Exp $
-.\"
-.TH libssh2_channel_flush_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_flush_ex - flush a channel
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid);
-
-int 
-libssh2_channel_flush(LIBSSH2_CHANNEL *channel);
-
-int 
-libssh2_channel_flush_stderr(LIBSSH2_CHANNEL *channel);
-
-.SH DESCRIPTION
-\fIchannel\fP - Active channel stream to flush.
-
-\fIstreamid\fP - Specific substream number to flush. Groups of substreams may 
-be flushed by passing on of the following Constants.
-.br
-\fBLIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA\fP: Flush all extended data substreams
-.br
-\fBLIBSSH2_CHANNEL_FLUSH_ALL\fP: Flush all substreams
-
-Flush the read buffer for a given channel instance. Individual substreams may 
-be flushed by number or using one of the provided macros.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
diff --git a/libssh2/share/man/man3/libssh2_channel_forward_accept.3 b/libssh2/share/man/man3/libssh2_channel_forward_accept.3
deleted file mode 100644 (file)
index 43232e5..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-.\" $Id: libssh2_channel_forward_accept.3,v 1.5 2007/06/13 16:41:33 jehousley Exp $
-.\"
-.TH libssh2_channel_forward_accept 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_forward_accept - accept a queued connection
-.SH SYNOPSIS
-#include <libssh2.h>
-
-LIBSSH2_CHANNEL *
-libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener);
-
-.SH DESCRIPTION
-\fIlistener\fP is a forwarding listener instance as returned by
-\fBlibssh2_channel_forward_listen(3)\fP.
-.SH RETURN VALUE
-A newly allocated channel instance or NULL on failure.
-.SH ERRORS
-\fILIBSSH2_ERROR_EAGAIN\fP - Marked for non-blocking I/O but the call 
-would block.
-.SH SEE ALSO
-.BR libssh2_channel_forward_listen(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_forward_cancel.3 b/libssh2/share/man/man3/libssh2_channel_forward_cancel.3
deleted file mode 100644 (file)
index 822e008..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-.\" $Id: libssh2_channel_forward_cancel.3,v 1.1 2007/06/13 19:53:09 jehousley Exp $
-.\"
-.TH libssh2_channel_forward_cancel 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_forward_cancel - cancel a forwarded TCP port
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener);
-
-.SH DESCRIPTION
-/fIlistener/fP - Forwarding listener instance as returned by 
-.BR libssh2_channel_forward_listen(3)
-
-Instruct the remote host to stop listening for new connections on a previously requested host/port.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-.SH SEE ALSO
-.BR libssh2_channel_forward_listen(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_forward_listen_ex.3 b/libssh2/share/man/man3/libssh2_channel_forward_listen_ex.3
deleted file mode 100644 (file)
index a719c9d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-.\" $Id: libssh2_channel_forward_listen_ex.3,v 1.7 2007/06/13 16:41:33 jehousley Exp $
-.\"
-.TH libssh2_channel_forward_listen_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_forward_listen_ex - listen to inbound connections
-.SH SYNOPSIS
-#include <libssh2.h>
-
-LIBSSH2_LISTENER * 
-libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, char *host, int port, int *bound_port, int queue_maxsize);
-
-LIBSSH2_LISTENER * 
-libssh2_channel_forward_listen(LIBSSH2_SESSION *session, int port);
-
-.SH DESCRIPTION
-Instruct the remote SSH server to begin listening for inbound TCP/IP
-connections. New connections will be queued by the library until accepted by
-\fIlibssh2_channel_forward_accept(3)\fP.
-
-\fIsession\fP - instance as returned by libssh2_session_init(). 
-
-\fIhost\fP - specific address to bind to on the remote host. Binding to
-0.0.0.0 (default when NULL is passed) will bind to all available addresses.
-
-\fIport\fP - port to bind to on the remote host. When 0 is passed, the remote
-host will select the first available dynamic port.
-
-\fIbound_port\fP - Populated with the actual port bound on the remote
-host. Useful when requesting dynamic port numbers.
-
-\fIqueue_maxsize\fP - Maximum number of pending connections to queue before
-rejecting further attempts.
-
-\fIlibssh2_channel_forward_listen(3)\fP is a macro.
-.SH RETURN VALUE
-A newly allocated LIBSSH2_LISTENER instance or NULL on failure.
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_PROTO\fP - An invalid SSH protocol response was received on the socket.
-
-\fILIBSSH2_ERROR_REQUEST_DENIED\fP - The remote server refused the request.
-
-\fILIBSSH2_ERROR_EAGAIN\fP - Marked for non-blocking I/O but the call would block.
-.SH SEE ALSO
-.BR libssh2_channel_forward_accept(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_free.3 b/libssh2/share/man/man3/libssh2_channel_free.3
deleted file mode 100644 (file)
index 73f8e1a..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-.\" $Id: libssh2_channel_free.3,v 1.1 2007/06/13 20:09:15 jehousley Exp $
-.\"
-.TH libssh2_channel_free 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_free - free all resources associated with a channel
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_channel_free(LIBSSH2_CHANNEL *channel);
-
-.SH DESCRIPTION
-\fIchannel\fP - Channel stream to free.
-
-Release all resources associated with a channel stream. If the channel has 
-not yet been closed with 
-.BR libssh2_channel_close(3)
-, it will be called automatically so that the remote end may know that it 
-can safely free its own resources.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH SEE ALSO
-.BR libssh2_channel_close(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_get_exit_status.3 b/libssh2/share/man/man3/libssh2_channel_get_exit_status.3
deleted file mode 100644 (file)
index ee070da..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-.\" $Id: libssh2_channel_get_exit_status.3,v 1.1 2007/06/15 10:53:04 jehousley Exp $
-.\"
-.TH libssh2_channel_get_exit_status 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_get_exit_status - get the remote exit code
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel)
-
-.SH DESCRIPTION
-\fIchannel\fP - Closed channel stream to retreive exit status from.
-
-Returns the exit code raised by the process running on the remote host at 
-the other end of the named channel. Note that the exit status may not be 
-available if the remote end has not yet set its status to closed.
-
-.SH RETURN VALUE
-Returns 0 on failure, otherwise the \fIExit Status\fP reported by remote host
diff --git a/libssh2/share/man/man3/libssh2_channel_handle_extended_data.3 b/libssh2/share/man/man3/libssh2_channel_handle_extended_data.3
deleted file mode 100644 (file)
index 9f556eb..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-.\" $Id: libssh2_channel_handle_extended_data.3,v 1.1 2007/06/13 20:09:15 jehousley Exp $
-.\"
-.TH libssh2_channel_handle_extended_data 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_handle_extended_data - set extended data handling mode
-.SH SYNOPSIS
-#include <libssh2.h>
-
-void 
-libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode);
-
-.SH DESCRIPTION
-\fIchannel\fP - Active channel stream to change extended data handling on.
-
-\fIignore_mode\fP - One of the three LIBSSH2_CHANNEL_EXTENDED_DATA_* Constants.
-.br
-\fBLIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL\fP: Queue extended data for eventual 
-reading
-.br
-\fBLIBSSH2_CHANNEL_EXTENDED_DATA_MERGE\fP: Treat extended data and ordinary 
-data the same. Merge all substreams such that calls to 
-.BR libssh2_channel_read(3)
-will pull from all substreams on a first-in/first-out basis.
-.br
-\fBLIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE\fP: Discard all extended data as it 
-arrives.
-
-Change how a channel deals with extended data packets. By default all 
-extended data is queued until read by 
-.BR libssh2_channel_read_ex(3)
-
-.SH RETURN VALUE
-None.
-
-.SH SEE ALSO
-.BR libssh2_channel_handle_extended_data2(3)
-.BR libssh2_channel_read_ex(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_handle_extended_data2.3 b/libssh2/share/man/man3/libssh2_channel_handle_extended_data2.3
deleted file mode 100644 (file)
index 97d4fd0..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-.\" $Id: libssh2_channel_handle_extended_data2.3,v 1.1 2007/06/13 20:09:15 jehousley Exp $
-.\"
-.TH libssh2_channel_handle_extended_data2 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_handle_extended_data2 - set extended data handling mode
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, int ignore_mode);
-
-.SH DESCRIPTION
-\fIchannel\fP - Active channel stream to change extended data handling on.
-
-\fIignore_mode\fP - One of the three LIBSSH2_CHANNEL_EXTENDED_DATA_* Constants.
-.br
-\fBLIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL\fP: Queue extended data for eventual 
-reading
-.br
-\fBLIBSSH2_CHANNEL_EXTENDED_DATA_MERGE\fP: Treat extended data and ordinary 
-data the same. Merge all substreams such that calls to 
-.BR libssh2_channel_read(3)
-will pull from all substreams on a first-in/first-out basis.
-.br
-\fBLIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE\fP: Discard all extended data as it 
-arrives.
-
-Change how a channel deals with extended data packets. By default all 
-extended data is queued until read by 
-.BR libssh2_channel_read_ex(3)
-
-.SH RETURN VALUE
-Return 0 on success or LIBSSH2_ERROR_EAGAIN when it would otherwise block.
-
-.SH SEE ALSO
-.BR libssh2_channel_handle_extended_data(3)
-.BR libssh2_channel_read_ex(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_open_ex.3 b/libssh2/share/man/man3/libssh2_channel_open_ex.3
deleted file mode 100644 (file)
index e152fb8..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-.\" $Id: libssh2_channel_open_ex.3,v 1.1 2007/06/13 20:54:25 jehousley Exp $
-.\"
-.TH libssh2_channel_open_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_open_ex - establish a generic session channel
-.SH SYNOPSIS
-#include <libssh2.h>
-
-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_CHANNEL *
-libssh2_channel_open_session(session);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fIchannel_type\fP - Channel type to open. Typically one of session, 
-direct-tcpip, or tcpip-forward. The SSH2 protocol allowed for additional 
-types including local, custom channel types.
-
-\fIchannel_type_len\fP - Length of channel_type
-
-\fIwindow_size\fP - Maximum amount of unacknowledged data remote host is 
-allowed to send before receiving an SSH_MSG_CHANNEL_WINDOW_ADJUST packet.
-
-\fIpacket_size\fP - Maximum number of bytes remote host is allowed to send 
-in a single SSH_MSG_CHANNEL_DATA or SSG_MSG_CHANNEL_EXTENDED_DATA packet.
-
-\fImessage\fP - Additional data as required by the selected channel_type.
-
-\fImessage_len\fP - Length of message parameter.
-
-Allocate a new channel for exchanging data with the server. This method is 
-typically called through its macroized form: 
-.BR libssh2_channel_open_session(3)
-or via 
-.BR libssh2_channel_direct_tcpip(3)
-or
-.BR libssh2_channel_forward_listen(3)
-
-.SH RETURN VALUE
-Pointer to a newly allocated LIBSSH2_CHANNEL instance, or NULL on errors.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_CHANNEL_FAILURE\fP - 
-
-\fILIBSSH2_ERROR_EAGAIN\fP - Marked for non-blocking I/O but the call would block.
-
-.SH SEE ALSO
-Add related functions
diff --git a/libssh2/share/man/man3/libssh2_channel_process_startup.3 b/libssh2/share/man/man3/libssh2_channel_process_startup.3
deleted file mode 100644 (file)
index 99342fd..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-.\" $Id: libssh2_channel_process_startup.3,v 1.1 2007/06/13 20:54:25 jehousley Exp $
-.\"
-.TH libssh2_channel_process_startup 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_process_startup - request a shell on a channel
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int
-libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const char *request, unsigned int request_len, const char *message, unsigned int message_len);
-
-int
-libssh2_channel_shell(LIBSSH2_CHANNEL *channel);
-
-int
-libssh2_channel_exec(LIBSSH2_CHANNEL *channel, const char *message);
-
-int
-libssh2_channel_subsystem(LIBSSH2_CHANNEL *channel, const char *message);
-
-.SH DESCRIPTION
-\fIchannel\fP - Active session channel instance.
-
-\fIrequest\fP - Type of process to startup. The SSH2 protocol currently 
-defines shell, exec, and subsystem as standard process services.
-
-\fIrequest_len\fP - Length of request parameter.
-
-\fImessage\fP - Request specific message data to include.
-
-\fImessage_len\fP - Length of message parameter.
-
-Initiate a request on a session type channel such as returned by 
-.BR libssh2_channel_open_session(3)
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_CHANNEL_REQUEST_DENIED\fP - 
-
-.SH SEE ALSO
-.BR libssh2_channel_open_session(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_read_ex.3 b/libssh2/share/man/man3/libssh2_channel_read_ex.3
deleted file mode 100644 (file)
index 4ecc6af..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-.\" $Id: libssh2_channel_read_ex.3,v 1.10 2007/06/13 16:41:33 jehousley Exp $
-.\"
-.TH libssh2_channel_read_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_read_ex - read data from a channel stream
-.SH SYNOPSIS
-#include <libssh2.h>
-
-ssize_t
-libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, size_t buflen);
-
-ssize_t
-libssh2_channel_read(LIBSSH2_CHANNEL *channel, char *buf, size_t buflen);
-
-ssize_t
-libssh2_channel_read_stderr(LIBSSH2_CHANNEL *channel, char *buf, size_t buflen);
-
-.SH DESCRIPTION
-Attempt to read data from an active channel stream. All channel streams have
-one standard I/O substream (stream_id == 0), and may have up to 2^32 extended
-data streams as identified by the selected \fIstream_id\fP. The SSH2 protocol
-currently defines a stream ID of 1 to be the stderr substream.
-
-\fIchannel\fP - active channel stream to read from. 
-
-\fIstream_id\fP - substream ID number (e.g. 0 or SSH_EXTENDED_DATA_STDERR) 
-
-\fIbuf\fP - pointer to storage buffer to read data into
-
-\fIbuflen\fP - size of the buf storage
-
-\fIlibssh2_channel_read(3)\fP and \fIlibssh2_channel_read_stderr(3)\fP are
-macros.
-.SH RETURN VALUE
-Actual number of bytes read or negative on failure. It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-.SH ERRORS
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_CHANNEL_CLOSED\fP - The channel has been closed.
-
-.SH SEE ALSO
-.BR libssh2_poll_channel_read(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_request_pty_ex.3 b/libssh2/share/man/man3/libssh2_channel_request_pty_ex.3
deleted file mode 100644 (file)
index ba69a2d..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-.\" $Id: libssh2_channel_request_pty_ex.3,v 1.1 2007/06/13 21:07:59 jehousley Exp $
-.\"
-.TH libssh2_channel_request_pty_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_request_pty_ex - short function description
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, const char *term, unsigned int term_len, const char *modes, unsigned int modes_len, int width, int height, int width_px, int height_px);
-
-int 
-libssh2_channel_request_pty(LIBSSH2_CHANNEL *channel, char *term);
-
-.SH DESCRIPTION
-\fIchannel\fP - Previously opened channel instance such as returned by 
-.BR libssh2_channel_open_session(3)
-
-\fIterm\fP - Terminal emulation (e.g. vt102, ansi, etc...)
-
-\fIterm_len\fP - Length of term parameter
-
-\fImodes\fP - Terminal mode modifier values
-
-\fImodes_len\fP - Length of modes parameter.
-
-\fIwidth\fP - Width of pty in characters
-
-\fIheight\fP - Height of pty in characters
-
-\fIwidth_px\fP - Width of pty in pixels
-
-\fIheight_px\fP - Height of pty in pixels
-
-Request a PTY on an established channel. Note that this does not make sense 
-for all channel types and may be ignored by the server despite returning 
-success.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_CHANNEL_REQUEST_DENIED\fP - 
-
-.SH SEE ALSO
-.BR libssh2_channel_open_session(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_send_eof.3 b/libssh2/share/man/man3/libssh2_channel_send_eof.3
deleted file mode 100644 (file)
index 60bc55e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-.\" $Id: libssh2_channel_send_eof.3,v 1.1 2007/06/13 21:07:59 jehousley Exp $
-.\"
-.TH libssh2_channel_send_eof 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_send_eof - send EOF to remote server
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel);
-
-.SH DESCRIPTION
-Tell the remote host that no further data will be sent on the specified 
-channel. Processes typically interpret this as a closed stdin descriptor.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-.SH SEE ALSO
-.BR libssh2_channel_wait_eof(3)
-.BR libssh2_channel_eof(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_set_blocking.3 b/libssh2/share/man/man3/libssh2_channel_set_blocking.3
deleted file mode 100644 (file)
index db2cc40..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-.\" $Id: libssh2_channel_set_blocking.3,v 1.5 2007/06/14 17:23:13 jehousley Exp $
-.\"
-.TH libssh2_channel_set_blocking 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_set_blocking - set or clear blocking mode on channel
-.SH SYNOPSIS
-#include <libssh2.h>
-
-void 
-libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
-
-.SH DESCRIPTION
-\fIchannel\fP - channel stream to set or clean blocking status on.
-
-\fIblocking\fP - Set to a non-zero value to make the channel block, or zero to
-make it non-blocking.
-
-Currently this is just a short cut call to 
-.BR libssh2_session_set_blocking(3)
-and therefore will affect the session and all channels.
-
-.SH RETURN VALUE
-None
-
-.SH SEE ALSO
-.BR libssh2_session_set_blocking(3)
-.BR libssh2_channel_read_ex(3)
-.BR libssh2_channel_write_ex(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_setenv_ex.3 b/libssh2/share/man/man3/libssh2_channel_setenv_ex.3
deleted file mode 100644 (file)
index 7688903..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-.\" $Id: libssh2_channel_setenv_ex.3,v 1.1 2007/06/13 21:30:15 jehousley Exp $
-.\"
-.TH libssh2_channel_setenv_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_setenv_ex - set an environment variable on the channel
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int
-libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varname, unsigned int varname_len, const char *value, unsigned int value_len);
-
-int
-libssh2_channel_setenv(LIBSSH2_CHANNEL *channel, char *varname, const char *value);
-
-.SH DESCRIPTION
-\fIchannel\fP - Previously opened channel instance such as returned by 
-.BR libssh2_channel_open_session(3)
-
-\fIvarname\fP - Name of environment variable to set on the remote 
-channel instance.
-
-\fIvarname_len\fP - Length of passed varname parameter.
-
-\fIvalue\fP - Value to set varname to.
-
-\fIvalue_len\fP - Length of value parameter.
-
-Set an environment variable in the remote channel's process space. Note that this does not make sense for all channel types and may be ignored by the server despite returning success.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_CHANNEL_REQUEST_DENIED\fP - 
-
-.SH SEE ALSO
-.BR libssh2_channel_open_session(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_wait_eof.3 b/libssh2/share/man/man3/libssh2_channel_wait_eof.3
deleted file mode 100644 (file)
index fbe1c13..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-.\" $Id: libssh2_channel_wait_eof.3,v 1.5 2007/06/13 16:41:33 jehousley Exp $
-.\"
-.TH libssh2_channel_wait_eof 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_wait_eof - wait for the remote to reply to an EOF request
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel);
-
-.SH DESCRIPTION
-Wait for the remote end to acknowledge an EOF request.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure. It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-.SH SEE ALSO
-.BR libssh2_channel_send_eof(3)
-.BR libssh2_channel_eof(3)
diff --git a/libssh2/share/man/man3/libssh2_channel_x11_req_ex.3 b/libssh2/share/man/man3/libssh2_channel_x11_req_ex.3
deleted file mode 100644 (file)
index 7a45722..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-.\" $Id: libssh2_channel_x11_req_ex.3,v 1.1 2007/06/13 21:30:15 jehousley Exp $
-.\"
-.TH libssh2_channel_x11_req_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_channel_x11_req_ex - request an X11 forwarding channel
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int
-libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, const char *auth_proto, const char *auth_cookie, int screen_number);
-
-int
-libssh2_channel_x11_req(LIBSSH2_CHANNEL *channel, int screen_number);
-
-.SH DESCRIPTION
-\fIchannel\fP - Previously opened channel instance such as returned by 
-.BR libssh2_channel_open_session(3)
-
-\fIsingle_connection\fP - non-zero to only forward a single connection.
-
-\fIauth_proto\fP - X11 authentication protocol to use
-
-\fIauth_cookie\fP - the cookie (hexadecimal encoded).
-
-\fIscreen_number\fP - the XLL screen to forward
-
-Request an X11 forwarding on \fIchannel\fP. To use X11 forwarding, 
-.BR libssh2_session_callback_set(3)
-must first be called to set \fBLIBSSH2_CALLBACK_X11/fP. This callback will 
-be invoked when the remote host accepts the X11 forwarding.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_CHANNEL_REQUEST_DENIED\fP - 
-
-.SH SEE ALSO
-.BR libssh2_channel_open_session(3)
-.BR libssh2_session_callback_set(3)
diff --git a/libssh2/share/man/man3/libssh2_hostkey_hash.3 b/libssh2/share/man/man3/libssh2_hostkey_hash.3
deleted file mode 100644 (file)
index 0345d28..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-.\" $Id: libssh2_hostkey_hash.3,v 1.1 2007/06/14 14:56:32 jehousley Exp $
-.\"
-.TH libssh2_hostkey_hash 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_hostkey_hash - return a hash of the remote host's key
-.SH SYNOPSIS
-#include <libssh2.h>
-
-const char *
-libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fIhash_type\fP - One of: \fBLIBSSH2_HOSTKEY_HASH_MD5\fP or 
-\fBLIBSSH2_HOSTKEY_HASH_SHA1\fP.
-
-Returns the computed digest of the remote system's hostkey. The length of 
-the returned string is hash_type specific (e.g. 16 bytes for MD5, 
-20 bytes for SHA1).
-
-.SH RETURN VALUE
-Computed hostkey hash value. or NULL if the session has not yet been started 
-up. (The hash consists of raw binary bytes, not hex digits, so is not 
-directly printable.)
-
-.SH SEE ALSO
-.BR libssh2_session_init(3)
diff --git a/libssh2/share/man/man3/libssh2_poll.3 b/libssh2/share/man/man3/libssh2_poll.3
deleted file mode 100644 (file)
index eb9ae5a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-.\" $Id: libssh2_poll.3,v 1.3 2007/06/13 12:51:11 jehousley Exp $
-.\"
-.TH libssh2_poll 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_poll - poll for activity on a socket, channel or listener
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout);
-.SH DESCRIPTION
-Poll for activity on a socket, channel, listener, or any combination of these
-three types. The calling semantics for this function generally match
-\fIpoll(2)\fP however the structure of fds is somewhat more complex in order
-to accommodate the disparate datatypes, POLLFD constants have been namespaced
-to avoid platform discrepancies, and revents has additional values defined.
-.SH "RETURN VALUE"
-Number of fds with interesting events.
-.SH SEE ALSO
-.BR libssh2_poll_channel_read(3)
diff --git a/libssh2/share/man/man3/libssh2_poll_channel_read.3 b/libssh2/share/man/man3/libssh2_poll_channel_read.3
deleted file mode 100644 (file)
index 7aa0325..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-.\" $Id: libssh2_poll_channel_read.3,v 1.2 2007/06/13 12:51:11 jehousley Exp $
-.\"
-.TH libssh2_poll_channel_read 3 "14 Dec 2006" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_poll_channel_read - check if data is available
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended);
-.SH DESCRIPTION
-\fIlibssh2_poll_channel_read(3)\fP checks to see if data is available in the
-\fIchannel\fP's read buffer. No attempt is made with this method to see if
-packets are available to be processed. For full polling support, use
-\fIlibssh2_poll(3)\fP.
-.SH RETURN VALUE
-Returns 1 when data is available and 0 otherwise.
-.SH SEE ALSO
-.BR libssh2_poll(3)
diff --git a/libssh2/share/man/man3/libssh2_scp_recv.3 b/libssh2/share/man/man3/libssh2_scp_recv.3
deleted file mode 100644 (file)
index 99f8cad..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-.\" $Id: libssh2_scp_recv.3,v 1.1 2007/06/14 14:56:32 jehousley Exp $
-.\"
-.TH libssh2_scp_recv 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_scp_recv - request a remote file via SCP
-.SH SYNOPSIS
-#include <libssh2.h>
-
-LIBSSH2_CHANNEL *
-libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fIpath\fP - Full path and filename of file to transfer
-
-\fIsb\fP - Populated with remote file's size, mode, mtime, and atime
-
-Request a file from the remote host via SCP. This 
-function acts as a wrapper calling 
-.BR libssh2_channel_open_session(3)
-,
-.BR libssh2_channel_exec(3)
-, and negotiating rcp protocol handshakes.
-
-.SH RETURN VALUE
-Pointer to a newly allocated LIBSSH2_CHANNEL instance, or NULL on errors.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SCP_PROTOCOL\fP - 
-
-\fILIBSSH2_ERROR_EAGAIN\fP - Marked for non-blocking I/O but the call would block.
-
-.SH SEE ALSO
-.BR libssh2_session_init(3)
-.BR libssh2_channel_open_session(3)
-.BR libssh2_channel_exec(3)
diff --git a/libssh2/share/man/man3/libssh2_scp_send_ex.3 b/libssh2/share/man/man3/libssh2_scp_send_ex.3
deleted file mode 100644 (file)
index 1b12893..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-.\" $Id: libssh2_scp_send_ex.3,v 1.1 2007/06/14 14:56:32 jehousley Exp $
-.\"
-.TH libssh2_scp_send_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_scp_send_ex - Send a file via SCP
-.SH SYNOPSIS
-#include <libssh2.h>
-
-LIBSSH2_CHANNEL *
-libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime);
-
-LIBSSH2_CHANNEL *
-libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fIpath\fP - Full path and filename of file to transfer
-
-\fImode\fP - File access mode to create file with
-
-\fIsize\fP - Size of file being transmitted (Must be known 
-ahead of time precisely)
-
-\fImtime\fP - mtime to assign to file being created
-
-\fIatime\fP - atime to assign to file being created (Set this and 
-mtime to zero to instruct remote host to use current time).
-
-Send a file to the remote host via SCP. This function 
-acts as a wrapper calling 
-.BR libssh2_channel_open_session(3)
-, 
-.BR libssh2_channel_exec(3)
-, and negotiating rcp protocol handshakes.
-
-.SH RETURN VALUE
-Pointer to a newly allocated LIBSSH2_CHANNEL instance, or NULL on errors.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SCP_PROTOCOL\fP - 
-
-\fILIBSSH2_ERROR_EAGAIN\fP - Marked for non-blocking I/O but the call would block.
-
-.SH SEE ALSO
-.BR libssh2_channel_open_session(3)
-.BR libssh2_channel_exec(3)
diff --git a/libssh2/share/man/man3/libssh2_session_abstract.3 b/libssh2/share/man/man3/libssh2_session_abstract.3
deleted file mode 100644 (file)
index b6ac5db..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-.\" $Id: libssh2_session_abstract.3,v 1.1 2007/06/14 15:26:58 jehousley Exp $
-.\"
-.TH libssh2_session_abstract 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_session_abstract - return a pointer to a session's abstract pointer
-.SH SYNOPSIS
-#include <libssh2.h>
-
-void **
-libssh2_session_abstract(LIBSSH2_SESSION *session);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init_ex(3)
-
-Return a pointer to where the abstract pointer provided to 
-.BR libssh2_session_init_ex(3)
- is stored. By providing a doubly de-referenced pointer, the internal 
- storage of the session instance may be modified in place.
-
-.SH RETURN VALUE
-A pointer to session internal storage whos contents point to previously 
-provided abstract data.
-
-.SH SEE ALSO
-.BR libssh2_session_init_ex(3)
diff --git a/libssh2/share/man/man3/libssh2_session_callback_set.3 b/libssh2/share/man/man3/libssh2_session_callback_set.3
deleted file mode 100644 (file)
index 75e73fd..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-.\" $Id: libssh2_session_callback_set.3,v 1.1 2007/06/14 15:26:58 jehousley Exp $
-.\"
-.TH libssh2_session_callback_set 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_session_callback_set - set a callback function
-.SH SYNOPSIS
-#include <libssh2.h>
-
-void *
-libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbtype, void *callback);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fIcbtype\fP - Callback type. One of the types listed in Callback Types.
-
-\fIcallback\fP - Pointer to custom callback function. The prototype for 
-this function must match the associated callback declaration macro.
-
-Sets a custom callback handler for a previously initialized session 
-object. Callbacks are triggered by the receipt of special packets at 
-the Transport layer. To disable a callback, set it to NULL.
-
-.SH RETURN VALUE
-Pointer to previous callback handler. Returns NULL if no 
-prior callback handler was set.
-
-.SH SEE ALSO
-.BR libssh2_session_init(3)
diff --git a/libssh2/share/man/man3/libssh2_session_disconnect_ex.3 b/libssh2/share/man/man3/libssh2_session_disconnect_ex.3
deleted file mode 100644 (file)
index 7548232..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-.\" $Id: libssh2_session_disconnect_ex.3,v 1.4 2007/06/13 16:41:33 jehousley Exp $
-.\"
-.TH libssh2_session_disconnect_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_session_disconnect_ex - terminate transport layer
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, const char *description, const char *lang);
-
-int 
-libssh2_session_disconnect(LIBSSH2_SESSION *session, const char *description);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fIreason\fP - One of the Disconnect Reason constants.
-
-\fIdescription\fP - Human readable reason for disconnection.
-
-\fIlang\fP - Localization string describing the langauge/encoding of the description provided.
-
-Send a disconnect message to the remote host associated with \fIsession\fP, 
-along with a \fIreason\fP symbol and a verbose \fIdescription\fP.
-
-As a convenience, the macro 
-.BR libssh2_session_disconnect(3)
-is provided. It calls
-.BR libssh2_session_disconnect_ex(3)
-with \fIreason\fP set to SSH_DISCONNECT_BY_APPLICATION 
-and \fIlang\fP set to an empty string.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-.SH SEE ALSO
-.BR libssh2_session_init(3)
diff --git a/libssh2/share/man/man3/libssh2_session_free.3 b/libssh2/share/man/man3/libssh2_session_free.3
deleted file mode 100644 (file)
index 0ea781d..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-.\" $Id: libssh2_session_free.3,v 1.4 2007/06/13 16:41:33 jehousley Exp $
-.\"
-.TH libssh2_session_free 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_session_free - frees resources associated with a session instance
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_session_free(LIBSSH2_SESSION *session);
-.SH DESCRIPTION
-Frees resources associated with a session instance. Typically called after
-.BR libssh2_session_disconnect(3)
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-.SH SEE ALSO
-.BR libssh2_session_init(3)
-.BR libssh2_session_disconnect(3)
diff --git a/libssh2/share/man/man3/libssh2_session_init.3 b/libssh2/share/man/man3/libssh2_session_init.3
deleted file mode 100644 (file)
index 651841d..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-.\" $Id: libssh2_session_init.3,v 1.6 2007/06/13 16:41:33 jehousley Exp $
-.\"
-.TH libssh2_session_init_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_session_init_ex - initializes an SSH session object
-.SH SYNOPSIS
-#include <libssh2.h>
-
-LIBSSH2_SESSION * 
-libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*myalloc)), LIBSSH2_FREE_FUNC((*myfree)), LIBSSH2_REALLOC_FUNC((*myrealloc)), void *abstract);
-
-LIBSSH2_SESSION *
-libssh2_session_init(void);
-
-.SH DESCRIPTION
-\fImyalloc\fP - Custom allocator function. Refer to the section on Callbacks 
-for implementing an allocator callback. Pass a value of NULL to use the 
-default system allocator.
-
-\fImyfree\fP - Custom de-allocator function. Refer to the section on Callbacks 
-for implementing a deallocator callback. Pass a value of NULL to use the 
-default system deallocator.
-
-\fImyrealloc\fP - Custom re-allocator function. Refer to the section on 
-Callbacks for implementing a reallocator callback. Pass a value of NULL to 
-use the default system reallocator.
-
-\fIabstract\fP - Arbitrary pointer to application specific callback data. 
-This value will be passed to any callback function associated with the named 
-session instance.
-
-Initializes an SSH session object. By default system memory allocators
-(malloc(), free(), realloc()) will be used for any dynamically allocated memory
-blocks. Alternate memory allocation functions may be specified using the
-extended version of this API call, and/or optional application specific data
-may be attached to the session object.
-
-This method must be called first, prior to configuring session options or
-starting up an SSH session with a remote server.
-.SH RETURN VALUE
-Pointer to a newly allocated LIBSSH2_SESSION instance, or NULL on errors.
-.SH SEE ALSO
-.BR libssh2_session_free(3)
-.BR libssh2_session_startup(3)
diff --git a/libssh2/share/man/man3/libssh2_session_last_errno.3 b/libssh2/share/man/man3/libssh2_session_last_errno.3
deleted file mode 100644 (file)
index 3efa04b..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-.\" $Id: libssh2_session_last_errno.3,v 1.1 2007/06/13 23:02:08 jehousley Exp $
-.\"
-.TH libssh2_session_last_errno 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_session_last_errno - get the most recent error number
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int
-libssh2_session_last_errno(LIBSSH2_SESSION *session);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-Determine the most recent error condition.
-
-.SH RETURN VALUE
-Numeric error code corresponding to the the Error Code constants.
-
-.SH SEE ALSO
-.BR libssh2_session_last_error(3)
diff --git a/libssh2/share/man/man3/libssh2_session_last_error.3 b/libssh2/share/man/man3/libssh2_session_last_error.3
deleted file mode 100644 (file)
index 8636ad2..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-.\" $Id: libssh2_session_last_error.3,v 1.1 2007/06/13 23:02:08 jehousley Exp $
-.\"
-.TH libssh2_session_last_error 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_session_last_error - get the most recent error
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int
-libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fIerrmsg\fP - If not NULL, is populated by reference with the human 
-readable form of the most recent error message.
-
-\fIerrmsg_len\fP - If not NULL, is populated by reference with the length 
-of errmsg. (The string is NUL-terminated, so the length is only useful as 
-an optimization, to avoid calling strlen.)
-
-\fIwant_buf\fP - If set to a non-zero value, "ownership" of the errmsg 
-buffer will be given to the calling scope. If necessary, the errmsg buffer 
-will be duplicated.
-
-Determine the most recent error condition and its cause.
-
-.SH RETURN VALUE
-Numeric error code corresponding to the the Error Code constants.
-
-.SH SEE ALSO
-.BR libssh2_session_last_errno(3)
diff --git a/libssh2/share/man/man3/libssh2_session_method_pref.3 b/libssh2/share/man/man3/libssh2_session_method_pref.3
deleted file mode 100644 (file)
index 17a9d4c..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-.\" $Id: libssh2_session_method_pref.3,v 1.1 2007/06/14 15:26:58 jehousley Exp $
-.\"
-.TH libssh2_session_method_pref 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_session_method_pref - set preferred key exchange method
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, const char *prefs);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fImethod_type\fP - One of the Method Type constants.
-
-\fIprefs\fP - Coma delimited list of preferred methods to use with 
-the most preferred listed first and the least preferred listed last. 
-If a method is listed which is not supported by libssh2 it will be 
-ignored and not sent to the remote host during protocol negotiation.
-
-Set preferred methods to be negotiated. These 
-preferrences must be set prior to calling 
-.BR libssh2_session_startup(3)
-as they are used during the protocol initiation phase.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_INVAL\fP - The requested method type was invalid.
-
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_METHOD_NOT_SUPPORTED\fP - The requested method is not supported.
-
-.SH SEE ALSO
-.BR libssh2_session_init(3)
-.BR libssh2_session_startup(3)
diff --git a/libssh2/share/man/man3/libssh2_session_methods.3 b/libssh2/share/man/man3/libssh2_session_methods.3
deleted file mode 100644 (file)
index bfc7be5..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-.\" $Id: libssh2_session_methods.3,v 1.1 2007/06/14 15:26:58 jehousley Exp $
-.\"
-.TH libssh2_session_methods 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_session_methods - return the currently active algorithms
-.SH SYNOPSIS
-#include <libssh2.h>
-
-const char *
-libssh2_session_methods(LIBSSH2_SESSION *session, int method_type);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fImethod_type\fP - One of the Method Type constants.
-
-Return the actual method negotiated for a particular transport parameter.
-
-.SH RETURN VALUE
-Negotiated method or NULL if the session has not yet been started.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_INVAL\fP - The requested method type was invalid.
-
-\fILIBSSH2_ERROR_METHOD_NONE\fP - 
-
-.SH SEE ALSO
-.BR libssh2_session_init(3)
diff --git a/libssh2/share/man/man3/libssh2_session_set_blocking.3 b/libssh2/share/man/man3/libssh2_session_set_blocking.3
deleted file mode 100644 (file)
index 3008be5..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-.\" $Id: libssh2_session_set_blocking.3,v 1.1 2007/06/14 17:23:13 jehousley Exp $
-.\"
-.TH libssh2_session_set_blocking 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_session_set_blocking - set or clear blocking mode on session
-.SH SYNOPSIS
-#include <libssh2.h>
-
-void 
-libssh2_session_set_blocking(LIBSSH2_SESSION *session, int blocking);
-
-.SH DESCRIPTION
-\fIsession\fP - session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fIblocking\fP - Set to a non-zero value to make the channel block, or zero to
-make it non-blocking.
-
-Set or clear blocking mode on the selected on the sessoin.  This will 
-instantly affect any channels associtated with this session. If a read is 
-performed on a session with no data currently available, a blocking 
-session will wait for data to arrive and return what it receives. 
-A non-blocking session will return immediately with an empty buffer.  
-If a write is performed on a session with
-no room for more data, a blocking session will wait for room.  A non-blocking
-session will return immediately without writing anything.
-
-.SH RETURN VALUE
-None
-
-.SH SEE ALSO
-.BR libssh2_session_init(3)
diff --git a/libssh2/share/man/man3/libssh2_session_startup.3 b/libssh2/share/man/man3/libssh2_session_startup.3
deleted file mode 100644 (file)
index 42c3bbe..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-.\" $Id: libssh2_session_startup.3,v 1.6 2007/06/13 16:41:33 jehousley Exp $
-.\"
-.TH libssh2_session_startup 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_session_startup - begin transport layer
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_session_startup(LIBSSH2_SESSION *session, int socket);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fIsocket\fP - Connected socket descriptor. Typically a TCP connection 
-though the protocol allows for any reliable transport and the library will 
-attempt to use any berkeley socket.
-
-Begin transport layer protocol negotiation with the connected host.
-.SH RETURN VALUE
-Returns 0 on success, negative on failure.
-.SH ERRORS
-\fILIBSSH2_ERROR_SOCKET_NONE\fP - The socket is invalid.
-
-\fILIBSSH2_ERROR_BANNER_SEND\fP - Unable to send banner to remote host.
-
-\fILIBSSH2_ERROR_KEX_FAILURE\fP - >Encryption key exchange with the remote 
-host failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_DISCONNECT\fP - The socket was disconnected.
-
-\fILIBSSH2_ERROR_PROTO\fP - An invalid SSH protocol response was received on 
-the socket.
-
-\fILIBSSH2_ERROR_EAGAIN\fP - Marked for non-blocking I/O but the call would block.
-
-.SH SEE ALSO
-.BR libssh2_session_free(3)
-.BR libssh2_session_init(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_close_handle.3 b/libssh2/share/man/man3/libssh2_sftp_close_handle.3
deleted file mode 100644 (file)
index 37c87e2..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-.\" $Id: libssh2_sftp_close_handle.3,v 1.1 2007/06/14 15:45:03 jehousley Exp $
-.\"
-.TH libssh2_sftp_close_handle 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_close_handle - close filehandle
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-int 
-libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle);
-
-int 
-libssh2_sftp_close(LIBSSH2_SFTP_HANDLE *handle);
-
-int 
-libssh2_sftp_closedir(LIBSSH2_SFTP_HANDLE *handle);
-
-.SH DESCRIPTION
-\fIhandle\fP - SFTP File Handle as returned by 
-.BR libssh2_sftp_open(3)
-or
-.BR libssh2_sftp_opendir(3)
-
-Close an active LIBSSH2_SFTP_HANDLE. Because files and directories 
-share the same underlying storage mechanism these methods may be used 
-interchangably. It is recommended that 
-.BR libssh2_sftp_close()
-be used for files and that 
-.BR libssh2_sftp_closedir()
-be used for directories so that future changes in the library 
-may cause minimal disruption.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
-
-\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was 
-received on the socket, or an SFTP operation caused an errorcode to 
-be returned by the server.
-
-.SH SEE ALSO
-.BR libssh2_sftp_open(3)
-.BR libssh2_sftp_opendir(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_fstat_ex.3 b/libssh2/share/man/man3/libssh2_sftp_fstat_ex.3
deleted file mode 100644 (file)
index 45e4f4f..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-.\" $Id: libssh2_sftp_fstat_ex.3,v 1.1 2007/06/14 15:45:03 jehousley Exp $
-.\"
-.TH libssh2_sftp_fstat_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_fstat_ex - get or set attributes on a file handle
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-int 
-libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_ATTRIBUTES *attrs, int setstat)
-
-int 
-libssh2_sftp_fstat(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_ATTRIBUTES *attrs)
-
-int 
-libssh2_sftp_fsetstat(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_ATTRIBUTES *attrs)
-
-.SH DESCRIPTION
-\fIhandle\fP - SFTP File Handle as returned by 
-.BR libssh2_sftp_open(3)
-
-\fIattrs\fP - Pointer to attribute structure to set file metadata 
-from or into depending on the value of setstat.
-
-\fIsetstat\fP - When non-zero, the file's metadata will be updated 
-with the data found in attrs according to the values of attrs->flags 
-and other relevant member attributes.
-
-Get or Set statbuf type data for a given LIBSSH2_SFTP_HANDLE instance.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
-
-\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was 
-received on the socket, or an SFTP operation caused an errorcode to 
-be returned by the server.
-
-.SH SEE ALSO
-.BR libssh2_sftp_open(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_init.3 b/libssh2/share/man/man3/libssh2_sftp_init.3
deleted file mode 100644 (file)
index c66a6d4..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-.\" $Id: libssh2_sftp_init.3,v 1.6 2007/06/13 16:41:33 jehousley Exp $
-.\"
-.TH libssh2_sftp_init 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_init - 
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-LIBSSH2_SFTP *
-libssh2_sftp_init(LIBSSH2_SESSION *session);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-Open a channel and initialize the SFTP subsystem. Although the SFTP subsystem
-operates over the same type of channel as those exported by the Channel API,
-the protocol itself implements its own unique binary packet protocol which
-must be managed with the libssh2_sftp_*() family of functions. When an SFTP
-session is complete, it must be destroyed using the
-.BR libssh2_sftp_shutdown(3)
-function.
-.SH RETURN VALUE
-A pointer to the newly allocated SFTP instance or NULL on failure.
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
-
-\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was 
-received on the socket, or an SFTP operation caused an errorcode to be 
-returned by the server.
-
-\fILIBSSH2_ERROR_EAGAIN\fP - Marked for non-blocking I/O but the call would block.
-
-.SH SEE ALSO
-.BR libssh2_sftp_shutdown(3)
-.BR libssh2_sftp_open_ex(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_last_error.3 b/libssh2/share/man/man3/libssh2_sftp_last_error.3
deleted file mode 100644 (file)
index 725262a..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-.\" $Id: libssh2_sftp_last_error.3,v 1.1 2007/06/14 16:08:43 jehousley Exp $
-.\"
-.TH libssh2_sftp_last_error 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_last_error - return the last SFTP-specific error code
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-unsigned long 
-libssh2_sftp_last_error(LIBSSH2_SFTP *sftp);
-
-.SH DESCRIPTION
-\fIsftp\fP - SFTP instance as returned by 
-.BR libssh2_sftp_init(3)
-
-Determines the last error code produced by the SFTP layer.
-
-.SH RETURN VALUE
-Current error code state of the SFTP instance.
-
-.SH SEE ALSO
-.BR libssh2_sftp_init(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_mkdir_ex.3 b/libssh2/share/man/man3/libssh2_sftp_mkdir_ex.3
deleted file mode 100644 (file)
index b0936f0..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-.\" $Id: libssh2_sftp_mkdir_ex.3,v 1.6 2007/06/13 16:41:33 jehousley Exp $
-.\"
-.TH libssh2_sftp_mkdir_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_mkdir_ex - create a directory on the remote file system
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-int 
-libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, long mode);
-
-int 
-libssh2_sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, long mode);
-
-.SH DESCRIPTION
-\fIsftp\fP - SFTP instance as returned by 
-.BR libssh2_sftp_init(3)
-
-\fIpath\fP - full path of the new directory to create. Note that the new 
-directory's parents must all exist priot to making this call.
-
-\fIpath_len\fP - length of the full path of the new directory to create.
-
-\fImode\fP - directory creation mode (e.g. 0755).
-
-Create a directory on the remote file system.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
-
-\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was 
-received on the socket, or an SFTP operation caused an errorcode to be 
-returned by the server.
-
-.SH SEE ALSO
-.BR libssh2_sftp_opendir(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_open_ex.3 b/libssh2/share/man/man3/libssh2_sftp_open_ex.3
deleted file mode 100644 (file)
index e70c275..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-.\" $Id: libssh2_sftp_open_ex.3,v 1.8 2007/06/13 16:41:33 jehousley Exp $
-.\"
-.TH libssh2_sftp_open_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_open - 
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-LIBSSH2_SFTP_HANDLE *
-libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, const char *filename, unsigned int filename_len, unsigned long flags, long mode, int open_type);
-
-LIBSSH2_SFTP_HANDLE *
-libssh2_sftp_open(LIBSSH2_SFTP *sftp, const char *filename, unsigned long flags, long mode);
-
-LIBSSH2_SFTP_HANDLE *
-libssh2_sftp_opendir(LIBSSH2_SFTP *sftp, const char *path);
-
-.SH DESCRIPTION
-\fIsftp\fP - SFTP instance as returned by 
-.BR libssh2_sftp_init(3)
-
-\fIfilename\fP - Remote file/directory resource to open 
-
-\fIfilename_len\fP - Length of filename 
-
-\fIflags\fP - Any (reasonable) combination of the LIBSSH2_FXF_* constants
-corresponding fopen modes.
-
-\fImode\fP - POSIX file permissions to assign if the file is being newly
-created.
-
-\fIopen_type\fP - Either of LIBSSH2_SFTP_OPENFILE (to open a file) or
-LIBSSH2_SFTP_OPENDIR (to open a directory).
-.SH RETURN VALUE
-A pointer to the newly created LIBSSH2_SFTP_HANDLE instance or NULL on
-failure.
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
-
-\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was 
-received on the socket, or an SFTP operation caused an errorcode to be 
-returned by the server.
-
-\fILIBSSH2_ERROR_EAGAIN\fP - Marked for non-blocking I/O but the call would block.
-
-.SH SEE ALSO
-.BR libssh_sftp_close(3)
-
diff --git a/libssh2/share/man/man3/libssh2_sftp_read.3 b/libssh2/share/man/man3/libssh2_sftp_read.3
deleted file mode 100644 (file)
index 15d7473..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-.\" $Id: libssh2_sftp_read.3,v 1.8 2007/06/13 16:41:33 jehousley Exp $
-.\"
-.TH libssh2_sftp_read 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_read - read data from an SFTP handle
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-ssize_t 
-libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen);
-
-.SH DESCRIPTION
-\fIhandle\fP is the SFTP File Handle as returned by 
-.BR libssh2_sftp_open(3)
-
-\fIbuffer\fP is a pointer to a pre-allocated buffer of at least
-
-\fIbuffer_maxlen\fP bytes to read data into.
-
-Reads a block of data from an LIBSSH2_SFTP_HANDLE. This method is modelled
-after the POSIX 
-.BR read(2)
-function and uses the same calling semantics. 
-.BR libssh2_sftp_read(3)
-will attempt to read as much as possible however it may not fill all of 
-buffer if the file pointer reaches the end or
-if further reads would cause the socket to block.
-
-.SH RETURN VALUE
-Number of bytes actually populated into buffer, or negative on failure.  
-It returns LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
-
-\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was 
-received on the socket, or an SFTP operation caused an errorcode to be 
-returned by the server.
-
-.SH SEE ALSO
-.BR libssh2_sftp_open(3)
-.BR libssh2_sftp_readnb(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_readdir.3 b/libssh2/share/man/man3/libssh2_sftp_readdir.3
deleted file mode 100644 (file)
index b85c4cb..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-.\" $Id: libssh2_sftp_readdir.3,v 1.11 2007/07/04 10:44:40 jehousley Exp $
-.\"
-.TH libssh2_sftp_readdir_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_readdir_ex - read directory data from an SFTP handle
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-int 
-libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, char *longentry, size_t longentry_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs);
-
-int 
-libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs);
-
-.SH DESCRIPTION
-\fIhandle\fP - is the SFTP File Handle as returned by 
-.BR libssh2_sftp_diropen(3)
-
-\fIbuffer\fP - is a pointer to a pre-allocated buffer of at least
-\fIbuffer_maxlen\fP bytes to read data into.
-
-\fIbuffer_maxlen\fP - is the length of buffer in bytes. If the length of the 
-filename is longer than the space provided by buffer_maxlen it will be 
-truncated to fit.
-
-\fIlongentry\fP - is a pointer to a pre-allocated buffer of at least
-\fIlongentry_maxlen\fP bytes to read data into.
-
-\fIlongentry_maxlen\fP - is the length of longentry in bytes. If the length 
-of the full directory entry is longer than the space provided by 
-longentry_maxlen it will be truncated to fit.
-
-\fIattrs\fP - is a pointer to LIBSSH2_SFTP_ATTRIBUTES storage to populate 
-statbuf style data into.
-
-Read a block of data from a LIBSSH2_SFTP_HANDLE. This method is modeled 
-after the POSIX 
-.BR readdir(2)
-however, it uses a variable sized directory entry (filename) buffer and 
-returns statbuf type data in the same call.
-
-.SH RETURN VALUE
-Number of bytes actually populated into buffer, or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
-
-\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was 
-received on the socket, or an SFTP operation caused an errorcode to be 
-returned by the server.
-
-.SH SEE ALSO
-.BR libssh2_sftp_opendir(3)
-.BR libssh2_sftp_closedir(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_rename_ex.3 b/libssh2/share/man/man3/libssh2_sftp_rename_ex.3
deleted file mode 100644 (file)
index 4277e48..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-.\" $Id: libssh2_sftp_rename_ex.3,v 1.1 2007/06/14 16:08:43 jehousley Exp $
-.\"
-.TH libssh2_sftp_rename_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_rename_ex - rename a file
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-int 
-libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, const char *source_filename, unsigned int source_filename_len, const char *dest_filename, unsigned int dest_filename_len, long flags);
-
-int 
-libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, const char *source_filename, const char *dest_filename);
-
-.SH DESCRIPTION
-\fIsftp\fP - SFTP instance as returned by 
-.BR libssh2_sftp_init(3)
-
-\fIsourcefile\fP - Path and name of the existing filesystem entry
-
-\fIsourcefile_len\fP - Length of the path and name of the existing 
-filesystem entry
-
-\fIdestfile\fP - Path and name of the target filesystem entry
-
-\fIdestfile_len\fP - Length of the path and name of the target 
-filesystem entry
-
-\fIflags\fP - 
-Bitmask flags made up of LIBSSH2_SFTP_RENAME_* constants.
-
-Rename a filesystem object on the remote filesystem. The semantics of 
-this command typically include the ability to move a filsystem object 
-between folders and/or filesystem mounts. If the LIBSSH2_SFTP_RENAME_OVERWRITE 
-flag is not set and the destfile entry already exists, the operation 
-will fail. Use of the other two flags indicate a preference (but not a 
-requirement) for the remote end to perform an atomic rename operation 
-and/or using native system calls when possible.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
-
-\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was 
-received on the socket, or an SFTP operation caused an errorcode to 
-be returned by the server.
-
-.SH SEE ALSO
-.BR libssh2_sftp_init(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_rmdir_ex.3 b/libssh2/share/man/man3/libssh2_sftp_rmdir_ex.3
deleted file mode 100644 (file)
index 5e5bf21..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-.\" $Id: libssh2_sftp_rmdir_ex.3,v 1.1 2007/06/14 16:08:43 jehousley Exp $
-.\"
-.TH libssh2_sftp_rmdir_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_rmdir_ex - rename a file
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-int 
-libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len);
-
-int 
-libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, const char *path);
-
-.SH DESCRIPTION
-\fIsftp\fP - SFTP instance as returned by 
-.BR libssh2_sftp_init(3)
-
-\fIsourcefile\fP - Full path of the existing directory to remove.
-
-\fIsourcefile_len\fP - Length of the full path of the existing directory to remove. 
-
-Remove a directory from the remote file system.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
-
-\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was 
-received on the socket, or an SFTP operation caused an errorcode to 
-be returned by the server.
-
-.SH SEE ALSO
-.BR libssh2_sftp_init(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_seek.3 b/libssh2/share/man/man3/libssh2_sftp_seek.3
deleted file mode 100644 (file)
index 62eaeb9..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-.\" $Id: libssh2_sftp_seek.3,v 1.1 2007/06/14 16:08:43 jehousley Exp $
-.\"
-.TH libssh2_sftp_seek 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_seek - set the read/write position indicator within a file
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-void 
-libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset);
-
-.SH DESCRIPTION
-\fIhandle\fP - SFTP File Handle as returned by 
-.BR libssh2_sftp_open(3)
-
-\fIoffset\fP - Number of bytes from the beginning of file to seek to.
-
-Move the file handle's internal pointer to an arbitrary location. 
-Note that libssh2 implements file pointers as a localized concept to make 
-file access appear more POSIX like. No packets are exchanged with the server 
-during a seek operation. The localized file pointer is simply used as a 
-convenience offset during read/write operations.
-
-.SH SEE ALSO
-.BR libssh2_sftp_open(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_shutdown.3 b/libssh2/share/man/man3/libssh2_sftp_shutdown.3
deleted file mode 100644 (file)
index 1a1defd..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-.\" $Id: libssh2_sftp_shutdown.3,v 1.1 2007/06/14 16:33:38 jehousley Exp $
-.\"
-.TH libssh2_sftp_shutdown 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_shutdown - shut down an SFTP session
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-int 
-libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp);
-
-.SH DESCRIPTION
-\fIsftp\fP - SFTP instance as returned by 
-.BR libssh2_sftp_init(3)
-
-Destroys a previously initialized SFTP session and frees all resources 
-associated with it.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH SEE ALSO
-.BR libssh2_sftp_init(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_stat_ex.3 b/libssh2/share/man/man3/libssh2_sftp_stat_ex.3
deleted file mode 100644 (file)
index cd96491..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-.\" $Id: libssh2_sftp_stat_ex.3,v 1.1 2007/06/14 16:33:38 jehousley Exp $
-.\"
-.TH libssh2_sftp_stat_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_stat_ex - rename a file
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-int 
-libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs);
-
-int 
-libssh2_sftp_stat(LIBSSH2_SFTP *sftp, const char *path, LIBSSH2_SFTP_ATTRIBUTES *attrs);
-
-int 
-libssh2_sftp_lstat(LIBSSH2_SFTP *sftp, const char *path, LIBSSH2_SFTP_ATTRIBUTES *attrs);
-
-int 
-libssh2_sftp_setstat(LIBSSH2_SFTP *sftp, const char *path, LIBSSH2_SFTP_ATTRIBUTES *attrs);
-
-.SH DESCRIPTION
-\fIsftp\fP - SFTP instance as returned by 
-.BR libssh2_sftp_init(3)
-
-\fIpath\fP - Remote filesystem object to stat/lstat/setstat.
-
-\fIpath_len\fP - Lenght of the name of the remote filesystem object 
-to stat/lstat/setstat.
-
-\fIstat_type\fP - One of the three constants specifying the type of 
-stat operation to perform.
-
-\fIattrs\fP - Pointer to attribute structure to set file metadata 
-from or into depending on the value of stat_type.
-
-Get or Set statbuf type data on a remote filesystem object. When 
-getting statbuf data, 
-.BR libssh2_sftp_stat(3)
-will follow all symlinks, while 
-.BR libssh2_sftp_lstat(3)
-will return data about the object encountered, even if that object 
-happens to be a symlink.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
-
-\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was 
-received on the socket, or an SFTP operation caused an errorcode to 
-be returned by the server.
-
-.SH SEE ALSO
-.BR libssh2_sftp_init(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_symlink_ex.3 b/libssh2/share/man/man3/libssh2_sftp_symlink_ex.3
deleted file mode 100644 (file)
index d5f5161..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-.\" $Id: libssh2_sftp_symlink_ex.3,v 1.1 2007/06/14 16:33:38 jehousley Exp $
-.\"
-.TH libssh2_sftp_symlink_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_symlink_ex - read or set a symbolic link
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-int 
-libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, char *target, unsigned int target_len, int link_type);
-
-int 
-libssh2_sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, char *target);
-
-int 
-libssh2_sftp_readlink(LIBSSH2_SFTP *sftp, const char *path, char *target, unsigned int target_len);
-
-int 
-libssh2_sftp_realpath(LIBSSH2_SFTP *sftp, const char *path, char *target, unsigned int target_len);
-
-.SH DESCRIPTION
-\fIsftp\fP - SFTP instance as returned by 
-.BR libssh2_sftp_init(3)
-
-\fIpath\fP - Remote filesystem object to create a symlink from or resolve.
-
-\fIpath_len\fP - Length of the name of the remote filesystem object to 
-create a symlink from or resolve.
-
-\fItarget\fP - 
-.br
-\fBLIBSSH2_SFTP_SYMLINK\fP: Remote filesystem object to link to.
-.br
-\fBLIBSSH2_SFTP_READLINK\fP: Pre-allocated buffer to resolve symlink target into.
-.br
-\fBLIBSSH2_SFTP_REALPATH\fP: Pre-allocated buffer to resolve realpath target into.
-
-\fItarget_len\fP - Length of the name of the remote filesystem target object.
-
-\fIlink_type\fP - One of the three previously mentioned constants which 
-determines the resulting behavior of this function.
-
-.BR libssh2_sftp_symlink(3)
-: Create a symbolic link between two filesystem objects.
-.br
-.BR libssh2_sftp_readlink(3)
-: Resolve a symbolic link filesystem object to its next target.
-.br
-.BR libssh2_sftp_realpath(3)
-: Resolve a complex, relative, or symlinked filepath to its effective target.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
-
-\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was 
-received on the socket, or an SFTP operation caused an errorcode to 
-be returned by the server.
-
-.SH SEE ALSO
-.BR libssh2_sftp_init(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_tell.3 b/libssh2/share/man/man3/libssh2_sftp_tell.3
deleted file mode 100644 (file)
index f21cba7..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-.\" $Id: libssh2_sftp_tell.3,v 1.1 2007/06/14 16:33:38 jehousley Exp $
-.\"
-.TH libssh2_sftp_tell 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_tell - get the current read/write position indicator for a file
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-size_t 
-libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle);
-
-.SH DESCRIPTION
-\fIhandle\fP - SFTP File Handle as returned by 
-.BR libssh2_sftp_open(3)
-
-Identify the current offset of the file handle's internal pointer. Note 
-that the SSH2 protocol does not have a notion of file pointers and that 
-libssh2 implements this using a localized file pointer which is updated 
-with each read/write call.
-
-.SH RETURN VALUE
-Current offset from beginning of file in bytes.
-
-.SH SEE ALSO
-.BR libssh2_sftp_open(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_unlink_ex.3 b/libssh2/share/man/man3/libssh2_sftp_unlink_ex.3
deleted file mode 100644 (file)
index 3f111c7..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-.\" $Id: libssh2_sftp_unlink_ex.3,v 1.1 2007/06/14 16:46:14 jehousley Exp $
-.\"
-.TH libssh2_sftp_unlink_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_unlink_ex - rename a file
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-int 
-libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, const char *filename, unsigned int filename_len);
-
-int 
-libssh2_sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename);
-
-.SH DESCRIPTION
-\fIsftp\fP - SFTP instance as returned by 
-.BR libssh2_sftp_init(3)
-
-\fIfilename\fP - Path and name of the existing filesystem entry
-
-\fIfilename_len\fP - Length of the path and name of the existing 
-filesystem entry
-
-Unlink (delete) a file from the remote filesystem.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
-
-\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was 
-received on the socket, or an SFTP operation caused an errorcode to 
-be returned by the server.
-
-.SH SEE ALSO
-.BR libssh2_sftp_init(3)
diff --git a/libssh2/share/man/man3/libssh2_sftp_write.3 b/libssh2/share/man/man3/libssh2_sftp_write.3
deleted file mode 100644 (file)
index 575a5e9..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-.\" $Id: libssh2_sftp_write.3,v 1.1 2007/06/14 16:46:14 jehousley Exp $
-.\"
-.TH libssh2_sftp_rename_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_sftp_rename_ex - rename a file
-.SH SYNOPSIS
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-ssize_t 
-libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, size_t count);
-
-.SH DESCRIPTION
-\fIhandle\fP - SFTP File Handle as returned by 
-.BR libssh2_sftp_open(3)
-
-\fIbuffer\fP - Pre-initialized data buffer to write to the LIBSSH2_SFTP_HANDLE.
-
-\fIcount\fP - Number of bytes from buffer to write. Note that it may not 
-be possible to write all bytes as requested.
-
-Write a block of data to a LIBSSH2_SFTP_HANDLE. This method is modeled after the POSIX write() function and uses the same calling semantics.
-
-.SH RETURN VALUE
-Actual number of bytes written or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
-
-\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response was 
-received on the socket, or an SFTP operation caused an errorcode to 
-be returned by the server.
-
-.SH SEE ALSO
-.BR libssh2_sftp_open(3)
diff --git a/libssh2/share/man/man3/libssh2_userauth_authenticated.3 b/libssh2/share/man/man3/libssh2_userauth_authenticated.3
deleted file mode 100644 (file)
index 4a9a10b..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-.\" $Id: libssh2_userauth_authenticated.3,v 1.1 2007/06/14 17:15:32 jehousley Exp $
-.\"
-.TH libssh2_userauth_authenticated 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_userauth_authenticated - return authentication status
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int 
-libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-Indicates whether or not the named session has been successfully authenticated.
-
-.SH RETURN VALUE
-Returns 1 if authenticated and 0 if not.
-
-.SH SEE ALSO
-.BR libssh2_session_init(3)
diff --git a/libssh2/share/man/man3/libssh2_userauth_list.3 b/libssh2/share/man/man3/libssh2_userauth_list.3
deleted file mode 100644 (file)
index 3ea3436..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-.\" $Id: libssh2_userauth_list.3,v 1.1 2007/06/14 17:15:32 jehousley Exp $
-.\"
-.TH libssh2_userauth_list 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_userauth_list - list the authentication methods supported by a server
-.SH SYNOPSIS
-#include <libssh2.h>
-
-char *
-libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fIusername\fP - Username which will be used while authenticating. Note 
-that most server implementations do not permit attempting authentication 
-with different usernames between requests. Therefore this must be the 
-same username you will use on later userauth calls.
-
-\fIusername_len\fP - Length of username parameter.
-
-Send a \fBSSH_USERAUTH_NONE\fP request to the remote host. Unless the 
-remote host is configured to accept none as a viable authentication 
-scheme (unlikely), it will return \fBSSH_USERAUTH_FAILURE\fB along with a 
-listing of what authentication schemes it does support. In the unlikely 
-event that none authentication succeeds, this method with return NULL. This 
-case may be distinguished from faily by examining 
-.BR libssh2_userauth_authenticated(3)
-
-.SH RETURN VALUE
-On success a comma delimited list of supported authentication schemes.  This list is 
-internally managed by libssh2.  On failure ruturns NULL.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_EAGAIN\fP - Marked for non-blocking I/O but the call
-
-.SH SEE ALSO
-.BR libssh2_session_init(3)
diff --git a/libssh2/share/man/man3/libssh2_userauth_password_ex.3 b/libssh2/share/man/man3/libssh2_userauth_password_ex.3
deleted file mode 100644 (file)
index 5b047e0..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-.\" $Id: libssh2_userauth_password_ex.3,v 1.1 2007/06/14 17:15:32 jehousley Exp $
-.\"
-.TH libssh2_userauth_password_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_userauth_password_ex - authenticate a session with username and password
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int
-libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len, const char *password, unsigned int password_len, LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)));
-
-int
-libssh2_userauth_password(LIBSSH2_SESSION *session, const char *username, const char *password);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fIusername\fP - Name of user to attempt plain password authentication for.
-
-\fIusername_len\fP - Length of username parameter.
-
-\fIpassword\fP - Password to use for authenticating username.
-
-\fIpassword_len\fP - Length of password parameter.
-
-\fIpasswd_change_cb\fP - If the host accepts authentication but 
-requests that the password be changed, this callback will be issued. 
-If no callback is defined, but server required password change, 
-authentication will fail.
-
-Attempt basic password authentication. Note that many SSH servers 
-which appear to support ordinary password authentication actually have 
-it disabled and use Keyboard Interactive authentication (routed via 
-PAM or another authentication backed) instead.
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_PASSWORD_EXPIRED\fP - 
-
-.SH SEE ALSO
-.BR libssh2_session_init(3)
diff --git a/libssh2/share/man/man3/libssh2_userauth_publickey_fromfile.3 b/libssh2/share/man/man3/libssh2_userauth_publickey_fromfile.3
deleted file mode 100644 (file)
index 041aada..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-.\" $Id: libssh2_userauth_publickey_fromfile.3,v 1.1 2007/06/14 17:15:32 jehousley Exp $
-.\"
-.TH libssh2_userauth_publickey_fromfile 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
-.SH NAME
-libssh2_userauth_publickey_fromfile - authenticate a session with a public key, read from a file
-.SH SYNOPSIS
-#include <libssh2.h>
-
-int
-libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len, const char *publickey, const char *privatekey, const char *passphrase);
-
-int
-libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, const char *publickey, const char *privatekey, const char *passphrase);
-
-.SH DESCRIPTION
-\fIsession\fP - Session instance as returned by 
-.BR libssh2_session_init(3)
-
-\fIusername\fP - Remote user name to authenticate as.
-
-\fIusername_len\fP - Length of username.
-
-\fIpublickey\fP - Path and name of public key file. (e.g. /etc/ssh/hostkey.pub)
-
-\fIprivatekey\fP - Path and name of private key file. (e.g. /etc/ssh/hostkey)
-
-\fIpassphrase\fP - Passphrase to use when decoding private key file.
-
-Attempt public key authentication using a PEM encoded private key file stored on disk
-
-.SH RETURN VALUE
-Return 0 on success or negative on failure.  It returns
-LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
-LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
-
-.SH ERRORS
-\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
-
-\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
-
-\fILIBSSH2_ERROR_SOCKET_TIMEOUT\fP - 
-
-\fILIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED\fP - >The username/public key 
-combination was invalid.
-
-\fILIBSSH2_ERROR_PUBLICKEY_UNVERIFIED\fP - The username/public key 
-combination was invalid, or the signature for the supplied public 
-key was invalid.
-
-.SH SEE ALSO
-.BR libssh2_session_init(3)