]> Joshua Wise's Git repositories - dumload.git/commitdiff
Initial commit.
authorJoshua Wise <jwise@andrew.cmu.edu>
Sat, 7 Aug 2010 06:11:29 +0000 (02:11 -0400)
committerJoshua Wise <jwise@andrew.cmu.edu>
Sat, 7 Aug 2010 06:11:29 +0000 (02:11 -0400)
131 files changed:
.classpath [new file with mode: 0644]
.project [new file with mode: 0644]
AndroidManifest.xml [new file with mode: 0644]
build.xml [new file with mode: 0644]
default.properties [new file with mode: 0644]
local.properties [new file with mode: 0644]
res/drawable-hdpi/icon.png [new file with mode: 0644]
res/drawable-ldpi/icon.png [new file with mode: 0644]
res/drawable-mdpi/icon.png [new file with mode: 0644]
res/layout/main.xml [new file with mode: 0644]
res/layout/passwd.xml [new file with mode: 0644]
res/values/strings.xml [new file with mode: 0644]
src/com/jcraft/jsch/Buffer.java [new file with mode: 0644]
src/com/jcraft/jsch/Channel.java [new file with mode: 0644]
src/com/jcraft/jsch/ChannelAgentForwarding.java [new file with mode: 0644]
src/com/jcraft/jsch/ChannelDirectTCPIP.java [new file with mode: 0644]
src/com/jcraft/jsch/ChannelExec.java [new file with mode: 0644]
src/com/jcraft/jsch/ChannelForwardedTCPIP.java [new file with mode: 0644]
src/com/jcraft/jsch/ChannelSession.java [new file with mode: 0644]
src/com/jcraft/jsch/ChannelSftp.java [new file with mode: 0644]
src/com/jcraft/jsch/ChannelShell.java [new file with mode: 0644]
src/com/jcraft/jsch/ChannelSubsystem.java [new file with mode: 0644]
src/com/jcraft/jsch/ChannelX11.java [new file with mode: 0644]
src/com/jcraft/jsch/Cipher.java [new file with mode: 0644]
src/com/jcraft/jsch/CipherNone.java [new file with mode: 0644]
src/com/jcraft/jsch/Compression.java [new file with mode: 0644]
src/com/jcraft/jsch/DH.java [new file with mode: 0644]
src/com/jcraft/jsch/DHG1.java [new file with mode: 0644]
src/com/jcraft/jsch/DHGEX.java [new file with mode: 0644]
src/com/jcraft/jsch/ForwardedTCPIPDaemon.java [new file with mode: 0644]
src/com/jcraft/jsch/GSSContext.java [new file with mode: 0644]
src/com/jcraft/jsch/HASH.java [new file with mode: 0644]
src/com/jcraft/jsch/HostKey.java [new file with mode: 0644]
src/com/jcraft/jsch/HostKeyRepository.java [new file with mode: 0644]
src/com/jcraft/jsch/IO.java [new file with mode: 0644]
src/com/jcraft/jsch/Identity.java [new file with mode: 0644]
src/com/jcraft/jsch/IdentityFile.java [new file with mode: 0644]
src/com/jcraft/jsch/JSch.java [new file with mode: 0644]
src/com/jcraft/jsch/JSchAuthCancelException.java [new file with mode: 0644]
src/com/jcraft/jsch/JSchException.java [new file with mode: 0644]
src/com/jcraft/jsch/JSchPartialAuthException.java [new file with mode: 0644]
src/com/jcraft/jsch/KeyExchange.java [new file with mode: 0644]
src/com/jcraft/jsch/KeyPair.java [new file with mode: 0644]
src/com/jcraft/jsch/KeyPairDSA.java [new file with mode: 0644]
src/com/jcraft/jsch/KeyPairGenDSA.java [new file with mode: 0644]
src/com/jcraft/jsch/KeyPairGenRSA.java [new file with mode: 0644]
src/com/jcraft/jsch/KeyPairRSA.java [new file with mode: 0644]
src/com/jcraft/jsch/KnownHosts.java [new file with mode: 0644]
src/com/jcraft/jsch/Logger.java [new file with mode: 0644]
src/com/jcraft/jsch/MAC.java [new file with mode: 0644]
src/com/jcraft/jsch/Packet.java [new file with mode: 0644]
src/com/jcraft/jsch/PortWatcher.java [new file with mode: 0644]
src/com/jcraft/jsch/Proxy.java [new file with mode: 0644]
src/com/jcraft/jsch/ProxyHTTP.java [new file with mode: 0644]
src/com/jcraft/jsch/ProxySOCKS4.java [new file with mode: 0644]
src/com/jcraft/jsch/ProxySOCKS5.java [new file with mode: 0644]
src/com/jcraft/jsch/Random.java [new file with mode: 0644]
src/com/jcraft/jsch/Request.java [new file with mode: 0644]
src/com/jcraft/jsch/RequestAgentForwarding.java [new file with mode: 0644]
src/com/jcraft/jsch/RequestEnv.java [new file with mode: 0644]
src/com/jcraft/jsch/RequestExec.java [new file with mode: 0644]
src/com/jcraft/jsch/RequestPtyReq.java [new file with mode: 0644]
src/com/jcraft/jsch/RequestSftp.java [new file with mode: 0644]
src/com/jcraft/jsch/RequestShell.java [new file with mode: 0644]
src/com/jcraft/jsch/RequestSignal.java [new file with mode: 0644]
src/com/jcraft/jsch/RequestSubsystem.java [new file with mode: 0644]
src/com/jcraft/jsch/RequestWindowChange.java [new file with mode: 0644]
src/com/jcraft/jsch/RequestX11.java [new file with mode: 0644]
src/com/jcraft/jsch/ServerSocketFactory.java [new file with mode: 0644]
src/com/jcraft/jsch/Session.java [new file with mode: 0644]
src/com/jcraft/jsch/SftpATTRS.java [new file with mode: 0644]
src/com/jcraft/jsch/SftpException.java [new file with mode: 0644]
src/com/jcraft/jsch/SftpProgressMonitor.java [new file with mode: 0644]
src/com/jcraft/jsch/SignatureDSA.java [new file with mode: 0644]
src/com/jcraft/jsch/SignatureRSA.java [new file with mode: 0644]
src/com/jcraft/jsch/SocketFactory.java [new file with mode: 0644]
src/com/jcraft/jsch/UIKeyboardInteractive.java [new file with mode: 0644]
src/com/jcraft/jsch/UserAuth.java [new file with mode: 0644]
src/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java [new file with mode: 0644]
src/com/jcraft/jsch/UserAuthKeyboardInteractive.java [new file with mode: 0644]
src/com/jcraft/jsch/UserAuthNone.java [new file with mode: 0644]
src/com/jcraft/jsch/UserAuthPassword.java [new file with mode: 0644]
src/com/jcraft/jsch/UserAuthPublicKey.java [new file with mode: 0644]
src/com/jcraft/jsch/UserInfo.java [new file with mode: 0644]
src/com/jcraft/jsch/Util.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/AES128CBC.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/AES128CTR.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/AES192CBC.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/AES192CTR.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/AES256CBC.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/AES256CTR.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/ARCFOUR.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/ARCFOUR128.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/ARCFOUR256.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/BlowfishCBC.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/DH.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/HMACMD5.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/HMACMD596.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/HMACSHA1.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/HMACSHA196.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/KeyPairGenDSA.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/KeyPairGenRSA.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/MD5.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/Random.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/SHA1.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/SignatureDSA.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/SignatureRSA.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/TripleDESCBC.java [new file with mode: 0644]
src/com/jcraft/jsch/jce/TripleDESCTR.java [new file with mode: 0644]
src/com/jcraft/jsch/jcraft/Compression.java [new file with mode: 0644]
src/com/jcraft/jsch/jcraft/HMAC.java [new file with mode: 0644]
src/com/jcraft/jsch/jcraft/HMACMD5.java [new file with mode: 0644]
src/com/jcraft/jsch/jcraft/HMACMD596.java [new file with mode: 0644]
src/com/jcraft/jsch/jcraft/HMACSHA1.java [new file with mode: 0644]
src/com/jcraft/jsch/jcraft/HMACSHA196.java [new file with mode: 0644]
src/com/jcraft/jzlib/Adler32.java [new file with mode: 0644]
src/com/jcraft/jzlib/Deflate.java [new file with mode: 0644]
src/com/jcraft/jzlib/InfBlocks.java [new file with mode: 0644]
src/com/jcraft/jzlib/InfCodes.java [new file with mode: 0644]
src/com/jcraft/jzlib/InfTree.java [new file with mode: 0644]
src/com/jcraft/jzlib/Inflate.java [new file with mode: 0644]
src/com/jcraft/jzlib/JZlib.java [new file with mode: 0644]
src/com/jcraft/jzlib/StaticTree.java [new file with mode: 0644]
src/com/jcraft/jzlib/Tree.java [new file with mode: 0644]
src/com/jcraft/jzlib/ZInputStream.java [new file with mode: 0644]
src/com/jcraft/jzlib/ZOutputStream.java [new file with mode: 0644]
src/com/jcraft/jzlib/ZStream.java [new file with mode: 0644]
src/com/jcraft/jzlib/ZStreamException.java [new file with mode: 0644]
src/com/joshuawise/dumload/Dumload.java [new file with mode: 0644]
src/com/joshuawise/dumload/NotifSlave.java [new file with mode: 0644]
src/com/joshuawise/dumload/Uploader.java [new file with mode: 0644]

diff --git a/.classpath b/.classpath
new file mode 100644 (file)
index 0000000..609aa00
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="src" path="gen"/>
+       <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/.project b/.project
new file mode 100644 (file)
index 0000000..f1d11b4
--- /dev/null
+++ b/.project
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>dumload</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>com.android.ide.eclipse.adt.ApkBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..b24610e
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.joshuawise.dumload"
+      android:versionCode="1"
+      android:versionName="1.0">
+    <application android:icon="@drawable/icon" android:label="Dumload">
+        <activity android:name=".Dumload"
+                  android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            
+
+</intent-filter>
+        <intent-filter><action android:name="android.intent.action.SEND"></action>
+        <category android:name="android.intent.category.DEFAULT" />
+<data android:mimeType="image/jpeg"></data>
+</intent-filter>
+</activity>
+
+<service android:name=".Uploader"><intent-filter><action android:name="com.joshuawise.dumload.Uploader" /></intent-filter></service>
+<activity android:name=".NotifSlave"><intent-filter><action android:name="com.joshuawise.dumload.NotifSlave" /></intent-filter></activity>
+    </application>
+
+
+
+<uses-permission android:name="android.permission.INTERNET"></uses-permission>
+<uses-permission android:name="android.permission.STATUS_BAR"></uses-permission>
+<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
+</manifest> 
\ No newline at end of file
diff --git a/build.xml b/build.xml
new file mode 100644 (file)
index 0000000..7ea4a86
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Dumload" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked in in Version
+         Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The build.properties file can be created by you and is never touched
+         by the 'android' tool. This is the place to change some of the default property values
+         used by the Ant rules.
+         Here are some properties you may want to change/update:
+
+         application.package
+             the name of your application package as defined in the manifest. Used by the
+             'uninstall' rule.
+         source.dir
+             the name of the source directory. Default is 'src'.
+         out.dir
+             the name of the output directory. Default is 'bin'.
+
+         Properties related to the SDK location or the project target should be updated
+          using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your application and
+         should be checked in in Version Control Systems.
+
+         -->
+    <property file="build.properties" />
+
+    <!-- The default.properties file is created and updated by the 'android' tool, as well
+         as ADT.
+         This file is an integral part of the build system for your application and
+         should be checked in in Version Control Systems. -->
+    <property file="default.properties" />
+
+    <!-- Custom Android task to deal with the project target, and import the proper rules.
+         This requires ant 1.6.0 or above. -->
+    <path id="android.antlibs">
+        <pathelement path="${sdk.dir}/tools/lib/anttasks.jar" />
+        <pathelement path="${sdk.dir}/tools/lib/sdklib.jar" />
+        <pathelement path="${sdk.dir}/tools/lib/androidprefs.jar" />
+        <pathelement path="${sdk.dir}/tools/lib/apkbuilder.jar" />
+        <pathelement path="${sdk.dir}/tools/lib/jarutils.jar" />
+    </path>
+
+    <taskdef name="setup"
+        classname="com.android.ant.SetupTask"
+        classpathref="android.antlibs" />
+
+    <!-- Execute the Android Setup task that will setup some properties specific to the target,
+         and import the build rules files.
+
+         The rules file is imported from
+            <SDK>/platforms/<target_platform>/templates/android_rules.xml
+
+         To customize some build steps for your project:
+         - copy the content of the main node <project> from android_rules.xml
+         - paste it in this build.xml below the <setup /> task.
+         - disable the import by changing the setup task below to <setup import="false" />
+
+         This will ensure that the properties are setup correctly but that your customized
+         build steps are used.
+    -->
+    <setup />
+
+</project>
diff --git a/default.properties b/default.properties
new file mode 100644 (file)
index 0000000..9d135cb
--- /dev/null
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+# 
+# This file must be checked in Version Control Systems.
+# 
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-7
diff --git a/local.properties b/local.properties
new file mode 100644 (file)
index 0000000..57f202f
--- /dev/null
@@ -0,0 +1,10 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+# 
+# This file must *NOT* be checked in Version Control Systems,
+# as it contains information specific to your local configuration.
+
+# location of the SDK. This is only used by Ant
+# For customization when using a Version Control System, please read the
+# header note.
+sdk.dir=/Users/joshua/android/android-sdk-mac_86
diff --git a/res/drawable-hdpi/icon.png b/res/drawable-hdpi/icon.png
new file mode 100644 (file)
index 0000000..8074c4c
Binary files /dev/null and b/res/drawable-hdpi/icon.png differ
diff --git a/res/drawable-ldpi/icon.png b/res/drawable-ldpi/icon.png
new file mode 100644 (file)
index 0000000..1095584
Binary files /dev/null and b/res/drawable-ldpi/icon.png differ
diff --git a/res/drawable-mdpi/icon.png b/res/drawable-mdpi/icon.png
new file mode 100644 (file)
index 0000000..a07c69f
Binary files /dev/null and b/res/drawable-mdpi/icon.png differ
diff --git a/res/layout/main.xml b/res/layout/main.xml
new file mode 100644 (file)
index 0000000..da4f82e
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    >
+<TextView  
+    android:id="@+id/suckit"
+    android:layout_width="fill_parent" 
+    android:layout_height="wrap_content" 
+    android:text="@string/hello"
+    />
+</LinearLayout>
diff --git a/res/layout/passwd.xml b/res/layout/passwd.xml
new file mode 100644 (file)
index 0000000..f475e8d
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:padding="10dp"
+    >
+<TextView  
+    android:id="@+id/prompt"
+    android:layout_width="fill_parent" 
+    android:layout_height="wrap_content" 
+    />
+<EditText
+    android:id="@+id/entry"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:background="@android:drawable/editbox_background"
+    android:password="true"
+    />
+<LinearLayout
+    android:orientation="horizontal"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    >
+<Button
+    android:id="@+id/ok"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:text="OK"
+    />
+<Button
+    android:id="@+id/cancel"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:text="Cancel"
+    />
+</LinearLayout>
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
new file mode 100644 (file)
index 0000000..4606407
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="hello">Hello World, Dumload!</string>
+    <string name="app_name">dumload</string>
+</resources>
diff --git a/src/com/jcraft/jsch/Buffer.java b/src/com/jcraft/jsch/Buffer.java
new file mode 100644 (file)
index 0000000..1393a12
--- /dev/null
@@ -0,0 +1,243 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public class Buffer{
+  final byte[] tmp=new byte[4];
+  byte[] buffer;
+  int index;
+  int s;
+  public Buffer(int size){
+    buffer=new byte[size];
+    index=0;
+    s=0;
+  }
+  public Buffer(byte[] buffer){
+    this.buffer=buffer;
+    index=0;
+    s=0;
+  }
+  public Buffer(){ this(1024*10*2); }
+  public void putByte(byte foo){
+    buffer[index++]=foo;
+  }
+  public void putByte(byte[] foo) {
+    putByte(foo, 0, foo.length);
+  }
+  public void putByte(byte[] foo, int begin, int length) {
+    System.arraycopy(foo, begin, buffer, index, length);
+    index+=length;
+  }
+  public void putString(byte[] foo){
+    putString(foo, 0, foo.length);
+  }
+  public void putString(byte[] foo, int begin, int length) {
+    putInt(length);
+    putByte(foo, begin, length);
+  }
+  public void putInt(int val) {
+    tmp[0]=(byte)(val >>> 24);
+    tmp[1]=(byte)(val >>> 16);
+    tmp[2]=(byte)(val >>> 8);
+    tmp[3]=(byte)(val);
+    System.arraycopy(tmp, 0, buffer, index, 4);
+    index+=4;
+  }
+  public void putLong(long val) {
+    tmp[0]=(byte)(val >>> 56);
+    tmp[1]=(byte)(val >>> 48);
+    tmp[2]=(byte)(val >>> 40);
+    tmp[3]=(byte)(val >>> 32);
+    System.arraycopy(tmp, 0, buffer, index, 4);
+    tmp[0]=(byte)(val >>> 24);
+    tmp[1]=(byte)(val >>> 16);
+    tmp[2]=(byte)(val >>> 8);
+    tmp[3]=(byte)(val);
+    System.arraycopy(tmp, 0, buffer, index+4, 4);
+    index+=8;
+  }
+  void skip(int n) {
+    index+=n;
+  }
+  void putPad(int n) {
+    while(n>0){
+      buffer[index++]=(byte)0;
+      n--;
+    }
+  }
+  public void putMPInt(byte[] foo){
+    int i=foo.length;
+    if((foo[0]&0x80)!=0){
+      i++;
+      putInt(i);
+      putByte((byte)0);
+    }
+    else{
+      putInt(i);
+    }
+    putByte(foo);
+  }
+  public int getLength(){
+    return index-s;
+  }
+  public int getOffSet(){
+    return s;
+  }
+  public void setOffSet(int s){
+    this.s=s;
+  }
+  public long getLong(){
+    long foo = getInt()&0xffffffffL;
+    foo = ((foo<<32)) | (getInt()&0xffffffffL);
+    return foo;
+  }
+  public int getInt(){
+    int foo = getShort();
+    foo = ((foo<<16)&0xffff0000) | (getShort()&0xffff);
+    return foo;
+  }
+  public long getUInt(){
+    long foo = 0L;
+    long bar = 0L;
+    foo = getByte();
+    foo = ((foo<<8)&0xff00)|(getByte()&0xff);
+    bar = getByte();
+    bar = ((bar<<8)&0xff00)|(getByte()&0xff);
+    foo = ((foo<<16)&0xffff0000) | (bar&0xffff);
+    return foo;
+  }
+  int getShort() {
+    int foo = getByte();
+    foo = ((foo<<8)&0xff00)|(getByte()&0xff);
+    return foo;
+  }
+  public int getByte() {
+    return (buffer[s++]&0xff);
+  }
+  public void getByte(byte[] foo) {
+    getByte(foo, 0, foo.length);
+  }
+  void getByte(byte[] foo, int start, int len) {
+    System.arraycopy(buffer, s, foo, start, len); 
+    s+=len;
+  }
+  public int getByte(int len) {
+    int foo=s;
+    s+=len;
+    return foo;
+  }
+  public byte[] getMPInt() {
+    int i=getInt();
+    byte[] foo=new byte[i];
+    getByte(foo, 0, i);
+    return foo;
+  }
+  public byte[] getMPIntBits() {
+    int bits=getInt();
+    int bytes=(bits+7)/8;
+    byte[] foo=new byte[bytes];
+    getByte(foo, 0, bytes);
+    if((foo[0]&0x80)!=0){
+      byte[] bar=new byte[foo.length+1];
+      bar[0]=0; // ??
+      System.arraycopy(foo, 0, bar, 1, foo.length);
+      foo=bar;
+    }
+    return foo;
+  }
+  public byte[] getString() {
+    int i = getInt();  // uint32
+    /*
+    if(i<0 ||  // bigger than 0x7fffffff
+       s+i>index){
+      //throw new java.io.IOException("invalid string length: "+(((long)i)&0xffffffffL));
+      i = index-s; // the session will be broken, but working around OOME.
+    }
+    */
+    byte[] foo=new byte[i];
+    getByte(foo, 0, i);
+    return foo;
+  }
+  byte[] getString(int[]start, int[]len) {
+    int i=getInt();
+    start[0]=getByte(i);
+    len[0]=i;
+    return buffer;
+  }
+  public void reset(){
+    index=0;
+    s=0;
+  }
+  public void shift(){
+    if(s==0)return;
+    System.arraycopy(buffer, s, buffer, 0, index-s);
+    index=index-s;
+    s=0;
+  }
+  void rewind(){
+    s=0;
+  }
+
+  byte getCommand(){
+    return buffer[5];
+  }
+
+/*
+  static String[] chars={
+    "0","1","2","3","4","5","6","7","8","9", "a","b","c","d","e","f"
+  };
+  static void dump_buffer(){
+    int foo;
+    for(int i=0; i<tmp_buffer_index; i++){
+        foo=tmp_buffer[i]&0xff;
+       System.err.print(chars[(foo>>>4)&0xf]);
+       System.err.print(chars[foo&0xf]);
+        if(i%16==15){
+          System.err.println("");
+         continue;
+       }
+        if(i>0 && i%2==1){
+          System.err.print(" ");
+       }
+    }
+    System.err.println("");
+  }
+  static void dump(byte[] b){
+    dump(b, 0, b.length);
+  }
+  static void dump(byte[] b, int s, int l){
+    for(int i=s; i<s+l; i++){
+      System.err.print(Integer.toHexString(b[i]&0xff)+":");
+    }
+    System.err.println("");
+  }
+*/
+
+}
diff --git a/src/com/jcraft/jsch/Channel.java b/src/com/jcraft/jsch/Channel.java
new file mode 100644 (file)
index 0000000..0e58bcf
--- /dev/null
@@ -0,0 +1,641 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+
+public abstract class Channel implements Runnable{
+
+  static final int SSH_MSG_CHANNEL_OPEN_CONFIRMATION=      91;
+  static final int SSH_MSG_CHANNEL_OPEN_FAILURE=           92;
+  static final int SSH_MSG_CHANNEL_WINDOW_ADJUST=          93;
+
+  static final int SSH_OPEN_ADMINISTRATIVELY_PROHIBITED=    1;
+  static final int SSH_OPEN_CONNECT_FAILED=                 2;
+  static final int SSH_OPEN_UNKNOWN_CHANNEL_TYPE=           3;
+  static final int SSH_OPEN_RESOURCE_SHORTAGE=              4;
+
+  static int index=0; 
+  private static java.util.Vector pool=new java.util.Vector();
+  static Channel getChannel(String type){
+    if(type.equals("session")){
+      return new ChannelSession();
+    }
+    if(type.equals("shell")){
+      return new ChannelShell();
+    }
+    if(type.equals("exec")){
+      return new ChannelExec();
+    }
+    if(type.equals("x11")){
+      return new ChannelX11();
+    }
+    if(type.equals("auth-agent@openssh.com")){
+      return new ChannelAgentForwarding();
+    }
+    if(type.equals("direct-tcpip")){
+      return new ChannelDirectTCPIP();
+    }
+    if(type.equals("forwarded-tcpip")){
+      return new ChannelForwardedTCPIP();
+    }
+    if(type.equals("sftp")){
+      return new ChannelSftp();
+    }
+    if(type.equals("subsystem")){
+      return new ChannelSubsystem();
+    }
+    return null;
+  }
+  static Channel getChannel(int id, Session session){
+    synchronized(pool){
+      for(int i=0; i<pool.size(); i++){
+        Channel c=(Channel)(pool.elementAt(i));
+        if(c.id==id && c.session==session) return c;
+      }
+    }
+    return null;
+  }
+  static void del(Channel c){
+    synchronized(pool){
+      pool.removeElement(c);
+    }
+  }
+
+  int id;
+  int recipient=-1;
+  byte[] type=Util.str2byte("foo");
+  int lwsize_max=0x100000;
+//int lwsize_max=0x20000;  // 32*1024*4
+  int lwsize=lwsize_max;  // local initial window size
+  int lmpsize=0x4000;     // local maximum packet size
+//int lmpsize=0x8000;     // local maximum packet size
+
+  long rwsize=0;         // remote initial window size
+  int rmpsize=0;        // remote maximum packet size
+
+  IO io=null;    
+  Thread thread=null;
+
+  boolean eof_local=false;
+  boolean eof_remote=false;
+
+  boolean close=false;
+  boolean connected=false;
+
+  int exitstatus=-1;
+
+  int reply=0; 
+  int connectTimeout=0;
+
+  private Session session;
+
+  int notifyme=0; 
+
+  Channel(){
+    synchronized(pool){
+      id=index++;
+      pool.addElement(this);
+    }
+  }
+  void setRecipient(int foo){
+    this.recipient=foo;
+  }
+  int getRecipient(){
+    return recipient;
+  }
+
+  void init() throws JSchException {
+  }
+
+  public void connect() throws JSchException{
+    connect(0);
+  }
+
+  public void connect(int connectTimeout) throws JSchException{
+    Session _session=getSession();
+    if(!_session.isConnected()){
+      throw new JSchException("session is down");
+    }
+    this.connectTimeout=connectTimeout;
+    try{
+      Buffer buf=new Buffer(100);
+      Packet packet=new Packet(buf);
+      // send
+      // byte   SSH_MSG_CHANNEL_OPEN(90)
+      // string channel type         //
+      // uint32 sender channel       // 0
+      // uint32 initial window size  // 0x100000(65536)
+      // uint32 maxmum packet size   // 0x4000(16384)
+      packet.reset();
+      buf.putByte((byte)90);
+      buf.putString(this.type);
+      buf.putInt(this.id);
+      buf.putInt(this.lwsize);
+      buf.putInt(this.lmpsize);
+      _session.write(packet);
+      int retry=1000;
+      long start=System.currentTimeMillis();
+      long timeout=connectTimeout;
+      while(this.getRecipient()==-1 &&
+           _session.isConnected() &&
+           retry>0){
+        if(timeout>0L){
+          if((System.currentTimeMillis()-start)>timeout){
+            retry=0;
+            continue;
+          }
+        }
+       try{Thread.sleep(50);}catch(Exception ee){}
+       retry--;
+      }
+      if(!_session.isConnected()){
+       throw new JSchException("session is down");
+      }
+      if(retry==0){
+        throw new JSchException("channel is not opened.");
+      }
+
+      /*
+       * At the failure in opening the channel on the sshd, 
+       * 'SSH_MSG_CHANNEL_OPEN_FAILURE' will be sent from sshd and it will
+       * be processed in Session#run().
+       */
+      if(this.isClosed()){
+        throw new JSchException("channel is not opened.");
+      }
+      connected=true;
+      start();
+    }
+    catch(Exception e){
+      connected=false;
+      disconnect();
+      if(e instanceof JSchException) 
+        throw (JSchException)e;
+      throw new JSchException(e.toString(), e);
+    }
+  }
+
+  public void setXForwarding(boolean foo){
+  }
+
+  public void start() throws JSchException{}
+
+  public boolean isEOF() {return eof_remote;}
+
+  void getData(Buffer buf){
+    setRecipient(buf.getInt());
+    setRemoteWindowSize(buf.getUInt());
+    setRemotePacketSize(buf.getInt());
+  }
+
+  public void setInputStream(InputStream in){
+    io.setInputStream(in, false);
+  }
+  public void setInputStream(InputStream in, boolean dontclose){
+    io.setInputStream(in, dontclose);
+  }
+  public void setOutputStream(OutputStream out){
+    io.setOutputStream(out, false);
+  }
+  public void setOutputStream(OutputStream out, boolean dontclose){
+    io.setOutputStream(out, dontclose);
+  }
+  public void setExtOutputStream(OutputStream out){
+    io.setExtOutputStream(out, false);
+  }
+  public void setExtOutputStream(OutputStream out, boolean dontclose){
+    io.setExtOutputStream(out, dontclose);
+  }
+  public InputStream getInputStream() throws IOException {
+    PipedInputStream in=
+      new MyPipedInputStream(
+                             32*1024  // this value should be customizable.
+                             );
+    io.setOutputStream(new PassiveOutputStream(in), false);
+    return in;
+  }
+  public InputStream getExtInputStream() throws IOException {
+    PipedInputStream in=
+      new MyPipedInputStream(
+                             32*1024  // this value should be customizable.
+                             );
+    io.setExtOutputStream(new PassiveOutputStream(in), false);
+    return in;
+  }
+  public OutputStream getOutputStream() throws IOException {
+    /*
+    PipedOutputStream out=new PipedOutputStream();
+    io.setInputStream(new PassiveInputStream(out
+                                             , 32*1024
+                                             ), false);
+    return out;
+    */
+
+    final Channel channel=this;
+    OutputStream out=new OutputStream(){
+        private int dataLen=0;
+        private Buffer buffer=null;
+        private Packet packet=null;
+        private boolean closed=false;
+        private synchronized void init() throws java.io.IOException{
+          buffer=new Buffer(rmpsize);
+          packet=new Packet(buffer);
+
+          byte[] _buf=buffer.buffer;
+          if(_buf.length-(14+0)-32-20<=0){
+            buffer=null;
+            packet=null;
+            throw new IOException("failed to initialize the channel.");
+          }
+
+        }
+        byte[] b=new byte[1];
+        public void write(int w) throws java.io.IOException{
+          b[0]=(byte)w;
+          write(b, 0, 1);
+        }
+        public void write(byte[] buf, int s, int l) throws java.io.IOException{
+          if(packet==null){
+            init();
+          }
+
+          if(closed){
+            throw new java.io.IOException("Already closed");
+          }
+
+          byte[] _buf=buffer.buffer;
+          int _bufl=_buf.length;
+          while(l>0){
+            int _l=l;
+            if(l>_bufl-(14+dataLen)-32-20){
+              _l=_bufl-(14+dataLen)-32-20;
+            }
+
+            if(_l<=0){
+              flush();
+              continue;
+            }
+
+            System.arraycopy(buf, s, _buf, 14+dataLen, _l);
+            dataLen+=_l;
+            s+=_l;
+            l-=_l;
+          }
+        }
+
+        public void flush() throws java.io.IOException{
+          if(closed){
+            throw new java.io.IOException("Already closed");
+          }
+          if(dataLen==0)
+            return;
+          packet.reset();
+          buffer.putByte((byte)Session.SSH_MSG_CHANNEL_DATA);
+          buffer.putInt(recipient);
+          buffer.putInt(dataLen);
+          buffer.skip(dataLen);
+          try{
+            int foo=dataLen;
+            dataLen=0;
+            getSession().write(packet, channel, foo);
+          }
+          catch(Exception e){
+            close();
+            throw new java.io.IOException(e.toString());
+          }
+
+        }
+        public void close() throws java.io.IOException{
+          if(packet==null){
+            try{
+              init();
+            }
+            catch(java.io.IOException e){
+              // close should be finished silently.
+              return;
+            }
+          }
+          if(closed){
+            return;
+          }
+          if(dataLen>0){
+            flush();
+          }
+          channel.eof();
+          closed=true;
+        }
+      };
+    return out;
+  }
+
+  class MyPipedInputStream extends PipedInputStream{
+    MyPipedInputStream() throws IOException{ super(); }
+    MyPipedInputStream(int size) throws IOException{
+      super();
+      buffer=new byte[size];
+    }
+    MyPipedInputStream(PipedOutputStream out) throws IOException{ super(out); }
+    MyPipedInputStream(PipedOutputStream out, int size) throws IOException{
+      super(out);
+      buffer=new byte[size];
+    }
+  }
+  void setLocalWindowSizeMax(int foo){ this.lwsize_max=foo; }
+  void setLocalWindowSize(int foo){ this.lwsize=foo; }
+  void setLocalPacketSize(int foo){ this.lmpsize=foo; }
+  synchronized void setRemoteWindowSize(long foo){ this.rwsize=foo; }
+  synchronized void addRemoteWindowSize(int foo){ 
+    this.rwsize+=foo; 
+    if(notifyme>0)
+      notifyAll();
+  }
+  void setRemotePacketSize(int foo){ this.rmpsize=foo; }
+
+  public void run(){
+  }
+
+  void write(byte[] foo) throws IOException {
+    write(foo, 0, foo.length);
+  }
+  void write(byte[] foo, int s, int l) throws IOException {
+    try{
+      io.put(foo, s, l);
+    }catch(NullPointerException e){}
+  }
+  void write_ext(byte[] foo, int s, int l) throws IOException {
+    try{
+      io.put_ext(foo, s, l);
+    }catch(NullPointerException e){}
+  }
+
+  void eof_remote(){
+    eof_remote=true;
+    try{
+      io.out_close();
+    }
+    catch(NullPointerException e){}
+  }
+
+  void eof(){
+    if(eof_local)return;
+    eof_local=true;
+
+    try{
+      Buffer buf=new Buffer(100);
+      Packet packet=new Packet(buf);
+      packet.reset();
+      buf.putByte((byte)Session.SSH_MSG_CHANNEL_EOF);
+      buf.putInt(getRecipient());
+      synchronized(this){
+        if(!close)
+          getSession().write(packet);
+      }
+    }
+    catch(Exception e){
+      //System.err.println("Channel.eof");
+      //e.printStackTrace();
+    }
+    /*
+    if(!isConnected()){ disconnect(); }
+    */
+  }
+
+  /*
+  http://www1.ietf.org/internet-drafts/draft-ietf-secsh-connect-24.txt
+
+5.3  Closing a Channel
+  When a party will no longer send more data to a channel, it SHOULD
+   send SSH_MSG_CHANNEL_EOF.
+
+            byte      SSH_MSG_CHANNEL_EOF
+            uint32    recipient_channel
+
+  No explicit response is sent to this message.  However, the
+   application may send EOF to whatever is at the other end of the
+  channel.  Note that the channel remains open after this message, and
+   more data may still be sent in the other direction.  This message
+   does not consume window space and can be sent even if no window space
+   is available.
+
+     When either party wishes to terminate the channel, it sends
+     SSH_MSG_CHANNEL_CLOSE.  Upon receiving this message, a party MUST
+   send back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this
+   message for the channel.  The channel is considered closed for a
+     party when it has both sent and received SSH_MSG_CHANNEL_CLOSE, and
+   the party may then reuse the channel number.  A party MAY send
+   SSH_MSG_CHANNEL_CLOSE without having sent or received
+   SSH_MSG_CHANNEL_EOF.
+
+            byte      SSH_MSG_CHANNEL_CLOSE
+            uint32    recipient_channel
+
+   This message does not consume window space and can be sent even if no
+   window space is available.
+
+   It is recommended that any data sent before this message is delivered
+     to the actual destination, if possible.
+  */
+
+  void close(){
+    if(close)return;
+    close=true;
+    eof_local=eof_remote=true;
+
+    try{
+      Buffer buf=new Buffer(100);
+      Packet packet=new Packet(buf);
+      packet.reset();
+      buf.putByte((byte)Session.SSH_MSG_CHANNEL_CLOSE);
+      buf.putInt(getRecipient());
+      synchronized(this){
+        getSession().write(packet);
+      }
+    }
+    catch(Exception e){
+      //e.printStackTrace();
+    }
+  }
+  public boolean isClosed(){
+    return close;
+  }
+  static void disconnect(Session session){
+    Channel[] channels=null;
+    int count=0;
+    synchronized(pool){
+      channels=new Channel[pool.size()];
+      for(int i=0; i<pool.size(); i++){
+       try{
+         Channel c=((Channel)(pool.elementAt(i)));
+         if(c.session==session){
+           channels[count++]=c;
+         }
+       }
+       catch(Exception e){
+       }
+      } 
+    }
+    for(int i=0; i<count; i++){
+      channels[i].disconnect();
+    }
+  }
+
+  public void disconnect(){
+    //System.err.println(this+":disconnect "+io+" "+connected);
+    //Thread.dumpStack();
+
+    try{
+
+      synchronized(this){
+        if(!connected){
+          return;
+        }
+        connected=false;
+      }
+
+      close();
+
+      eof_remote=eof_local=true;
+
+      thread=null;
+
+      try{
+        if(io!=null){
+          io.close();
+        }
+      }
+      catch(Exception e){
+        //e.printStackTrace();
+      }
+      // io=null;
+    }
+    finally{
+      Channel.del(this);
+    }
+  }
+
+  public boolean isConnected(){
+    Session _session=this.session;
+    if(_session!=null){
+      return _session.isConnected() && connected;
+    }
+    return false;
+  }
+
+  public void sendSignal(String signal) throws Exception {
+    RequestSignal request=new RequestSignal();
+    request.setSignal(signal);
+    request.request(getSession(), this);
+  }
+
+//  public String toString(){
+//      return "Channel: type="+new String(type)+",id="+id+",recipient="+recipient+",window_size="+window_size+",packet_size="+packet_size;
+//  }
+
+/*
+  class OutputThread extends Thread{
+    Channel c;
+    OutputThread(Channel c){ this.c=c;}
+    public void run(){c.output_thread();}
+  }
+*/
+
+  class PassiveInputStream extends MyPipedInputStream{
+    PipedOutputStream out;
+    PassiveInputStream(PipedOutputStream out, int size) throws IOException{
+      super(out, size);
+      this.out=out;
+    }
+    PassiveInputStream(PipedOutputStream out) throws IOException{
+      super(out);
+      this.out=out;
+    }
+    public void close() throws IOException{
+      if(out!=null){
+        this.out.close();
+      }
+      out=null;
+    }
+  }
+  class PassiveOutputStream extends PipedOutputStream{
+    PassiveOutputStream(PipedInputStream in) throws IOException{
+      super(in);
+    }
+  }
+
+  void setExitStatus(int status){ exitstatus=status; }
+  public int getExitStatus(){ return exitstatus; }
+
+  void setSession(Session session){
+    this.session=session;
+  }
+
+  public Session getSession() throws JSchException{ 
+    Session _session=session;
+    if(_session==null){
+      throw new JSchException("session is not available");
+    }
+    return _session;
+  }
+  public int getId(){ return id; }
+
+  protected void sendOpenConfirmation() throws Exception{
+    Buffer buf=new Buffer(100);
+    Packet packet=new Packet(buf);
+    packet.reset();
+    buf.putByte((byte)SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
+    buf.putInt(getRecipient());
+    buf.putInt(id);
+    buf.putInt(lwsize);
+    buf.putInt(lmpsize);
+    getSession().write(packet);
+  }
+
+  protected void sendOpenFailure(int reasoncode){
+    try{
+      Buffer buf=new Buffer(100);
+      Packet packet=new Packet(buf);
+      packet.reset();
+      buf.putByte((byte)SSH_MSG_CHANNEL_OPEN_FAILURE);
+      buf.putInt(getRecipient());
+      buf.putInt(reasoncode);
+      buf.putString(Util.str2byte("open failed"));
+      buf.putString(Util.empty);
+      getSession().write(packet);
+    }
+    catch(Exception e){
+    }
+  }
+}
diff --git a/src/com/jcraft/jsch/ChannelAgentForwarding.java b/src/com/jcraft/jsch/ChannelAgentForwarding.java
new file mode 100644 (file)
index 0000000..9fb8cb0
--- /dev/null
@@ -0,0 +1,227 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.net.*;
+import java.util.Vector;
+
+class ChannelAgentForwarding extends Channel{
+
+  static private final int LOCAL_WINDOW_SIZE_MAX=0x20000;
+  static private final int LOCAL_MAXIMUM_PACKET_SIZE=0x4000;
+
+  private final int SSH2_AGENTC_REQUEST_IDENTITIES=11;
+  private final int SSH2_AGENT_IDENTITIES_ANSWER=12;
+  private final int SSH2_AGENTC_SIGN_REQUEST=13;
+  private final int SSH2_AGENT_SIGN_RESPONSE=14;
+  private final int SSH2_AGENTC_ADD_IDENTITY=17;
+  private final int SSH2_AGENTC_REMOVE_IDENTITY=18;
+  private final int SSH2_AGENTC_REMOVE_ALL_IDENTITIES=19;
+  private final int SSH2_AGENT_FAILURE=30;
+
+  boolean init=true;
+
+  private Buffer rbuf=null;
+  private Buffer wbuf=null;
+  private Packet packet=null;
+  private Buffer mbuf=null;
+
+  ChannelAgentForwarding(){
+    super();
+
+    setLocalWindowSizeMax(LOCAL_WINDOW_SIZE_MAX);
+    setLocalWindowSize(LOCAL_WINDOW_SIZE_MAX);
+    setLocalPacketSize(LOCAL_MAXIMUM_PACKET_SIZE);
+
+    type=Util.str2byte("auth-agent@openssh.com");
+    rbuf=new Buffer();
+    rbuf.reset();
+    //wbuf=new Buffer(rmpsize);
+    //packet=new Packet(wbuf);
+    mbuf=new Buffer();
+    connected=true;
+  }
+
+  public void run(){
+    try{
+      sendOpenConfirmation();
+    }
+    catch(Exception e){
+      close=true;
+      disconnect();
+    }
+  }
+
+  void write(byte[] foo, int s, int l) throws java.io.IOException {
+
+    if(packet==null){
+      wbuf=new Buffer(rmpsize);
+      packet=new Packet(wbuf);
+    }
+
+    rbuf.shift();
+    if(rbuf.buffer.length<rbuf.index+l){
+      byte[] newbuf=new byte[rbuf.s+l];
+      System.arraycopy(rbuf.buffer, 0, newbuf, 0, rbuf.buffer.length);
+      rbuf.buffer=newbuf;
+    }
+
+    rbuf.putByte(foo, s, l);
+
+    int mlen=rbuf.getInt();
+    if(mlen>rbuf.getLength()){
+      rbuf.s-=4;
+      return;
+    }
+
+    int typ=rbuf.getByte();
+
+    Session _session=null;
+    try{
+      _session=getSession();
+    }
+    catch(JSchException e){
+      throw new java.io.IOException(e.toString());
+    }
+
+    Vector identities=_session.jsch.identities;
+    UserInfo userinfo=_session.getUserInfo();
+
+    if(typ==SSH2_AGENTC_REQUEST_IDENTITIES){ 
+      mbuf.reset();
+      mbuf.putByte((byte)SSH2_AGENT_IDENTITIES_ANSWER);
+      synchronized(identities){
+        int count=0;
+        for(int i=0; i<identities.size(); i++){
+          Identity identity=(Identity)(identities.elementAt(i));
+          if(identity.getPublicKeyBlob()!=null)
+            count++;
+        }
+        mbuf.putInt(count);
+        for(int i=0; i<identities.size(); i++){
+          Identity identity=(Identity)(identities.elementAt(i));
+          byte[] pubkeyblob=identity.getPublicKeyBlob();
+          if(pubkeyblob==null)
+            continue;
+          mbuf.putString(pubkeyblob);
+          mbuf.putString(Util.empty);
+        }
+      }
+      byte[] bar=new byte[mbuf.getLength()];
+      mbuf.getByte(bar);
+
+      send(bar);
+    }
+    else if(typ==SSH2_AGENTC_SIGN_REQUEST){
+      byte[] blob=rbuf.getString();
+      byte[] data=rbuf.getString();
+      int flags=rbuf.getInt();
+
+//      if((flags & 1)!=0){ //SSH_AGENT_OLD_SIGNATURE // old OpenSSH 2.0, 2.1
+//        datafellows = SSH_BUG_SIGBLOB;
+//      }
+
+      Identity identity=null;
+      synchronized(identities){
+        for(int i=0; i<identities.size(); i++){
+          Identity _identity=(Identity)(identities.elementAt(i));
+          if(_identity.getPublicKeyBlob()==null)
+            continue;
+          if(!Util.array_equals(blob, _identity.getPublicKeyBlob())){
+            continue;
+          }
+          if(_identity.isEncrypted()){
+            if(userinfo==null)
+              continue;
+            while(_identity.isEncrypted()){
+              if(!userinfo.promptPassphrase("Passphrase for "+_identity.getName())){
+                break;
+              }
+
+              String _passphrase=userinfo.getPassphrase();
+              if(_passphrase==null){
+                break;
+              }
+
+              byte[] passphrase=Util.str2byte(_passphrase);
+              try{
+                if(_identity.setPassphrase(passphrase)){
+                  break;
+                }
+              }
+              catch(JSchException e){
+                break;
+              }
+            }
+          }
+
+          if(!_identity.isEncrypted()){
+            identity=_identity;
+            break;
+          }
+        }
+      }
+
+      byte[] signature=null;
+
+      if(identity!=null){
+        signature=identity.getSignature(data);
+      }
+
+      mbuf.reset();
+      if(signature==null){
+        mbuf.putByte((byte)SSH2_AGENT_FAILURE);
+      }
+      else{
+        mbuf.putByte((byte)SSH2_AGENT_SIGN_RESPONSE);
+        mbuf.putString(signature);
+      }
+
+      byte[] bar=new byte[mbuf.getLength()];
+      mbuf.getByte(bar);
+
+      send(bar);
+    }
+  }
+
+  private void send(byte[] message){
+    packet.reset();
+    wbuf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA);
+    wbuf.putInt(recipient);
+    wbuf.putInt(4+message.length);
+    wbuf.putString(message);
+
+    try{
+      getSession().write(packet, this, 4+message.length);
+    }
+    catch(Exception e){
+    }
+  }
+}
diff --git a/src/com/jcraft/jsch/ChannelDirectTCPIP.java b/src/com/jcraft/jsch/ChannelDirectTCPIP.java
new file mode 100644 (file)
index 0000000..12ad8d5
--- /dev/null
@@ -0,0 +1,183 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.io.*;
+
+public class ChannelDirectTCPIP extends Channel{
+
+  static private final int LOCAL_WINDOW_SIZE_MAX=0x20000;
+  static private final int LOCAL_MAXIMUM_PACKET_SIZE=0x4000;
+
+  String host;
+  int port;
+
+  String originator_IP_address="127.0.0.1";
+  int originator_port=0;
+
+  ChannelDirectTCPIP(){
+    super();
+    setLocalWindowSizeMax(LOCAL_WINDOW_SIZE_MAX);
+    setLocalWindowSize(LOCAL_WINDOW_SIZE_MAX);
+    setLocalPacketSize(LOCAL_MAXIMUM_PACKET_SIZE);
+  }
+
+  void init (){
+    try{ 
+      io=new IO();
+    }
+    catch(Exception e){
+      System.err.println(e);
+    }
+  }
+
+  public void connect() throws JSchException{
+    try{
+      Session _session=getSession();
+      if(!_session.isConnected()){
+        throw new JSchException("session is down");
+      }
+      Buffer buf=new Buffer(150);
+      Packet packet=new Packet(buf);
+      // send
+      // byte   SSH_MSG_CHANNEL_OPEN(90)
+      // string channel type         //
+      // uint32 sender channel       // 0
+      // uint32 initial window size  // 0x100000(65536)
+      // uint32 maxmum packet size   // 0x4000(16384)
+
+      packet.reset();
+      buf.putByte((byte)90);
+      buf.putString(Util.str2byte("direct-tcpip"));
+      buf.putInt(id);
+      buf.putInt(lwsize);
+      buf.putInt(lmpsize);
+      buf.putString(Util.str2byte(host));
+      buf.putInt(port);
+      buf.putString(Util.str2byte(originator_IP_address));
+      buf.putInt(originator_port);
+      _session.write(packet);
+
+      int retry=1000;
+      try{
+        while(this.getRecipient()==-1 && 
+              _session.isConnected() &&
+              retry>0 &&
+              !eof_remote){
+          //Thread.sleep(500);
+          Thread.sleep(50);
+          retry--;
+        }
+      }
+      catch(Exception ee){
+      }
+      if(!_session.isConnected()){
+       throw new JSchException("session is down");
+      }
+      if(retry==0 || this.eof_remote){
+        throw new JSchException("channel is not opened.");
+      }
+      /*
+      if(this.eof_remote){      // failed to open
+        disconnect();
+        return;
+      }
+      */
+
+      connected=true;
+
+      if(io.in!=null){
+        thread=new Thread(this);
+        thread.setName("DirectTCPIP thread "+_session.getHost());
+        if(_session.daemon_thread){
+          thread.setDaemon(_session.daemon_thread);
+        }
+        thread.start();
+      }
+    }
+    catch(Exception e){
+      io.close();
+      io=null;
+      Channel.del(this);
+      if (e instanceof JSchException) {
+        throw (JSchException) e;
+      }
+    }
+  }
+
+  public void run(){
+
+    Buffer buf=new Buffer(rmpsize);
+    Packet packet=new Packet(buf);
+    int i=0;
+
+    try{
+      Session _session=getSession();
+      while(isConnected() &&
+            thread!=null && 
+            io!=null && 
+            io.in!=null){
+        i=io.in.read(buf.buffer, 
+                     14, 
+                     buf.buffer.length-14
+                     -32 -20 // padding and mac
+                     );
+
+        if(i<=0){
+          eof();
+          break;
+        }
+        if(close)break;
+        packet.reset();
+        buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA);
+        buf.putInt(recipient);
+        buf.putInt(i);
+        buf.skip(i);
+        _session.write(packet, this, i);
+      }
+    }
+    catch(Exception e){
+    }
+    disconnect();
+    //System.err.println("connect end");
+  }
+
+  public void setInputStream(InputStream in){
+    io.setInputStream(in);
+  }
+  public void setOutputStream(OutputStream out){
+    io.setOutputStream(out);
+  }
+
+  public void setHost(String host){this.host=host;}
+  public void setPort(int port){this.port=port;}
+  public void setOrgIPAddress(String foo){this.originator_IP_address=foo;}
+  public void setOrgPort(int foo){this.originator_port=foo;}
+}
diff --git a/src/com/jcraft/jsch/ChannelExec.java b/src/com/jcraft/jsch/ChannelExec.java
new file mode 100644 (file)
index 0000000..df8869c
--- /dev/null
@@ -0,0 +1,83 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.util.*;
+
+public class ChannelExec extends ChannelSession{
+
+  byte[] command=new byte[0];
+
+  public void start() throws JSchException{
+    Session _session=getSession();
+    try{
+      sendRequests();
+      Request request=new RequestExec(command);
+      request.request(_session, this);
+    }
+    catch(Exception e){
+      if(e instanceof JSchException) throw (JSchException)e;
+      if(e instanceof Throwable)
+        throw new JSchException("ChannelExec", (Throwable)e);
+      throw new JSchException("ChannelExec");
+    }
+
+    if(io.in!=null){
+      thread=new Thread(this);
+      thread.setName("Exec thread "+_session.getHost());
+      if(_session.daemon_thread){
+        thread.setDaemon(_session.daemon_thread);
+      }
+      thread.start();
+    }
+  }
+
+  public void setCommand(String command){ 
+    this.command=Util.str2byte(command);
+  }
+  public void setCommand(byte[] command){ 
+    this.command=command;
+  }
+
+  void init() throws JSchException {
+    io.setInputStream(getSession().in);
+    io.setOutputStream(getSession().out);
+  }
+
+  public void setErrStream(java.io.OutputStream out){
+    setExtOutputStream(out);
+  }
+  public void setErrStream(java.io.OutputStream out, boolean dontclose){
+    setExtOutputStream(out, dontclose);
+  }
+  public java.io.InputStream getErrStream() throws java.io.IOException {
+    return getExtInputStream();
+  }
+}
diff --git a/src/com/jcraft/jsch/ChannelForwardedTCPIP.java b/src/com/jcraft/jsch/ChannelForwardedTCPIP.java
new file mode 100644 (file)
index 0000000..faafa17
--- /dev/null
@@ -0,0 +1,311 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.net.*;
+import java.io.*;
+
+public class ChannelForwardedTCPIP extends Channel{
+
+  static java.util.Vector pool=new java.util.Vector();
+
+  static private final int LOCAL_WINDOW_SIZE_MAX=0x20000;
+//static private final int LOCAL_WINDOW_SIZE_MAX=0x100000;
+  static private final int LOCAL_MAXIMUM_PACKET_SIZE=0x4000;
+
+  static private final int TIMEOUT=10*1000;
+
+  SocketFactory factory=null;
+  private Socket socket=null;
+  private ForwardedTCPIPDaemon daemon=null;
+  String target;
+  int lport;
+  int rport;
+
+  ChannelForwardedTCPIP(){
+    super();
+    setLocalWindowSizeMax(LOCAL_WINDOW_SIZE_MAX);
+    setLocalWindowSize(LOCAL_WINDOW_SIZE_MAX);
+    setLocalPacketSize(LOCAL_MAXIMUM_PACKET_SIZE);
+    io=new IO();
+    connected=true;
+  }
+
+  public void run(){
+    try{ 
+      if(lport==-1){
+        Class c=Class.forName(target);
+        daemon=(ForwardedTCPIPDaemon)c.newInstance();
+
+        PipedOutputStream out=new PipedOutputStream();
+        io.setInputStream(new PassiveInputStream(out
+                                                 , 32*1024
+                                                 ), false);
+
+        daemon.setChannel(this, getInputStream(), out);
+        Object[] foo=getPort(getSession(), rport);
+        daemon.setArg((Object[])foo[3]);
+
+        new Thread(daemon).start();
+      }
+      else{
+        socket=(factory==null) ? 
+           Util.createSocket(target, lport, TIMEOUT) : 
+          factory.createSocket(target, lport);
+        socket.setTcpNoDelay(true);
+        io.setInputStream(socket.getInputStream());
+        io.setOutputStream(socket.getOutputStream());
+      }
+      sendOpenConfirmation();
+    }
+    catch(Exception e){
+      sendOpenFailure(SSH_OPEN_ADMINISTRATIVELY_PROHIBITED);
+      close=true;
+      disconnect();
+      return; 
+    }
+
+    thread=Thread.currentThread();
+    Buffer buf=new Buffer(rmpsize);
+    Packet packet=new Packet(buf);
+    int i=0;
+    try{
+      while(thread!=null && 
+            io!=null && 
+            io.in!=null){
+        i=io.in.read(buf.buffer, 
+                     14, 
+                     buf.buffer.length-14
+                     -32 -20 // padding and mac
+                     );
+        if(i<=0){
+          eof();
+          break;
+        }
+        packet.reset();
+        if(close)break;
+        buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA);
+        buf.putInt(recipient);
+        buf.putInt(i);
+        buf.skip(i);
+        getSession().write(packet, this, i);
+      }
+    }
+    catch(Exception e){
+      //System.err.println(e);
+    }
+    //thread=null;
+    //eof();
+    disconnect();
+  }
+
+  void getData(Buffer buf){
+    setRecipient(buf.getInt());
+    setRemoteWindowSize(buf.getUInt());
+    setRemotePacketSize(buf.getInt());
+    byte[] addr=buf.getString();
+    int port=buf.getInt();
+    byte[] orgaddr=buf.getString();
+    int orgport=buf.getInt();
+
+    /*
+    System.err.println("addr: "+Util.byte2str(addr));
+    System.err.println("port: "+port);
+    System.err.println("orgaddr: "+Util.byte2str(orgaddr));
+    System.err.println("orgport: "+orgport);
+    */
+
+    Session _session=null;
+    try{
+      _session=getSession();
+    }
+    catch(JSchException e){
+      // session has been already down.
+    }
+
+    synchronized(pool){
+      for(int i=0; i<pool.size(); i++){
+        Object[] foo=(Object[])(pool.elementAt(i));
+        if(foo[0]!=_session) continue;
+        if(((Integer)foo[1]).intValue()!=port) continue;
+        this.rport=port;
+        this.target=(String)foo[2];
+        if(foo[3]==null || (foo[3] instanceof Object[])){ this.lport=-1; }
+        else{ this.lport=((Integer)foo[3]).intValue(); }
+        if(foo.length>=6){
+          this.factory=((SocketFactory)foo[5]);
+        }
+        break;
+      }
+      if(target==null){
+        //System.err.println("??");
+      }
+    }
+  }
+
+  static Object[] getPort(Session session, int rport){
+    synchronized(pool){
+      for(int i=0; i<pool.size(); i++){
+        Object[] bar=(Object[])(pool.elementAt(i));
+        if(bar[0]!=session) continue;
+        if(((Integer)bar[1]).intValue()!=rport) continue;
+        return bar;
+      }
+      return null;
+    }
+  }
+
+  static String[] getPortForwarding(Session session){
+    java.util.Vector foo=new java.util.Vector();
+    synchronized(pool){
+      for(int i=0; i<pool.size(); i++){
+        Object[] bar=(Object[])(pool.elementAt(i));
+        if(bar[0]!=session) continue;
+        if(bar[3]==null){ foo.addElement(bar[1]+":"+bar[2]+":"); }
+        else{ foo.addElement(bar[1]+":"+bar[2]+":"+bar[3]); }
+      }
+    }
+    String[] bar=new String[foo.size()];
+    for(int i=0; i<foo.size(); i++){
+      bar[i]=(String)(foo.elementAt(i));
+    }
+    return bar;
+  }
+
+  static String normalize(String address){
+    if(address==null){ return "localhost"; }
+    else if(address.length()==0 || address.equals("*")){ return ""; }
+    else{ return address; }
+  }
+
+  static void addPort(Session session, String _address_to_bind, int port, String target, int lport, SocketFactory factory) throws JSchException{
+    String address_to_bind=normalize(_address_to_bind);
+    synchronized(pool){
+      if(getPort(session, port)!=null){
+        throw new JSchException("PortForwardingR: remote port "+port+" is already registered.");
+      }
+      Object[] foo=new Object[6];
+      foo[0]=session; foo[1]=new Integer(port);
+      foo[2]=target; foo[3]=new Integer(lport);
+      foo[4]=address_to_bind;
+      foo[5]=factory;
+      pool.addElement(foo);
+    }
+  }
+  static void addPort(Session session, String _address_to_bind, int port, String daemon, Object[] arg) throws JSchException{
+    String address_to_bind=normalize(_address_to_bind);
+    synchronized(pool){
+      if(getPort(session, port)!=null){
+        throw new JSchException("PortForwardingR: remote port "+port+" is already registered.");
+      }
+      Object[] foo=new Object[5];
+      foo[0]=session; foo[1]=new Integer(port);
+      foo[2]=daemon; foo[3]=arg;
+      foo[4]=address_to_bind; 
+      pool.addElement(foo);
+    }
+  }
+  static void delPort(ChannelForwardedTCPIP c){
+    Session _session=null;
+    try{
+      _session=c.getSession();
+    }
+    catch(JSchException e){
+      // session has been already down.
+    }
+    if(_session!=null)
+      delPort(_session, c.rport);
+  }
+  static void delPort(Session session, int rport){
+    delPort(session, null, rport);
+  }
+  static void delPort(Session session, String address_to_bind, int rport){
+    synchronized(pool){
+      Object[] foo=null;
+      for(int i=0; i<pool.size(); i++){
+        Object[] bar=(Object[])(pool.elementAt(i));
+        if(bar[0]!=session) continue;
+        if(((Integer)bar[1]).intValue()!=rport) continue;
+        foo=bar;
+        break;
+      }
+      if(foo==null)return;
+      pool.removeElement(foo);
+      if(address_to_bind==null){
+        address_to_bind=(String)foo[4];
+      }        
+      if(address_to_bind==null){
+        address_to_bind="0.0.0.0";
+      }
+    }
+
+    Buffer buf=new Buffer(100); // ??
+    Packet packet=new Packet(buf);
+
+    try{
+      // byte SSH_MSG_GLOBAL_REQUEST 80
+      // string "cancel-tcpip-forward"
+      // boolean want_reply
+      // string  address_to_bind (e.g. "127.0.0.1")
+      // uint32  port number to bind
+      packet.reset();
+      buf.putByte((byte) 80/*SSH_MSG_GLOBAL_REQUEST*/);
+      buf.putString(Util.str2byte("cancel-tcpip-forward"));
+      buf.putByte((byte)0);
+      buf.putString(Util.str2byte(address_to_bind));
+      buf.putInt(rport);
+      session.write(packet);
+    }
+    catch(Exception e){
+//    throw new JSchException(e.toString());
+    }
+  }
+  static void delPort(Session session){
+    int[] rport=null;
+    int count=0;
+    synchronized(pool){
+      rport=new int[pool.size()];
+      for(int i=0; i<pool.size(); i++){
+        Object[] bar=(Object[])(pool.elementAt(i));
+        if(bar[0]==session) {
+          rport[count++]=((Integer)bar[1]).intValue();
+        }
+      }
+    }
+    for(int i=0; i<count; i++){
+      delPort(session, rport[i]);
+    }
+  }
+
+  public int getRemotePort(){return rport;}
+  void setSocketFactory(SocketFactory factory){
+    this.factory=factory;
+  }
+}
diff --git a/src/com/jcraft/jsch/ChannelSession.java b/src/com/jcraft/jsch/ChannelSession.java
new file mode 100644 (file)
index 0000000..17b7ef2
--- /dev/null
@@ -0,0 +1,276 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.util.*;
+
+class ChannelSession extends Channel{
+  private static byte[] _session=Util.str2byte("session");
+
+  protected boolean agent_forwarding=false;
+  protected boolean xforwading=false;
+  protected Hashtable env=null;
+
+  protected boolean pty=false;
+
+  protected String ttype="vt100";
+  protected int tcol=80;
+  protected int trow=24;
+  protected int twp=640;
+  protected int thp=480;
+  protected byte[] terminal_mode=null;
+
+  ChannelSession(){
+    super();
+    type=_session;
+    io=new IO();
+  }
+
+  /**
+   * Enable the agent forwarding.
+   *
+   * @param enable
+   */
+  public void setAgentForwarding(boolean enable){ 
+    agent_forwarding=enable;
+  }
+
+  /**
+   * Enable the X11 forwarding.
+   *
+   * @param enable
+   * @see RFC4254 6.3.1. Requesting X11 Forwarding
+   */
+  public void setXForwarding(boolean enable){
+    xforwading=enable; 
+  }
+
+  /**
+   * @deprecated Use {@link #setEnv(String, String)} or {@link #setEnv(byte[], byte[])} instead.
+   * @see #setEnv(String, String)
+   * @see #setEnv(byte[], byte[])
+   */
+  public void setEnv(Hashtable env){ 
+    synchronized(this){
+      this.env=env; 
+    }
+  }
+
+  /**
+   * Set the environment variable. 
+   * If <code>name</code> and <code>value</code> are needed to be passed 
+   * to the remote in your faivorite encoding,use 
+   * {@link #setEnv(byte[], byte[])}.
+   *
+   * @param name A name for environment variable.
+   * @param value A value for environment variable.
+   * @see RFC4254 6.4 Environment Variable Passing
+   */
+  public void setEnv(String name, String value){
+    setEnv(Util.str2byte(name), Util.str2byte(value));
+  }
+
+  /**
+   * Set the environment variable.
+   *
+   * @param name A name of environment variable.
+   * @param value A value of environment variable.
+   * @see #setEnv(String, String)
+   * @see RFC4254 6.4 Environment Variable Passing
+   */
+  public void setEnv(byte[] name, byte[] value){
+    synchronized(this){
+      getEnv().put(name, value);
+    }
+  }
+
+  private Hashtable getEnv(){
+    if(env==null)
+      env=new Hashtable();
+    return env;
+  }
+
+  /**
+   * Allocate a Pseudo-Terminal.
+   *
+   * @param enable
+   * @see RFC4254 6.2. Requesting a Pseudo-Terminal
+   */
+  public void setPty(boolean enable){ 
+    pty=enable; 
+  }
+
+  /**
+   * Set the terminal mode.
+   * 
+   * @param terminal_mode
+   */
+  public void setTerminalMode(byte[] terminal_mode){
+    this.terminal_mode=terminal_mode;
+  }
+
+  /**
+   * Change the window dimension interactively.
+   * 
+   * @param col terminal width, columns
+   * @param row terminal height, rows
+   * @param wp terminal width, pixels
+   * @param hp terminal height, pixels
+   * @see RFC4254 6.7. Window Dimension Change Message
+   */
+  public void setPtySize(int col, int row, int wp, int hp){
+    setPtyType(this.ttype, col, row, wp, hp);
+    if(!pty || !isConnected()){
+      return;
+    }
+    try{
+      RequestWindowChange request=new RequestWindowChange();
+      request.setSize(col, row, wp, hp);
+      request.request(getSession(), this);
+    }
+    catch(Exception e){
+      //System.err.println("ChannelSessio.setPtySize: "+e);
+    }
+  }
+
+  /**
+   * Set the terminal type.
+   * This method is not effective after Channel#connect().
+   *
+   * @param ttype terminal type(for example, "vt100")
+   * @see #setPtyType(String, int, int, int, int)
+   */
+  public void setPtyType(String ttype){
+    setPtyType(ttype, 80, 24, 640, 480);
+  }
+
+  /**
+   * Set the terminal type.
+   * This method is not effective after Channel#connect().
+   *
+   * @param ttype terminal type(for example, "vt100")
+   * @param col terminal width, columns
+   * @param row terminal height, rows
+   * @param wp terminal width, pixels
+   * @param hp terminal height, pixels
+   */
+  public void setPtyType(String ttype, int col, int row, int wp, int hp){
+    this.ttype=ttype;
+    this.tcol=col;
+    this.trow=row;
+    this.twp=wp;
+    this.thp=hp;
+  }
+
+  protected void sendRequests() throws Exception{
+    Session _session=getSession();
+    Request request;
+    if(agent_forwarding){
+      request=new RequestAgentForwarding();
+      request.request(_session, this);
+    }
+
+    if(xforwading){
+      request=new RequestX11();
+      request.request(_session, this);
+    }
+
+    if(pty){
+      request=new RequestPtyReq();
+      ((RequestPtyReq)request).setTType(ttype);
+      ((RequestPtyReq)request).setTSize(tcol, trow, twp, thp);
+      if(terminal_mode!=null){
+        ((RequestPtyReq)request).setTerminalMode(terminal_mode);
+      }
+      request.request(_session, this);
+    }
+
+    if(env!=null){
+      for(Enumeration _env=env.keys(); _env.hasMoreElements();){
+        Object name=_env.nextElement();
+        Object value=env.get(name);
+        request=new RequestEnv();
+        ((RequestEnv)request).setEnv(toByteArray(name), 
+                                     toByteArray(value));
+        request.request(_session, this);
+      }
+    }
+  }
+
+  private byte[] toByteArray(Object o){
+    if(o instanceof String){
+      return Util.str2byte((String)o);
+    }
+    return (byte[])o;
+  }
+
+  public void run(){
+    //System.err.println(this+":run >");
+
+    Buffer buf=new Buffer(rmpsize);
+    Packet packet=new Packet(buf);
+    int i=-1;
+    try{
+      while(isConnected() &&
+           thread!=null && 
+            io!=null && 
+            io.in!=null){
+        i=io.in.read(buf.buffer, 
+                     14,    
+                     buf.buffer.length-14
+                     -32 -20 // padding and mac
+                    );
+       if(i==0)continue;
+       if(i==-1){
+         eof();
+         break;
+       }
+       if(close)break;
+        //System.out.println("write: "+i);
+        packet.reset();
+        buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA);
+        buf.putInt(recipient);
+        buf.putInt(i);
+        buf.skip(i);
+       getSession().write(packet, this, i);
+      }
+    }
+    catch(Exception e){
+      //System.err.println("# ChannelExec.run");
+      //e.printStackTrace();
+    }
+    Thread _thread=thread; 
+    if(_thread!=null){
+      synchronized(_thread){ _thread.notifyAll(); }
+    }
+    thread=null;
+    //System.err.println(this+":run <");
+  }
+}
diff --git a/src/com/jcraft/jsch/ChannelSftp.java b/src/com/jcraft/jsch/ChannelSftp.java
new file mode 100644 (file)
index 0000000..cea923e
--- /dev/null
@@ -0,0 +1,2447 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.io.*;
+
+import java.util.Vector;
+
+public class ChannelSftp extends ChannelSession{
+
+  private static final byte SSH_FXP_INIT=               1;
+  private static final byte SSH_FXP_VERSION=            2;
+  private static final byte SSH_FXP_OPEN=               3;
+  private static final byte SSH_FXP_CLOSE=              4;
+  private static final byte SSH_FXP_READ=               5;
+  private static final byte SSH_FXP_WRITE=              6;
+  private static final byte SSH_FXP_LSTAT=              7;
+  private static final byte SSH_FXP_FSTAT=              8;
+  private static final byte SSH_FXP_SETSTAT=            9;
+  private static final byte SSH_FXP_FSETSTAT=          10;
+  private static final byte SSH_FXP_OPENDIR=           11;
+  private static final byte SSH_FXP_READDIR=           12;
+  private static final byte SSH_FXP_REMOVE=            13;
+  private static final byte SSH_FXP_MKDIR=             14;
+  private static final byte SSH_FXP_RMDIR=             15;
+  private static final byte SSH_FXP_REALPATH=          16;
+  private static final byte SSH_FXP_STAT=              17;
+  private static final byte SSH_FXP_RENAME=            18;
+  private static final byte SSH_FXP_READLINK=          19;
+  private static final byte SSH_FXP_SYMLINK=           20;
+  private static final byte SSH_FXP_STATUS=           101;
+  private static final byte SSH_FXP_HANDLE=           102;
+  private static final byte SSH_FXP_DATA=             103;
+  private static final byte SSH_FXP_NAME=             104;
+  private static final byte SSH_FXP_ATTRS=            105;
+  private static final byte SSH_FXP_EXTENDED=         (byte)200;
+  private static final byte SSH_FXP_EXTENDED_REPLY=   (byte)201;
+
+  // pflags
+  private static final int SSH_FXF_READ=           0x00000001;
+  private static final int SSH_FXF_WRITE=          0x00000002;
+  private static final int SSH_FXF_APPEND=         0x00000004;
+  private static final int SSH_FXF_CREAT=          0x00000008;
+  private static final int SSH_FXF_TRUNC=          0x00000010;
+  private static final int SSH_FXF_EXCL=           0x00000020;
+
+  private static final int SSH_FILEXFER_ATTR_SIZE=         0x00000001;
+  private static final int SSH_FILEXFER_ATTR_UIDGID=       0x00000002;
+  private static final int SSH_FILEXFER_ATTR_PERMISSIONS=  0x00000004;
+  private static final int SSH_FILEXFER_ATTR_ACMODTIME=    0x00000008;
+  private static final int SSH_FILEXFER_ATTR_EXTENDED=     0x80000000;
+
+  public static final int SSH_FX_OK=                            0;
+  public static final int SSH_FX_EOF=                           1;
+  public static final int SSH_FX_NO_SUCH_FILE=                  2;
+  public static final int SSH_FX_PERMISSION_DENIED=             3;
+  public static final int SSH_FX_FAILURE=                       4;
+  public static final int SSH_FX_BAD_MESSAGE=                   5;
+  public static final int SSH_FX_NO_CONNECTION=                 6;
+  public static final int SSH_FX_CONNECTION_LOST=               7;
+  public static final int SSH_FX_OP_UNSUPPORTED=                8;
+/*
+   SSH_FX_OK
+      Indicates successful completion of the operation.
+   SSH_FX_EOF
+     indicates end-of-file condition; for SSH_FX_READ it means that no
+       more data is available in the file, and for SSH_FX_READDIR it
+      indicates that no more files are contained in the directory.
+   SSH_FX_NO_SUCH_FILE
+      is returned when a reference is made to a file which should exist
+      but doesn't.
+   SSH_FX_PERMISSION_DENIED
+      is returned when the authenticated user does not have sufficient
+      permissions to perform the operation.
+   SSH_FX_FAILURE
+      is a generic catch-all error message; it should be returned if an
+      error occurs for which there is no more specific error code
+      defined.
+   SSH_FX_BAD_MESSAGE
+      may be returned if a badly formatted packet or protocol
+      incompatibility is detected.
+   SSH_FX_NO_CONNECTION
+      is a pseudo-error which indicates that the client has no
+      connection to the server (it can only be generated locally by the
+      client, and MUST NOT be returned by servers).
+   SSH_FX_CONNECTION_LOST
+      is a pseudo-error which indicates that the connection to the
+      server has been lost (it can only be generated locally by the
+      client, and MUST NOT be returned by servers).
+   SSH_FX_OP_UNSUPPORTED
+      indicates that an attempt was made to perform an operation which
+      is not supported for the server (it may be generated locally by
+      the client if e.g.  the version number exchange indicates that a
+      required feature is not supported by the server, or it may be
+      returned by the server if the server does not implement an
+      operation).
+*/
+  private static final int MAX_MSG_LENGTH = 256* 1024;
+
+  public static final int OVERWRITE=0;
+  public static final int RESUME=1;
+  public static final int APPEND=2;
+
+  private boolean interactive=false;
+  private int seq=1;
+  private int[] ackid=new int[1];
+  private Buffer buf;
+  private Packet packet=new Packet(buf);
+
+  private int client_version=3;
+  private int server_version=3;
+  private String version=String.valueOf(client_version);
+
+  private java.util.Hashtable extensions=null;
+  private InputStream io_in=null;
+
+/*
+10. Changes from previous protocol versions
+  The SSH File Transfer Protocol has changed over time, before it's
+   standardization.  The following is a description of the incompatible
+   changes between different versions.
+10.1 Changes between versions 3 and 2
+   o  The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added.
+   o  The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were added.
+   o  The SSH_FXP_STATUS message was changed to include fields `error
+      message' and `language tag'.
+10.2 Changes between versions 2 and 1
+   o  The SSH_FXP_RENAME message was added.
+10.3 Changes between versions 1 and 0
+   o  Implementation changes, no actual protocol changes.
+*/
+
+  private static final String file_separator=java.io.File.separator;
+  private static final char file_separatorc=java.io.File.separatorChar;
+  private static boolean fs_is_bs=(byte)java.io.File.separatorChar == '\\';
+
+  private String cwd;
+  private String home;
+  private String lcwd;
+
+  private static final String UTF8="UTF-8";
+  private String fEncoding=UTF8;
+  private boolean fEncoding_is_utf8=true;
+
+  void init(){
+  }
+
+  public void start() throws JSchException{
+    try{
+
+      PipedOutputStream pos=new PipedOutputStream();
+      io.setOutputStream(pos);
+      PipedInputStream pis=new MyPipedInputStream(pos, 32*1024);
+      io.setInputStream(pis);
+
+      io_in=io.in;
+
+      if(io_in==null){
+        throw new JSchException("channel is down");
+      }
+
+      Request request=new RequestSftp();
+      request.request(getSession(), this);
+
+      /*
+      System.err.println("lmpsize: "+lmpsize);
+      System.err.println("lwsize: "+lwsize);
+      System.err.println("rmpsize: "+rmpsize);
+      System.err.println("rwsize: "+rwsize);
+      */
+
+      buf=new Buffer(rmpsize);
+      packet=new Packet(buf);
+      int i=0;
+      int length;
+      int type;
+      byte[] str;
+
+      // send SSH_FXP_INIT
+      sendINIT();
+
+      // receive SSH_FXP_VERSION
+      Header header=new Header();
+      header=header(buf, header);
+      length=header.length;
+      if(length > MAX_MSG_LENGTH){
+        throw new SftpException(SSH_FX_FAILURE, 
+                                "Received message is too long: " + length);
+      }
+      type=header.type;             // 2 -> SSH_FXP_VERSION
+      server_version=header.rid;
+      //System.err.println("SFTP protocol server-version="+server_version);
+      if(length>0){
+        extensions=new java.util.Hashtable();
+        // extension data
+        fill(buf, length);
+        byte[] extension_name=null;
+        byte[] extension_data=null;
+        while(length>0){
+          extension_name=buf.getString();
+          length-=(4+extension_name.length);
+          extension_data=buf.getString();
+          length-=(4+extension_data.length);
+          extensions.put(Util.byte2str(extension_name),
+                         Util.byte2str(extension_data));
+        }
+      }
+
+      lcwd=new File(".").getCanonicalPath();
+    }
+    catch(Exception e){
+      //System.err.println(e);
+      if(e instanceof JSchException) throw (JSchException)e;
+      if(e instanceof Throwable)
+        throw new JSchException(e.toString(), (Throwable)e);
+      throw new JSchException(e.toString());
+    }
+  }
+
+  public void quit(){ disconnect();}
+  public void exit(){ disconnect();}
+  public void lcd(String path) throws SftpException{
+    path=localAbsolutePath(path);
+    if((new File(path)).isDirectory()){
+      try{
+       path=(new File(path)).getCanonicalPath();
+      }
+      catch(Exception e){}
+      lcwd=path;
+      return;
+    }
+    throw new SftpException(SSH_FX_NO_SUCH_FILE, "No such directory");
+  }
+
+  public void cd(String path) throws SftpException{
+    try{
+      path=remoteAbsolutePath(path);
+
+      path=isUnique(path);
+
+      byte[] str=_realpath(path);
+      SftpATTRS attr=_stat(str);
+
+      if((attr.getFlags()&SftpATTRS.SSH_FILEXFER_ATTR_PERMISSIONS)==0){
+        throw new SftpException(SSH_FX_FAILURE, 
+                                "Can't change directory: "+path);
+      }
+      if(!attr.isDir()){
+        throw new SftpException(SSH_FX_FAILURE, 
+                                "Can't change directory: "+path);
+      }
+
+      setCwd(Util.byte2str(str, fEncoding));
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  public void put(String src, String dst) throws SftpException{
+    put(src, dst, null, OVERWRITE);
+  }
+  public void put(String src, String dst, int mode) throws SftpException{
+    put(src, dst, null, mode);
+  }
+  public void put(String src, String dst, 
+                 SftpProgressMonitor monitor) throws SftpException{
+    put(src, dst, monitor, OVERWRITE);
+  }
+  public void put(String src, String dst, 
+                 SftpProgressMonitor monitor, int mode) throws SftpException{
+    src=localAbsolutePath(src);
+    dst=remoteAbsolutePath(dst);
+
+    try{
+
+      Vector v=glob_remote(dst);
+      int vsize=v.size();
+      if(vsize!=1){
+        if(vsize==0){
+          if(isPattern(dst))
+            throw new SftpException(SSH_FX_FAILURE, dst);
+          else
+            dst=Util.unquote(dst);
+        }
+        throw new SftpException(SSH_FX_FAILURE, v.toString());
+      }
+      else{
+        dst=(String)(v.elementAt(0));
+      }
+
+      boolean isRemoteDir=isRemoteDir(dst);
+
+      v=glob_local(src);
+      vsize=v.size();
+
+      StringBuffer dstsb=null;
+      if(isRemoteDir){
+        if(!dst.endsWith("/")){
+           dst+="/";
+        }
+        dstsb=new StringBuffer(dst);
+      }
+      else if(vsize>1){
+        throw new SftpException(SSH_FX_FAILURE, 
+                                "Copying multiple files, but the destination is missing or a file.");
+      }
+
+      for(int j=0; j<vsize; j++){
+       String _src=(String)(v.elementAt(j));
+       String _dst=null;
+       if(isRemoteDir){
+         int i=_src.lastIndexOf(file_separatorc);
+          if(fs_is_bs){
+            int ii=_src.lastIndexOf('/');
+            if(ii!=-1 && ii>i)
+              i=ii; 
+          }
+         if(i==-1) dstsb.append(_src);
+         else dstsb.append(_src.substring(i + 1));
+          _dst=dstsb.toString();
+          dstsb.delete(dst.length(), _dst.length());
+       }
+        else{
+          _dst=dst;
+        }
+        //System.err.println("_dst "+_dst);
+
+       long size_of_dst=0;
+       if(mode==RESUME){
+         try{
+           SftpATTRS attr=_stat(_dst);
+           size_of_dst=attr.getSize();
+         }
+         catch(Exception eee){
+           //System.err.println(eee);
+         }
+         long size_of_src=new File(_src).length();
+         if(size_of_src<size_of_dst){
+           throw new SftpException(SSH_FX_FAILURE, 
+                                    "failed to resume for "+_dst);
+         }
+         if(size_of_src==size_of_dst){
+           return;
+         }
+       }
+
+        if(monitor!=null){
+         monitor.init(SftpProgressMonitor.PUT, _src, _dst,
+                      (new File(_src)).length());
+         if(mode==RESUME){
+           monitor.count(size_of_dst);
+         }
+        }
+       FileInputStream fis=null;
+       try{
+         fis=new FileInputStream(_src);
+         _put(fis, _dst, monitor, mode);
+       }
+       finally{
+         if(fis!=null) {
+           fis.close();
+         }
+       }
+      }
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, e.toString(), (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, e.toString());
+    }
+  }
+  public void put(InputStream src, String dst) throws SftpException{
+    put(src, dst, null, OVERWRITE);
+  }
+  public void put(InputStream src, String dst, int mode) throws SftpException{
+    put(src, dst, null, mode);
+  }
+  public void put(InputStream src, String dst, 
+                 SftpProgressMonitor monitor) throws SftpException{
+    put(src, dst, monitor, OVERWRITE);
+  }
+  public void put(InputStream src, String dst, 
+                 SftpProgressMonitor monitor, int mode) throws SftpException{
+    try{
+      dst=remoteAbsolutePath(dst);
+
+      Vector v=glob_remote(dst);
+      int vsize=v.size();
+      if(vsize!=1){
+        if(vsize==0){
+          if(isPattern(dst))
+            throw new SftpException(SSH_FX_FAILURE, dst);
+          else
+            dst=Util.unquote(dst);
+        }
+        throw new SftpException(SSH_FX_FAILURE, v.toString());
+      }
+      else{
+        dst=(String)(v.elementAt(0));
+      }
+
+      if(isRemoteDir(dst)){
+        throw new SftpException(SSH_FX_FAILURE, dst+" is a directory");
+      }
+
+      _put(src, dst, monitor, mode);
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, e.toString(), (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, e.toString());
+    }
+  }
+
+  public void _put(InputStream src, String dst, 
+                 SftpProgressMonitor monitor, int mode) throws SftpException{
+    try{
+      byte[] dstb=Util.str2byte(dst, fEncoding);
+      long skip=0;
+      if(mode==RESUME || mode==APPEND){
+       try{
+         SftpATTRS attr=_stat(dstb);
+         skip=attr.getSize();
+       }
+       catch(Exception eee){
+         //System.err.println(eee);
+       }
+      }
+      if(mode==RESUME && skip>0){
+       long skipped=src.skip(skip);
+       if(skipped<skip){
+         throw new SftpException(SSH_FX_FAILURE, "failed to resume for "+dst);
+       }
+      }
+
+      if(mode==OVERWRITE){ sendOPENW(dstb); }
+      else{ sendOPENA(dstb); }
+
+      Header header=new Header();
+      header=header(buf, header);
+      int length=header.length;
+      int type=header.type;
+
+      fill(buf, length);
+
+      if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
+       throw new SftpException(SSH_FX_FAILURE, "invalid type="+type);
+      }
+      if(type==SSH_FXP_STATUS){
+        int i=buf.getInt();
+        throwStatusError(buf, i);
+      }
+      byte[] handle=buf.getString();         // handle
+      byte[] data=null;
+
+      boolean dontcopy=true;
+
+      if(!dontcopy){
+        data=new byte[buf.buffer.length
+                      -(5+13+21+handle.length
+                        +32 +20 // padding and mac
+                        )
+        ];
+      }
+
+      long offset=0;
+      if(mode==RESUME || mode==APPEND){
+       offset+=skip;
+      }
+
+      int startid=seq;
+      int _ackid=seq;
+      int ackcount=0;
+      while(true){
+        int nread=0;
+        int s=0;
+        int datalen=0;
+        int count=0;
+
+        if(!dontcopy){
+          datalen=data.length-s;
+        }
+        else{
+          data=buf.buffer;
+          s=5+13+21+handle.length;
+          datalen=buf.buffer.length -s
+            -32 -20; // padding and mac
+        }
+
+        do{
+          nread=src.read(data, s, datalen);
+          if(nread>0){
+            s+=nread;
+            datalen-=nread;
+            count+=nread;
+          }
+        }
+        while(datalen>0 && nread>0); 
+        if(count<=0)break;
+
+        int _i=count;
+        while(_i>0){
+          _i-=sendWRITE(handle, offset, data, 0, _i);
+          if((seq-1)==startid ||
+             io_in.available()>=1024){
+            while(io_in.available()>0){
+              if(checkStatus(ackid, header)){
+                _ackid=ackid[0];
+                if(startid>_ackid || _ackid>seq-1){
+                  if(_ackid==seq){
+                    System.err.println("ack error: startid="+startid+" seq="+seq+" _ackid="+_ackid);
+                  } 
+                  else{
+                    //throw new SftpException(SSH_FX_FAILURE, "ack error:");
+                    throw new SftpException(SSH_FX_FAILURE, "ack error: startid="+startid+" seq="+seq+" _ackid="+_ackid);
+                  }
+                }
+                ackcount++;
+              }
+              else{
+                break;
+              }
+            }
+          }
+        }
+        offset+=count;
+       if(monitor!=null && !monitor.count(count)){
+          break;
+       }
+      }
+      int _ackcount=seq-startid;
+      while(_ackcount>ackcount){
+        if(!checkStatus(null, header)){
+          break;
+        }
+        ackcount++;
+      }
+      if(monitor!=null)monitor.end();
+      _sendCLOSE(handle, header);
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, e.toString(), (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, e.toString());
+    }
+  }
+
+  public OutputStream put(String dst) throws SftpException{
+    return put(dst, (SftpProgressMonitor)null, OVERWRITE);
+  }
+  public OutputStream put(String dst, final int mode) throws SftpException{
+    return put(dst, (SftpProgressMonitor)null, mode);
+  }
+  public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode) throws SftpException{
+    return put(dst, monitor, mode, 0);
+  }
+  public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode, long offset) throws SftpException{
+    dst=remoteAbsolutePath(dst);
+    try{
+
+      dst=isUnique(dst);
+
+      if(isRemoteDir(dst)){
+       throw new SftpException(SSH_FX_FAILURE, dst+" is a directory");
+      }
+
+      byte[] dstb=Util.str2byte(dst, fEncoding);
+
+      long skip=0;
+      if(mode==RESUME || mode==APPEND){
+       try{
+         SftpATTRS attr=_stat(dstb);
+         skip=attr.getSize();
+       }
+       catch(Exception eee){
+         //System.err.println(eee);
+       }
+      }
+
+      if(mode==OVERWRITE){ sendOPENW(dstb); }
+      else{ sendOPENA(dstb); }
+
+      Header header=new Header();
+      header=header(buf, header);
+      int length=header.length;
+      int type=header.type;
+
+      fill(buf, length);
+
+      if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
+       throw new SftpException(SSH_FX_FAILURE, "");
+      }
+      if(type==SSH_FXP_STATUS){
+        int i=buf.getInt();
+        throwStatusError(buf, i);
+      }
+      final byte[] handle=buf.getString();         // handle
+
+      if(mode==RESUME || mode==APPEND){
+       offset+=skip;
+      }
+
+      final long[] _offset=new long[1];
+      _offset[0]=offset;
+      OutputStream out = new OutputStream(){
+        private boolean init=true;
+        private boolean isClosed=false;
+        private int[] ackid=new int[1];
+        private int startid=0;
+        private int _ackid=0;
+        private int ackcount=0;
+        private int writecount=0;
+        private Header header=new Header();          
+
+        public void write(byte[] d) throws java.io.IOException{
+          write(d, 0, d.length);
+        }
+
+        public void write(byte[] d, int s, int len) throws java.io.IOException{
+          if(init){
+            startid=seq;
+            _ackid=seq;
+            init=false;
+          }
+
+          if(isClosed){
+            throw new IOException("stream already closed");
+          }
+
+          try{
+            int _len=len;
+            while(_len>0){
+              int sent=sendWRITE(handle, _offset[0], d, s, _len);
+              writecount++;
+              _offset[0]+=sent;
+              s+=sent;
+              _len-=sent;
+              if((seq-1)==startid ||
+                 io_in.available()>=1024){
+                while(io_in.available()>0){
+                  if(checkStatus(ackid, header)){
+                    _ackid=ackid[0];
+                    if(startid>_ackid || _ackid>seq-1){
+                      throw new SftpException(SSH_FX_FAILURE, "");
+                    }
+                    ackcount++;
+                  }
+                  else{
+                    break;
+                  }
+                }
+              }
+            }
+           if(monitor!=null && !monitor.count(len)){
+              close();
+              throw new IOException("canceled");
+           }
+          }
+          catch(IOException e){ throw e; }
+          catch(Exception e){ throw new IOException(e.toString());  }
+        }
+
+        byte[] _data=new byte[1];
+        public void write(int foo) throws java.io.IOException{
+          _data[0]=(byte)foo;
+          write(_data, 0, 1);
+        }
+
+        public void flush() throws java.io.IOException{
+
+          if(isClosed){
+            throw new IOException("stream already closed");
+          }
+
+          if(!init){
+            try{
+              while(writecount>ackcount){
+                if(!checkStatus(null, header)){
+                  break;
+                }
+                ackcount++;
+              }
+            }
+            catch(SftpException e){
+              throw new IOException(e.toString());
+            }
+          }
+        }
+
+        public void close() throws java.io.IOException{
+          if(isClosed){
+            return;
+          }
+          flush();
+          if(monitor!=null)monitor.end();
+          try{ _sendCLOSE(handle, header); }
+          catch(IOException e){ throw e; }
+          catch(Exception e){
+            throw new IOException(e.toString());
+          }
+          isClosed=true;
+        }
+      };
+      return out;
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  public void get(String src, String dst) throws SftpException{
+    get(src, dst, null, OVERWRITE);
+  }
+  public void get(String src, String dst,
+                 SftpProgressMonitor monitor) throws SftpException{
+    get(src, dst, monitor, OVERWRITE);
+  }
+  public void get(String src, String dst,
+                 SftpProgressMonitor monitor, int mode) throws SftpException{
+    // System.out.println("get: "+src+" "+dst);
+
+    src=remoteAbsolutePath(src);
+    dst=localAbsolutePath(dst);
+
+    try{
+      Vector v=glob_remote(src);
+      int vsize=v.size();
+      if(vsize==0){
+        throw new SftpException(SSH_FX_NO_SUCH_FILE, "No such file");
+      }
+
+      File dstFile=new File(dst);
+      boolean isDstDir=dstFile.isDirectory();
+      StringBuffer dstsb=null;
+      if(isDstDir){
+        if(!dst.endsWith(file_separator)){
+          dst+=file_separator;
+        }
+        dstsb=new StringBuffer(dst);
+      }
+      else if(vsize>1){
+        throw new SftpException(SSH_FX_FAILURE, 
+                                "Copying multiple files, but destination is missing or a file.");
+      }
+
+      for(int j=0; j<vsize; j++){
+       String _src=(String)(v.elementAt(j));
+       SftpATTRS attr=_stat(_src);
+        if(attr.isDir()){
+          throw new SftpException(SSH_FX_FAILURE, 
+                                  "not supported to get directory "+_src);
+        } 
+
+       String _dst=null;
+       if(isDstDir){
+         int i=_src.lastIndexOf('/');
+         if(i==-1) dstsb.append(_src);
+         else dstsb.append(_src.substring(i + 1));
+          _dst=dstsb.toString();
+          dstsb.delete(dst.length(), _dst.length());
+       }
+        else{
+          _dst=dst;
+        }
+
+       if(mode==RESUME){
+         long size_of_src=attr.getSize();
+         long size_of_dst=new File(_dst).length();
+         if(size_of_dst>size_of_src){
+           throw new SftpException(SSH_FX_FAILURE, 
+                                    "failed to resume for "+_dst);
+         }
+         if(size_of_dst==size_of_src){
+           return;
+         }
+       }
+
+       if(monitor!=null){
+         monitor.init(SftpProgressMonitor.GET, _src, _dst, attr.getSize());
+         if(mode==RESUME){
+           monitor.count(new File(_dst).length());
+         }
+       }
+
+       FileOutputStream fos=null;
+        try{
+          if(mode==OVERWRITE){
+            fos=new FileOutputStream(_dst);
+          }
+          else{
+            fos=new FileOutputStream(_dst, true); // append
+          }
+          // System.err.println("_get: "+_src+", "+_dst);
+          _get(_src, fos, monitor, mode, new File(_dst).length());
+        }
+        finally{
+          if(fos!=null){
+            fos.close();
+          }
+        }
+      }
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+  public void get(String src, OutputStream dst) throws SftpException{
+    get(src, dst, null, OVERWRITE, 0);
+  }
+  public void get(String src, OutputStream dst,
+                 SftpProgressMonitor monitor) throws SftpException{
+    get(src, dst, monitor, OVERWRITE, 0);
+  }
+  public void get(String src, OutputStream dst,
+                  SftpProgressMonitor monitor, int mode, long skip) throws SftpException{
+//System.err.println("get: "+src+", "+dst);
+    try{
+      src=remoteAbsolutePath(src);
+
+      src=isUnique(src);
+
+      if(monitor!=null){
+       SftpATTRS attr=_stat(src);
+        monitor.init(SftpProgressMonitor.GET, src, "??", attr.getSize());
+        if(mode==RESUME){
+          monitor.count(skip);
+        }
+      }
+      _get(src, dst, monitor, mode, skip);
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  private void _get(String src, OutputStream dst,
+                    SftpProgressMonitor monitor, int mode, long skip) throws SftpException{
+    //System.err.println("_get: "+src+", "+dst);
+
+    byte[] srcb=Util.str2byte(src, fEncoding);
+    try{
+      sendOPENR(srcb);
+
+      Header header=new Header();
+      header=header(buf, header);
+      int length=header.length;
+      int type=header.type;
+
+      fill(buf, length);
+
+      if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
+       throw new SftpException(SSH_FX_FAILURE, "");
+      }
+
+      if(type==SSH_FXP_STATUS){
+        int i=buf.getInt();
+        throwStatusError(buf, i);
+      }
+
+      byte[] handle=buf.getString();         // filename
+
+      long offset=0;
+      if(mode==RESUME){
+       offset+=skip;
+      }
+
+      int request_len=0;
+      loop:
+      while(true){
+
+        request_len=buf.buffer.length-13;
+        if(server_version==0){ request_len=1024; }
+        sendREAD(handle, offset, request_len);
+
+        header=header(buf, header);
+        length=header.length;
+        type=header.type;
+
+        if(type==SSH_FXP_STATUS){
+          fill(buf, length);
+          int i=buf.getInt();    
+          if(i==SSH_FX_EOF){
+            break loop;
+          }
+          throwStatusError(buf, i);
+        }
+
+        if(type!=SSH_FXP_DATA){ 
+         break loop;
+        }
+
+        buf.rewind();
+        fill(buf.buffer, 0, 4); length-=4;
+        int i=buf.getInt();   // length of data 
+        int foo=i;
+
+        while(foo>0){
+          int bar=foo;
+          if(bar>buf.buffer.length){
+            bar=buf.buffer.length;
+          }
+          i=io_in.read(buf.buffer, 0, bar);
+          if(i<0){
+            break loop;
+         }
+          int data_len=i;
+          dst.write(buf.buffer, 0, data_len);
+
+          offset+=data_len;
+          foo-=data_len;
+
+          if(monitor!=null){
+            if(!monitor.count(data_len)){
+              while(foo>0){
+                i=io_in.read(buf.buffer, 
+                             0, 
+                             (buf.buffer.length<foo?buf.buffer.length:foo));
+                if(i<=0) break;
+                foo-=i;
+              }
+              break loop;
+            }
+          }
+
+        }
+       //System.err.println("length: "+length);  // length should be 0
+      }
+      dst.flush();
+
+      if(monitor!=null)monitor.end();
+      _sendCLOSE(handle, header);
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  public InputStream get(String src) throws SftpException{
+    return get(src, null, 0L);
+  }
+  public InputStream get(String src, SftpProgressMonitor monitor) throws SftpException{
+    return get(src, monitor, 0L);
+  }
+
+  /**
+   * @deprecated  This method will be deleted in the future.
+   */
+  public InputStream get(String src, int mode) throws SftpException{
+    return get(src, null, 0L);
+  }
+  /**
+   * @deprecated  This method will be deleted in the future.
+   */
+  public InputStream get(String src, final SftpProgressMonitor monitor, final int mode) throws SftpException{
+    return get(src, monitor, 0L);
+  }
+  public InputStream get(String src, final SftpProgressMonitor monitor, final long skip) throws SftpException{
+    src=remoteAbsolutePath(src);
+    try{
+      src=isUnique(src);
+
+      byte[] srcb=Util.str2byte(src, fEncoding);
+
+      SftpATTRS attr=_stat(srcb);
+      if(monitor!=null){
+        monitor.init(SftpProgressMonitor.GET, src, "??", attr.getSize());
+      }
+
+      sendOPENR(srcb);
+
+      Header header=new Header();
+      header=header(buf, header);
+      int length=header.length;
+      int type=header.type;
+
+      fill(buf, length);
+
+      if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
+       throw new SftpException(SSH_FX_FAILURE, "");
+      }
+      if(type==SSH_FXP_STATUS){
+        int i=buf.getInt();
+        throwStatusError(buf, i);
+      }
+
+      final byte[] handle=buf.getString();         // handle
+
+      java.io.InputStream in=new java.io.InputStream(){
+           long offset=skip;
+           boolean closed=false;
+           int rest_length=0;
+           byte[] _data=new byte[1];
+           byte[] rest_byte=new byte[1024];
+           Header header=new Header();
+
+           public int read() throws java.io.IOException{
+             if(closed)return -1;
+             int i=read(_data, 0, 1);
+             if (i==-1) { return -1; }
+             else {
+               return _data[0]&0xff;
+             }
+           }
+           public int read(byte[] d) throws java.io.IOException{
+             if(closed)return -1;
+             return read(d, 0, d.length);
+           }
+           public int read(byte[] d, int s, int len) throws java.io.IOException{
+             if(closed)return -1;
+             if(d==null){throw new NullPointerException();}
+             if(s<0 || len <0 || s+len>d.length){
+               throw new IndexOutOfBoundsException();
+             } 
+             if(len==0){ return 0; }
+
+             if(rest_length>0){
+               int foo=rest_length;
+               if(foo>len) foo=len;
+               System.arraycopy(rest_byte, 0, d, s, foo);
+               if(foo!=rest_length){
+                 System.arraycopy(rest_byte, foo, 
+                                  rest_byte, 0, rest_length-foo);
+               }
+
+               if(monitor!=null){
+                 if(!monitor.count(foo)){
+                   close();
+                   return -1;
+                 }
+               }
+
+               rest_length-=foo;
+               return foo;
+             }
+
+             if(buf.buffer.length-13<len){
+               len=buf.buffer.length-13;
+             }
+             if(server_version==0 && len>1024){
+               len=1024; 
+             }
+
+             try{sendREAD(handle, offset, len);}
+             catch(Exception e){ throw new IOException("error"); }
+
+             header=header(buf, header);
+             rest_length=header.length;
+             int type=header.type;
+             int id=header.rid;
+
+             if(type!=SSH_FXP_STATUS && type!=SSH_FXP_DATA){ 
+               throw new IOException("error");
+             }
+             if(type==SSH_FXP_STATUS){
+               fill(buf, rest_length);
+               int i=buf.getInt();    
+               rest_length=0;
+               if(i==SSH_FX_EOF){
+                 close();
+                 return -1;
+               }
+               //throwStatusError(buf, i);
+               throw new IOException("error");
+             }
+             buf.rewind();
+             fill(buf.buffer, 0, 4);
+             int i=buf.getInt(); rest_length-=4;
+
+             offset+=rest_length;
+             int foo=i;
+             if(foo>0){
+               int bar=rest_length;
+               if(bar>len){
+                 bar=len;
+               }
+               i=io_in.read(d, s, bar);
+               if(i<0){
+                 return -1;
+               }
+               rest_length-=i;
+
+               if(rest_length>0){
+                 if(rest_byte.length<rest_length){
+                   rest_byte=new byte[rest_length];
+                 }
+                 int _s=0;
+                 int _len=rest_length;
+                 int j;
+                 while(_len>0){
+                   j=io_in.read(rest_byte, _s, _len);
+                   if(j<=0)break;
+                   _s+=j;
+                   _len-=j;
+                 }
+               }
+
+               if(monitor!=null){
+                 if(!monitor.count(i)){
+                   close();
+                   return -1;
+                 }
+               }
+
+               return i;
+             }
+             return 0; // ??
+           }
+           public void close() throws IOException{
+             if(closed)return;
+             closed=true;
+             if(monitor!=null)monitor.end();
+             try{_sendCLOSE(handle, header);}
+             catch(Exception e){throw new IOException("error");}
+           }
+         };
+       return in;
+     }
+     catch(Exception e){
+       if(e instanceof SftpException) throw (SftpException)e;
+       if(e instanceof Throwable)
+         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+       throw new SftpException(SSH_FX_FAILURE, "");
+     }
+   }
+
+   public java.util.Vector ls(String path) throws SftpException{
+     //System.out.println("ls: "+path);
+     try{
+       path=remoteAbsolutePath(path);
+       byte[] pattern=null;
+       java.util.Vector v=new java.util.Vector();
+
+       int foo=path.lastIndexOf('/');
+       String dir=path.substring(0, ((foo==0)?1:foo));
+       String _pattern=path.substring(foo+1);
+       dir=Util.unquote(dir);
+
+       // If pattern has included '*' or '?', we need to convert
+       // to UTF-8 string before globbing.
+       byte[][] _pattern_utf8=new byte[1][];
+       boolean pattern_has_wildcard=isPattern(_pattern, _pattern_utf8);
+
+       if(pattern_has_wildcard){
+         pattern=_pattern_utf8[0];
+       }
+       else{
+         String upath=Util.unquote(path);
+         //SftpATTRS attr=_lstat(upath);
+         SftpATTRS attr=_stat(upath);
+         if(attr.isDir()){
+           pattern=null;
+           dir=upath;
+         }
+         else{
+           /*
+             // If we can generage longname by ourself,
+             // we don't have to use openDIR.
+           String filename=Util.unquote(_pattern);
+           String longname=...
+           v.addElement(new LsEntry(filename, longname, attr));
+           return v;
+           */
+
+           if(fEncoding_is_utf8){
+             pattern=_pattern_utf8[0];
+             pattern=Util.unquote(pattern);
+           }
+           else{
+             _pattern=Util.unquote(_pattern);
+             pattern=Util.str2byte(_pattern, fEncoding);
+           }
+
+         }
+       }
+
+       sendOPENDIR(Util.str2byte(dir, fEncoding));
+
+       Header header=new Header();
+       header=header(buf, header);
+       int length=header.length;
+       int type=header.type;
+
+       fill(buf, length);
+
+       if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
+         throw new SftpException(SSH_FX_FAILURE, "");
+       }
+       if(type==SSH_FXP_STATUS){
+         int i=buf.getInt();
+         throwStatusError(buf, i);
+       }
+
+       byte[] handle=buf.getString();         // handle
+
+       while(true){
+         sendREADDIR(handle);
+
+         header=header(buf, header);
+         length=header.length;
+         type=header.type;
+         if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){
+           throw new SftpException(SSH_FX_FAILURE, "");
+         }
+         if(type==SSH_FXP_STATUS){ 
+           fill(buf, length);
+           int i=buf.getInt();
+           if(i==SSH_FX_EOF)
+             break;
+           throwStatusError(buf, i);
+         }
+
+         buf.rewind();
+         fill(buf.buffer, 0, 4); length-=4;
+         int count=buf.getInt();
+
+         byte[] str;
+         int flags;
+
+         buf.reset();
+         while(count>0){
+           if(length>0){
+             buf.shift();
+             int j=(buf.buffer.length>(buf.index+length)) ? 
+               length : 
+               (buf.buffer.length-buf.index);
+             int i=fill(buf.buffer, buf.index, j);
+             buf.index+=i;
+             length-=i;
+           }
+           byte[] filename=buf.getString();
+           byte[] longname=null;
+           if(server_version<=3){
+             longname=buf.getString();
+           }
+           SftpATTRS attrs=SftpATTRS.getATTR(buf);
+
+           boolean find=false;
+           String f=null;
+           if(pattern==null){
+             find=true;
+           }
+           else if(!pattern_has_wildcard){
+             find=Util.array_equals(pattern, filename);
+           }
+           else{
+             byte[] _filename=filename;
+             if(!fEncoding_is_utf8){
+               f=Util.byte2str(_filename, fEncoding);
+               _filename=Util.str2byte(f, UTF8);
+             }
+             find=Util.glob(pattern, _filename);
+           }
+
+           if(find){
+             if(f==null){
+               f=Util.byte2str(filename, fEncoding);
+             }
+             String l=null;
+             if(longname==null){
+               // TODO: we need to generate long name from attrs
+               //       for the sftp protocol 4(and later).
+               l=attrs.toString()+" "+f;
+             }
+             else{
+               l=Util.byte2str(longname, fEncoding);
+             }
+             v.addElement(new LsEntry(f, l, attrs));
+           }
+
+           count--; 
+         }
+       }
+       _sendCLOSE(handle, header);
+
+       /*
+       if(v.size()==1 && pattern_has_wildcard){
+         LsEntry le=(LsEntry)v.elementAt(0);
+         if(le.getAttrs().isDir()){
+           String f=le.getFilename();
+           if(isPattern(f)){
+             f=Util.quote(f);
+           }
+           if(!dir.endsWith("/")){
+             dir+="/";
+           }
+           v=null;
+           return ls(dir+f);
+         }
+       }
+       */
+
+       return v;
+     }
+     catch(Exception e){
+       if(e instanceof SftpException) throw (SftpException)e;
+       if(e instanceof Throwable)
+         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+       throw new SftpException(SSH_FX_FAILURE, "");
+     }
+   }
+   public String readlink(String path) throws SftpException{
+     try{
+
+       if(server_version<3){
+         throw new SftpException(SSH_FX_OP_UNSUPPORTED, 
+                                 "The remote sshd is too old to support symlink operation.");
+       }
+
+       path=remoteAbsolutePath(path);
+
+       path=isUnique(path);
+
+       sendREADLINK(Util.str2byte(path, fEncoding));
+
+       Header header=new Header();
+       header=header(buf, header);
+       int length=header.length;
+       int type=header.type;
+
+       fill(buf, length);
+
+       if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){
+         throw new SftpException(SSH_FX_FAILURE, "");
+       }
+       if(type==SSH_FXP_NAME){
+         int count=buf.getInt();       // count
+         byte[] filename=null;
+         for(int i=0; i<count; i++){
+           filename=buf.getString();
+           if(server_version<=3){
+             byte[] longname=buf.getString();
+           }
+           SftpATTRS.getATTR(buf);
+         }
+         return Util.byte2str(filename, fEncoding);
+       }
+
+       int i=buf.getInt();
+       throwStatusError(buf, i);
+     }
+     catch(Exception e){
+       if(e instanceof SftpException) throw (SftpException)e;
+       if(e instanceof Throwable)
+         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+       throw new SftpException(SSH_FX_FAILURE, "");
+     }
+     return null;
+   }
+   public void symlink(String oldpath, String newpath) throws SftpException{
+     if(server_version<3){
+       throw new SftpException(SSH_FX_OP_UNSUPPORTED, 
+                               "The remote sshd is too old to support symlink operation.");
+     }
+
+     try{
+       oldpath=remoteAbsolutePath(oldpath);
+       newpath=remoteAbsolutePath(newpath);
+
+       oldpath=isUnique(oldpath);
+
+       if(isPattern(newpath)){
+         throw new SftpException(SSH_FX_FAILURE, newpath);
+       }
+       newpath=Util.unquote(newpath);
+
+       sendSYMLINK(Util.str2byte(oldpath, fEncoding),
+                   Util.str2byte(newpath, fEncoding));
+
+       Header header=new Header();
+       header=header(buf, header);
+       int length=header.length;
+       int type=header.type;
+
+       fill(buf, length);
+
+       if(type!=SSH_FXP_STATUS){
+         throw new SftpException(SSH_FX_FAILURE, "");
+       }
+
+       int i=buf.getInt();
+       if(i==SSH_FX_OK) return;
+       throwStatusError(buf, i);
+     }
+     catch(Exception e){
+       if(e instanceof SftpException) throw (SftpException)e;
+       if(e instanceof Throwable)
+         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+       throw new SftpException(SSH_FX_FAILURE, "");
+     }
+   }
+
+   public void rename(String oldpath, String newpath) throws SftpException{
+     if(server_version<2){
+       throw new SftpException(SSH_FX_OP_UNSUPPORTED, 
+                               "The remote sshd is too old to support rename operation.");
+     }
+
+     try{
+       oldpath=remoteAbsolutePath(oldpath);
+       newpath=remoteAbsolutePath(newpath);
+
+       oldpath=isUnique(oldpath);
+
+       Vector v=glob_remote(newpath);
+       int vsize=v.size();
+       if(vsize>=2){
+         throw new SftpException(SSH_FX_FAILURE, v.toString());
+       }
+       if(vsize==1){
+         newpath=(String)(v.elementAt(0));
+       }
+       else{  // vsize==0
+         if(isPattern(newpath))
+           throw new SftpException(SSH_FX_FAILURE, newpath);
+         newpath=Util.unquote(newpath);
+       }
+
+       sendRENAME(Util.str2byte(oldpath, fEncoding),
+                  Util.str2byte(newpath, fEncoding));
+
+       Header header=new Header();
+       header=header(buf, header);
+       int length=header.length;
+       int type=header.type;
+
+       fill(buf, length);
+
+       if(type!=SSH_FXP_STATUS){
+         throw new SftpException(SSH_FX_FAILURE, "");
+       }
+
+       int i=buf.getInt();
+       if(i==SSH_FX_OK) return;
+       throwStatusError(buf, i);
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+  public void rm(String path) throws SftpException{
+    try{
+      path=remoteAbsolutePath(path);
+
+      Vector v=glob_remote(path);
+      int vsize=v.size();
+
+      Header header=new Header();
+
+      for(int j=0; j<vsize; j++){
+       path=(String)(v.elementAt(j));
+        sendREMOVE(Util.str2byte(path, fEncoding));
+
+        header=header(buf, header);
+        int length=header.length;
+        int type=header.type;
+
+        fill(buf, length);
+
+        if(type!=SSH_FXP_STATUS){
+         throw new SftpException(SSH_FX_FAILURE, "");
+        }
+        int i=buf.getInt();
+       if(i!=SSH_FX_OK){
+         throwStatusError(buf, i);
+       }
+      }
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  private boolean isRemoteDir(String path){
+    try{
+      sendSTAT(Util.str2byte(path, fEncoding));
+
+      Header header=new Header();
+      header=header(buf, header);
+      int length=header.length;
+      int type=header.type;
+
+      fill(buf, length);
+
+      if(type!=SSH_FXP_ATTRS){
+        return false; 
+      }
+      SftpATTRS attr=SftpATTRS.getATTR(buf);
+      return attr.isDir();
+    }
+    catch(Exception e){}
+    return false;
+  }
+
+  public void chgrp(int gid, String path) throws SftpException{
+    try{
+      path=remoteAbsolutePath(path);
+
+      Vector v=glob_remote(path);
+      int vsize=v.size();
+      for(int j=0; j<vsize; j++){
+       path=(String)(v.elementAt(j));
+
+        SftpATTRS attr=_stat(path);
+
+       attr.setFLAGS(0);
+       attr.setUIDGID(attr.uid, gid); 
+       _setStat(path, attr);
+      }
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  public void chown(int uid, String path) throws SftpException{
+    try{
+      path=remoteAbsolutePath(path);
+
+      Vector v=glob_remote(path);
+      int vsize=v.size();
+      for(int j=0; j<vsize; j++){
+       path=(String)(v.elementAt(j));
+
+        SftpATTRS attr=_stat(path);
+
+       attr.setFLAGS(0);
+       attr.setUIDGID(uid, attr.gid); 
+       _setStat(path, attr);
+      }
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  public void chmod(int permissions, String path) throws SftpException{
+    try{
+      path=remoteAbsolutePath(path);
+
+      Vector v=glob_remote(path);
+      int vsize=v.size();
+      for(int j=0; j<vsize; j++){
+       path=(String)(v.elementAt(j));
+
+       SftpATTRS attr=_stat(path);
+
+       attr.setFLAGS(0);
+       attr.setPERMISSIONS(permissions); 
+       _setStat(path, attr);
+      }
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  public void setMtime(String path, int mtime) throws SftpException{
+    try{
+      path=remoteAbsolutePath(path);
+
+      Vector v=glob_remote(path);
+      int vsize=v.size();
+      for(int j=0; j<vsize; j++){
+       path=(String)(v.elementAt(j));
+
+        SftpATTRS attr=_stat(path);
+
+       attr.setFLAGS(0);
+       attr.setACMODTIME(attr.getATime(), mtime);
+       _setStat(path, attr);
+      }
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  public void rmdir(String path) throws SftpException{
+    try{
+      path=remoteAbsolutePath(path);
+
+      Vector v=glob_remote(path);
+      int vsize=v.size();
+
+      Header header=new Header();
+
+      for(int j=0; j<vsize; j++){
+       path=(String)(v.elementAt(j));
+       sendRMDIR(Util.str2byte(path, fEncoding));
+
+        header=header(buf, header);
+        int length=header.length;
+        int type=header.type;
+
+        fill(buf, length);
+
+       if(type!=SSH_FXP_STATUS){
+         throw new SftpException(SSH_FX_FAILURE, "");
+       }
+
+       int i=buf.getInt();
+       if(i!=SSH_FX_OK){
+         throwStatusError(buf, i);
+       }
+      }
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  public void mkdir(String path) throws SftpException{
+    try{
+      path=remoteAbsolutePath(path);
+
+      sendMKDIR(Util.str2byte(path, fEncoding), null);
+
+      Header header=new Header();      
+      header=header(buf, header);
+      int length=header.length;
+      int type=header.type;
+
+      fill(buf, length);
+
+      if(type!=SSH_FXP_STATUS){
+       throw new SftpException(SSH_FX_FAILURE, "");
+      }
+
+      int i=buf.getInt();
+      if(i==SSH_FX_OK) return;
+      throwStatusError(buf, i);
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  public SftpATTRS stat(String path) throws SftpException{
+    try{
+      path=remoteAbsolutePath(path);
+
+      path=isUnique(path);
+
+      return _stat(path);
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+    //return null;
+  }
+
+  private SftpATTRS _stat(byte[] path) throws SftpException{
+    try{
+
+      sendSTAT(path);
+
+      Header header=new Header();
+      header=header(buf, header);
+      int length=header.length;
+      int type=header.type;
+
+      fill(buf, length);
+
+      if(type!=SSH_FXP_ATTRS){
+       if(type==SSH_FXP_STATUS){
+         int i=buf.getInt();
+         throwStatusError(buf, i);
+       }
+       throw new SftpException(SSH_FX_FAILURE, "");
+      }
+      SftpATTRS attr=SftpATTRS.getATTR(buf);
+      return attr;
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+    //return null;
+  }
+
+  private SftpATTRS _stat(String path) throws SftpException{
+    return _stat(Util.str2byte(path, fEncoding));
+  }
+
+  public SftpATTRS lstat(String path) throws SftpException{
+    try{
+      path=remoteAbsolutePath(path);
+
+      path=isUnique(path);
+
+      return _lstat(path);
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  private SftpATTRS _lstat(String path) throws SftpException{
+    try{
+      sendLSTAT(Util.str2byte(path, fEncoding));
+
+      Header header=new Header();
+      header=header(buf, header);
+      int length=header.length;
+      int type=header.type;
+
+      fill(buf, length);
+
+      if(type!=SSH_FXP_ATTRS){
+       if(type==SSH_FXP_STATUS){
+         int i=buf.getInt();
+         throwStatusError(buf, i);
+       }
+       throw new SftpException(SSH_FX_FAILURE, "");
+      }
+      SftpATTRS attr=SftpATTRS.getATTR(buf);
+      return attr;
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  private byte[] _realpath(String path) throws SftpException, IOException, Exception{
+    sendREALPATH(Util.str2byte(path, fEncoding));
+
+    Header header=new Header();
+    header=header(buf, header);
+    int length=header.length;
+    int type=header.type;
+
+    fill(buf, length);
+
+    if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+    int i;
+    if(type==SSH_FXP_STATUS){
+      i=buf.getInt();
+      throwStatusError(buf, i);
+    }
+    i=buf.getInt();   // count
+
+    byte[] str=null;
+    while(i-->0){
+      str=buf.getString();  // absolute path;
+      if(server_version<=3){
+        byte[] lname=buf.getString();  // long filename
+      }
+      SftpATTRS attr=SftpATTRS.getATTR(buf);  // dummy attribute
+    }
+    return str;
+  }
+
+  public void setStat(String path, SftpATTRS attr) throws SftpException{
+    try{
+      path=remoteAbsolutePath(path);
+
+      Vector v=glob_remote(path);
+      int vsize=v.size();
+      for(int j=0; j<vsize; j++){
+       path=(String)(v.elementAt(j));
+       _setStat(path, attr);
+      }
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+  private void _setStat(String path, SftpATTRS attr) throws SftpException{
+    try{
+      sendSETSTAT(Util.str2byte(path, fEncoding), attr);
+
+      Header header=new Header();
+      header=header(buf, header);
+      int length=header.length;
+      int type=header.type;
+
+      fill(buf, length);
+
+      if(type!=SSH_FXP_STATUS){
+       throw new SftpException(SSH_FX_FAILURE, "");
+      }
+      int i=buf.getInt();
+      if(i!=SSH_FX_OK){
+       throwStatusError(buf, i);
+      }
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  public String pwd() throws SftpException{ return getCwd(); }
+  public String lpwd(){ return lcwd; }
+  public String version(){ return version; }
+  public String getHome() throws SftpException {
+    if(home==null){
+      try{
+        byte[] _home=_realpath("");
+        home=Util.byte2str(_home, fEncoding);
+      }
+      catch(Exception e){
+        if(e instanceof SftpException) throw (SftpException)e;
+        if(e instanceof Throwable)
+          throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+        throw new SftpException(SSH_FX_FAILURE, "");
+      }
+    }
+    return home; 
+  }
+
+  private String getCwd() throws SftpException{
+    if(cwd==null)
+      cwd=getHome();
+    return cwd;
+  }
+
+  private void setCwd(String cwd){
+    this.cwd=cwd;
+  }
+
+  private void read(byte[] buf, int s, int l) throws IOException, SftpException{
+    int i=0;
+    while(l>0){
+      i=io_in.read(buf, s, l);
+      if(i<=0){
+        throw new SftpException(SSH_FX_FAILURE, "");
+      }
+      s+=i;
+      l-=i;
+    }
+  }
+
+  private boolean checkStatus(int[] ackid, Header header) throws IOException, SftpException{
+    header=header(buf, header);
+    int length=header.length;
+    int type=header.type;
+    if(ackid!=null)
+      ackid[0]=header.rid;
+
+    fill(buf, length);
+
+    if(type!=SSH_FXP_STATUS){ 
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+    int i=buf.getInt();
+    if(i!=SSH_FX_OK){
+      throwStatusError(buf, i);
+    }
+    return true;
+  }
+  private boolean _sendCLOSE(byte[] handle, Header header) throws Exception{
+    sendCLOSE(handle);
+    return checkStatus(null, header);
+  }
+
+  private void sendINIT() throws Exception{
+    packet.reset();
+    putHEAD(SSH_FXP_INIT, 5);
+    buf.putInt(3);                // version 3
+    getSession().write(packet, this, 5+4);
+  }
+
+  private void sendREALPATH(byte[] path) throws Exception{
+    sendPacketPath(SSH_FXP_REALPATH, path);
+  }
+  private void sendSTAT(byte[] path) throws Exception{
+    sendPacketPath(SSH_FXP_STAT, path);
+  }
+  private void sendLSTAT(byte[] path) throws Exception{
+    sendPacketPath(SSH_FXP_LSTAT, path);
+  }
+  private void sendFSTAT(byte[] handle) throws Exception{
+    sendPacketPath(SSH_FXP_FSTAT, handle);
+  }
+  private void sendSETSTAT(byte[] path, SftpATTRS attr) throws Exception{
+    packet.reset();
+    putHEAD(SSH_FXP_SETSTAT, 9+path.length+attr.length());
+    buf.putInt(seq++);
+    buf.putString(path);             // path
+    attr.dump(buf);
+    getSession().write(packet, this, 9+path.length+attr.length()+4);
+  }
+  private void sendREMOVE(byte[] path) throws Exception{
+    sendPacketPath(SSH_FXP_REMOVE, path);
+  }
+  private void sendMKDIR(byte[] path, SftpATTRS attr) throws Exception{
+    packet.reset();
+    putHEAD(SSH_FXP_MKDIR, 9+path.length+(attr!=null?attr.length():4));
+    buf.putInt(seq++);
+    buf.putString(path);             // path
+    if(attr!=null) attr.dump(buf);
+    else buf.putInt(0);
+    getSession().write(packet, this, 9+path.length+(attr!=null?attr.length():4)+4);
+  }
+  private void sendRMDIR(byte[] path) throws Exception{
+    sendPacketPath(SSH_FXP_RMDIR, path);
+  }
+  private void sendSYMLINK(byte[] p1, byte[] p2) throws Exception{
+    sendPacketPath(SSH_FXP_SYMLINK, p1, p2);
+  }
+  private void sendREADLINK(byte[] path) throws Exception{
+    sendPacketPath(SSH_FXP_READLINK, path);
+  }
+  private void sendOPENDIR(byte[] path) throws Exception{
+    sendPacketPath(SSH_FXP_OPENDIR, path);
+  }
+  private void sendREADDIR(byte[] path) throws Exception{
+    sendPacketPath(SSH_FXP_READDIR, path);
+  }
+  private void sendRENAME(byte[] p1, byte[] p2) throws Exception{
+    sendPacketPath(SSH_FXP_RENAME, p1, p2);
+  }
+  private void sendCLOSE(byte[] path) throws Exception{
+    sendPacketPath(SSH_FXP_CLOSE, path);
+  }
+  private void sendOPENR(byte[] path) throws Exception{
+    sendOPEN(path, SSH_FXF_READ);
+  }
+  private void sendOPENW(byte[] path) throws Exception{
+    sendOPEN(path, SSH_FXF_WRITE|SSH_FXF_CREAT|SSH_FXF_TRUNC);
+  }
+  private void sendOPENA(byte[] path) throws Exception{
+    sendOPEN(path, SSH_FXF_WRITE|/*SSH_FXF_APPEND|*/SSH_FXF_CREAT);
+  }
+  private void sendOPEN(byte[] path, int mode) throws Exception{
+    packet.reset();
+    putHEAD(SSH_FXP_OPEN, 17+path.length);
+    buf.putInt(seq++);
+    buf.putString(path);
+    buf.putInt(mode);
+    buf.putInt(0);           // attrs
+    getSession().write(packet, this, 17+path.length+4);
+  }
+  private void sendPacketPath(byte fxp, byte[] path) throws Exception{
+    packet.reset();
+    putHEAD(fxp, 9+path.length);
+    buf.putInt(seq++);
+    buf.putString(path);             // path
+    getSession().write(packet, this, 9+path.length+4);
+  }
+  private void sendPacketPath(byte fxp, byte[] p1, byte[] p2) throws Exception{
+    packet.reset();
+    putHEAD(fxp, 13+p1.length+p2.length);
+    buf.putInt(seq++);
+    buf.putString(p1);
+    buf.putString(p2);
+    getSession().write(packet, this, 13+p1.length+p2.length+4);
+  }
+
+  private int sendWRITE(byte[] handle, long offset, 
+                        byte[] data, int start, int length) throws Exception{
+    int _length=length;
+    packet.reset();
+    if(buf.buffer.length<buf.index+13+21+handle.length+length
+       +32 +20  // padding and mac
+){
+      _length=buf.buffer.length-(buf.index+13+21+handle.length
+                                 +32 +20  // padding and mac
+);
+      //System.err.println("_length="+_length+" length="+length);
+    }
+
+    putHEAD(SSH_FXP_WRITE, 21+handle.length+_length);       // 14
+    buf.putInt(seq++);                                      //  4
+    buf.putString(handle);                                  //  4+handle.length
+    buf.putLong(offset);                                    //  8
+    if(buf.buffer!=data){
+    buf.putString(data, start, _length);                    //  4+_length
+    }
+    else{
+      buf.putInt(_length);
+      buf.skip(_length);
+    }
+    getSession().write(packet, this, 21+handle.length+_length+4);
+    return _length;
+  }
+
+  private void sendREAD(byte[] handle, long offset, int length) throws Exception{
+    packet.reset();
+    putHEAD(SSH_FXP_READ, 21+handle.length);
+    buf.putInt(seq++);
+    buf.putString(handle);
+    buf.putLong(offset);
+    buf.putInt(length);
+    getSession().write(packet, this, 21+handle.length+4);
+  }
+
+  private void putHEAD(byte type, int length) throws Exception{
+    buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA);
+    buf.putInt(recipient);
+    buf.putInt(length+4);
+    buf.putInt(length);
+    buf.putByte(type);
+  }
+
+  private Vector glob_remote(String _path) throws Exception{
+    Vector v=new Vector();
+    int i=0;
+
+    int foo=_path.lastIndexOf('/');
+    if(foo<0){  // it is not absolute path.
+      v.addElement(Util.unquote(_path)); 
+      return v;
+    }
+
+    String dir=_path.substring(0, ((foo==0)?1:foo));
+    String _pattern=_path.substring(foo+1);
+
+    dir=Util.unquote(dir);
+
+    byte[] pattern=null;
+    byte[][] _pattern_utf8=new byte[1][];
+    boolean pattern_has_wildcard=isPattern(_pattern, _pattern_utf8);
+
+    if(!pattern_has_wildcard){
+      if(!dir.equals("/"))
+        dir+="/";
+      v.addElement(dir+Util.unquote(_pattern));
+      return v;
+    }
+
+    pattern=_pattern_utf8[0];
+
+    sendOPENDIR(Util.str2byte(dir, fEncoding));
+
+    Header header=new Header();
+    header=header(buf, header);
+    int length=header.length;
+    int type=header.type;
+
+    fill(buf, length);
+
+    if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+    if(type==SSH_FXP_STATUS){
+      i=buf.getInt();
+      throwStatusError(buf, i);
+    }
+
+    byte[] handle=buf.getString();         // filename
+    String pdir=null;                      // parent directory
+
+    while(true){
+      sendREADDIR(handle);
+      header=header(buf, header);
+      length=header.length;
+      type=header.type;
+
+      if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){
+       throw new SftpException(SSH_FX_FAILURE, "");
+      }
+      if(type==SSH_FXP_STATUS){ 
+        fill(buf, length);
+       break;
+      }
+
+      buf.rewind();
+      fill(buf.buffer, 0, 4); length-=4;
+      int count=buf.getInt();
+
+      byte[] str;
+      int flags;
+
+      buf.reset();
+      while(count>0){
+       if(length>0){
+         buf.shift();
+          int j=(buf.buffer.length>(buf.index+length)) ? length : (buf.buffer.length-buf.index);
+         i=io_in.read(buf.buffer, buf.index, j);
+         if(i<=0)break;
+         buf.index+=i;
+         length-=i;
+       }
+
+       byte[] filename=buf.getString();
+       //System.err.println("filename: "+new String(filename));
+        if(server_version<=3){
+          str=buf.getString();  // longname
+        }
+       SftpATTRS attrs=SftpATTRS.getATTR(buf);
+
+        byte[] _filename=filename;
+        String f=null;
+        boolean found=false;
+
+        if(!fEncoding_is_utf8){
+          f=Util.byte2str(filename, fEncoding);
+          _filename=Util.str2byte(f, UTF8);
+        }
+        found=Util.glob(pattern, _filename);
+
+       if(found){
+          if(f==null){
+            f=Util.byte2str(filename, fEncoding);
+          }
+          if(pdir==null){
+            pdir=dir;
+            if(!pdir.endsWith("/")){
+              pdir+="/";
+            }
+          }
+         v.addElement(pdir+f);
+       }
+       count--; 
+      }
+    }
+    if(_sendCLOSE(handle, header)) 
+      return v;
+    return null;
+  }
+
+  private boolean isPattern(byte[] path){
+    int i=path.length-1;
+    while(i>=0){
+      if(path[i]=='*' || path[i]=='?'){
+        if(i>0 && path[i-1]=='\\'){
+          i--;
+          if(i>0 && path[i-1]=='\\'){    // \\* or \\?
+            break;
+          }
+        }
+        else{
+          break;
+        }
+      }
+      i--;
+    }
+    // System.err.println("isPattern: ["+(new String(path))+"] "+(!(i<0)));
+    return !(i<0);
+  }
+
+  private Vector glob_local(String _path) throws Exception{
+//System.err.println("glob_local: "+_path);
+    Vector v=new Vector();
+    byte[] path=Util.str2byte(_path, UTF8);
+    int i=path.length-1;
+    while(i>=0){
+      if(path[i]!='*' && path[i]!='?'){
+        i--;
+        continue;
+      }
+      if(!fs_is_bs &&
+         i>0 && path[i-1]=='\\'){
+        i--;
+        if(i>0 && path[i-1]=='\\'){
+          i--;
+          i--;
+          continue;
+        }
+      }
+      break;
+    }
+
+    if(i<0){ v.addElement(fs_is_bs ? _path : Util.unquote(_path)); return v;}
+
+    while(i>=0){
+      if(path[i]==file_separatorc ||
+         (fs_is_bs && path[i]=='/')){ // On Windows, '/' is also the separator.
+        break;
+      }
+      i--;
+    }
+
+    if(i<0){ v.addElement(fs_is_bs ? _path : Util.unquote(_path)); return v;}
+
+    byte[] dir;
+    if(i==0){dir=new byte[]{(byte)file_separatorc};}
+    else{ 
+      dir=new byte[i];
+      System.arraycopy(path, 0, dir, 0, i);
+    }
+
+    byte[] pattern=new byte[path.length-i-1];
+    System.arraycopy(path, i+1, pattern, 0, pattern.length);
+
+//System.err.println("dir: "+new String(dir)+" pattern: "+new String(pattern));
+    try{
+      String[] children=(new File(Util.byte2str(dir, UTF8))).list();
+      String pdir=Util.byte2str(dir)+file_separator;
+      for(int j=0; j<children.length; j++){
+//System.err.println("children: "+children[j]);
+       if(Util.glob(pattern, Util.str2byte(children[j], UTF8))){
+         v.addElement(pdir+children[j]);
+       }
+      }
+    }
+    catch(Exception e){
+    }
+    return v;
+  }
+
+  private void throwStatusError(Buffer buf, int i) throws SftpException{
+    if(server_version>=3 &&   // WindRiver's sftp will send invalid 
+       buf.getLength()>=4){   // SSH_FXP_STATUS packet.
+      byte[] str=buf.getString();
+      //byte[] tag=buf.getString();
+      throw new SftpException(i, Util.byte2str(str, UTF8));
+    }
+    else{
+      throw new SftpException(i, "Failure");
+    }
+  }
+
+  private static boolean isLocalAbsolutePath(String path){
+    return (new File(path)).isAbsolute();
+  }
+
+  public void disconnect(){
+    super.disconnect();
+  }
+
+  private boolean isPattern(String path, byte[][] utf8){
+    byte[] _path=Util.str2byte(path, UTF8);
+    if(utf8!=null)
+      utf8[0]=_path;
+    return isPattern(_path);
+  }
+
+  private boolean isPattern(String path){
+    return isPattern(path, null);
+  }
+
+  private void fill(Buffer buf, int len)  throws IOException{
+    buf.reset();
+    fill(buf.buffer, 0, len);
+    buf.skip(len);
+  }
+
+  private int fill(byte[] buf, int s, int len) throws IOException{
+    int i=0;
+    int foo=s;
+    while(len>0){
+      i=io_in.read(buf, s, len);
+      if(i<=0){
+        throw new IOException("inputstream is closed");
+        //return (s-foo)==0 ? i : s-foo;
+      }
+      s+=i;
+      len-=i;
+    }
+    return s-foo;
+  }
+  private void skip(long foo) throws IOException{
+    while(foo>0){
+      long bar=io_in.skip(foo);
+      if(bar<=0) 
+        break;
+      foo-=bar;
+    }
+  }
+
+  class Header{
+    int length;
+    int type;
+    int rid;
+  }
+  private Header header(Buffer buf, Header header) throws IOException{
+    buf.rewind();
+    int i=fill(buf.buffer, 0, 9);
+    header.length=buf.getInt()-5;
+    header.type=buf.getByte()&0xff;
+    header.rid=buf.getInt();  
+    return header;
+  }
+
+  private String remoteAbsolutePath(String path) throws SftpException{
+    if(path.charAt(0)=='/') return path;
+    String cwd=getCwd();
+//    if(cwd.equals(getHome())) return path;
+    if(cwd.endsWith("/")) return cwd+path;
+    return cwd+"/"+path;
+  }
+
+  private String localAbsolutePath(String path){
+    if(isLocalAbsolutePath(path)) return path;
+    if(lcwd.endsWith(file_separator)) return lcwd+path;
+    return lcwd+file_separator+path;
+  }
+
+  /**
+   * This method will check if the given string can be expanded to the
+   * unique string.  If it can be expanded to mutiple files, SftpException
+   * will be thrown.
+   * @return the returned string is unquoted.
+   */
+  private String isUnique(String path) throws SftpException, Exception{
+    Vector v=glob_remote(path);
+    if(v.size()!=1){
+      throw new SftpException(SSH_FX_FAILURE, path+" is not unique: "+v.toString());
+    }
+    return (String)(v.elementAt(0));
+  }
+
+  public int getServerVersion() throws SftpException{
+    if(!isConnected()){
+      throw new SftpException(SSH_FX_FAILURE, "The channel is not connected.");
+    }
+    return server_version;
+  }
+
+  public void setFilenameEncoding(String encoding) throws SftpException{
+    int sversion=getServerVersion();
+    if(sversion > 3 && 
+       !encoding.equals(UTF8)){
+      throw new SftpException(SSH_FX_FAILURE, 
+                              "The encoding can not be changed for this sftp server.");
+    }
+    if(encoding.equals(UTF8)){
+      encoding=UTF8;
+    }
+    fEncoding=encoding;
+    fEncoding_is_utf8=fEncoding.equals(UTF8);
+  }
+
+  public String getExtension(String key){
+    if(extensions==null)
+      return null;
+    return (String)extensions.get(key);
+  }
+
+  public String realpath(String path) throws SftpException{
+    try{
+      byte[] _path=_realpath(remoteAbsolutePath(path));
+      return Util.byte2str(_path, fEncoding);
+    }
+    catch(Exception e){
+      if(e instanceof SftpException) throw (SftpException)e;
+      if(e instanceof Throwable)
+        throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
+      throw new SftpException(SSH_FX_FAILURE, "");
+    }
+  }
+
+  public class LsEntry implements Comparable{
+    private  String filename;
+    private  String longname;
+    private  SftpATTRS attrs;
+    LsEntry(String filename, String longname, SftpATTRS attrs){
+      setFilename(filename);
+      setLongname(longname);
+      setAttrs(attrs);
+    }
+    public String getFilename(){return filename;};
+    void setFilename(String filename){this.filename = filename;};
+    public String getLongname(){return longname;};
+    void setLongname(String longname){this.longname = longname;};
+    public SftpATTRS getAttrs(){return attrs;};
+    void setAttrs(SftpATTRS attrs) {this.attrs = attrs;};
+    public String toString(){ return longname; }
+    public int compareTo(Object o) throws ClassCastException{
+      if(o instanceof LsEntry){
+        return filename.compareTo(((LsEntry)o).getFilename());
+      }
+      throw new ClassCastException("a decendent of LsEntry must be given.");
+    }
+  }
+}
diff --git a/src/com/jcraft/jsch/ChannelShell.java b/src/com/jcraft/jsch/ChannelShell.java
new file mode 100644 (file)
index 0000000..b956e1d
--- /dev/null
@@ -0,0 +1,70 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.util.*;
+
+public class ChannelShell extends ChannelSession{
+
+  ChannelShell(){
+    super();
+    pty=true;
+  }
+
+  public void start() throws JSchException{
+    Session _session=getSession();
+    try{
+      sendRequests();
+
+      Request request=new RequestShell();
+      request.request(_session, this);
+    }
+    catch(Exception e){
+      if(e instanceof JSchException) throw (JSchException)e;
+      if(e instanceof Throwable)
+        throw new JSchException("ChannelShell", (Throwable)e);
+      throw new JSchException("ChannelShell");
+    }
+
+    if(io.in!=null){
+      thread=new Thread(this);
+      thread.setName("Shell for "+_session.host);
+      if(_session.daemon_thread){
+        thread.setDaemon(_session.daemon_thread);
+      }
+      thread.start();
+    }
+  }
+
+  void init() throws JSchException {
+    io.setInputStream(getSession().in);
+    io.setOutputStream(getSession().out);
+  }
+}
diff --git a/src/com/jcraft/jsch/ChannelSubsystem.java b/src/com/jcraft/jsch/ChannelSubsystem.java
new file mode 100644 (file)
index 0000000..e485177
--- /dev/null
@@ -0,0 +1,83 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2005-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public class ChannelSubsystem extends ChannelSession{
+  boolean xforwading=false;
+  boolean pty=false;
+  boolean want_reply=true;
+  String subsystem="";
+  public void setXForwarding(boolean foo){ xforwading=true; }
+  public void setPty(boolean foo){ pty=foo; }
+  public void setWantReply(boolean foo){ want_reply=foo; }
+  public void setSubsystem(String foo){ subsystem=foo; }
+  public void start() throws JSchException{
+    Session _session=getSession();
+    try{
+      Request request;
+      if(xforwading){
+        request=new RequestX11();
+        request.request(_session, this);
+      }
+      if(pty){
+       request=new RequestPtyReq();
+       request.request(_session, this);
+      }
+      request=new RequestSubsystem();
+      ((RequestSubsystem)request).request(_session, this, subsystem, want_reply);
+    }
+    catch(Exception e){
+      if(e instanceof JSchException){ throw (JSchException)e; }
+      if(e instanceof Throwable)
+        throw new JSchException("ChannelSubsystem", (Throwable)e);
+      throw new JSchException("ChannelSubsystem");
+    }
+    if(io.in!=null){
+      thread=new Thread(this);
+      thread.setName("Subsystem for "+_session.host);
+      if(_session.daemon_thread){
+        thread.setDaemon(_session.daemon_thread);
+      }
+      thread.start();
+    }
+  }
+
+  void init() throws JSchException {
+    io.setInputStream(getSession().in);
+    io.setOutputStream(getSession().out);
+  }
+
+  public void setErrStream(java.io.OutputStream out){
+    setExtOutputStream(out);
+  }
+  public java.io.InputStream getErrStream() throws java.io.IOException {
+    return getExtInputStream();
+  }
+}
diff --git a/src/com/jcraft/jsch/ChannelX11.java b/src/com/jcraft/jsch/ChannelX11.java
new file mode 100644 (file)
index 0000000..e469a73
--- /dev/null
@@ -0,0 +1,268 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.net.*;
+
+class ChannelX11 extends Channel{
+
+  static private final int LOCAL_WINDOW_SIZE_MAX=0x20000;
+  static private final int LOCAL_MAXIMUM_PACKET_SIZE=0x4000;
+
+  static private final int TIMEOUT=10*1000;
+
+  private static String host="127.0.0.1";
+  private static int port=6000;
+
+  private boolean init=true;
+
+  static byte[] cookie=null;
+  private static byte[] cookie_hex=null;
+
+  private static java.util.Hashtable faked_cookie_pool=new java.util.Hashtable();
+  private static java.util.Hashtable faked_cookie_hex_pool=new java.util.Hashtable();
+
+  private static byte[] table={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,
+                               0x61,0x62,0x63,0x64,0x65,0x66};
+
+  private Socket socket = null;
+
+  static int revtable(byte foo){
+    for(int i=0; i<table.length; i++){
+      if(table[i]==foo)return i;
+    }
+    return 0;
+  }
+  static void setCookie(String foo){
+    cookie_hex=Util.str2byte(foo); 
+    cookie=new byte[16];
+    for(int i=0; i<16; i++){
+       cookie[i]=(byte)(((revtable(cookie_hex[i*2])<<4)&0xf0) |
+                        ((revtable(cookie_hex[i*2+1]))&0xf));
+    }
+  }
+  static void setHost(String foo){ host=foo; }
+  static void setPort(int foo){ port=foo; }
+  static byte[] getFakedCookie(Session session){
+    synchronized(faked_cookie_hex_pool){
+      byte[] foo=(byte[])faked_cookie_hex_pool.get(session);
+      if(foo==null){
+       Random random=Session.random;
+       foo=new byte[16];
+       synchronized(random){
+         random.fill(foo, 0, 16);
+       }
+/*
+System.err.print("faked_cookie: ");
+for(int i=0; i<foo.length; i++){
+    System.err.print(Integer.toHexString(foo[i]&0xff)+":");
+}
+System.err.println("");
+*/
+       faked_cookie_pool.put(session, foo);
+       byte[] bar=new byte[32];
+       for(int i=0; i<16; i++){
+         bar[2*i]=table[(foo[i]>>>4)&0xf];
+         bar[2*i+1]=table[(foo[i])&0xf];
+       }
+       faked_cookie_hex_pool.put(session, bar);
+       foo=bar;
+      }
+      return foo;
+    }
+  }
+
+  ChannelX11(){
+    super();
+
+    setLocalWindowSizeMax(LOCAL_WINDOW_SIZE_MAX);
+    setLocalWindowSize(LOCAL_WINDOW_SIZE_MAX);
+    setLocalPacketSize(LOCAL_MAXIMUM_PACKET_SIZE);
+
+    type=Util.str2byte("x11");
+
+    connected=true;
+    /*
+    try{ 
+      socket=Util.createSocket(host, port, TIMEOUT);
+      socket.setTcpNoDelay(true);
+      io=new IO();
+      io.setInputStream(socket.getInputStream());
+      io.setOutputStream(socket.getOutputStream());
+    }
+    catch(Exception e){
+      //System.err.println(e);
+    }
+    */
+  }
+
+  public void run(){
+
+    try{ 
+      socket=Util.createSocket(host, port, TIMEOUT);
+      socket.setTcpNoDelay(true);
+      io=new IO();
+      io.setInputStream(socket.getInputStream());
+      io.setOutputStream(socket.getOutputStream());
+      sendOpenConfirmation();
+    }
+    catch(Exception e){
+      sendOpenFailure(SSH_OPEN_ADMINISTRATIVELY_PROHIBITED);
+      close=true;
+      disconnect();
+      return;
+    }
+
+    thread=Thread.currentThread();
+    Buffer buf=new Buffer(rmpsize);
+    Packet packet=new Packet(buf);
+    int i=0;
+    try{
+      while(thread!=null &&
+            io!=null &&
+            io.in!=null){
+        i=io.in.read(buf.buffer, 
+                    14, 
+                    buf.buffer.length-14
+                    -32 -20 // padding and mac
+                    );
+       if(i<=0){
+         eof();
+          break;
+       }
+       if(close)break;
+        packet.reset();
+        buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA);
+        buf.putInt(recipient);
+        buf.putInt(i);
+        buf.skip(i);
+       getSession().write(packet, this, i);
+      }
+    }
+    catch(Exception e){
+      //System.err.println(e);
+    }
+    disconnect();
+  }
+
+  private byte[] cache=new byte[0];
+  private byte[] addCache(byte[] foo, int s, int l){
+    byte[] bar=new byte[cache.length+l];
+    System.arraycopy(foo, s, bar, cache.length, l);
+    if(cache.length>0)
+      System.arraycopy(cache, 0, bar, 0, cache.length);
+    cache=bar;
+    return cache;
+  }
+
+  void write(byte[] foo, int s, int l) throws java.io.IOException {
+    //if(eof_local)return;
+
+    if(init){
+
+      Session _session=null;
+      try{
+        _session=getSession();
+      }
+      catch(JSchException e){
+        throw new java.io.IOException(e.toString());
+      }
+
+      foo=addCache(foo, s, l);
+      s=0; 
+      l=foo.length;
+
+      if(l<9)
+        return;
+
+      int plen=(foo[s+6]&0xff)*256+(foo[s+7]&0xff);
+      int dlen=(foo[s+8]&0xff)*256+(foo[s+9]&0xff);
+
+      if((foo[s]&0xff)==0x42){
+      }
+      else if((foo[s]&0xff)==0x6c){
+         plen=((plen>>>8)&0xff)|((plen<<8)&0xff00);
+         dlen=((dlen>>>8)&0xff)|((dlen<<8)&0xff00);
+      }
+      else{
+         // ??
+      }
+
+      if(l<12+plen+((-plen)&3)+dlen)
+        return;
+
+      byte[] bar=new byte[dlen];
+      System.arraycopy(foo, s+12+plen+((-plen)&3), bar, 0, dlen);
+      byte[] faked_cookie=null;
+
+      synchronized(faked_cookie_pool){
+       faked_cookie=(byte[])faked_cookie_pool.get(_session);
+      }
+
+      /*
+System.err.print("faked_cookie: ");
+for(int i=0; i<faked_cookie.length; i++){
+    System.err.print(Integer.toHexString(faked_cookie[i]&0xff)+":");
+}
+System.err.println("");
+System.err.print("bar: ");
+for(int i=0; i<bar.length; i++){
+    System.err.print(Integer.toHexString(bar[i]&0xff)+":");
+}
+System.err.println("");
+      */
+
+      if(equals(bar, faked_cookie)){
+        if(cookie!=null)
+          System.arraycopy(cookie, 0, foo, s+12+plen+((-plen)&3), dlen);
+      }
+      else{
+         //System.err.println("wrong cookie");
+          thread=null;
+          eof();
+          io.close();
+          disconnect();
+      }
+      init=false;
+      io.put(foo, s, l);
+      cache=null;
+      return;
+    }
+    io.put(foo, s, l);
+  }
+
+  private static boolean equals(byte[] foo, byte[] bar){
+    if(foo.length!=bar.length)return false;
+    for(int i=0; i<foo.length; i++){
+      if(foo[i]!=bar[i])return false;
+    }
+    return true;
+  }
+}
diff --git a/src/com/jcraft/jsch/Cipher.java b/src/com/jcraft/jsch/Cipher.java
new file mode 100644 (file)
index 0000000..b7ac84c
--- /dev/null
@@ -0,0 +1,40 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface Cipher{
+  static int ENCRYPT_MODE=0;
+  static int DECRYPT_MODE=1;
+  int getIVSize(); 
+  int getBlockSize(); 
+  void init(int mode, byte[] key, byte[] iv) throws Exception; 
+  void update(byte[] foo, int s1, int len, byte[] bar, int s2) throws Exception;
+  boolean isCBC();
+}
diff --git a/src/com/jcraft/jsch/CipherNone.java b/src/com/jcraft/jsch/CipherNone.java
new file mode 100644 (file)
index 0000000..ff50c5b
--- /dev/null
@@ -0,0 +1,42 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public class CipherNone implements Cipher{
+  private static final int ivsize=8;
+  private static final int bsize=16;
+  public int getIVSize(){return ivsize;} 
+  public int getBlockSize(){return bsize;}
+  public void init(int mode, byte[] key, byte[] iv) throws Exception{
+  }
+  public void update(byte[] foo, int s1, int len, byte[] bar, int s2) throws Exception{
+  }
+  public boolean isCBC(){return false; }
+}
diff --git a/src/com/jcraft/jsch/Compression.java b/src/com/jcraft/jsch/Compression.java
new file mode 100644 (file)
index 0000000..091073c
--- /dev/null
@@ -0,0 +1,38 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface Compression{
+  static public final int INFLATER=0;
+  static public final int DEFLATER=1;
+  void init(int type, int level);
+  int compress(byte[] buf, int start, int len);
+  byte[] uncompress(byte[] buf, int start, int[] len);
+}
diff --git a/src/com/jcraft/jsch/DH.java b/src/com/jcraft/jsch/DH.java
new file mode 100644 (file)
index 0000000..8e43021
--- /dev/null
@@ -0,0 +1,39 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface DH{
+  void init() throws Exception;
+  void setP(byte[] p);
+  void setG(byte[] g);
+  byte[] getE() throws Exception;
+  void setF(byte[] f);
+  byte[] getK() throws Exception;
+}
diff --git a/src/com/jcraft/jsch/DHG1.java b/src/com/jcraft/jsch/DHG1.java
new file mode 100644 (file)
index 0000000..3e8b807
--- /dev/null
@@ -0,0 +1,310 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public class DHG1 extends KeyExchange{
+
+  static final byte[] g={ 2 };
+  static final byte[] p={
+(byte)0x00,
+(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF, 
+(byte)0xC9,(byte)0x0F,(byte)0xDA,(byte)0xA2,(byte)0x21,(byte)0x68,(byte)0xC2,(byte)0x34,
+(byte)0xC4,(byte)0xC6,(byte)0x62,(byte)0x8B,(byte)0x80,(byte)0xDC,(byte)0x1C,(byte)0xD1,
+(byte)0x29,(byte)0x02,(byte)0x4E,(byte)0x08,(byte)0x8A,(byte)0x67,(byte)0xCC,(byte)0x74,
+(byte)0x02,(byte)0x0B,(byte)0xBE,(byte)0xA6,(byte)0x3B,(byte)0x13,(byte)0x9B,(byte)0x22,
+(byte)0x51,(byte)0x4A,(byte)0x08,(byte)0x79,(byte)0x8E,(byte)0x34,(byte)0x04,(byte)0xDD,
+(byte)0xEF,(byte)0x95,(byte)0x19,(byte)0xB3,(byte)0xCD,(byte)0x3A,(byte)0x43,(byte)0x1B,
+(byte)0x30,(byte)0x2B,(byte)0x0A,(byte)0x6D,(byte)0xF2,(byte)0x5F,(byte)0x14,(byte)0x37,
+(byte)0x4F,(byte)0xE1,(byte)0x35,(byte)0x6D,(byte)0x6D,(byte)0x51,(byte)0xC2,(byte)0x45,
+(byte)0xE4,(byte)0x85,(byte)0xB5,(byte)0x76,(byte)0x62,(byte)0x5E,(byte)0x7E,(byte)0xC6,
+(byte)0xF4,(byte)0x4C,(byte)0x42,(byte)0xE9,(byte)0xA6,(byte)0x37,(byte)0xED,(byte)0x6B,
+(byte)0x0B,(byte)0xFF,(byte)0x5C,(byte)0xB6,(byte)0xF4,(byte)0x06,(byte)0xB7,(byte)0xED,
+(byte)0xEE,(byte)0x38,(byte)0x6B,(byte)0xFB,(byte)0x5A,(byte)0x89,(byte)0x9F,(byte)0xA5,
+(byte)0xAE,(byte)0x9F,(byte)0x24,(byte)0x11,(byte)0x7C,(byte)0x4B,(byte)0x1F,(byte)0xE6,
+(byte)0x49,(byte)0x28,(byte)0x66,(byte)0x51,(byte)0xEC,(byte)0xE6,(byte)0x53,(byte)0x81,
+(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF
+};
+
+  private static final int SSH_MSG_KEXDH_INIT=                     30;
+  private static final int SSH_MSG_KEXDH_REPLY=                    31;
+
+  static final int RSA=0;
+  static final int DSS=1;
+  private int type=0;
+
+  private int state;
+
+  DH dh;
+//  HASH sha;
+
+//  byte[] K;
+//  byte[] H;
+
+  byte[] V_S;
+  byte[] V_C;
+  byte[] I_S;
+  byte[] I_C;
+
+//  byte[] K_S;
+
+  byte[] e;
+
+  private Buffer buf;
+  private Packet packet;
+
+  public void init(Session session,
+                  byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{
+    this.session=session;
+    this.V_S=V_S;      
+    this.V_C=V_C;      
+    this.I_S=I_S;      
+    this.I_C=I_C;      
+
+//    sha=new SHA1();
+//    sha.init();
+    try{
+      Class c=Class.forName(session.getConfig("sha-1"));
+      sha=(HASH)(c.newInstance());
+      sha.init();
+    }
+    catch(Exception e){
+      System.err.println(e);
+    }
+
+    buf=new Buffer();
+    packet=new Packet(buf);
+
+    try{
+      Class c=Class.forName(session.getConfig("dh"));
+      dh=(DH)(c.newInstance());
+      dh.init();
+    }
+    catch(Exception e){
+      //System.err.println(e);
+      throw e;
+    }
+
+    dh.setP(p);
+    dh.setG(g);
+
+    // The client responds with:
+    // byte  SSH_MSG_KEXDH_INIT(30)
+    // mpint e <- g^x mod p
+    //         x is a random number (1 < x < (p-1)/2)
+
+    e=dh.getE();
+
+    packet.reset();
+    buf.putByte((byte)SSH_MSG_KEXDH_INIT);
+    buf.putMPInt(e);
+    session.write(packet);
+
+    if(JSch.getLogger().isEnabled(Logger.INFO)){
+      JSch.getLogger().log(Logger.INFO, 
+                           "SSH_MSG_KEXDH_INIT sent");
+      JSch.getLogger().log(Logger.INFO, 
+                           "expecting SSH_MSG_KEXDH_REPLY");
+    }
+
+    state=SSH_MSG_KEXDH_REPLY;
+  }
+
+  public boolean next(Buffer _buf) throws Exception{
+    int i,j;
+
+    switch(state){
+    case SSH_MSG_KEXDH_REPLY:
+      // The server responds with:
+      // byte      SSH_MSG_KEXDH_REPLY(31)
+      // string    server public host key and certificates (K_S)
+      // mpint     f
+      // string    signature of H
+      j=_buf.getInt();
+      j=_buf.getByte();
+      j=_buf.getByte();
+      if(j!=31){
+       System.err.println("type: must be 31 "+j);
+       return false;
+      }
+
+      K_S=_buf.getString();
+      // K_S is server_key_blob, which includes ....
+      // string ssh-dss
+      // impint p of dsa
+      // impint q of dsa
+      // impint g of dsa
+      // impint pub_key of dsa
+      //System.err.print("K_S: "); //dump(K_S, 0, K_S.length);
+      byte[] f=_buf.getMPInt();
+      byte[] sig_of_H=_buf.getString();
+      /*
+for(int ii=0; ii<sig_of_H.length;ii++){
+  System.err.print(Integer.toHexString(sig_of_H[ii]&0xff));
+  System.err.print(": ");
+}
+System.err.println("");
+      */
+
+      dh.setF(f);
+      K=dh.getK();
+
+      //The hash H is computed as the HASH hash of the concatenation of the
+      //following:
+      // string    V_C, the client's version string (CR and NL excluded)
+      // string    V_S, the server's version string (CR and NL excluded)
+      // string    I_C, the payload of the client's SSH_MSG_KEXINIT
+      // string    I_S, the payload of the server's SSH_MSG_KEXINIT
+      // string    K_S, the host key
+      // mpint     e, exchange value sent by the client
+      // mpint     f, exchange value sent by the server
+      // mpint     K, the shared secret
+      // This value is called the exchange hash, and it is used to authenti-
+      // cate the key exchange.
+      buf.reset();
+      buf.putString(V_C); buf.putString(V_S);
+      buf.putString(I_C); buf.putString(I_S);
+      buf.putString(K_S);
+      buf.putMPInt(e); buf.putMPInt(f);
+      buf.putMPInt(K);
+      byte[] foo=new byte[buf.getLength()];
+      buf.getByte(foo);
+      sha.update(foo, 0, foo.length);
+      H=sha.digest();
+      //System.err.print("H -> "); //dump(H, 0, H.length);
+
+      i=0;
+      j=0;
+      j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+       ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+      String alg=Util.byte2str(K_S, i, j);
+      i+=j;
+
+      boolean result=false;
+
+      if(alg.equals("ssh-rsa")){
+       byte[] tmp;
+       byte[] ee;
+       byte[] n;
+
+       type=RSA;
+
+       j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+         ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+       tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+       ee=tmp;
+       j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+         ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+       tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+       n=tmp;
+       
+//     SignatureRSA sig=new SignatureRSA();
+//     sig.init();
+
+       SignatureRSA sig=null;
+       try{
+         Class c=Class.forName(session.getConfig("signature.rsa"));
+         sig=(SignatureRSA)(c.newInstance());
+         sig.init();
+       }
+       catch(Exception e){
+         System.err.println(e);
+       }
+
+       sig.setPubKey(ee, n);   
+       sig.update(H);
+       result=sig.verify(sig_of_H);
+
+        if(JSch.getLogger().isEnabled(Logger.INFO)){
+          JSch.getLogger().log(Logger.INFO, 
+                               "ssh_rsa_verify: signature "+result);
+        }
+
+      }
+      else if(alg.equals("ssh-dss")){
+       byte[] q=null;
+       byte[] tmp;
+       byte[] p;
+       byte[] g;
+      
+       type=DSS;
+
+       j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+         ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+       tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+       p=tmp;
+       j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+         ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+       tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+       q=tmp;
+       j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+         ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+       tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+       g=tmp;
+       j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+         ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+       tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+       f=tmp;
+//     SignatureDSA sig=new SignatureDSA();
+//     sig.init();
+       SignatureDSA sig=null;
+       try{
+         Class c=Class.forName(session.getConfig("signature.dss"));
+         sig=(SignatureDSA)(c.newInstance());
+         sig.init();
+       }
+       catch(Exception e){
+         System.err.println(e);
+       }
+       sig.setPubKey(f, p, q, g);   
+       sig.update(H);
+       result=sig.verify(sig_of_H);
+
+        if(JSch.getLogger().isEnabled(Logger.INFO)){
+          JSch.getLogger().log(Logger.INFO, 
+                               "ssh_dss_verify: signature "+result);
+        }
+
+      }
+      else{
+       System.err.println("unknown alg");
+      }            
+      state=STATE_END;
+      return result;
+    }
+    return false;
+  }
+
+  public String getKeyType(){
+    if(type==DSS) return "DSA";
+    return "RSA";
+  }
+
+  public int getState(){return state; }
+}
diff --git a/src/com/jcraft/jsch/DHGEX.java b/src/com/jcraft/jsch/DHGEX.java
new file mode 100644 (file)
index 0000000..79d994a
--- /dev/null
@@ -0,0 +1,340 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public class DHGEX extends KeyExchange{
+
+  private static final int SSH_MSG_KEX_DH_GEX_GROUP=               31;
+  private static final int SSH_MSG_KEX_DH_GEX_INIT=                32;
+  private static final int SSH_MSG_KEX_DH_GEX_REPLY=               33;
+  private static final int SSH_MSG_KEX_DH_GEX_REQUEST=             34;
+
+  static int min=1024;
+
+//  static int min=512;
+  static int preferred=1024;
+  static int max=1024;
+
+//  static int preferred=1024;
+//  static int max=2000;
+
+  static final int RSA=0;
+  static final int DSS=1;
+  private int type=0;
+
+  private int state;
+
+//  com.jcraft.jsch.DH dh;
+  DH dh;
+
+  byte[] V_S;
+  byte[] V_C;
+  byte[] I_S;
+  byte[] I_C;
+
+  private Buffer buf;
+  private Packet packet;
+
+  private byte[] p;
+  private byte[] g;
+  private byte[] e;
+  //private byte[] f;
+
+  public void init(Session session,
+                  byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception{
+    this.session=session;
+    this.V_S=V_S;      
+    this.V_C=V_C;      
+    this.I_S=I_S;      
+    this.I_C=I_C;      
+
+    try{
+      Class c=Class.forName(session.getConfig("sha-1"));
+      sha=(HASH)(c.newInstance());
+      sha.init();
+    }
+    catch(Exception e){
+      System.err.println(e);
+    }
+
+    buf=new Buffer();
+    packet=new Packet(buf);
+
+    try{
+      Class c=Class.forName(session.getConfig("dh"));
+      dh=(com.jcraft.jsch.DH)(c.newInstance());
+      dh.init();
+    }
+    catch(Exception e){
+//      System.err.println(e);
+      throw e;
+    }
+
+    packet.reset();
+    buf.putByte((byte)SSH_MSG_KEX_DH_GEX_REQUEST);
+    buf.putInt(min);
+    buf.putInt(preferred);
+    buf.putInt(max);
+    session.write(packet); 
+
+    if(JSch.getLogger().isEnabled(Logger.INFO)){
+      JSch.getLogger().log(Logger.INFO, 
+                           "SSH_MSG_KEX_DH_GEX_REQUEST("+min+"<"+preferred+"<"+max+") sent");
+      JSch.getLogger().log(Logger.INFO, 
+                           "expecting SSH_MSG_KEX_DH_GEX_GROUP");
+    }
+
+    state=SSH_MSG_KEX_DH_GEX_GROUP;
+  }
+
+  public boolean next(Buffer _buf) throws Exception{
+    int i,j;
+    switch(state){
+    case SSH_MSG_KEX_DH_GEX_GROUP:
+      // byte  SSH_MSG_KEX_DH_GEX_GROUP(31)
+      // mpint p, safe prime
+      // mpint g, generator for subgroup in GF (p)
+      _buf.getInt();
+      _buf.getByte();
+      j=_buf.getByte();
+      if(j!=SSH_MSG_KEX_DH_GEX_GROUP){
+       System.err.println("type: must be SSH_MSG_KEX_DH_GEX_GROUP "+j);
+       return false;
+      }
+
+      p=_buf.getMPInt();
+      g=_buf.getMPInt();
+      /*
+for(int iii=0; iii<p.length; iii++){
+System.err.println("0x"+Integer.toHexString(p[iii]&0xff)+",");
+}
+System.err.println("");
+for(int iii=0; iii<g.length; iii++){
+System.err.println("0x"+Integer.toHexString(g[iii]&0xff)+",");
+}
+      */
+      dh.setP(p);
+      dh.setG(g);
+
+      // The client responds with:
+      // byte  SSH_MSG_KEX_DH_GEX_INIT(32)
+      // mpint e <- g^x mod p
+      //         x is a random number (1 < x < (p-1)/2)
+
+      e=dh.getE();
+
+      packet.reset();
+      buf.putByte((byte)SSH_MSG_KEX_DH_GEX_INIT);
+      buf.putMPInt(e);
+      session.write(packet);
+
+      if(JSch.getLogger().isEnabled(Logger.INFO)){
+        JSch.getLogger().log(Logger.INFO, 
+                             "SSH_MSG_KEX_DH_GEX_INIT sent");
+        JSch.getLogger().log(Logger.INFO, 
+                             "expecting SSH_MSG_KEX_DH_GEX_REPLY");
+      }
+
+      state=SSH_MSG_KEX_DH_GEX_REPLY;
+      return true;
+      //break;
+
+    case SSH_MSG_KEX_DH_GEX_REPLY:
+      // The server responds with:
+      // byte      SSH_MSG_KEX_DH_GEX_REPLY(33)
+      // string    server public host key and certificates (K_S)
+      // mpint     f
+      // string    signature of H
+      j=_buf.getInt();
+      j=_buf.getByte();
+      j=_buf.getByte();
+      if(j!=SSH_MSG_KEX_DH_GEX_REPLY){
+       System.err.println("type: must be SSH_MSG_KEX_DH_GEX_REPLY "+j);
+       return false;
+      }
+
+      K_S=_buf.getString();
+      // K_S is server_key_blob, which includes ....
+      // string ssh-dss
+      // impint p of dsa
+      // impint q of dsa
+      // impint g of dsa
+      // impint pub_key of dsa
+      //System.err.print("K_S: "); dump(K_S, 0, K_S.length);
+
+      byte[] f=_buf.getMPInt();
+      byte[] sig_of_H=_buf.getString();
+
+      dh.setF(f);
+      K=dh.getK();
+
+      //The hash H is computed as the HASH hash of the concatenation of the
+      //following:
+      // string    V_C, the client's version string (CR and NL excluded)
+      // string    V_S, the server's version string (CR and NL excluded)
+      // string    I_C, the payload of the client's SSH_MSG_KEXINIT
+      // string    I_S, the payload of the server's SSH_MSG_KEXINIT
+      // string    K_S, the host key
+      // uint32    min, minimal size in bits of an acceptable group
+      // uint32   n, preferred size in bits of the group the server should send
+      // uint32    max, maximal size in bits of an acceptable group
+      // mpint     p, safe prime
+      // mpint     g, generator for subgroup
+      // mpint     e, exchange value sent by the client
+      // mpint     f, exchange value sent by the server
+      // mpint     K, the shared secret
+      // This value is called the exchange hash, and it is used to authenti-
+      // cate the key exchange.
+
+      buf.reset();
+      buf.putString(V_C); buf.putString(V_S);
+      buf.putString(I_C); buf.putString(I_S);
+      buf.putString(K_S);
+      buf.putInt(min); buf.putInt(preferred); buf.putInt(max);
+      buf.putMPInt(p); buf.putMPInt(g); buf.putMPInt(e); buf.putMPInt(f);
+      buf.putMPInt(K);
+
+      byte[] foo=new byte[buf.getLength()];
+      buf.getByte(foo);
+      sha.update(foo, 0, foo.length);
+
+      H=sha.digest();
+
+      // System.err.print("H -> "); dump(H, 0, H.length);
+
+      i=0;
+      j=0;
+      j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+       ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+      String alg=Util.byte2str(K_S, i, j);
+      i+=j;
+
+      boolean result=false;
+      if(alg.equals("ssh-rsa")){
+       byte[] tmp;
+       byte[] ee;
+       byte[] n;
+       
+       type=RSA;
+
+       j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+         ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+       tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+       ee=tmp;
+       j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+         ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+       tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+       n=tmp;
+
+//     SignatureRSA sig=new SignatureRSA();
+//     sig.init();
+
+       SignatureRSA sig=null;
+       try{
+         Class c=Class.forName(session.getConfig("signature.rsa"));
+         sig=(SignatureRSA)(c.newInstance());
+         sig.init();
+       }
+       catch(Exception e){
+         System.err.println(e);
+       }
+
+       sig.setPubKey(ee, n);   
+       sig.update(H);
+       result=sig.verify(sig_of_H);
+
+        if(JSch.getLogger().isEnabled(Logger.INFO)){
+          JSch.getLogger().log(Logger.INFO, 
+                               "ssh_rsa_verify: signature "+result);
+        }
+
+      }
+      else if(alg.equals("ssh-dss")){
+       byte[] q=null;
+       byte[] tmp;
+
+       type=DSS;
+
+       j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+         ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+       tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+       p=tmp;
+       j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+         ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+       tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+       q=tmp;
+       j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+         ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+       tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+       g=tmp;
+       j=((K_S[i++]<<24)&0xff000000)|((K_S[i++]<<16)&0x00ff0000)|
+         ((K_S[i++]<<8)&0x0000ff00)|((K_S[i++])&0x000000ff);
+       tmp=new byte[j]; System.arraycopy(K_S, i, tmp, 0, j); i+=j;
+       f=tmp;
+       
+//     SignatureDSA sig=new SignatureDSA();
+//     sig.init();
+
+       SignatureDSA sig=null;
+       try{
+         Class c=Class.forName(session.getConfig("signature.dss"));
+         sig=(SignatureDSA)(c.newInstance());
+         sig.init();
+       }
+       catch(Exception e){
+         System.err.println(e);
+       }
+
+       sig.setPubKey(f, p, q, g);   
+       sig.update(H);
+       result=sig.verify(sig_of_H);
+
+        if(JSch.getLogger().isEnabled(Logger.INFO)){
+          JSch.getLogger().log(Logger.INFO, 
+                               "ssh_dss_verify: signature "+result);
+        }
+
+      }
+      else{
+       System.err.println("unknown alg");
+      }            
+      state=STATE_END;
+      return result;
+    }
+    return false;
+  }
+
+  public String getKeyType(){
+    if(type==DSS) return "DSA";
+    return "RSA";
+  }
+
+  public int getState(){return state; }
+}
diff --git a/src/com/jcraft/jsch/ForwardedTCPIPDaemon.java b/src/com/jcraft/jsch/ForwardedTCPIPDaemon.java
new file mode 100644 (file)
index 0000000..d071a07
--- /dev/null
@@ -0,0 +1,36 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+import java.io.*;
+
+public interface ForwardedTCPIPDaemon extends Runnable{
+  void setChannel(ChannelForwardedTCPIP channel, InputStream in, OutputStream out);
+  void setArg(Object[] arg);
+}
diff --git a/src/com/jcraft/jsch/GSSContext.java b/src/com/jcraft/jsch/GSSContext.java
new file mode 100644 (file)
index 0000000..42edb8d
--- /dev/null
@@ -0,0 +1,38 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2004-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface GSSContext{
+  public void create(String user, String host) throws JSchException;
+  public boolean isEstablished();
+  public byte[] init(byte[] token, int s, int l) throws JSchException;
+  public byte[] getMIC(byte[] message, int s, int l);
+  public void dispose();
+}
diff --git a/src/com/jcraft/jsch/HASH.java b/src/com/jcraft/jsch/HASH.java
new file mode 100644 (file)
index 0000000..c29c341
--- /dev/null
@@ -0,0 +1,37 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface HASH{
+  void init() throws Exception;
+  int getBlockSize();
+  void update(byte[] foo, int start, int len) throws Exception;
+  byte[] digest() throws Exception;
+}
diff --git a/src/com/jcraft/jsch/HostKey.java b/src/com/jcraft/jsch/HostKey.java
new file mode 100644 (file)
index 0000000..b847045
--- /dev/null
@@ -0,0 +1,104 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public class HostKey{
+  private static final byte[] sshdss=Util.str2byte("ssh-dss");
+  private static final byte[] sshrsa=Util.str2byte("ssh-rsa");
+
+  protected static final int GUESS=0;
+  public static final int SSHDSS=1;
+  public static final int SSHRSA=2;
+  static final int UNKNOWN=3;
+
+  protected String host;
+  protected int type;
+  protected byte[] key;
+
+  public HostKey(String host, byte[] key) throws JSchException {
+    this(host, GUESS, key);
+  }
+
+  public HostKey(String host, int type, byte[] key) throws JSchException {
+    this.host=host; 
+    if(type==GUESS){
+      if(key[8]=='d'){ this.type=SSHDSS; }
+      else if(key[8]=='r'){ this.type=SSHRSA; }
+      else { throw new JSchException("invalid key type");}
+    }
+    else{
+      this.type=type; 
+    }
+    this.key=key;
+  }
+
+  public String getHost(){ return host; }
+  public String getType(){
+    if(type==SSHDSS){ return Util.byte2str(sshdss); }
+    if(type==SSHRSA){ return Util.byte2str(sshrsa);}
+    return "UNKNOWN";
+  }
+  public String getKey(){
+    return Util.byte2str(Util.toBase64(key, 0, key.length));
+  }
+  public String getFingerPrint(JSch jsch){
+    HASH hash=null;
+    try{
+      Class c=Class.forName(jsch.getConfig("md5"));
+      hash=(HASH)(c.newInstance());
+    }
+    catch(Exception e){ System.err.println("getFingerPrint: "+e); }
+    return Util.getFingerPrint(hash, key);
+  }
+
+  boolean isMatched(String _host){
+    return isIncluded(_host);
+  }
+
+  private boolean isIncluded(String _host){
+    int i=0;
+    String hosts=this.host; 
+    int hostslen=hosts.length();
+    int hostlen=_host.length();
+    int j;
+    while(i<hostslen){
+      j=hosts.indexOf(',', i);
+      if(j==-1){
+       if(hostlen!=hostslen-i) return false;
+       return hosts.regionMatches(true, i, _host, 0, hostlen);
+      }
+      if(hostlen==(j-i)){
+       if(hosts.regionMatches(true, i, _host, 0, hostlen)) return true;
+      }
+      i=j+1;
+    }
+    return false;
+  }
+}
diff --git a/src/com/jcraft/jsch/HostKeyRepository.java b/src/com/jcraft/jsch/HostKeyRepository.java
new file mode 100644 (file)
index 0000000..aae6c98
--- /dev/null
@@ -0,0 +1,44 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2004-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface HostKeyRepository{
+  final int OK=0;
+  final int NOT_INCLUDED=1;
+  final int CHANGED=2;
+
+  int check(String host, byte[] key);
+  void add(HostKey hostkey, UserInfo ui);
+  void remove(String host, String type);
+  void remove(String host, String type, byte[] key);
+  String getKnownHostsRepositoryID();
+  HostKey[] getHostKey();
+  HostKey[] getHostKey(String host, String type);
+}
diff --git a/src/com/jcraft/jsch/IO.java b/src/com/jcraft/jsch/IO.java
new file mode 100644 (file)
index 0000000..87ef8ad
--- /dev/null
@@ -0,0 +1,132 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.io.*;
+
+public class IO{
+  InputStream in;
+  OutputStream out;
+  OutputStream out_ext;
+
+  private boolean in_dontclose=false;
+  private boolean out_dontclose=false;
+  private boolean out_ext_dontclose=false;
+
+  void setOutputStream(OutputStream out){ this.out=out; }
+  void setOutputStream(OutputStream out, boolean dontclose){
+    this.out_dontclose=dontclose;
+    setOutputStream(out);
+  }
+  void setExtOutputStream(OutputStream out){ this.out_ext=out; }
+  void setExtOutputStream(OutputStream out, boolean dontclose){
+    this.out_ext_dontclose=dontclose;
+    setExtOutputStream(out);
+  }
+  void setInputStream(InputStream in){ this.in=in; }
+  void setInputStream(InputStream in, boolean dontclose){
+    this.in_dontclose=dontclose;
+    setInputStream(in);
+  }
+
+  public void put(Packet p) throws IOException, java.net.SocketException {
+    out.write(p.buffer.buffer, 0, p.buffer.index);
+    out.flush();
+  }
+  void put(byte[] array, int begin, int length) throws IOException {
+    out.write(array, begin, length);
+    out.flush();
+  }
+  void put_ext(byte[] array, int begin, int length) throws IOException {
+    out_ext.write(array, begin, length);
+    out_ext.flush();
+  }
+
+  int getByte() throws IOException {
+    return in.read();
+  }
+
+  void getByte(byte[] array) throws IOException {
+    getByte(array, 0, array.length);
+  }
+
+  void getByte(byte[] array, int begin, int length) throws IOException {
+    do{
+      int completed = in.read(array, begin, length);
+      if(completed<0){
+       throw new IOException("End of IO Stream Read");
+      }
+      begin+=completed;
+      length-=completed;
+    }
+    while (length>0);
+  }
+
+  void out_close(){
+    try{
+      if(out!=null && !out_dontclose) out.close();
+      out=null;
+    }
+    catch(Exception ee){}
+  }
+
+  public void close(){
+    try{
+      if(in!=null && !in_dontclose) in.close();
+      in=null;
+    }
+    catch(Exception ee){}
+
+    out_close();
+
+    try{
+      if(out_ext!=null && !out_ext_dontclose) out_ext.close();
+      out_ext=null;
+    }
+    catch(Exception ee){}
+  }
+
+  /*
+  public void finalize() throws Throwable{
+    try{
+      if(in!=null) in.close();
+    }
+    catch(Exception ee){}
+    try{
+      if(out!=null) out.close();
+    }
+    catch(Exception ee){}
+    try{
+      if(out_ext!=null) out_ext.close();
+    }
+    catch(Exception ee){}
+  }
+  */
+}
diff --git a/src/com/jcraft/jsch/Identity.java b/src/com/jcraft/jsch/Identity.java
new file mode 100644 (file)
index 0000000..099fabf
--- /dev/null
@@ -0,0 +1,41 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface Identity{
+  public boolean setPassphrase(byte[] passphrase) throws JSchException;
+  public byte[] getPublicKeyBlob();
+  public byte[] getSignature(byte[] data);
+  public boolean decrypt();
+  public String getAlgName();
+  public String getName();
+  public boolean isEncrypted();
+  public void clear();
+}
diff --git a/src/com/jcraft/jsch/IdentityFile.java b/src/com/jcraft/jsch/IdentityFile.java
new file mode 100644 (file)
index 0000000..8a43cd5
--- /dev/null
@@ -0,0 +1,886 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.io.*;
+
+class IdentityFile implements Identity{
+  String identity;
+  byte[] key;
+  byte[] iv;
+  private JSch jsch;
+  private HASH hash;
+  private byte[] encoded_data;
+
+  private Cipher cipher;
+
+  // DSA
+  private byte[] P_array;    
+  private byte[] Q_array;    
+  private byte[] G_array;    
+  private byte[] pub_array;    
+  private byte[] prv_array;    
+  // RSA
+  private  byte[] n_array;   // modulus
+  private  byte[] e_array;   // public exponent
+  private  byte[] d_array;   // private exponent
+//  private String algname="ssh-dss";
+  private String algname="ssh-rsa";
+
+  private static final int ERROR=0;
+  private static final int RSA=1;
+  private static final int DSS=2;
+  private static final int UNKNOWN=3;
+
+  private static final int OPENSSH=0;
+  private static final int FSECURE=1;
+  private static final int PUTTY=2;
+
+  private int type=ERROR;
+  private int keytype=OPENSSH;
+
+  private byte[] publickeyblob=null;
+
+  private boolean encrypted=true;
+
+  static IdentityFile newInstance(String prvfile, String pubfile, JSch jsch) throws JSchException{
+    byte[] prvkey=null;
+    byte[] pubkey=null;
+
+    File file=null;
+    FileInputStream fis=null;
+    try{
+      file=new File(prvfile);
+      fis=new FileInputStream(prvfile);
+      prvkey=new byte[(int)(file.length())];
+      int len=0;
+      while(true){
+        int i=fis.read(prvkey, len, prvkey.length-len);
+        if(i<=0)
+          break;
+        len+=i;
+      }
+      fis.close();
+    }
+    catch(Exception e){
+      try{ if(fis!=null) fis.close();}
+      catch(Exception ee){}
+      if(e instanceof Throwable)
+        throw new JSchException(e.toString(), (Throwable)e);
+      throw new JSchException(e.toString());
+    }
+
+    String _pubfile=pubfile;
+    if(pubfile==null){
+      _pubfile=prvfile+".pub";
+    }
+
+    try{
+      file=new File(_pubfile);
+      fis = new FileInputStream(_pubfile);
+      pubkey=new byte[(int)(file.length())];
+      int len=0;
+      while(true){
+        int i=fis.read(pubkey, len, pubkey.length-len);
+        if(i<=0)
+          break;
+        len+=i;
+      }
+      fis.close();
+    }
+    catch(Exception e){
+      try{ if(fis!=null) fis.close();}
+      catch(Exception ee){}
+      if(pubfile!=null){  
+        // The pubfile is explicitry given, but not accessible.
+        if(e instanceof Throwable)
+          throw new JSchException(e.toString(), (Throwable)e);
+        throw new JSchException(e.toString());
+      }
+    }
+    return newInstance(prvfile, prvkey, pubkey, jsch);
+  }
+
+  static IdentityFile newInstance(String name, byte[] prvkey, byte[] pubkey, JSch jsch) throws JSchException{
+    try{
+      return new IdentityFile(name, prvkey, pubkey, jsch);
+    }
+    finally{
+      Util.bzero(prvkey);
+    }
+  }
+
+  private IdentityFile(String name, byte[] prvkey, byte[] pubkey, JSch jsch) throws JSchException{
+    this.identity=name;
+    this.jsch=jsch;
+    try{
+      Class c;
+      c=Class.forName((String)jsch.getConfig("3des-cbc"));
+      cipher=(Cipher)(c.newInstance());
+      key=new byte[cipher.getBlockSize()];   // 24
+      iv=new byte[cipher.getIVSize()];       // 8
+      c=Class.forName((String)jsch.getConfig("md5"));
+      hash=(HASH)(c.newInstance());
+      hash.init();
+
+      byte[] buf=prvkey;
+      int len=buf.length;
+
+      int i=0;
+
+      while(i<len){
+        if(buf[i] == '-' && i+4<len && 
+           buf[i+1] == '-' && buf[i+2] == '-' && 
+           buf[i+3] == '-' && buf[i+4] == '-'){
+          break;
+        }
+        i++;
+      }
+
+      while(i<len){
+        if(buf[i]=='B'&& i+3<len && buf[i+1]=='E'&& buf[i+2]=='G'&& buf[i+3]=='I'){
+          i+=6;            
+          if(buf[i]=='D'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=DSS; }
+         else if(buf[i]=='R'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=RSA; }
+         else if(buf[i]=='S'&& buf[i+1]=='S'&& buf[i+2]=='H'){ // FSecure
+           type=UNKNOWN;
+           keytype=FSECURE;
+         }
+         else{
+            //System.err.println("invalid format: "+identity);
+           throw new JSchException("invalid privatekey: "+identity);
+         }
+          i+=3;
+         continue;
+       }
+        if(buf[i]=='A'&& i+7<len && buf[i+1]=='E'&& buf[i+2]=='S'&& buf[i+3]=='-' && 
+           buf[i+4]=='2'&& buf[i+5]=='5'&& buf[i+6]=='6'&& buf[i+7]=='-'){
+          i+=8;
+          if(Session.checkCipher((String)jsch.getConfig("aes256-cbc"))){
+            c=Class.forName((String)jsch.getConfig("aes256-cbc"));
+            cipher=(Cipher)(c.newInstance());
+            key=new byte[cipher.getBlockSize()];
+            iv=new byte[cipher.getIVSize()];
+          }
+          else{
+            throw new JSchException("privatekey: aes256-cbc is not available "+identity);
+          }
+          continue;
+        }
+        if(buf[i]=='C'&& i+3<len && buf[i+1]=='B'&& buf[i+2]=='C'&& buf[i+3]==','){
+          i+=4;
+         for(int ii=0; ii<iv.length; ii++){
+            iv[ii]=(byte)(((a2b(buf[i++])<<4)&0xf0)+
+                         (a2b(buf[i++])&0xf));
+         }
+         continue;
+       }
+       if(buf[i]==0x0d && i+1<len && buf[i+1]==0x0a){
+         i++;
+         continue;
+       }
+       if(buf[i]==0x0a && i+1<len){
+         if(buf[i+1]==0x0a){ i+=2; break; }
+         if(buf[i+1]==0x0d &&
+            i+2<len && buf[i+2]==0x0a){
+            i+=3; break;
+         }
+         boolean inheader=false;
+         for(int j=i+1; j<len; j++){
+           if(buf[j]==0x0a) break;
+           //if(buf[j]==0x0d) break;
+           if(buf[j]==':'){inheader=true; break;}
+         }
+         if(!inheader){
+           i++; 
+           encrypted=false;    // no passphrase
+           break;
+         }
+       }
+       i++;
+      }
+
+      if(type==ERROR){
+       throw new JSchException("invalid privatekey: "+identity);
+      }
+
+      int start=i;
+      while(i<len){
+        if(buf[i]==0x0a){
+         boolean xd=(buf[i-1]==0x0d);
+          System.arraycopy(buf, i+1, 
+                          buf, 
+                          i-(xd ? 1 : 0), 
+                          len-i-1-(xd ? 1 : 0)
+                          );
+         if(xd)len--;
+          len--;
+          continue;
+        }
+        if(buf[i]=='-'){  break; }
+        i++;
+      }
+      encoded_data=Util.fromBase64(buf, start, i-start);
+
+      if(encoded_data.length>4 &&            // FSecure
+        encoded_data[0]==(byte)0x3f &&
+        encoded_data[1]==(byte)0x6f &&
+        encoded_data[2]==(byte)0xf9 &&
+        encoded_data[3]==(byte)0xeb){
+
+       Buffer _buf=new Buffer(encoded_data);
+       _buf.getInt();  // 0x3f6ff9be
+       _buf.getInt();
+       byte[]_type=_buf.getString();
+       //System.err.println("type: "+new String(_type)); 
+       byte[] _cipher=_buf.getString();
+       String cipher=Util.byte2str(_cipher);
+       //System.err.println("cipher: "+cipher); 
+       if(cipher.equals("3des-cbc")){
+          _buf.getInt();
+          byte[] foo=new byte[encoded_data.length-_buf.getOffSet()];
+          _buf.getByte(foo);
+          encoded_data=foo;
+          encrypted=true;
+          throw new JSchException("unknown privatekey format: "+identity);
+       }
+       else if(cipher.equals("none")){
+          _buf.getInt();
+          //_buf.getInt();
+
+           encrypted=false;
+
+          byte[] foo=new byte[encoded_data.length-_buf.getOffSet()];
+          _buf.getByte(foo);
+          encoded_data=foo;
+       }
+
+      }
+
+      if(pubkey==null){
+        return;
+      }
+      
+      buf=pubkey;
+      len=buf.length;
+
+      if(buf.length>4 &&             // FSecure's public key
+        buf[0]=='-' && buf[1]=='-' && buf[2]=='-' && buf[3]=='-'){
+       i=0;
+       do{i++;}while(len>i && buf[i]!=0x0a);
+       if(len<=i) return;
+       while(i<len){
+         if(buf[i]==0x0a){
+           boolean inheader=false;
+           for(int j=i+1; j<len; j++){
+             if(buf[j]==0x0a) break;
+             if(buf[j]==':'){inheader=true; break;}
+           }
+           if(!inheader){
+             i++; 
+             break;
+           }
+         }
+         i++;
+       }
+       if(len<=i) return;
+
+       start=i;
+       while(i<len){
+         if(buf[i]==0x0a){
+           System.arraycopy(buf, i+1, buf, i, len-i-1);
+           len--;
+           continue;
+         }
+         if(buf[i]=='-'){  break; }
+         i++;
+       }
+       publickeyblob=Util.fromBase64(buf, start, i-start);
+
+       if(type==UNKNOWN && publickeyblob.length>8){
+         if(publickeyblob[8]=='d'){
+           type=DSS;
+         }
+         else if(publickeyblob[8]=='r'){
+           type=RSA;
+         }
+       }
+      }
+      else{
+       if(buf[0]!='s'|| buf[1]!='s'|| buf[2]!='h'|| buf[3]!='-') return;
+       i=0;
+       while(i<len){ if(buf[i]==' ')break; i++;} i++;
+       if(i>=len) return;
+       start=i;
+       while(i<len){ if(buf[i]==' ' || buf[i]=='\n')break; i++;}
+       publickeyblob=Util.fromBase64(buf, start, i-start);
+        if(publickeyblob.length<4+7){  // It must start with "ssh-XXX".
+          if(JSch.getLogger().isEnabled(Logger.WARN)){
+            JSch.getLogger().log(Logger.WARN, 
+                                 "failed to parse the public key");
+          }
+          publickeyblob=null;
+        }
+      }
+    }
+    catch(Exception e){
+      //System.err.println("IdentityFile: "+e);
+      if(e instanceof JSchException) throw (JSchException)e;
+      if(e instanceof Throwable)
+        throw new JSchException(e.toString(), (Throwable)e);
+      throw new JSchException(e.toString());
+    }
+  }
+
+  public String getAlgName(){
+    if(type==RSA) return "ssh-rsa";
+    return "ssh-dss"; 
+  }
+
+  public boolean setPassphrase(byte[] _passphrase) throws JSchException{
+    /*
+      hash is MD5
+      h(0) <- hash(passphrase, iv);
+      h(n) <- hash(h(n-1), passphrase, iv);
+      key <- (h(0),...,h(n))[0,..,key.length];
+    */
+    try{
+      if(encrypted){
+       if(_passphrase==null) return false;
+       byte[] passphrase=_passphrase;
+       int hsize=hash.getBlockSize();
+       byte[] hn=new byte[key.length/hsize*hsize+
+                          (key.length%hsize==0?0:hsize)];
+       byte[] tmp=null;
+       if(keytype==OPENSSH){
+         for(int index=0; index+hsize<=hn.length;){
+           if(tmp!=null){ hash.update(tmp, 0, tmp.length); }
+           hash.update(passphrase, 0, passphrase.length);
+           hash.update(iv, 0, iv.length > 8 ? 8: iv.length);
+           tmp=hash.digest();
+           System.arraycopy(tmp, 0, hn, index, tmp.length);
+           index+=tmp.length;
+         }
+         System.arraycopy(hn, 0, key, 0, key.length); 
+       }
+       else if(keytype==FSECURE){
+         for(int index=0; index+hsize<=hn.length;){
+           if(tmp!=null){ hash.update(tmp, 0, tmp.length); }
+           hash.update(passphrase, 0, passphrase.length);
+           tmp=hash.digest();
+           System.arraycopy(tmp, 0, hn, index, tmp.length);
+           index+=tmp.length;
+         }
+         System.arraycopy(hn, 0, key, 0, key.length); 
+       }
+        Util.bzero(passphrase);
+      }
+      if(decrypt()){
+       encrypted=false;
+       return true;
+      }
+      P_array=Q_array=G_array=pub_array=prv_array=null;
+      return false;
+    }
+    catch(Exception e){
+      if(e instanceof JSchException) throw (JSchException)e;
+      if(e instanceof Throwable)
+        throw new JSchException(e.toString(), (Throwable)e);
+      throw new JSchException(e.toString());
+    }
+  }
+
+  public byte[] getPublicKeyBlob(){
+    if(publickeyblob!=null) return publickeyblob;
+    if(type==RSA) return getPublicKeyBlob_rsa();
+    return getPublicKeyBlob_dss();
+  }
+
+  byte[] getPublicKeyBlob_rsa(){
+    if(e_array==null) return null;
+    Buffer buf=new Buffer("ssh-rsa".length()+4+
+                          e_array.length+4+ 
+                          n_array.length+4);
+    buf.putString(Util.str2byte("ssh-rsa"));
+    buf.putString(e_array);
+    buf.putString(n_array);
+    return buf.buffer;
+  }
+
+  byte[] getPublicKeyBlob_dss(){
+    if(P_array==null) return null;
+    Buffer buf=new Buffer("ssh-dss".length()+4+
+                          P_array.length+4+ 
+                          Q_array.length+4+ 
+                          G_array.length+4+ 
+                          pub_array.length+4);
+    buf.putString(Util.str2byte("ssh-dss"));
+    buf.putString(P_array);
+    buf.putString(Q_array);
+    buf.putString(G_array);
+    buf.putString(pub_array);
+    return buf.buffer;
+  }
+
+  public byte[] getSignature(byte[] data){
+    if(type==RSA) return getSignature_rsa(data);
+    return getSignature_dss(data);
+  }
+
+  byte[] getSignature_rsa(byte[] data){
+    try{      
+      Class c=Class.forName((String)jsch.getConfig("signature.rsa"));
+      SignatureRSA rsa=(SignatureRSA)(c.newInstance());
+
+      rsa.init();
+      rsa.setPrvKey(d_array, n_array);
+
+      rsa.update(data);
+      byte[] sig = rsa.sign();
+      Buffer buf=new Buffer("ssh-rsa".length()+4+
+                           sig.length+4);
+      buf.putString(Util.str2byte("ssh-rsa"));
+      buf.putString(sig);
+      return buf.buffer;
+    }
+    catch(Exception e){
+    }
+    return null;
+  }
+
+  byte[] getSignature_dss(byte[] data){
+/*
+    byte[] foo;
+    int i;
+    System.err.print("P ");
+    foo=P_array;
+    for(i=0;  i<foo.length; i++){
+      System.err.print(Integer.toHexString(foo[i]&0xff)+":");
+    }
+    System.err.println("");
+    System.err.print("Q ");
+    foo=Q_array;
+    for(i=0;  i<foo.length; i++){
+      System.err.print(Integer.toHexString(foo[i]&0xff)+":");
+    }
+    System.err.println("");
+    System.err.print("G ");
+    foo=G_array;
+    for(i=0;  i<foo.length; i++){
+      System.err.print(Integer.toHexString(foo[i]&0xff)+":");
+    }
+    System.err.println("");
+*/
+
+    try{      
+      Class c=Class.forName((String)jsch.getConfig("signature.dss"));
+      SignatureDSA dsa=(SignatureDSA)(c.newInstance());
+      dsa.init();
+      dsa.setPrvKey(prv_array, P_array, Q_array, G_array);
+
+      dsa.update(data);
+      byte[] sig = dsa.sign();
+      Buffer buf=new Buffer("ssh-dss".length()+4+
+                           sig.length+4);
+      buf.putString(Util.str2byte("ssh-dss"));
+      buf.putString(sig);
+      return buf.buffer;
+    }
+    catch(Exception e){
+      //System.err.println("e "+e);
+    }
+    return null;
+  }
+
+  public boolean decrypt(){
+    if(type==RSA) return decrypt_rsa();
+    return decrypt_dss();
+  }
+
+  boolean decrypt_rsa(){
+    byte[] p_array;
+    byte[] q_array;
+    byte[] dmp1_array;
+    byte[] dmq1_array;
+    byte[] iqmp_array;
+
+    try{
+      byte[] plain;
+      if(encrypted){
+       if(keytype==OPENSSH){
+         cipher.init(Cipher.DECRYPT_MODE, key, iv);
+         plain=new byte[encoded_data.length];
+         cipher.update(encoded_data, 0, encoded_data.length, plain, 0);
+       }
+       else if(keytype==FSECURE){
+         for(int i=0; i<iv.length; i++)iv[i]=0;
+         cipher.init(Cipher.DECRYPT_MODE, key, iv);
+         plain=new byte[encoded_data.length];
+         cipher.update(encoded_data, 0, encoded_data.length, plain, 0);
+       }
+       else{
+         return false;
+       }
+      }
+      else{
+       if(n_array!=null) return true;
+       plain=encoded_data;
+      }
+
+      if(keytype==FSECURE){              // FSecure   
+       Buffer buf=new Buffer(plain);
+        int foo=buf.getInt();
+        if(plain.length!=foo+4){
+          return false;
+        }
+       e_array=buf.getMPIntBits();
+        d_array=buf.getMPIntBits();
+       n_array=buf.getMPIntBits();
+       byte[] u_array=buf.getMPIntBits();
+       p_array=buf.getMPIntBits();
+       q_array=buf.getMPIntBits();
+        return true;
+      }
+
+      int index=0;
+      int length=0;
+
+      if(plain[index]!=0x30)return false;
+      index++; // SEQUENCE
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+
+      if(plain[index]!=0x02)return false;
+      index++; // INTEGER
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      index+=length;
+
+//System.err.println("int: len="+length);
+//System.err.print(Integer.toHexString(plain[index-1]&0xff)+":");
+//System.err.println("");
+
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      n_array=new byte[length];
+      System.arraycopy(plain, index, n_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: N len="+length);
+for(int i=0; i<n_array.length; i++){
+System.err.print(Integer.toHexString(n_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      e_array=new byte[length];
+      System.arraycopy(plain, index, e_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: E len="+length);
+for(int i=0; i<e_array.length; i++){
+System.err.print(Integer.toHexString(e_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      d_array=new byte[length];
+      System.arraycopy(plain, index, d_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: D len="+length);
+for(int i=0; i<d_array.length; i++){
+System.err.print(Integer.toHexString(d_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      p_array=new byte[length];
+      System.arraycopy(plain, index, p_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: P len="+length);
+for(int i=0; i<p_array.length; i++){
+System.err.print(Integer.toHexString(p_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      q_array=new byte[length];
+      System.arraycopy(plain, index, q_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: q len="+length);
+for(int i=0; i<q_array.length; i++){
+System.err.print(Integer.toHexString(q_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      dmp1_array=new byte[length];
+      System.arraycopy(plain, index, dmp1_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: dmp1 len="+length);
+for(int i=0; i<dmp1_array.length; i++){
+System.err.print(Integer.toHexString(dmp1_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      dmq1_array=new byte[length];
+      System.arraycopy(plain, index, dmq1_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: dmq1 len="+length);
+for(int i=0; i<dmq1_array.length; i++){
+System.err.print(Integer.toHexString(dmq1_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      iqmp_array=new byte[length];
+      System.arraycopy(plain, index, iqmp_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: iqmp len="+length);
+for(int i=0; i<iqmp_array.length; i++){
+System.err.print(Integer.toHexString(iqmp_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+    }
+    catch(Exception e){
+      //System.err.println(e);
+      return false;
+    }
+    return true;
+  }
+
+  boolean decrypt_dss(){
+    try{
+      byte[] plain;
+      if(encrypted){
+       if(keytype==OPENSSH){
+         cipher.init(Cipher.DECRYPT_MODE, key, iv);
+         plain=new byte[encoded_data.length];
+         cipher.update(encoded_data, 0, encoded_data.length, plain, 0);
+/*
+for(int i=0; i<plain.length; i++){
+System.err.print(Integer.toHexString(plain[i]&0xff)+":");
+}
+System.err.println("");
+*/
+       }
+       else if(keytype==FSECURE){
+         for(int i=0; i<iv.length; i++)iv[i]=0;
+         cipher.init(Cipher.DECRYPT_MODE, key, iv);
+         plain=new byte[encoded_data.length];
+         cipher.update(encoded_data, 0, encoded_data.length, plain, 0);
+       }
+       else{
+         return false;
+       }
+      }
+      else{
+       if(P_array!=null) return true;
+       plain=encoded_data;
+      }
+
+      if(keytype==FSECURE){              // FSecure   
+       Buffer buf=new Buffer(plain);
+        int foo=buf.getInt();
+        if(plain.length!=foo+4){
+          return false;
+        }
+       P_array=buf.getMPIntBits();
+        G_array=buf.getMPIntBits();
+       Q_array=buf.getMPIntBits();
+       pub_array=buf.getMPIntBits();
+       prv_array=buf.getMPIntBits();
+        return true;
+      }
+
+      int index=0;
+      int length=0;
+      if(plain[index]!=0x30)return false;
+      index++; // SEQUENCE
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      if(plain[index]!=0x02)return false;
+      index++; // INTEGER
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      index+=length;
+
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      P_array=new byte[length];
+      System.arraycopy(plain, index, P_array, 0, length);
+      index+=length;
+
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      Q_array=new byte[length];
+      System.arraycopy(plain, index, Q_array, 0, length);
+      index+=length;
+
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      G_array=new byte[length];
+      System.arraycopy(plain, index, G_array, 0, length);
+      index+=length;
+
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      pub_array=new byte[length];
+      System.arraycopy(plain, index, pub_array, 0, length);
+      index+=length;
+
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      prv_array=new byte[length];
+      System.arraycopy(plain, index, prv_array, 0, length);
+      index+=length;
+    }
+    catch(Exception e){
+      //System.err.println(e);
+      //e.printStackTrace();
+      return false;
+    }
+    return true;
+  }
+
+  public boolean isEncrypted(){
+    return encrypted;
+  }
+
+  public String getName(){
+    return identity;
+  }
+
+  private byte a2b(byte c){
+    if('0'<=c&&c<='9') return (byte)(c-'0');
+    if('a'<=c&&c<='z') return (byte)(c-'a'+10);
+    return (byte)(c-'A'+10);
+  }
+
+  public boolean equals(Object o){
+    if(!(o instanceof IdentityFile)) return super.equals(o);
+    IdentityFile foo=(IdentityFile)o;
+    return getName().equals(foo.getName());
+  }
+
+  public void clear(){
+    Util.bzero(encoded_data);
+    Util.bzero(prv_array);
+    Util.bzero(d_array);
+    Util.bzero(key);
+    Util.bzero(iv);
+  }
+
+  public void finalize (){
+    clear();
+  }
+}
diff --git a/src/com/jcraft/jsch/JSch.java b/src/com/jcraft/jsch/JSch.java
new file mode 100644 (file)
index 0000000..540fc1e
--- /dev/null
@@ -0,0 +1,296 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.io.InputStream;
+import java.util.Vector;
+
+public class JSch{
+  static java.util.Hashtable config=new java.util.Hashtable();
+  static{
+//  config.put("kex", "diffie-hellman-group-exchange-sha1");
+    config.put("kex", "diffie-hellman-group1-sha1,diffie-hellman-group-exchange-sha1");
+    config.put("server_host_key", "ssh-rsa,ssh-dss");
+//    config.put("server_host_key", "ssh-dss,ssh-rsa");
+
+    config.put("cipher.s2c", 
+               "aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc");
+    config.put("cipher.c2s",
+               "aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc");
+
+    config.put("mac.s2c", "hmac-md5,hmac-sha1,hmac-sha1-96,hmac-md5-96");
+    config.put("mac.c2s", "hmac-md5,hmac-sha1,hmac-sha1-96,hmac-md5-96");
+    config.put("compression.s2c", "none");
+    // config.put("compression.s2c", "zlib@openssh.com,zlib,none");
+    config.put("compression.c2s", "none");
+    // config.put("compression.c2s", "zlib@openssh.com,zlib,none");
+
+    config.put("lang.s2c", "");
+    config.put("lang.c2s", "");
+
+    config.put("compression_level", "6");
+
+    config.put("diffie-hellman-group-exchange-sha1", 
+                                "com.jcraft.jsch.DHGEX");
+    config.put("diffie-hellman-group1-sha1", 
+                               "com.jcraft.jsch.DHG1");
+
+    config.put("dh",            "com.jcraft.jsch.jce.DH");
+    config.put("3des-cbc",      "com.jcraft.jsch.jce.TripleDESCBC");
+    config.put("blowfish-cbc",  "com.jcraft.jsch.jce.BlowfishCBC");
+    config.put("hmac-sha1",     "com.jcraft.jsch.jce.HMACSHA1");
+    config.put("hmac-sha1-96",  "com.jcraft.jsch.jce.HMACSHA196");
+    config.put("hmac-md5",      "com.jcraft.jsch.jce.HMACMD5");
+    config.put("hmac-md5-96",   "com.jcraft.jsch.jce.HMACMD596");
+    config.put("sha-1",         "com.jcraft.jsch.jce.SHA1");
+    config.put("md5",           "com.jcraft.jsch.jce.MD5");
+    config.put("signature.dss", "com.jcraft.jsch.jce.SignatureDSA");
+    config.put("signature.rsa", "com.jcraft.jsch.jce.SignatureRSA");
+    config.put("keypairgen.dsa",   "com.jcraft.jsch.jce.KeyPairGenDSA");
+    config.put("keypairgen.rsa",   "com.jcraft.jsch.jce.KeyPairGenRSA");
+    config.put("random",        "com.jcraft.jsch.jce.Random");
+
+    config.put("none",           "com.jcraft.jsch.CipherNone");
+
+    config.put("aes128-cbc",    "com.jcraft.jsch.jce.AES128CBC");
+    config.put("aes192-cbc",    "com.jcraft.jsch.jce.AES192CBC");
+    config.put("aes256-cbc",    "com.jcraft.jsch.jce.AES256CBC");
+
+    config.put("aes128-ctr",    "com.jcraft.jsch.jce.AES128CTR");
+    config.put("aes192-ctr",    "com.jcraft.jsch.jce.AES192CTR");
+    config.put("aes256-ctr",    "com.jcraft.jsch.jce.AES256CTR");
+    config.put("3des-ctr",      "com.jcraft.jsch.jce.TripleDESCTR");
+    config.put("arcfour",      "com.jcraft.jsch.jce.ARCFOUR");
+    config.put("arcfour128",      "com.jcraft.jsch.jce.ARCFOUR128");
+    config.put("arcfour256",      "com.jcraft.jsch.jce.ARCFOUR256");
+
+    config.put("userauth.none",    "com.jcraft.jsch.UserAuthNone");
+    config.put("userauth.password",    "com.jcraft.jsch.UserAuthPassword");
+    config.put("userauth.keyboard-interactive",    "com.jcraft.jsch.UserAuthKeyboardInteractive");
+    config.put("userauth.publickey",    "com.jcraft.jsch.UserAuthPublicKey");
+
+    config.put("zlib",             "com.jcraft.jsch.jcraft.Compression");
+    config.put("zlib@openssh.com", "com.jcraft.jsch.jcraft.Compression");
+
+    config.put("StrictHostKeyChecking",  "ask");
+    config.put("HashKnownHosts",  "no");
+    //config.put("HashKnownHosts",  "yes");
+    config.put("PreferredAuthentications", "gssapi-with-mic,publickey,keyboard-interactive,password");
+
+    config.put("CheckCiphers", "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcfour128,arcfour256");
+  }
+  java.util.Vector pool=new java.util.Vector();
+  java.util.Vector identities=new java.util.Vector();
+  private HostKeyRepository known_hosts=null;
+
+  private static final Logger DEVNULL=new Logger(){
+      public boolean isEnabled(int level){return false;}
+      public void log(int level, String message){}
+    };
+  static Logger logger=DEVNULL;
+
+  public JSch(){
+
+    try{
+      String osname=(String)(System.getProperties().get("os.name"));
+      if(osname!=null && osname.equals("Mac OS X")){
+        config.put("hmac-sha1",     "com.jcraft.jsch.jcraft.HMACSHA1"); 
+        config.put("hmac-md5",      "com.jcraft.jsch.jcraft.HMACMD5"); 
+        config.put("hmac-md5-96",   "com.jcraft.jsch.jcraft.HMACMD596"); 
+        config.put("hmac-sha1-96",  "com.jcraft.jsch.jcraft.HMACSHA196"); 
+      }
+    }
+    catch(Exception e){
+    }
+
+  }
+
+  public Session getSession(String username, String host) throws JSchException { return getSession(username, host, 22); }
+  public Session getSession(String username, String host, int port) throws JSchException {
+    if(username==null){
+      throw new JSchException("username must not be null.");
+    }
+    if(host==null){
+      throw new JSchException("host must not be null.");
+    }
+    Session s=new Session(this); 
+    s.setUserName(username);
+    s.setHost(host);
+    s.setPort(port);
+    //pool.addElement(s);
+    return s;
+  }
+
+  protected void addSession(Session session){
+    synchronized(pool){
+      pool.addElement(session);
+    }
+  }
+
+  protected boolean removeSession(Session session){
+    synchronized(pool){
+      return pool.remove(session);
+    }
+  }
+  public void setHostKeyRepository(HostKeyRepository hkrepo){
+    known_hosts=hkrepo;
+  }
+
+  public void setKnownHosts(String filename) throws JSchException{
+    if(known_hosts==null) known_hosts=new KnownHosts(this);
+    if(known_hosts instanceof KnownHosts){
+      synchronized(known_hosts){
+       ((KnownHosts)known_hosts).setKnownHosts(filename); 
+      }
+    }
+  }
+
+  public void setKnownHosts(InputStream stream) throws JSchException{ 
+    if(known_hosts==null) known_hosts=new KnownHosts(this);
+    if(known_hosts instanceof KnownHosts){
+      synchronized(known_hosts){
+       ((KnownHosts)known_hosts).setKnownHosts(stream); 
+      }
+    }
+  }
+
+  public HostKeyRepository getHostKeyRepository(){ 
+    if(known_hosts==null) known_hosts=new KnownHosts(this);
+    return known_hosts; 
+  }
+
+  public void addIdentity(String prvkey) throws JSchException{
+    addIdentity(prvkey, (byte[])null);
+  }
+
+  public void addIdentity(String prvkey, String passphrase) throws JSchException{
+    byte[] _passphrase=null;
+    if(passphrase!=null){
+      _passphrase=Util.str2byte(passphrase);
+    }
+    addIdentity(prvkey, _passphrase);
+    if(_passphrase!=null)
+      Util.bzero(_passphrase);
+  }
+
+  public void addIdentity(String prvkey, byte[] passphrase) throws JSchException{
+    Identity identity=IdentityFile.newInstance(prvkey, null, this);
+    addIdentity(identity, passphrase);
+  }
+  public void addIdentity(String prvkey, String pubkey, byte[] passphrase) throws JSchException{
+    Identity identity=IdentityFile.newInstance(prvkey, pubkey, this);
+    addIdentity(identity, passphrase);
+  }
+
+  public void addIdentity(String name, byte[]prvkey, byte[]pubkey, byte[] passphrase) throws JSchException{
+    Identity identity=IdentityFile.newInstance(name, prvkey, pubkey, this);
+    addIdentity(identity, passphrase);
+  }
+
+  public void addIdentity(Identity identity, byte[] passphrase) throws JSchException{
+    if(passphrase!=null){
+      try{ 
+        byte[] goo=new byte[passphrase.length];
+        System.arraycopy(passphrase, 0, goo, 0, passphrase.length);
+        passphrase=goo;
+        identity.setPassphrase(passphrase); 
+      }
+      finally{
+        Util.bzero(passphrase);
+      }
+    }
+    synchronized(identities){
+      if(!identities.contains(identity)){
+       identities.addElement(identity);
+      }
+    }
+  }
+
+  public void removeIdentity(String name) throws JSchException{
+    synchronized(identities){
+      for(int i=0; i<identities.size(); i++){
+        Identity identity=(Identity)(identities.elementAt(i));
+       if(!identity.getName().equals(name))
+          continue;
+        identities.removeElement(identity);
+        identity.clear();
+        break;
+      }
+    }
+  }
+
+  public Vector getIdentityNames() throws JSchException{
+    Vector foo=new Vector();
+    synchronized(identities){
+      for(int i=0; i<identities.size(); i++){
+        Identity identity=(Identity)(identities.elementAt(i));
+        foo.addElement(identity.getName());
+      }
+    }
+    return foo;
+  }
+
+  public void removeAllIdentity() throws JSchException{
+    synchronized(identities){
+      Vector foo=getIdentityNames();
+      for(int i=0; i<foo.size(); i++){
+        String name=((String)foo.elementAt(i));
+        removeIdentity(name);
+      }
+    }
+  }
+
+  public static String getConfig(String key){ 
+    synchronized(config){
+      return (String)(config.get(key));
+    } 
+  }
+
+  public static void setConfig(java.util.Hashtable newconf){
+    synchronized(config){
+      for(java.util.Enumeration e=newconf.keys() ; e.hasMoreElements() ;) {
+       String key=(String)(e.nextElement());
+       config.put(key, (String)(newconf.get(key)));
+      }
+    }
+  }
+
+  public static void setConfig(String key, String value){
+    config.put(key, value);
+  }
+
+  public static void setLogger(Logger logger){
+    if(logger==null) JSch.logger=DEVNULL;
+    JSch.logger=logger;
+  }
+  static Logger getLogger(){
+    return logger;
+  }
+}
diff --git a/src/com/jcraft/jsch/JSchAuthCancelException.java b/src/com/jcraft/jsch/JSchAuthCancelException.java
new file mode 100644 (file)
index 0000000..13a5e8d
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+class JSchAuthCancelException extends JSchException{
+  //private static final long serialVersionUID=3204965907117900987L;
+  String method;
+  JSchAuthCancelException () {
+    super();
+  }
+  JSchAuthCancelException (String s) {
+    super(s);
+    this.method=s;
+  }
+  public String getMethod(){
+    return method;
+  }
+}
diff --git a/src/com/jcraft/jsch/JSchException.java b/src/com/jcraft/jsch/JSchException.java
new file mode 100644 (file)
index 0000000..5119fc6
--- /dev/null
@@ -0,0 +1,48 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public class JSchException extends Exception{
+  //private static final long serialVersionUID=-1319309923966731989L;
+  private Throwable cause=null;
+  public JSchException () {
+    super();
+  }
+  public JSchException (String s) {
+    super(s);
+  }
+  public JSchException (String s, Throwable e) {
+    super(s);
+    this.cause=e;
+  }
+  public Throwable getCause(){
+    return this.cause;
+  }
+}
diff --git a/src/com/jcraft/jsch/JSchPartialAuthException.java b/src/com/jcraft/jsch/JSchPartialAuthException.java
new file mode 100644 (file)
index 0000000..edae89b
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+class JSchPartialAuthException extends JSchException{
+  //private static final long serialVersionUID=-378849862323360367L;
+  String methods;
+  public JSchPartialAuthException () {
+    super();
+  }
+  public JSchPartialAuthException (String s) {
+    super(s);
+    this.methods=s;
+  }
+  public String getMethods(){
+    return methods;
+  }
+}
diff --git a/src/com/jcraft/jsch/KeyExchange.java b/src/com/jcraft/jsch/KeyExchange.java
new file mode 100644 (file)
index 0000000..5be3ac0
--- /dev/null
@@ -0,0 +1,159 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public abstract class KeyExchange{
+
+  static final int PROPOSAL_KEX_ALGS=0;
+  static final int PROPOSAL_SERVER_HOST_KEY_ALGS=1;
+  static final int PROPOSAL_ENC_ALGS_CTOS=2;
+  static final int PROPOSAL_ENC_ALGS_STOC=3;
+  static final int PROPOSAL_MAC_ALGS_CTOS=4;
+  static final int PROPOSAL_MAC_ALGS_STOC=5;
+  static final int PROPOSAL_COMP_ALGS_CTOS=6;
+  static final int PROPOSAL_COMP_ALGS_STOC=7;
+  static final int PROPOSAL_LANG_CTOS=8;
+  static final int PROPOSAL_LANG_STOC=9;
+  static final int PROPOSAL_MAX=10;
+
+  //static String kex_algs="diffie-hellman-group-exchange-sha1"+
+  //                       ",diffie-hellman-group1-sha1";
+
+//static String kex="diffie-hellman-group-exchange-sha1";
+  static String kex="diffie-hellman-group1-sha1";
+  static String server_host_key="ssh-rsa,ssh-dss";
+  static String enc_c2s="blowfish-cbc";
+  static String enc_s2c="blowfish-cbc";
+  static String mac_c2s="hmac-md5";     // hmac-md5,hmac-sha1,hmac-ripemd160,
+                                        // hmac-sha1-96,hmac-md5-96
+  static String mac_s2c="hmac-md5";
+//static String comp_c2s="none";        // zlib
+//static String comp_s2c="none";
+  static String lang_c2s="";
+  static String lang_s2c="";
+
+  public static final int STATE_END=0;
+
+  protected Session session=null;
+  protected HASH sha=null;
+  protected byte[] K=null;
+  protected byte[] H=null;
+  protected byte[] K_S=null;
+
+  public abstract void init(Session session, 
+                           byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws Exception;
+  public abstract boolean next(Buffer buf) throws Exception;
+  public abstract String getKeyType();
+  public abstract int getState();
+
+  /*
+  void dump(byte[] foo){
+    for(int i=0; i<foo.length; i++){
+      if((foo[i]&0xf0)==0)System.err.print("0");
+      System.err.print(Integer.toHexString(foo[i]&0xff));
+      if(i%16==15){System.err.println(""); continue;}
+      if(i%2==1)System.err.print(" ");
+    }
+  } 
+  */
+
+  protected static String[] guess(byte[]I_S, byte[]I_C){
+    String[] guess=new String[PROPOSAL_MAX];
+    Buffer sb=new Buffer(I_S); sb.setOffSet(17);
+    Buffer cb=new Buffer(I_C); cb.setOffSet(17);
+
+    for(int i=0; i<PROPOSAL_MAX; i++){
+      byte[] sp=sb.getString();  // server proposal
+      byte[] cp=cb.getString();  // client proposal
+      int j=0;
+      int k=0;
+
+      loop:
+      while(j<cp.length){
+       while(j<cp.length && cp[j]!=',')j++; 
+       if(k==j) return null;
+       String algorithm=Util.byte2str(cp, k, j-k);
+       int l=0;
+       int m=0;
+       while(l<sp.length){
+         while(l<sp.length && sp[l]!=',')l++; 
+         if(m==l) return null;
+         if(algorithm.equals(Util.byte2str(sp, m, l-m))){
+           guess[i]=algorithm;
+           break loop;
+         }
+         l++;
+         m=l;
+       }       
+       j++;
+       k=j;
+      }
+      if(j==0){
+       guess[i]="";
+      }
+      else if(guess[i]==null){
+       return null;
+      }
+    }
+
+    if(JSch.getLogger().isEnabled(Logger.INFO)){
+      JSch.getLogger().log(Logger.INFO, 
+                           "kex: server->client"+
+                           " "+guess[PROPOSAL_ENC_ALGS_STOC]+
+                           " "+guess[PROPOSAL_MAC_ALGS_STOC]+
+                           " "+guess[PROPOSAL_COMP_ALGS_STOC]);
+      JSch.getLogger().log(Logger.INFO, 
+                           "kex: client->server"+
+                           " "+guess[PROPOSAL_ENC_ALGS_CTOS]+
+                           " "+guess[PROPOSAL_MAC_ALGS_CTOS]+
+                           " "+guess[PROPOSAL_COMP_ALGS_CTOS]);
+    }
+
+//    for(int i=0; i<PROPOSAL_MAX; i++){
+//      System.err.println("guess: ["+guess[i]+"]");
+//    }
+
+    return guess;
+  }
+
+  public String getFingerPrint(){
+    HASH hash=null;
+    try{
+      Class c=Class.forName(session.getConfig("md5"));
+      hash=(HASH)(c.newInstance());
+    }
+    catch(Exception e){ System.err.println("getFingerPrint: "+e); }
+    return Util.getFingerPrint(hash, getHostKey());
+  }
+  byte[] getK(){ return K; }
+  byte[] getH(){ return H; }
+  HASH getHash(){ return sha; }
+  byte[] getHostKey(){ return K_S; }
+}
diff --git a/src/com/jcraft/jsch/KeyPair.java b/src/com/jcraft/jsch/KeyPair.java
new file mode 100644 (file)
index 0000000..5d6392a
--- /dev/null
@@ -0,0 +1,665 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.io.FileOutputStream;
+import java.io.FileInputStream;
+import java.io.File;
+
+public abstract class KeyPair{
+  public static final int ERROR=0;
+  public static final int DSA=1;
+  public static final int RSA=2;
+  public static final int UNKNOWN=3;
+
+  static final int VENDOR_OPENSSH=0;
+  static final int VENDOR_FSECURE=1;
+  int vendor=VENDOR_OPENSSH;
+
+  private static final byte[] cr=Util.str2byte("\n");
+
+  public static KeyPair genKeyPair(JSch jsch, int type) throws JSchException{
+    return genKeyPair(jsch, type, 1024);
+  }
+  public static KeyPair genKeyPair(JSch jsch, int type, int key_size) throws JSchException{
+    KeyPair kpair=null;
+    if(type==DSA){ kpair=new KeyPairDSA(jsch); }
+    else if(type==RSA){ kpair=new KeyPairRSA(jsch); }
+    if(kpair!=null){
+      kpair.generate(key_size);
+    }
+    return kpair;
+  }
+
+  abstract void generate(int key_size) throws JSchException;
+
+  abstract byte[] getBegin();
+  abstract byte[] getEnd();
+  abstract int getKeySize();
+
+  JSch jsch=null;
+  private Cipher cipher;
+  private HASH hash;
+  private Random random;
+
+  private byte[] passphrase;
+
+  public KeyPair(JSch jsch){
+    this.jsch=jsch;
+  }
+
+  static byte[][] header={Util.str2byte("Proc-Type: 4,ENCRYPTED"),
+                          Util.str2byte("DEK-Info: DES-EDE3-CBC,")};
+
+  abstract byte[] getPrivateKey();
+
+  public void writePrivateKey(java.io.OutputStream out){
+    byte[] plain=getPrivateKey();
+    byte[][] _iv=new byte[1][];
+    byte[] encoded=encrypt(plain, _iv);
+    if(encoded!=plain)
+      Util.bzero(plain);
+    byte[] iv=_iv[0];
+    byte[] prv=Util.toBase64(encoded, 0, encoded.length);
+
+    try{
+      out.write(getBegin()); out.write(cr);
+      if(passphrase!=null){
+       out.write(header[0]); out.write(cr);
+       out.write(header[1]); 
+       for(int i=0; i<iv.length; i++){
+         out.write(b2a((byte)((iv[i]>>>4)&0x0f)));
+         out.write(b2a((byte)(iv[i]&0x0f)));
+       }
+        out.write(cr);
+       out.write(cr);
+      }
+      int i=0;
+      while(i<prv.length){
+       if(i+64<prv.length){
+         out.write(prv, i, 64);
+         out.write(cr);
+         i+=64;
+         continue;
+       }
+       out.write(prv, i, prv.length-i);
+       out.write(cr);
+       break;
+      }
+      out.write(getEnd()); out.write(cr);
+      //out.close();
+    }
+    catch(Exception e){
+    }
+  }
+
+  private static byte[] space=Util.str2byte(" ");
+
+  abstract byte[] getKeyTypeName();
+  public abstract int getKeyType();
+
+  public byte[] getPublicKeyBlob(){ return publickeyblob; }
+
+  public void writePublicKey(java.io.OutputStream out, String comment){
+    byte[] pubblob=getPublicKeyBlob();
+    byte[] pub=Util.toBase64(pubblob, 0, pubblob.length);
+    try{
+      out.write(getKeyTypeName()); out.write(space);
+      out.write(pub, 0, pub.length); out.write(space);
+      out.write(Util.str2byte(comment));
+      out.write(cr);
+    }
+    catch(Exception e){
+    }
+  }
+
+  public void writePublicKey(String name, String comment) throws java.io.FileNotFoundException, java.io.IOException{
+    FileOutputStream fos=new FileOutputStream(name);
+    writePublicKey(fos, comment);
+    fos.close();
+  }
+
+  public void writeSECSHPublicKey(java.io.OutputStream out, String comment){
+    byte[] pubblob=getPublicKeyBlob();
+    byte[] pub=Util.toBase64(pubblob, 0, pubblob.length);
+    try{
+      out.write(Util.str2byte("---- BEGIN SSH2 PUBLIC KEY ----")); out.write(cr);
+      out.write(Util.str2byte("Comment: \""+comment+"\"")); out.write(cr);
+      int index=0;
+      while(index<pub.length){
+       int len=70;
+       if((pub.length-index)<len)len=pub.length-index;
+       out.write(pub, index, len); out.write(cr);
+       index+=len;
+      }
+      out.write(Util.str2byte("---- END SSH2 PUBLIC KEY ----")); out.write(cr);
+    }
+    catch(Exception e){
+    }
+  }
+
+  public void writeSECSHPublicKey(String name, String comment) throws java.io.FileNotFoundException, java.io.IOException{
+    FileOutputStream fos=new FileOutputStream(name);
+    writeSECSHPublicKey(fos, comment);
+    fos.close();
+  }
+
+
+  public void writePrivateKey(String name) throws java.io.FileNotFoundException, java.io.IOException{
+    FileOutputStream fos=new FileOutputStream(name);
+    writePrivateKey(fos);
+    fos.close();
+  }
+
+  public String getFingerPrint(){
+    if(hash==null) hash=genHash();
+    byte[] kblob=getPublicKeyBlob();
+    if(kblob==null) return null;
+    return getKeySize()+" "+Util.getFingerPrint(hash, kblob);
+  }
+
+  private byte[] encrypt(byte[] plain, byte[][] _iv){
+    if(passphrase==null) return plain;
+
+    if(cipher==null) cipher=genCipher();
+    byte[] iv=_iv[0]=new byte[cipher.getIVSize()];
+
+    if(random==null) random=genRandom();
+    random.fill(iv, 0, iv.length);
+
+    byte[] key=genKey(passphrase, iv);
+    byte[] encoded=plain;
+
+    // PKCS#5Padding
+    {
+      //int bsize=cipher.getBlockSize();
+      int bsize=cipher.getIVSize();
+      byte[] foo=new byte[(encoded.length/bsize+1)*bsize];
+      System.arraycopy(encoded, 0, foo, 0, encoded.length);
+      int padding=bsize-encoded.length%bsize;
+      for(int i=foo.length-1; (foo.length-padding)<=i; i--){
+        foo[i]=(byte)padding;
+      }
+      encoded=foo;
+    }
+
+    try{
+      cipher.init(Cipher.ENCRYPT_MODE, key, iv);
+      cipher.update(encoded, 0, encoded.length, encoded, 0);
+    }
+    catch(Exception e){
+      //System.err.println(e);
+    }
+    Util.bzero(key);
+    return encoded;
+  }
+
+  abstract boolean parse(byte[] data);
+
+  private byte[] decrypt(byte[] data, byte[] passphrase, byte[] iv){
+    /*
+    if(iv==null){  // FSecure
+      iv=new byte[8];
+      for(int i=0; i<iv.length; i++)iv[i]=0;
+    }
+    */
+    try{
+      byte[] key=genKey(passphrase, iv);
+      cipher.init(Cipher.DECRYPT_MODE, key, iv);
+      Util.bzero(key);
+      byte[] plain=new byte[data.length];
+      cipher.update(data, 0, data.length, plain, 0);
+      return plain;
+    }
+    catch(Exception e){
+      //System.err.println(e);
+    }
+    return null;
+  }
+
+  int writeSEQUENCE(byte[] buf, int index, int len){
+    buf[index++]=0x30;
+    index=writeLength(buf, index, len);
+    return index;
+  }
+  int writeINTEGER(byte[] buf, int index, byte[] data){
+    buf[index++]=0x02;
+    index=writeLength(buf, index, data.length);
+    System.arraycopy(data, 0, buf, index, data.length);
+    index+=data.length;
+    return index;
+  }
+
+  int countLength(int len){
+    int i=1;
+    if(len<=0x7f) return i;
+    while(len>0){
+      len>>>=8;
+      i++;
+    }
+    return i;
+  }
+
+  int writeLength(byte[] data, int index, int len){
+    int i=countLength(len)-1;
+    if(i==0){
+      data[index++]=(byte)len;
+      return index;
+    }
+    data[index++]=(byte)(0x80|i);
+    int j=index+i;
+    while(i>0){
+      data[index+i-1]=(byte)(len&0xff);
+      len>>>=8;
+      i--;
+    }
+    return j;
+  }
+
+  private Random genRandom(){
+    if(random==null){
+      try{
+       Class c=Class.forName(jsch.getConfig("random"));
+        random=(Random)(c.newInstance());
+      }
+      catch(Exception e){ System.err.println("connect: random "+e); }
+    }
+    return random;
+  }
+
+  private HASH genHash(){
+    try{
+      Class c=Class.forName(jsch.getConfig("md5"));
+      hash=(HASH)(c.newInstance());
+      hash.init();
+    }
+    catch(Exception e){
+    }
+    return hash;
+  }
+  private Cipher genCipher(){
+    try{
+      Class c;
+      c=Class.forName(jsch.getConfig("3des-cbc"));
+      cipher=(Cipher)(c.newInstance());
+    }
+    catch(Exception e){
+    }
+    return cipher;
+  }
+
+  /*
+    hash is MD5
+    h(0) <- hash(passphrase, iv);
+    h(n) <- hash(h(n-1), passphrase, iv);
+    key <- (h(0),...,h(n))[0,..,key.length];
+  */
+  synchronized byte[] genKey(byte[] passphrase, byte[] iv){
+    if(cipher==null) cipher=genCipher();
+    if(hash==null) hash=genHash();
+
+    byte[] key=new byte[cipher.getBlockSize()];
+    int hsize=hash.getBlockSize();
+    byte[] hn=new byte[key.length/hsize*hsize+
+                      (key.length%hsize==0?0:hsize)];
+    try{
+      byte[] tmp=null;
+      if(vendor==VENDOR_OPENSSH){
+       for(int index=0; index+hsize<=hn.length;){
+         if(tmp!=null){ hash.update(tmp, 0, tmp.length); }
+         hash.update(passphrase, 0, passphrase.length);
+         hash.update(iv, 0, iv.length);
+         tmp=hash.digest();
+         System.arraycopy(tmp, 0, hn, index, tmp.length);
+         index+=tmp.length;
+       }
+       System.arraycopy(hn, 0, key, 0, key.length); 
+      }
+      else if(vendor==VENDOR_FSECURE){
+       for(int index=0; index+hsize<=hn.length;){
+         if(tmp!=null){ hash.update(tmp, 0, tmp.length); }
+         hash.update(passphrase, 0, passphrase.length);
+         tmp=hash.digest();
+         System.arraycopy(tmp, 0, hn, index, tmp.length);
+         index+=tmp.length;
+       }
+       System.arraycopy(hn, 0, key, 0, key.length); 
+      }
+    }
+    catch(Exception e){
+      System.err.println(e);
+    }
+    return key;
+  } 
+
+  public void setPassphrase(String passphrase){
+    if(passphrase==null || passphrase.length()==0){
+      setPassphrase((byte[])null);
+    }
+    else{
+      setPassphrase(Util.str2byte(passphrase));
+    }
+  }
+  public void setPassphrase(byte[] passphrase){
+    if(passphrase!=null && passphrase.length==0) 
+      passphrase=null;
+    this.passphrase=passphrase;
+  }
+
+  private boolean encrypted=false;
+  private byte[] data=null;
+  private byte[] iv=null;
+  private byte[] publickeyblob=null;
+
+  public boolean isEncrypted(){ return encrypted; }
+  public boolean decrypt(String _passphrase){
+    if(_passphrase==null || _passphrase.length()==0){
+      return !encrypted;
+    }
+    return decrypt(Util.str2byte(_passphrase));
+  }
+  public boolean decrypt(byte[] _passphrase){
+    if(!encrypted){
+      return true;
+    }
+    if(_passphrase==null){
+      return !encrypted;
+    }
+    byte[] bar=new byte[_passphrase.length];
+    System.arraycopy(_passphrase, 0, bar, 0, bar.length);
+    _passphrase=bar;
+    byte[] foo=decrypt(data, _passphrase, iv);
+    Util.bzero(_passphrase);
+    if(parse(foo)){
+      encrypted=false;
+    }
+    return !encrypted;
+  }
+
+  public static KeyPair load(JSch jsch, String prvkey) throws JSchException{
+    String pubkey=prvkey+".pub";
+    if(!new File(pubkey).exists()){
+      pubkey=null;
+    }
+    return load(jsch, prvkey, pubkey);
+  }
+  public static KeyPair load(JSch jsch, String prvkey, String pubkey) throws JSchException{
+
+    byte[] iv=new byte[8];       // 8
+    boolean encrypted=true;
+    byte[] data=null;
+
+    byte[] publickeyblob=null;
+
+    int type=ERROR;
+    int vendor=VENDOR_OPENSSH;
+
+    try{
+      File file=new File(prvkey);
+      FileInputStream fis=new FileInputStream(prvkey);
+      byte[] buf=new byte[(int)(file.length())];
+      int len=0;
+      while(true){
+        int i=fis.read(buf, len, buf.length-len);
+        if(i<=0)
+          break;
+        len+=i;
+      }
+      fis.close();
+
+      int i=0;
+
+      while(i<len){
+        if(buf[i]=='B'&& buf[i+1]=='E'&& buf[i+2]=='G'&& buf[i+3]=='I'){
+          i+=6;            
+          if(buf[i]=='D'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=DSA; }
+         else if(buf[i]=='R'&& buf[i+1]=='S'&& buf[i+2]=='A'){ type=RSA; }
+         else if(buf[i]=='S'&& buf[i+1]=='S'&& buf[i+2]=='H'){ // FSecure
+           type=UNKNOWN;
+           vendor=VENDOR_FSECURE;
+         }
+         else{
+            //System.err.println("invalid format: "+identity);
+           throw new JSchException("invalid privatekey: "+prvkey);
+         }
+          i+=3;
+         continue;
+       }
+        if(buf[i]=='C'&& buf[i+1]=='B'&& buf[i+2]=='C'&& buf[i+3]==','){
+          i+=4;
+         for(int ii=0; ii<iv.length; ii++){
+            iv[ii]=(byte)(((a2b(buf[i++])<<4)&0xf0)+(a2b(buf[i++])&0xf));
+         }
+         continue;
+       }
+       if(buf[i]==0x0d &&
+          i+1<buf.length && buf[i+1]==0x0a){
+         i++;
+         continue;
+       }
+       if(buf[i]==0x0a && i+1<buf.length){
+         if(buf[i+1]==0x0a){ i+=2; break; }
+         if(buf[i+1]==0x0d &&
+            i+2<buf.length && buf[i+2]==0x0a){
+            i+=3; break;
+         }
+         boolean inheader=false;
+         for(int j=i+1; j<buf.length; j++){
+           if(buf[j]==0x0a) break;
+           //if(buf[j]==0x0d) break;
+           if(buf[j]==':'){inheader=true; break;}
+         }
+         if(!inheader){
+           i++; 
+           encrypted=false;    // no passphrase
+           break;
+         }
+       }
+       i++;
+      }
+
+      if(type==ERROR){
+       throw new JSchException("invalid privatekey: "+prvkey);
+      }
+
+      int start=i;
+      while(i<len){
+        if(buf[i]==0x0a){
+         boolean xd=(buf[i-1]==0x0d);
+          System.arraycopy(buf, i+1, 
+                          buf, 
+                          i-(xd ? 1 : 0), 
+                          len-i-1-(xd ? 1 : 0)
+                          );
+         if(xd)len--;
+          len--;
+          continue;
+        }
+        if(buf[i]=='-'){  break; }
+        i++;
+      }
+      data=Util.fromBase64(buf, start, i-start);
+
+      if(data.length>4 &&            // FSecure
+        data[0]==(byte)0x3f &&
+        data[1]==(byte)0x6f &&
+        data[2]==(byte)0xf9 &&
+        data[3]==(byte)0xeb){
+
+       Buffer _buf=new Buffer(data);
+       _buf.getInt();  // 0x3f6ff9be
+       _buf.getInt();
+       byte[]_type=_buf.getString();
+       //System.err.println("type: "+new String(_type)); 
+       byte[] _cipher=_buf.getString();
+       String cipher=Util.byte2str(_cipher);
+       //System.err.println("cipher: "+cipher); 
+       if(cipher.equals("3des-cbc")){
+          _buf.getInt();
+          byte[] foo=new byte[data.length-_buf.getOffSet()];
+          _buf.getByte(foo);
+          data=foo;
+          encrypted=true;
+          throw new JSchException("unknown privatekey format: "+prvkey);
+       }
+       else if(cipher.equals("none")){
+          _buf.getInt();
+          _buf.getInt();
+
+           encrypted=false;
+
+          byte[] foo=new byte[data.length-_buf.getOffSet()];
+          _buf.getByte(foo);
+          data=foo;
+       }
+      }
+
+      if(pubkey!=null){
+       try{
+         file=new File(pubkey);
+         fis=new FileInputStream(pubkey);
+         buf=new byte[(int)(file.length())];
+          len=0;
+          while(true){
+            i=fis.read(buf, len, buf.length-len);
+            if(i<=0)
+              break;
+            len+=i;
+          }
+         fis.close();
+
+         if(buf.length>4 &&             // FSecure's public key
+            buf[0]=='-' && buf[1]=='-' && buf[2]=='-' && buf[3]=='-'){
+
+           boolean valid=true;
+           i=0;
+           do{i++;}while(buf.length>i && buf[i]!=0x0a);
+           if(buf.length<=i) {valid=false;}
+
+           while(valid){
+             if(buf[i]==0x0a){
+               boolean inheader=false;
+               for(int j=i+1; j<buf.length; j++){
+                 if(buf[j]==0x0a) break;
+                 if(buf[j]==':'){inheader=true; break;}
+               }
+               if(!inheader){
+                 i++; 
+                 break;
+               }
+             }
+             i++;
+           }
+           if(buf.length<=i){valid=false;}
+
+           start=i;
+           while(valid && i<len){
+             if(buf[i]==0x0a){
+               System.arraycopy(buf, i+1, buf, i, len-i-1);
+               len--;
+               continue;
+             }
+             if(buf[i]=='-'){  break; }
+             i++;
+           }
+           if(valid){
+             publickeyblob=Util.fromBase64(buf, start, i-start);
+             if(type==UNKNOWN){
+               if(publickeyblob[8]=='d'){ type=DSA; }
+               else if(publickeyblob[8]=='r'){ type=RSA; }
+             }
+           }
+         }
+         else{
+           if(buf[0]=='s'&& buf[1]=='s'&& buf[2]=='h' && buf[3]=='-'){
+             i=0;
+             while(i<len){ if(buf[i]==' ')break; i++;} i++;
+             if(i<len){
+               start=i;
+               while(i<len){ if(buf[i]==' ')break; i++;}
+               publickeyblob=Util.fromBase64(buf, start, i-start);
+             }
+           }
+         }
+       }
+       catch(Exception ee){
+       }
+      }
+    }
+    catch(Exception e){
+      if(e instanceof JSchException) throw (JSchException)e;
+      if(e instanceof Throwable)
+        throw new JSchException(e.toString(), (Throwable)e);
+      throw new JSchException(e.toString());
+    }
+
+    KeyPair kpair=null;
+    if(type==DSA){ kpair=new KeyPairDSA(jsch); }
+    else if(type==RSA){ kpair=new KeyPairRSA(jsch); }
+
+    if(kpair!=null){
+      kpair.encrypted=encrypted;
+      kpair.publickeyblob=publickeyblob;
+      kpair.vendor=vendor;
+
+      if(encrypted){
+       kpair.iv=iv;
+       kpair.data=data;
+      }
+      else{
+       if(kpair.parse(data)){
+         return kpair;
+       }
+       else{
+         throw new JSchException("invalid privatekey: "+prvkey);
+       }
+      }
+    }
+
+    return kpair;
+  }
+
+  static private byte a2b(byte c){
+    if('0'<=c&&c<='9') return (byte)(c-'0');
+    return (byte)(c-'a'+10);
+  }
+  static private byte b2a(byte c){
+    if(0<=c&&c<=9) return (byte)(c+'0');
+    return (byte)(c-10+'A');
+  }
+
+  public void dispose(){
+    Util.bzero(passphrase);
+  }
+
+  public void finalize (){
+    dispose();
+  }
+}
diff --git a/src/com/jcraft/jsch/KeyPairDSA.java b/src/com/jcraft/jsch/KeyPairDSA.java
new file mode 100644 (file)
index 0000000..ad4f112
--- /dev/null
@@ -0,0 +1,221 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public class KeyPairDSA extends KeyPair{
+  private byte[] P_array;
+  private byte[] Q_array;
+  private byte[] G_array;
+  private byte[] pub_array;
+  private byte[] prv_array;
+
+  //private int key_size=0;
+  private int key_size=1024;
+
+  public KeyPairDSA(JSch jsch){
+    super(jsch);
+  }
+
+  void generate(int key_size) throws JSchException{
+    this.key_size=key_size;
+    try{
+      Class c=Class.forName(jsch.getConfig("keypairgen.dsa"));
+      KeyPairGenDSA keypairgen=(KeyPairGenDSA)(c.newInstance());
+      keypairgen.init(key_size);
+      P_array=keypairgen.getP();
+      Q_array=keypairgen.getQ();
+      G_array=keypairgen.getG();
+      pub_array=keypairgen.getY();
+      prv_array=keypairgen.getX();
+
+      keypairgen=null;
+    }
+    catch(Exception e){
+      //System.err.println("KeyPairDSA: "+e); 
+      if(e instanceof Throwable)
+        throw new JSchException(e.toString(), (Throwable)e);
+      throw new JSchException(e.toString());
+    }
+  }
+
+  private static final byte[] begin=Util.str2byte("-----BEGIN DSA PRIVATE KEY-----");
+  private static final byte[] end=Util.str2byte("-----END DSA PRIVATE KEY-----");
+
+  byte[] getBegin(){ return begin; }
+  byte[] getEnd(){ return end; }
+
+  byte[] getPrivateKey(){
+    int content=
+      1+countLength(1) + 1 +                           // INTEGER
+      1+countLength(P_array.length) + P_array.length + // INTEGER  P
+      1+countLength(Q_array.length) + Q_array.length + // INTEGER  Q
+      1+countLength(G_array.length) + G_array.length + // INTEGER  G
+      1+countLength(pub_array.length) + pub_array.length + // INTEGER  pub
+      1+countLength(prv_array.length) + prv_array.length;  // INTEGER  prv
+
+    int total=
+      1+countLength(content)+content;   // SEQUENCE
+
+    byte[] plain=new byte[total];
+    int index=0;
+    index=writeSEQUENCE(plain, index, content);
+    index=writeINTEGER(plain, index, new byte[1]);  // 0
+    index=writeINTEGER(plain, index, P_array);
+    index=writeINTEGER(plain, index, Q_array);
+    index=writeINTEGER(plain, index, G_array);
+    index=writeINTEGER(plain, index, pub_array);
+    index=writeINTEGER(plain, index, prv_array);
+    return plain;
+  }
+
+  boolean parse(byte[] plain){
+    try{
+
+      if(vendor==VENDOR_FSECURE){
+       if(plain[0]!=0x30){              // FSecure
+         Buffer buf=new Buffer(plain);
+         buf.getInt();
+         P_array=buf.getMPIntBits();
+         G_array=buf.getMPIntBits();
+         Q_array=buf.getMPIntBits();
+         pub_array=buf.getMPIntBits();
+         prv_array=buf.getMPIntBits();
+         return true;
+       }
+       return false;
+      }
+
+      int index=0;
+      int length=0;
+
+      if(plain[index]!=0x30)return false;
+      index++; // SEQUENCE
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+
+      if(plain[index]!=0x02)return false;
+      index++; // INTEGER
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      index+=length;
+
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      P_array=new byte[length];
+      System.arraycopy(plain, index, P_array, 0, length);
+      index+=length;
+
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      Q_array=new byte[length];
+      System.arraycopy(plain, index, Q_array, 0, length);
+      index+=length;
+
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      G_array=new byte[length];
+      System.arraycopy(plain, index, G_array, 0, length);
+      index+=length;
+
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      pub_array=new byte[length];
+      System.arraycopy(plain, index, pub_array, 0, length);
+      index+=length;
+
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      prv_array=new byte[length];
+      System.arraycopy(plain, index, prv_array, 0, length);
+      index+=length;
+    }
+    catch(Exception e){
+      //System.err.println(e);
+      //e.printStackTrace();
+      return false;
+    }
+    return true;
+  }
+
+  public byte[] getPublicKeyBlob(){
+    byte[] foo=super.getPublicKeyBlob();
+    if(foo!=null) return foo;
+
+    if(P_array==null) return null;
+
+    Buffer buf=new Buffer(sshdss.length+4+
+                         P_array.length+4+ 
+                         Q_array.length+4+ 
+                         G_array.length+4+ 
+                         pub_array.length+4);
+    buf.putString(sshdss);
+    buf.putString(P_array);
+    buf.putString(Q_array);
+    buf.putString(G_array);
+    buf.putString(pub_array);
+    return buf.buffer;
+  }
+
+  private static final byte[] sshdss=Util.str2byte("ssh-dss");
+  byte[] getKeyTypeName(){return sshdss;}
+  public int getKeyType(){return DSA;}
+
+  public int getKeySize(){return key_size; }
+  public void dispose(){
+    super.dispose();
+    Util.bzero(prv_array);
+  }
+}
diff --git a/src/com/jcraft/jsch/KeyPairGenDSA.java b/src/com/jcraft/jsch/KeyPairGenDSA.java
new file mode 100644 (file)
index 0000000..1656163
--- /dev/null
@@ -0,0 +1,39 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface KeyPairGenDSA{
+  void init(int key_size) throws Exception;
+  byte[] getX();
+  byte[] getY();
+  byte[] getP();
+  byte[] getQ();
+  byte[] getG();
+}
diff --git a/src/com/jcraft/jsch/KeyPairGenRSA.java b/src/com/jcraft/jsch/KeyPairGenRSA.java
new file mode 100644 (file)
index 0000000..eb2a5f3
--- /dev/null
@@ -0,0 +1,43 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface KeyPairGenRSA{
+  void init(int key_size) throws Exception;
+  byte[] getD();
+  byte[] getE();
+  byte[] getN();
+
+  byte[] getC();
+  byte[] getEP();
+  byte[] getEQ();
+  byte[] getP();
+  byte[] getQ();
+}
diff --git a/src/com/jcraft/jsch/KeyPairRSA.java b/src/com/jcraft/jsch/KeyPairRSA.java
new file mode 100644 (file)
index 0000000..9f52f28
--- /dev/null
@@ -0,0 +1,320 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public class KeyPairRSA extends KeyPair{
+  private byte[] prv_array;
+  private byte[] pub_array;
+  private byte[] n_array;
+
+  private byte[] p_array;  // prime p
+  private byte[] q_array;  // prime q
+  private byte[] ep_array; // prime exponent p
+  private byte[] eq_array; // prime exponent q
+  private byte[] c_array;  // coefficient
+
+  //private int key_size=0;
+  private int key_size=1024;
+
+  public KeyPairRSA(JSch jsch){
+    super(jsch);
+  }
+
+  void generate(int key_size) throws JSchException{
+    this.key_size=key_size;
+    try{
+      Class c=Class.forName(jsch.getConfig("keypairgen.rsa"));
+      KeyPairGenRSA keypairgen=(KeyPairGenRSA)(c.newInstance());
+      keypairgen.init(key_size);
+      pub_array=keypairgen.getE();
+      prv_array=keypairgen.getD();
+      n_array=keypairgen.getN();
+
+      p_array=keypairgen.getP();
+      q_array=keypairgen.getQ();
+      ep_array=keypairgen.getEP();
+      eq_array=keypairgen.getEQ();
+      c_array=keypairgen.getC();
+
+      keypairgen=null;
+    }
+    catch(Exception e){
+      //System.err.println("KeyPairRSA: "+e); 
+      if(e instanceof Throwable)
+        throw new JSchException(e.toString(), (Throwable)e);
+      throw new JSchException(e.toString());
+    }
+  }
+
+  private static final byte[] begin=Util.str2byte("-----BEGIN RSA PRIVATE KEY-----");
+  private static final byte[] end=Util.str2byte("-----END RSA PRIVATE KEY-----");
+
+  byte[] getBegin(){ return begin; }
+  byte[] getEnd(){ return end; }
+
+  byte[] getPrivateKey(){
+    int content=
+      1+countLength(1) + 1 +                           // INTEGER
+      1+countLength(n_array.length) + n_array.length + // INTEGER  N
+      1+countLength(pub_array.length) + pub_array.length + // INTEGER  pub
+      1+countLength(prv_array.length) + prv_array.length+  // INTEGER  prv
+      1+countLength(p_array.length) + p_array.length+      // INTEGER  p
+      1+countLength(q_array.length) + q_array.length+      // INTEGER  q
+      1+countLength(ep_array.length) + ep_array.length+    // INTEGER  ep
+      1+countLength(eq_array.length) + eq_array.length+    // INTEGER  eq
+      1+countLength(c_array.length) + c_array.length;      // INTEGER  c
+
+    int total=
+      1+countLength(content)+content;   // SEQUENCE
+
+    byte[] plain=new byte[total];
+    int index=0;
+    index=writeSEQUENCE(plain, index, content);
+    index=writeINTEGER(plain, index, new byte[1]);  // 0
+    index=writeINTEGER(plain, index, n_array);
+    index=writeINTEGER(plain, index, pub_array);
+    index=writeINTEGER(plain, index, prv_array);
+    index=writeINTEGER(plain, index, p_array);
+    index=writeINTEGER(plain, index, q_array);
+    index=writeINTEGER(plain, index, ep_array);
+    index=writeINTEGER(plain, index, eq_array);
+    index=writeINTEGER(plain, index, c_array);
+    return plain;
+  }
+
+  boolean parse(byte [] plain){
+    /*
+    byte[] p_array;
+    byte[] q_array;
+    byte[] dmp1_array;
+    byte[] dmq1_array;
+    byte[] iqmp_array;
+    */
+    try{
+      int index=0;
+      int length=0;
+
+      if(vendor==VENDOR_FSECURE){
+       if(plain[index]!=0x30){                  // FSecure
+         Buffer buf=new Buffer(plain);
+         pub_array=buf.getMPIntBits();
+         prv_array=buf.getMPIntBits();
+         n_array=buf.getMPIntBits();
+         byte[] u_array=buf.getMPIntBits();
+         p_array=buf.getMPIntBits();
+         q_array=buf.getMPIntBits();
+         return true;
+       }
+       return false;
+      }
+
+      index++; // SEQUENCE
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+
+      if(plain[index]!=0x02)return false;
+      index++; // INTEGER
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      index+=length;
+
+//System.err.println("int: len="+length);
+//System.err.print(Integer.toHexString(plain[index-1]&0xff)+":");
+//System.err.println("");
+
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      n_array=new byte[length];
+      System.arraycopy(plain, index, n_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: N len="+length);
+for(int i=0; i<n_array.length; i++){
+System.err.print(Integer.toHexString(n_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      pub_array=new byte[length];
+      System.arraycopy(plain, index, pub_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: E len="+length);
+for(int i=0; i<pub_array.length; i++){
+System.err.print(Integer.toHexString(pub_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      prv_array=new byte[length];
+      System.arraycopy(plain, index, prv_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: prv len="+length);
+for(int i=0; i<prv_array.length; i++){
+System.err.print(Integer.toHexString(prv_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      p_array=new byte[length];
+      System.arraycopy(plain, index, p_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: P len="+length);
+for(int i=0; i<p_array.length; i++){
+System.err.print(Integer.toHexString(p_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      q_array=new byte[length];
+      System.arraycopy(plain, index, q_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: q len="+length);
+for(int i=0; i<q_array.length; i++){
+System.err.print(Integer.toHexString(q_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      ep_array=new byte[length];
+      System.arraycopy(plain, index, ep_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: ep len="+length);
+for(int i=0; i<ep_array.length; i++){
+System.err.print(Integer.toHexString(ep_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      eq_array=new byte[length];
+      System.arraycopy(plain, index, eq_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: eq len="+length);
+for(int i=0; i<eq_array.length; i++){
+System.err.print(Integer.toHexString(eq_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+      index++;
+      length=plain[index++]&0xff;
+      if((length&0x80)!=0){
+        int foo=length&0x7f; length=0;
+        while(foo-->0){ length=(length<<8)+(plain[index++]&0xff); }
+      }
+      c_array=new byte[length];
+      System.arraycopy(plain, index, c_array, 0, length);
+      index+=length;
+/*
+System.err.println("int: c len="+length);
+for(int i=0; i<c_array.length; i++){
+System.err.print(Integer.toHexString(c_array[i]&0xff)+":");
+}
+System.err.println("");
+*/
+    }
+    catch(Exception e){
+      //System.err.println(e);
+      return false;
+    }
+    return true;
+  }
+
+
+  public byte[] getPublicKeyBlob(){
+    byte[] foo=super.getPublicKeyBlob();
+    if(foo!=null) return foo;
+
+    if(pub_array==null) return null;
+
+    Buffer buf=new Buffer(sshrsa.length+4+
+                         pub_array.length+4+ 
+                         n_array.length+4);
+    buf.putString(sshrsa);
+    buf.putString(pub_array);
+    buf.putString(n_array);
+    return buf.buffer;
+  }
+
+  private static final byte[] sshrsa=Util.str2byte("ssh-rsa");
+  byte[] getKeyTypeName(){return sshrsa;}
+  public int getKeyType(){return RSA;}
+
+  public int getKeySize(){return key_size; }
+  public void dispose(){
+    super.dispose();
+    Util.bzero(prv_array);
+  }
+}
diff --git a/src/com/jcraft/jsch/KnownHosts.java b/src/com/jcraft/jsch/KnownHosts.java
new file mode 100644 (file)
index 0000000..88c9feb
--- /dev/null
@@ -0,0 +1,506 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.io.*;
+
+public
+class KnownHosts implements HostKeyRepository{
+  private static final String _known_hosts="known_hosts";
+
+  /*
+  static final int SSHDSS=0;
+  static final int SSHRSA=1;
+  static final int UNKNOWN=2;
+  */
+
+  private JSch jsch=null;
+  private String known_hosts=null;
+  private java.util.Vector pool=null;
+
+  private MAC hmacsha1=null;
+
+  KnownHosts(JSch jsch){
+    super();
+    this.jsch=jsch;
+    pool=new java.util.Vector();
+  }
+
+  void setKnownHosts(String foo) throws JSchException{
+    try{
+      known_hosts=foo;
+      FileInputStream fis=new FileInputStream(foo);
+      setKnownHosts(fis);
+    }
+    catch(FileNotFoundException e){
+    } 
+  }
+  void setKnownHosts(InputStream foo) throws JSchException{
+    pool.removeAllElements();
+    StringBuffer sb=new StringBuffer();
+    byte i;
+    int j;
+    boolean error=false;
+    try{
+      InputStream fis=foo;
+      String host;
+      String key=null;
+      int type;
+      byte[] buf=new byte[1024];
+      int bufl=0;
+loop:
+      while(true){
+       bufl=0;
+        while(true){
+          j=fis.read();
+          if(j==-1){
+            if(bufl==0){ break loop; }
+            else{ break; }
+          }
+         if(j==0x0d){ continue; }
+         if(j==0x0a){ break; }
+          if(buf.length<=bufl){
+            if(bufl>1024*10) break;   // too long...
+            byte[] newbuf=new byte[buf.length*2];
+            System.arraycopy(buf, 0, newbuf, 0, buf.length);
+            buf=newbuf;
+          }
+          buf[bufl++]=(byte)j;
+       }
+
+       j=0;
+        while(j<bufl){
+          i=buf[j];
+         if(i==' '||i=='\t'){ j++; continue; }
+         if(i=='#'){
+           addInvalidLine(Util.byte2str(buf, 0, bufl));
+           continue loop;
+         }
+         break;
+       }
+       if(j>=bufl){ 
+         addInvalidLine(Util.byte2str(buf, 0, bufl));
+         continue loop; 
+       }
+
+        sb.setLength(0);
+        while(j<bufl){
+          i=buf[j++];
+          if(i==0x20 || i=='\t'){ break; }
+          sb.append((char)i);
+       }
+       host=sb.toString();
+       if(j>=bufl || host.length()==0){
+         addInvalidLine(Util.byte2str(buf, 0, bufl));
+         continue loop; 
+       }
+
+        sb.setLength(0);
+       type=-1;
+        while(j<bufl){
+          i=buf[j++];
+          if(i==0x20 || i=='\t'){ break; }
+          sb.append((char)i);
+       }
+       if(sb.toString().equals("ssh-dss")){ type=HostKey.SSHDSS; }
+       else if(sb.toString().equals("ssh-rsa")){ type=HostKey.SSHRSA; }
+       else { j=bufl; }
+       if(j>=bufl){
+         addInvalidLine(Util.byte2str(buf, 0, bufl));
+         continue loop; 
+       }
+
+        sb.setLength(0);
+        while(j<bufl){
+          i=buf[j++];
+          if(i==0x0d){ continue; }
+          if(i==0x0a){ break; }
+          sb.append((char)i);
+       }
+       key=sb.toString();
+       if(key.length()==0){
+         addInvalidLine(Util.byte2str(buf, 0, bufl));
+         continue loop; 
+       }
+
+       //System.err.println(host);
+       //System.err.println("|"+key+"|");
+
+       HostKey hk = null;
+        hk = new HashedHostKey(host, type, 
+                               Util.fromBase64(Util.str2byte(key), 0, 
+                                               key.length()));
+       pool.addElement(hk);
+      }
+      fis.close();
+      if(error){
+       throw new JSchException("KnownHosts: invalid format");
+      }
+    }
+    catch(Exception e){
+      if(e instanceof JSchException)
+       throw (JSchException)e;         
+      if(e instanceof Throwable)
+        throw new JSchException(e.toString(), (Throwable)e);
+      throw new JSchException(e.toString());
+    }
+  }
+  private void addInvalidLine(String line) throws JSchException {
+    HostKey hk = new HostKey(line, HostKey.UNKNOWN, null);
+    pool.addElement(hk);
+  }
+  String getKnownHostsFile(){ return known_hosts; }
+  public String getKnownHostsRepositoryID(){ return known_hosts; }
+
+  public int check(String host, byte[] key){
+    int result=NOT_INCLUDED;
+    if(host==null){
+      return result;
+    }
+
+    int type=getType(key);
+    HostKey hk;
+
+    synchronized(pool){
+      for(int i=0; i<pool.size(); i++){
+        hk=(HostKey)(pool.elementAt(i));
+        if(hk.isMatched(host) && hk.type==type){
+          if(Util.array_equals(hk.key, key)){
+            return OK;
+          }
+          else{
+            result=CHANGED;
+         }
+        }
+      }
+    }
+
+    if(result==NOT_INCLUDED &&
+       host.startsWith("[") &&
+       host.indexOf("]:")>1
+       ){
+      return check(host.substring(1, host.indexOf("]:")), key);
+    }
+
+    return result;
+  }
+  public void add(HostKey hostkey, UserInfo userinfo){
+    int type=hostkey.type;
+    String host=hostkey.getHost();
+    byte[] key=hostkey.key;
+
+    HostKey hk=null;
+    synchronized(pool){
+      for(int i=0; i<pool.size(); i++){
+        hk=(HostKey)(pool.elementAt(i));
+        if(hk.isMatched(host) && hk.type==type){
+/*
+         if(Util.array_equals(hk.key, key)){ return; }
+         if(hk.host.equals(host)){
+           hk.key=key;
+           return;
+         }
+         else{
+           hk.host=deleteSubString(hk.host, host);
+           break;
+         }
+*/
+        }
+      }
+    }
+
+    hk=hostkey;
+
+    pool.addElement(hk);
+
+    String bar=getKnownHostsRepositoryID();
+    if(bar!=null){
+      boolean foo=true;
+      File goo=new File(bar);
+      if(!goo.exists()){
+        foo=false;
+        if(userinfo!=null){
+          foo=userinfo.promptYesNo(bar+" does not exist.\n"+
+                                   "Are you sure you want to create it?"
+                                   );
+          goo=goo.getParentFile();
+          if(foo && goo!=null && !goo.exists()){
+            foo=userinfo.promptYesNo("The parent directory "+goo+" does not exist.\n"+
+                                     "Are you sure you want to create it?"
+                                     );
+            if(foo){
+              if(!goo.mkdirs()){
+                userinfo.showMessage(goo+" has not been created.");
+                foo=false;
+              }
+              else{
+                userinfo.showMessage(goo+" has been succesfully created.\nPlease check its access permission.");
+              }
+            }
+          }
+          if(goo==null)foo=false;
+        }
+      }
+      if(foo){
+        try{ 
+          sync(bar); 
+        }
+        catch(Exception e){ System.err.println("sync known_hosts: "+e); }
+      }
+    }
+  }
+
+  public HostKey[] getHostKey(){
+    return getHostKey(null, null);
+  }
+  public HostKey[] getHostKey(String host, String type){
+    synchronized(pool){
+      int count=0;
+      for(int i=0; i<pool.size(); i++){
+       HostKey hk=(HostKey)pool.elementAt(i);
+       if(hk.type==HostKey.UNKNOWN) continue;
+       if(host==null || 
+          (hk.isMatched(host) && 
+           (type==null || hk.getType().equals(type)))){
+         count++;
+       }
+      }
+      if(count==0)return null;
+      HostKey[] foo=new HostKey[count];
+      int j=0;
+      for(int i=0; i<pool.size(); i++){
+       HostKey hk=(HostKey)pool.elementAt(i);
+       if(hk.type==HostKey.UNKNOWN) continue;
+       if(host==null || 
+          (hk.isMatched(host) && 
+           (type==null || hk.getType().equals(type)))){
+         foo[j++]=hk;
+       }
+      }
+      return foo;
+    }
+  }
+  public void remove(String host, String type){
+    remove(host, type, null);
+  }
+  public void remove(String host, String type, byte[] key){
+    boolean sync=false;
+    synchronized(pool){
+    for(int i=0; i<pool.size(); i++){
+      HostKey hk=(HostKey)(pool.elementAt(i));
+      if(host==null ||
+        (hk.isMatched(host) && 
+         (type==null || (hk.getType().equals(type) &&
+                         (key==null || Util.array_equals(key, hk.key)))))){
+        String hosts=hk.getHost();
+        if(hosts.equals(host) || 
+           ((hk instanceof HashedHostKey) &&
+            ((HashedHostKey)hk).isHashed())){
+          pool.removeElement(hk);
+        }
+        else{
+          hk.host=deleteSubString(hosts, host);
+        }
+       sync=true;
+      }
+    }
+    }
+    if(sync){
+      try{sync();}catch(Exception e){};
+    }
+  }
+
+  protected void sync() throws IOException { 
+    if(known_hosts!=null)
+      sync(known_hosts); 
+  }
+  protected synchronized void sync(String foo) throws IOException {
+    if(foo==null) return;
+    FileOutputStream fos=new FileOutputStream(foo);
+    dump(fos);
+    fos.close();
+  }
+
+  private static final byte[] space={(byte)0x20};
+  private static final byte[] cr=Util.str2byte("\n");
+  void dump(OutputStream out) throws IOException {
+    try{
+      HostKey hk;
+      synchronized(pool){
+      for(int i=0; i<pool.size(); i++){
+        hk=(HostKey)(pool.elementAt(i));
+        //hk.dump(out);
+       String host=hk.getHost();
+       String type=hk.getType();
+       if(type.equals("UNKNOWN")){
+         out.write(Util.str2byte(host));
+         out.write(cr);
+         continue;
+       }
+       out.write(Util.str2byte(host));
+       out.write(space);
+       out.write(Util.str2byte(type));
+       out.write(space);
+       out.write(Util.str2byte(hk.getKey()));
+       out.write(cr);
+      }
+      }
+    }
+    catch(Exception e){
+      System.err.println(e);
+    }
+  }
+  private int getType(byte[] key){
+    if(key[8]=='d') return HostKey.SSHDSS;
+    if(key[8]=='r') return HostKey.SSHRSA;
+    return HostKey.UNKNOWN;
+  }
+  private String deleteSubString(String hosts, String host){
+    int i=0;
+    int hostlen=host.length();
+    int hostslen=hosts.length();
+    int j;
+    while(i<hostslen){
+      j=hosts.indexOf(',', i);
+      if(j==-1) break;
+      if(!host.equals(hosts.substring(i, j))){
+        i=j+1;   
+        continue;
+      }
+      return hosts.substring(0, i)+hosts.substring(j+1);
+    }
+    if(hosts.endsWith(host) && hostslen-i==hostlen){
+      return hosts.substring(0, (hostlen==hostslen) ? 0 :hostslen-hostlen-1);
+    }
+    return hosts;
+  }
+
+  private synchronized MAC getHMACSHA1(){
+    if(hmacsha1==null){
+      try{
+        Class c=Class.forName(jsch.getConfig("hmac-sha1"));
+        hmacsha1=(MAC)(c.newInstance());
+      }
+      catch(Exception e){ 
+        System.err.println("hmacsha1: "+e); 
+      }
+    }
+    return hmacsha1;
+  }
+
+  HostKey createHashedHostKey(String host, byte[]key) throws JSchException {
+    HashedHostKey hhk=new HashedHostKey(host, key);
+    hhk.hash();
+    return hhk;
+  } 
+  class HashedHostKey extends HostKey{
+    private static final String HASH_MAGIC="|1|";
+    private static final String HASH_DELIM="|";
+
+    private boolean hashed=false;
+    byte[] salt=null;
+    byte[] hash=null;
+
+
+    HashedHostKey(String host, byte[] key) throws JSchException {
+      this(host, GUESS, key);
+    }
+    HashedHostKey(String host, int type, byte[] key) throws JSchException {
+      super(host, type, key);
+      if(this.host.startsWith(HASH_MAGIC) &&
+         this.host.substring(HASH_MAGIC.length()).indexOf(HASH_DELIM)>0){
+        String data=this.host.substring(HASH_MAGIC.length());
+        String _salt=data.substring(0, data.indexOf(HASH_DELIM));
+        String _hash=data.substring(data.indexOf(HASH_DELIM)+1);
+        salt=Util.fromBase64(Util.str2byte(_salt), 0, _salt.length());
+        hash=Util.fromBase64(Util.str2byte(_hash), 0, _hash.length());
+        if(salt.length!=20 ||  // block size of hmac-sha1
+           hash.length!=20){
+          salt=null;
+          hash=null;
+          return;
+        }
+        hashed=true;
+      }
+    }
+
+    boolean isMatched(String _host){
+      if(!hashed){
+        return super.isMatched(_host);
+      }
+      MAC macsha1=getHMACSHA1();
+      try{
+        synchronized(macsha1){
+          macsha1.init(salt);
+          byte[] foo=Util.str2byte(_host);
+          macsha1.update(foo, 0, foo.length);
+          byte[] bar=new byte[macsha1.getBlockSize()];
+          macsha1.doFinal(bar, 0);
+          return Util.array_equals(hash, bar);
+        }
+      }
+      catch(Exception e){
+        System.out.println(e);
+      }
+      return false;
+    }
+
+    boolean isHashed(){
+      return hashed;
+    }
+
+    void hash(){
+      if(hashed)
+        return;
+      MAC macsha1=getHMACSHA1();
+      if(salt==null){
+        Random random=Session.random;
+        synchronized(random){
+          salt=new byte[macsha1.getBlockSize()];
+          random.fill(salt, 0, salt.length);
+        }
+      }
+      try{
+        synchronized(macsha1){
+          macsha1.init(salt);
+          byte[] foo=Util.str2byte(host);
+          macsha1.update(foo, 0, foo.length);
+          hash=new byte[macsha1.getBlockSize()];
+          macsha1.doFinal(hash, 0);
+        }
+      }
+      catch(Exception e){
+      }
+      host=HASH_MAGIC+Util.byte2str(Util.toBase64(salt, 0, salt.length))+
+        HASH_DELIM+Util.byte2str(Util.toBase64(hash, 0, hash.length));
+      hashed=true;
+    }
+  }
+}
diff --git a/src/com/jcraft/jsch/Logger.java b/src/com/jcraft/jsch/Logger.java
new file mode 100644 (file)
index 0000000..6b48b7f
--- /dev/null
@@ -0,0 +1,54 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface Logger{
+
+  public final int DEBUG=0;
+  public final int INFO=1;
+  public final int WARN=2;
+  public final int ERROR=3;
+  public final int FATAL=4;
+
+  public boolean isEnabled(int level);
+
+  public void log(int level, String message);
+
+  /*
+  public final Logger SIMPLE_LOGGER=new Logger(){
+      public boolean isEnabled(int level){return true;}
+      public void log(int level, String message){System.err.println(message);}
+    };
+  final Logger DEVNULL=new Logger(){
+      public boolean isEnabled(int level){return false;}
+      public void log(int level, String message){}
+    };
+  */
+}
diff --git a/src/com/jcraft/jsch/MAC.java b/src/com/jcraft/jsch/MAC.java
new file mode 100644 (file)
index 0000000..14884b4
--- /dev/null
@@ -0,0 +1,39 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface MAC{
+  String getName();
+  int getBlockSize(); 
+  void init(byte[] key) throws Exception; 
+  void update(byte[] foo, int start, int len);
+  void update(int foo);
+  void doFinal(byte[] buf, int offset);
+}
diff --git a/src/com/jcraft/jsch/Packet.java b/src/com/jcraft/jsch/Packet.java
new file mode 100644 (file)
index 0000000..56a2dd9
--- /dev/null
@@ -0,0 +1,114 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public class Packet{
+
+  private static Random random=null;
+  static void setRandom(Random foo){ random=foo;}
+
+  Buffer buffer;
+  byte[] ba4=new byte[4]; 
+  public Packet(Buffer buffer){
+    this.buffer=buffer;
+  }
+  public void reset(){
+    buffer.index=5;
+  }
+  void padding(int bsize){
+    int len=buffer.index;
+    int pad=(-len)&(bsize-1);
+    if(pad<bsize){
+      pad+=bsize;
+    }
+    len=len+pad-4;
+    ba4[0]=(byte)(len>>>24);
+    ba4[1]=(byte)(len>>>16);
+    ba4[2]=(byte)(len>>>8);
+    ba4[3]=(byte)(len);
+    System.arraycopy(ba4, 0, buffer.buffer, 0, 4);
+    buffer.buffer[4]=(byte)pad;
+    synchronized(random){
+      random.fill(buffer.buffer, buffer.index, pad);
+    }
+    buffer.skip(pad);
+    //buffer.putPad(pad);
+/*
+for(int i=0; i<buffer.index; i++){
+System.err.print(Integer.toHexString(buffer.buffer[i]&0xff)+":");
+}
+System.err.println("");
+*/
+  }
+
+  int shift(int len, int mac){
+    int s=len+5+9;
+    int pad=(-s)&15;
+    if(pad<16)pad+=16;
+    s+=pad;
+    s+=mac;
+
+    /**/
+    if(buffer.buffer.length<s+buffer.index-5-9-len){
+      byte[] foo=new byte[s+buffer.index-5-9-len];
+      System.arraycopy(buffer.buffer, 0, foo, 0, buffer.buffer.length);
+      buffer.buffer=foo;
+    }
+    /**/
+
+//if(buffer.buffer.length<len+5+9)
+//  System.err.println("buffer.buffer.length="+buffer.buffer.length+" len+5+9="+(len+5+9));
+
+//if(buffer.buffer.length<s)
+//  System.err.println("buffer.buffer.length="+buffer.buffer.length+" s="+(s));
+
+    System.arraycopy(buffer.buffer, 
+                    len+5+9, 
+                    buffer.buffer, s, buffer.index-5-9-len);
+
+    buffer.index=10;
+    buffer.putInt(len);
+    buffer.index=len+5+9;
+    return s;
+  }
+  void unshift(byte command, int recipient, int s, int len){
+    System.arraycopy(buffer.buffer, 
+                    s, 
+                    buffer.buffer, 5+9, len);
+    buffer.buffer[5]=command;
+    buffer.index=6;
+    buffer.putInt(recipient);
+    buffer.putInt(len);
+    buffer.index=len+5+9;
+  }
+  Buffer getBuffer(){
+    return buffer;
+  }
+}
diff --git a/src/com/jcraft/jsch/PortWatcher.java b/src/com/jcraft/jsch/PortWatcher.java
new file mode 100644 (file)
index 0000000..8f83a0f
--- /dev/null
@@ -0,0 +1,194 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.net.*;
+import java.io.*;
+
+class PortWatcher implements Runnable{
+  private static java.util.Vector pool=new java.util.Vector();
+  private static InetAddress anyLocalAddress=null;
+  static{
+    // 0.0.0.0
+/*
+    try{ anyLocalAddress=InetAddress.getByAddress(new byte[4]); }
+    catch(UnknownHostException e){
+    }
+*/
+    try{ anyLocalAddress=InetAddress.getByName("0.0.0.0"); }
+    catch(UnknownHostException e){
+    }
+  }
+
+  Session session;
+  int lport;
+  int rport;
+  String host;
+  InetAddress boundaddress;
+  Runnable thread;
+  ServerSocket ss;
+
+  static String[] getPortForwarding(Session session){
+    java.util.Vector foo=new java.util.Vector();
+    synchronized(pool){
+      for(int i=0; i<pool.size(); i++){
+       PortWatcher p=(PortWatcher)(pool.elementAt(i));
+       if(p.session==session){
+         foo.addElement(p.lport+":"+p.host+":"+p.rport);
+       }
+      }
+    }
+    String[] bar=new String[foo.size()];
+    for(int i=0; i<foo.size(); i++){
+      bar[i]=(String)(foo.elementAt(i));
+    }
+    return bar;
+  }
+  static PortWatcher getPort(Session session, String address, int lport) throws JSchException{
+    InetAddress addr;
+    try{
+      addr=InetAddress.getByName(address);
+    }
+    catch(UnknownHostException uhe){
+      throw new JSchException("PortForwardingL: invalid address "+address+" specified.", uhe);
+    }
+    synchronized(pool){
+      for(int i=0; i<pool.size(); i++){
+       PortWatcher p=(PortWatcher)(pool.elementAt(i));
+       if(p.session==session && p.lport==lport){
+         if(/*p.boundaddress.isAnyLocalAddress() ||*/
+             (anyLocalAddress!=null &&  p.boundaddress.equals(anyLocalAddress)) ||
+            p.boundaddress.equals(addr))
+         return p;
+       }
+      }
+      return null;
+    }
+  }
+  static PortWatcher addPort(Session session, String address, int lport, String host, int rport, ServerSocketFactory ssf) throws JSchException{
+    if(getPort(session, address, lport)!=null){
+      throw new JSchException("PortForwardingL: local port "+ address+":"+lport+" is already registered.");
+    }
+    PortWatcher pw=new PortWatcher(session, address, lport, host, rport, ssf);
+    pool.addElement(pw);
+    return pw;
+  }
+  static void delPort(Session session, String address, int lport) throws JSchException{
+    PortWatcher pw=getPort(session, address, lport);
+    if(pw==null){
+      throw new JSchException("PortForwardingL: local port "+address+":"+lport+" is not registered.");
+    }
+    pw.delete();
+    pool.removeElement(pw);
+  }
+  static void delPort(Session session){
+    synchronized(pool){
+      PortWatcher[] foo=new PortWatcher[pool.size()];
+      int count=0;
+      for(int i=0; i<pool.size(); i++){
+       PortWatcher p=(PortWatcher)(pool.elementAt(i));
+       if(p.session==session) {
+         p.delete();
+         foo[count++]=p;
+       }
+      }
+      for(int i=0; i<count; i++){
+       PortWatcher p=foo[i];
+       pool.removeElement(p);
+      }
+    }
+  }
+  PortWatcher(Session session, 
+             String address, int lport, 
+             String host, int rport,
+              ServerSocketFactory factory) throws JSchException{
+    this.session=session;
+    this.lport=lport;
+    this.host=host;
+    this.rport=rport;
+    try{
+      boundaddress=InetAddress.getByName(address);
+      ss=(factory==null) ? 
+        new ServerSocket(lport, 0, boundaddress) :
+        factory.createServerSocket(lport, 0, boundaddress);
+    }
+    catch(Exception e){ 
+      //System.err.println(e);
+      String message="PortForwardingL: local port "+address+":"+lport+" cannot be bound.";
+      if(e instanceof Throwable)
+        throw new JSchException(message, (Throwable)e);
+      throw new JSchException(message);
+    }
+    if(lport==0){
+      int assigned=ss.getLocalPort();
+      if(assigned!=-1)
+        this.lport=assigned;
+    }
+  }
+
+  public void run(){
+    thread=this;
+    try{
+      while(thread!=null){
+        Socket socket=ss.accept();
+       socket.setTcpNoDelay(true);
+        InputStream in=socket.getInputStream();
+        OutputStream out=socket.getOutputStream();
+        ChannelDirectTCPIP channel=new ChannelDirectTCPIP();
+        channel.init();
+        channel.setInputStream(in);
+        channel.setOutputStream(out);
+       session.addChannel(channel);
+       ((ChannelDirectTCPIP)channel).setHost(host);
+       ((ChannelDirectTCPIP)channel).setPort(rport);
+       ((ChannelDirectTCPIP)channel).setOrgIPAddress(socket.getInetAddress().getHostAddress());
+       ((ChannelDirectTCPIP)channel).setOrgPort(socket.getPort());
+        channel.connect();
+       if(channel.exitstatus!=-1){
+       }
+      }
+    }
+    catch(Exception e){
+      //System.err.println("! "+e);
+    }
+
+    delete();
+  }
+
+  void delete(){
+    thread=null;
+    try{ 
+      if(ss!=null)ss.close();
+      ss=null;
+    }
+    catch(Exception e){
+    }
+  }
+}
diff --git a/src/com/jcraft/jsch/Proxy.java b/src/com/jcraft/jsch/Proxy.java
new file mode 100644 (file)
index 0000000..8980d89
--- /dev/null
@@ -0,0 +1,40 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.io.*;
+import java.net.Socket;
+public interface Proxy{
+  void connect(SocketFactory socket_factory, String host, int port, int timeout) throws Exception;
+  InputStream getInputStream();
+  OutputStream getOutputStream();
+  Socket getSocket();
+  void close();
+}
diff --git a/src/com/jcraft/jsch/ProxyHTTP.java b/src/com/jcraft/jsch/ProxyHTTP.java
new file mode 100644 (file)
index 0000000..ba9eb09
--- /dev/null
@@ -0,0 +1,180 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.io.*;
+import java.net.*;
+
+public class ProxyHTTP implements Proxy{
+  private static int DEFAULTPORT=80;
+  private String proxy_host;
+  private int proxy_port;
+  private InputStream in;
+  private OutputStream out;
+  private Socket socket;
+
+  private String user;
+  private String passwd;
+
+  public ProxyHTTP(String proxy_host){
+    int port=DEFAULTPORT;
+    String host=proxy_host;
+    if(proxy_host.indexOf(':')!=-1){
+      try{
+       host=proxy_host.substring(0, proxy_host.indexOf(':'));
+       port=Integer.parseInt(proxy_host.substring(proxy_host.indexOf(':')+1));
+      }
+      catch(Exception e){
+      }
+    }
+    this.proxy_host=host;
+    this.proxy_port=port;
+  }
+  public ProxyHTTP(String proxy_host, int proxy_port){
+    this.proxy_host=proxy_host;
+    this.proxy_port=proxy_port;
+  }
+  public void setUserPasswd(String user, String passwd){
+    this.user=user;
+    this.passwd=passwd;
+  }
+  public void connect(SocketFactory socket_factory, String host, int port, int timeout) throws JSchException{
+    try{
+      if(socket_factory==null){
+        socket=Util.createSocket(proxy_host, proxy_port, timeout);    
+        in=socket.getInputStream();
+        out=socket.getOutputStream();
+      }
+      else{
+        socket=socket_factory.createSocket(proxy_host, proxy_port);
+        in=socket_factory.getInputStream(socket);
+        out=socket_factory.getOutputStream(socket);
+      }
+      if(timeout>0){
+        socket.setSoTimeout(timeout);
+      }
+      socket.setTcpNoDelay(true);
+
+      out.write(Util.str2byte("CONNECT "+host+":"+port+" HTTP/1.0\r\n"));
+
+      if(user!=null && passwd!=null){
+       byte[] code=Util.str2byte(user+":"+passwd);
+       code=Util.toBase64(code, 0, code.length);
+       out.write(Util.str2byte("Proxy-Authorization: Basic "));
+       out.write(code);
+       out.write(Util.str2byte("\r\n"));
+      }
+
+      out.write(Util.str2byte("\r\n"));
+      out.flush();
+
+      int foo=0;
+
+      StringBuffer sb=new StringBuffer();
+      while(foo>=0){
+        foo=in.read(); if(foo!=13){sb.append((char)foo);  continue;}
+        foo=in.read(); if(foo!=10){continue;}
+        break;
+      }
+      if(foo<0){
+        throw new IOException();
+      }
+
+      String response=sb.toString(); 
+      String reason="Unknow reason";
+      int code=-1;
+      try{
+        foo=response.indexOf(' ');
+        int bar=response.indexOf(' ', foo+1);
+        code=Integer.parseInt(response.substring(foo+1, bar));
+        reason=response.substring(bar+1);
+      }
+      catch(Exception e){
+      }
+      if(code!=200){
+        throw new IOException("proxy error: "+reason);
+      }
+
+      /*
+      while(foo>=0){
+        foo=in.read(); if(foo!=13) continue;
+        foo=in.read(); if(foo!=10) continue;
+        foo=in.read(); if(foo!=13) continue;      
+        foo=in.read(); if(foo!=10) continue;
+        break;
+      }
+      */
+
+      int count=0;
+      while(true){
+        count=0;
+        while(foo>=0){
+          foo=in.read(); if(foo!=13){count++;  continue;}
+          foo=in.read(); if(foo!=10){continue;}
+          break;
+        }
+        if(foo<0){
+          throw new IOException();
+        }
+        if(count==0)break;
+      }
+    }
+    catch(RuntimeException e){
+      throw e;
+    }
+    catch(Exception e){
+      try{ if(socket!=null)socket.close(); }
+      catch(Exception eee){
+      }
+      String message="ProxyHTTP: "+e.toString();
+      if(e instanceof Throwable)
+        throw new JSchException(message, (Throwable)e);
+      throw new JSchException(message);
+    }
+  }
+  public InputStream getInputStream(){ return in; }
+  public OutputStream getOutputStream(){ return out; }
+  public Socket getSocket(){ return socket; }
+  public void close(){
+    try{
+      if(in!=null)in.close();
+      if(out!=null)out.close();
+      if(socket!=null)socket.close();
+    }
+    catch(Exception e){
+    }
+    in=null;
+    out=null;
+    socket=null;
+  }
+  public static int getDefaultPort(){
+    return DEFAULTPORT;
+  }
+}
diff --git a/src/com/jcraft/jsch/ProxySOCKS4.java b/src/com/jcraft/jsch/ProxySOCKS4.java
new file mode 100644 (file)
index 0000000..d3d0e8d
--- /dev/null
@@ -0,0 +1,212 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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 depends on following documents,
+   - SOCKS: A protocol for TCP proxy across firewalls, Ying-Da Lee
+     http://www.socks.nec.com/protocol/socks4.protocol
+ */
+
+package com.jcraft.jsch;
+
+import java.io.*;
+import java.net.*;
+
+public class ProxySOCKS4 implements Proxy{
+  private static int DEFAULTPORT=1080;
+  private String proxy_host;
+  private int proxy_port;
+  private InputStream in;
+  private OutputStream out;
+  private Socket socket;
+  private String user;
+  private String passwd;
+
+  public ProxySOCKS4(String proxy_host){
+    int port=DEFAULTPORT;
+    String host=proxy_host;
+    if(proxy_host.indexOf(':')!=-1){
+      try{
+       host=proxy_host.substring(0, proxy_host.indexOf(':'));
+       port=Integer.parseInt(proxy_host.substring(proxy_host.indexOf(':')+1));
+      }
+      catch(Exception e){
+      }
+    }
+    this.proxy_host=host;
+    this.proxy_port=port;
+  }
+  public ProxySOCKS4(String proxy_host, int proxy_port){
+    this.proxy_host=proxy_host;
+    this.proxy_port=proxy_port;
+  }
+  public void setUserPasswd(String user, String passwd){
+    this.user=user;
+    this.passwd=passwd;
+  }
+  public void connect(SocketFactory socket_factory, String host, int port, int timeout) throws JSchException{
+    try{
+      if(socket_factory==null){
+        socket=Util.createSocket(proxy_host, proxy_port, timeout);
+        //socket=new Socket(proxy_host, proxy_port);    
+        in=socket.getInputStream();
+        out=socket.getOutputStream();
+      }
+      else{
+        socket=socket_factory.createSocket(proxy_host, proxy_port);
+        in=socket_factory.getInputStream(socket);
+        out=socket_factory.getOutputStream(socket);
+      }
+      if(timeout>0){
+        socket.setSoTimeout(timeout);
+      }
+      socket.setTcpNoDelay(true);
+
+      byte[] buf=new byte[1024];
+      int index=0;
+
+/*
+   1) CONNECT
+   
+   The client connects to the SOCKS server and sends a CONNECT request when
+   it wants to establish a connection to an application server. The client
+   includes in the request packet the IP address and the port number of the
+   destination host, and userid, in the following format.
+   
+               +----+----+----+----+----+----+----+----+----+----+....+----+
+               | VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
+               +----+----+----+----+----+----+----+----+----+----+....+----+
+   # of bytes:   1    1      2              4           variable       1
+   
+   VN is the SOCKS protocol version number and should be 4. CD is the
+   SOCKS command code and should be 1 for CONNECT request. NULL is a byte
+   of all zero bits.
+*/
+     
+      index=0;
+      buf[index++]=4;
+      buf[index++]=1;
+
+      buf[index++]=(byte)(port>>>8);
+      buf[index++]=(byte)(port&0xff);
+
+      try{
+        InetAddress addr=InetAddress.getByName(host);
+        byte[] byteAddress = addr.getAddress();
+        for (int i = 0; i < byteAddress.length; i++) {
+          buf[index++]=byteAddress[i];
+        }
+      }
+      catch(UnknownHostException uhe){
+        throw new JSchException("ProxySOCKS4: "+uhe.toString(), uhe);
+      }
+
+      if(user!=null){
+        System.arraycopy(Util.str2byte(user), 0, buf, index, user.length());
+        index+=user.length();
+      }
+      buf[index++]=0;
+      out.write(buf, 0, index);
+
+/*
+   The SOCKS server checks to see whether such a request should be granted
+   based on any combination of source IP address, destination IP address,
+   destination port number, the userid, and information it may obtain by
+   consulting IDENT, cf. RFC 1413.  If the request is granted, the SOCKS
+   server makes a connection to the specified port of the destination host.
+   A reply packet is sent to the client when this connection is established,
+   or when the request is rejected or the operation fails. 
+   
+               +----+----+----+----+----+----+----+----+
+               | VN | CD | DSTPORT |      DSTIP        |
+               +----+----+----+----+----+----+----+----+
+   # of bytes:   1    1      2              4
+   
+   VN is the version of the reply code and should be 0. CD is the result
+   code with one of the following values:
+   
+   90: request granted
+   91: request rejected or failed
+   92: request rejected becasue SOCKS server cannot connect to
+       identd on the client
+   93: request rejected because the client program and identd
+       report different user-ids
+   
+   The remaining fields are ignored.
+*/
+
+      int len=8;
+      int s=0;
+      while(s<len){
+        int i=in.read(buf, s, len-s);
+        if(i<=0){
+          throw new JSchException("ProxySOCKS4: stream is closed");
+        }
+        s+=i;
+      }
+      if(buf[0]!=0){
+        throw new JSchException("ProxySOCKS4: server returns VN "+buf[0]);
+      }
+      if(buf[1]!=90){
+        try{ socket.close(); }
+       catch(Exception eee){
+       }
+        String message="ProxySOCKS4: server returns CD "+buf[1];
+        throw new JSchException(message);
+      }
+    }
+    catch(RuntimeException e){
+      throw e;
+    }
+    catch(Exception e){
+      try{ if(socket!=null)socket.close(); }
+      catch(Exception eee){
+      }
+      throw new JSchException("ProxySOCKS4: "+e.toString());
+    }
+  }
+  public InputStream getInputStream(){ return in; }
+  public OutputStream getOutputStream(){ return out; }
+  public Socket getSocket(){ return socket; }
+  public void close(){
+    try{
+      if(in!=null)in.close();
+      if(out!=null)out.close();
+      if(socket!=null)socket.close();
+    }
+    catch(Exception e){
+    }
+    in=null;
+    out=null;
+    socket=null;
+  }
+  public static int getDefaultPort(){
+    return DEFAULTPORT;
+  }
+}
diff --git a/src/com/jcraft/jsch/ProxySOCKS5.java b/src/com/jcraft/jsch/ProxySOCKS5.java
new file mode 100644 (file)
index 0000000..295e76a
--- /dev/null
@@ -0,0 +1,349 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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 depends on following documents,
+   - RFC 1928  SOCKS Protocol Verseion 5  
+   - RFC 1929  Username/Password Authentication for SOCKS V5. 
+ */
+
+package com.jcraft.jsch;
+
+import java.io.*;
+import java.net.*;
+
+public class ProxySOCKS5 implements Proxy{
+  private static int DEFAULTPORT=1080;
+  private String proxy_host;
+  private int proxy_port;
+  private InputStream in;
+  private OutputStream out;
+  private Socket socket;
+  private String user;
+  private String passwd;
+
+  public ProxySOCKS5(String proxy_host){
+    int port=DEFAULTPORT;
+    String host=proxy_host;
+    if(proxy_host.indexOf(':')!=-1){
+      try{
+       host=proxy_host.substring(0, proxy_host.indexOf(':'));
+       port=Integer.parseInt(proxy_host.substring(proxy_host.indexOf(':')+1));
+      }
+      catch(Exception e){
+      }
+    }
+    this.proxy_host=host;
+    this.proxy_port=port;
+  }
+  public ProxySOCKS5(String proxy_host, int proxy_port){
+    this.proxy_host=proxy_host;
+    this.proxy_port=proxy_port;
+  }
+  public void setUserPasswd(String user, String passwd){
+    this.user=user;
+    this.passwd=passwd;
+  }
+  public void connect(SocketFactory socket_factory, String host, int port, int timeout) throws JSchException{
+    try{
+      if(socket_factory==null){
+        socket=Util.createSocket(proxy_host, proxy_port, timeout);
+        //socket=new Socket(proxy_host, proxy_port);    
+        in=socket.getInputStream();
+        out=socket.getOutputStream();
+      }
+      else{
+        socket=socket_factory.createSocket(proxy_host, proxy_port);
+        in=socket_factory.getInputStream(socket);
+        out=socket_factory.getOutputStream(socket);
+      }
+      if(timeout>0){
+        socket.setSoTimeout(timeout);
+      }
+      socket.setTcpNoDelay(true);
+
+      byte[] buf=new byte[1024];
+      int index=0;
+
+/*
+                   +----+----------+----------+
+                   |VER | NMETHODS | METHODS  |
+                   +----+----------+----------+
+                   | 1  |    1     | 1 to 255 |
+                   +----+----------+----------+
+
+   The VER field is set to X'05' for this version of the protocol.  The
+   NMETHODS field contains the number of method identifier octets that
+   appear in the METHODS field.
+
+   The values currently defined for METHOD are:
+
+          o  X'00' NO AUTHENTICATION REQUIRED
+          o  X'01' GSSAPI
+          o  X'02' USERNAME/PASSWORD
+          o  X'03' to X'7F' IANA ASSIGNED
+          o  X'80' to X'FE' RESERVED FOR PRIVATE METHODS
+          o  X'FF' NO ACCEPTABLE METHODS
+*/
+
+      buf[index++]=5;
+
+      buf[index++]=2;
+      buf[index++]=0;           // NO AUTHENTICATION REQUIRED
+      buf[index++]=2;           // USERNAME/PASSWORD
+
+      out.write(buf, 0, index);
+
+/*
+    The server selects from one of the methods given in METHODS, and
+    sends a METHOD selection message:
+
+                         +----+--------+
+                         |VER | METHOD |
+                         +----+--------+
+                         | 1  |   1    |
+                         +----+--------+
+*/
+      //in.read(buf, 0, 2);
+      fill(in, buf, 2);
+      boolean check=false;
+      switch((buf[1])&0xff){
+        case 0:                // NO AUTHENTICATION REQUIRED
+          check=true;
+          break;
+        case 2:                // USERNAME/PASSWORD
+          if(user==null || passwd==null)break;
+
+/*
+   Once the SOCKS V5 server has started, and the client has selected the
+   Username/Password Authentication protocol, the Username/Password
+   subnegotiation begins.  This begins with the client producing a
+   Username/Password request:
+
+           +----+------+----------+------+----------+
+           |VER | ULEN |  UNAME   | PLEN |  PASSWD  |
+           +----+------+----------+------+----------+
+           | 1  |  1   | 1 to 255 |  1   | 1 to 255 |
+           +----+------+----------+------+----------+
+
+   The VER field contains the current version of the subnegotiation,
+   which is X'01'. The ULEN field contains the length of the UNAME field
+   that follows. The UNAME field contains the username as known to the
+   source operating system. The PLEN field contains the length of the
+   PASSWD field that follows. The PASSWD field contains the password
+   association with the given UNAME.
+*/
+          index=0;
+          buf[index++]=1;
+          buf[index++]=(byte)(user.length());
+         System.arraycopy(Util.str2byte(user), 0, buf, index, user.length());
+         index+=user.length();
+          buf[index++]=(byte)(passwd.length());
+         System.arraycopy(Util.str2byte(passwd), 0, buf, index, passwd.length());
+         index+=passwd.length();
+
+          out.write(buf, 0, index);
+
+/*
+   The server verifies the supplied UNAME and PASSWD, and sends the
+   following response:
+
+                        +----+--------+
+                        |VER | STATUS |
+                        +----+--------+
+                        | 1  |   1    |
+                        +----+--------+
+
+   A STATUS field of X'00' indicates success. If the server returns a
+   `failure' (STATUS value other than X'00') status, it MUST close the
+   connection.
+*/
+          //in.read(buf, 0, 2);
+          fill(in, buf, 2);
+          if(buf[1]==0)
+            check=true;
+          break;
+        default:
+      }
+
+      if(!check){
+        try{ socket.close(); }
+       catch(Exception eee){
+       }
+        throw new JSchException("fail in SOCKS5 proxy");
+      }
+
+/*
+      The SOCKS request is formed as follows:
+
+        +----+-----+-------+------+----------+----------+
+        |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
+        +----+-----+-------+------+----------+----------+
+        | 1  |  1  | X'00' |  1   | Variable |    2     |
+        +----+-----+-------+------+----------+----------+
+
+      Where:
+
+      o  VER    protocol version: X'05'
+      o  CMD
+         o  CONNECT X'01'
+         o  BIND X'02'
+         o  UDP ASSOCIATE X'03'
+      o  RSV    RESERVED
+         o  ATYP   address type of following address
+         o  IP V4 address: X'01'
+         o  DOMAINNAME: X'03'
+         o  IP V6 address: X'04'
+      o  DST.ADDR       desired destination address
+      o  DST.PORT desired destination port in network octet
+         order
+*/
+     
+      index=0;
+      buf[index++]=5;
+      buf[index++]=1;       // CONNECT
+      buf[index++]=0;
+
+      byte[] hostb=Util.str2byte(host);
+      int len=hostb.length;
+      buf[index++]=3;      // DOMAINNAME
+      buf[index++]=(byte)(len);
+      System.arraycopy(hostb, 0, buf, index, len);
+      index+=len;
+      buf[index++]=(byte)(port>>>8);
+      buf[index++]=(byte)(port&0xff);
+
+      out.write(buf, 0, index);
+
+/*
+   The SOCKS request information is sent by the client as soon as it has
+   established a connection to the SOCKS server, and completed the
+   authentication negotiations.  The server evaluates the request, and
+   returns a reply formed as follows:
+
+        +----+-----+-------+------+----------+----------+
+        |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
+        +----+-----+-------+------+----------+----------+
+        | 1  |  1  | X'00' |  1   | Variable |    2     |
+        +----+-----+-------+------+----------+----------+
+
+   Where:
+
+   o  VER    protocol version: X'05'
+   o  REP    Reply field:
+      o  X'00' succeeded
+      o  X'01' general SOCKS server failure
+      o  X'02' connection not allowed by ruleset
+      o  X'03' Network unreachable
+      o  X'04' Host unreachable
+      o  X'05' Connection refused
+      o  X'06' TTL expired
+      o  X'07' Command not supported
+      o  X'08' Address type not supported
+      o  X'09' to X'FF' unassigned
+    o  RSV    RESERVED
+    o  ATYP   address type of following address
+      o  IP V4 address: X'01'
+      o  DOMAINNAME: X'03'
+      o  IP V6 address: X'04'
+    o  BND.ADDR       server bound address
+    o  BND.PORT       server bound port in network octet order
+*/
+
+      //in.read(buf, 0, 4);
+      fill(in, buf, 4);
+
+      if(buf[1]!=0){
+        try{ socket.close(); }
+       catch(Exception eee){
+       }
+        throw new JSchException("ProxySOCKS5: server returns "+buf[1]);
+      }
+
+      switch(buf[3]&0xff){
+        case 1:
+          //in.read(buf, 0, 6);
+          fill(in, buf, 6);
+         break;
+        case 3:
+          //in.read(buf, 0, 1);
+          fill(in, buf, 1);
+          //in.read(buf, 0, buf[0]+2);
+          fill(in, buf, (buf[0]&0xff)+2);
+         break;
+        case 4:
+          //in.read(buf, 0, 18);
+          fill(in, buf, 18);
+          break;
+        default:
+      }
+    }
+    catch(RuntimeException e){
+      throw e;
+    }
+    catch(Exception e){
+      try{ if(socket!=null)socket.close(); }
+      catch(Exception eee){
+      }
+      String message="ProxySOCKS5: "+e.toString();
+      if(e instanceof Throwable)
+        throw new JSchException(message, (Throwable)e);
+      throw new JSchException(message);
+    }
+  }
+  public InputStream getInputStream(){ return in; }
+  public OutputStream getOutputStream(){ return out; }
+  public Socket getSocket(){ return socket; }
+  public void close(){
+    try{
+      if(in!=null)in.close();
+      if(out!=null)out.close();
+      if(socket!=null)socket.close();
+    }
+    catch(Exception e){
+    }
+    in=null;
+    out=null;
+    socket=null;
+  }
+  public static int getDefaultPort(){
+    return DEFAULTPORT;
+  }
+  private void fill(InputStream in, byte[] buf, int len) throws JSchException, IOException{
+    int s=0;
+    while(s<len){
+      int i=in.read(buf, s, len-s);
+      if(i<=0){
+        throw new JSchException("ProxySOCKS5: stream is closed");
+      }
+      s+=i;
+    }
+  }
+}
diff --git a/src/com/jcraft/jsch/Random.java b/src/com/jcraft/jsch/Random.java
new file mode 100644 (file)
index 0000000..59e5e73
--- /dev/null
@@ -0,0 +1,34 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface Random{
+  void fill(byte[] foo, int start, int len);
+}
diff --git a/src/com/jcraft/jsch/Request.java b/src/com/jcraft/jsch/Request.java
new file mode 100644 (file)
index 0000000..7584819
--- /dev/null
@@ -0,0 +1,69 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+abstract class Request{
+  private boolean reply=false;
+  private Session session=null;
+  private Channel channel=null;
+  void request(Session session, Channel channel) throws Exception{
+    this.session=session;
+    this.channel=channel;
+    if(channel.connectTimeout>0){
+      setReply(true);
+    }
+  }
+  boolean waitForReply(){ return reply; }
+  void setReply(boolean reply){ this.reply=reply; }
+  void write(Packet packet) throws Exception{
+    if(reply){
+      channel.reply=-1;
+    }
+    session.write(packet);
+    if(reply){
+      long start=System.currentTimeMillis();
+      long timeout=channel.connectTimeout;
+      while(channel.isConnected() && channel.reply==-1){
+       try{Thread.sleep(10);}
+       catch(Exception ee){
+       }
+        if(timeout>0L &&
+           (System.currentTimeMillis()-start)>timeout){
+          channel.reply=0;
+          throw new JSchException("channel request: timeout");
+        }
+      }
+
+      if(channel.reply==0){
+       throw new JSchException("failed to send channel request");
+      }
+    }
+  }
+}
diff --git a/src/com/jcraft/jsch/RequestAgentForwarding.java b/src/com/jcraft/jsch/RequestAgentForwarding.java
new file mode 100644 (file)
index 0000000..3e72c21
--- /dev/null
@@ -0,0 +1,53 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+class RequestAgentForwarding extends Request{
+  public void request(Session session, Channel channel) throws Exception{
+    super.request(session, channel);
+
+    setReply(false);
+
+    Buffer buf=new Buffer();
+    Packet packet=new Packet(buf);
+
+    // byte      SSH_MSG_CHANNEL_REQUEST(98)
+    // uint32 recipient channel
+    // string request type        // "auth-agent-req@openssh.com"
+    // boolean want reply         // 0
+    packet.reset();
+    buf.putByte((byte) Session.SSH_MSG_CHANNEL_REQUEST);
+    buf.putInt(channel.getRecipient());
+    buf.putString(Util.str2byte("auth-agent-req@openssh.com"));
+    buf.putByte((byte)(waitForReply() ? 1 : 0));
+    write(packet);
+    session.agent_forwarding=true;
+  }
+}
diff --git a/src/com/jcraft/jsch/RequestEnv.java b/src/com/jcraft/jsch/RequestEnv.java
new file mode 100644 (file)
index 0000000..a2b1ff0
--- /dev/null
@@ -0,0 +1,54 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+class RequestEnv extends Request{
+  byte[] name=new byte[0];
+  byte[] value=new byte[0];
+  void setEnv(byte[] name, byte[] value){
+    this.name=name;
+    this.value=value;
+  }
+  public void request(Session session, Channel channel) throws Exception{
+    super.request(session, channel);
+
+    Buffer buf=new Buffer();
+    Packet packet=new Packet(buf);
+
+    packet.reset();
+    buf.putByte((byte) Session.SSH_MSG_CHANNEL_REQUEST);
+    buf.putInt(channel.getRecipient());
+    buf.putString(Util.str2byte("env"));
+    buf.putByte((byte)(waitForReply() ? 1 : 0));
+    buf.putString(name);
+    buf.putString(value);
+    write(packet);
+  }
+}
diff --git a/src/com/jcraft/jsch/RequestExec.java b/src/com/jcraft/jsch/RequestExec.java
new file mode 100644 (file)
index 0000000..0cd047b
--- /dev/null
@@ -0,0 +1,57 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+class RequestExec extends Request{
+  private byte[] command=new byte[0];
+  RequestExec(byte[] command){
+    this.command=command;
+  }
+  public void request(Session session, Channel channel) throws Exception{
+    super.request(session, channel);
+
+    Buffer buf=new Buffer();
+    Packet packet=new Packet(buf);
+
+    // send
+    // byte     SSH_MSG_CHANNEL_REQUEST(98)
+    // uint32 recipient channel
+    // string request type       // "exec"
+    // boolean want reply        // 0
+    // string command
+    packet.reset();
+    buf.putByte((byte) Session.SSH_MSG_CHANNEL_REQUEST);
+    buf.putInt(channel.getRecipient());
+    buf.putString(Util.str2byte("exec"));
+    buf.putByte((byte)(waitForReply() ? 1 : 0));
+    buf.putString(command);
+    write(packet);
+  }
+}
diff --git a/src/com/jcraft/jsch/RequestPtyReq.java b/src/com/jcraft/jsch/RequestPtyReq.java
new file mode 100644 (file)
index 0000000..1024158
--- /dev/null
@@ -0,0 +1,78 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+class RequestPtyReq extends Request{
+  private String ttype="vt100";
+  private int tcol=80;
+  private int trow=24;
+  private int twp=640;
+  private int thp=480;
+
+  private byte[] terminal_mode=Util.empty;
+
+  void setCode(String cookie){
+  }
+
+  void setTType(String ttype){
+    this.ttype=ttype;
+  }
+  
+  void setTerminalMode(byte[] terminal_mode){
+    this.terminal_mode=terminal_mode;
+  }
+
+  void setTSize(int tcol, int trow, int twp, int thp){
+    this.tcol=tcol;
+    this.trow=trow;
+    this.twp=twp;
+    this.thp=thp;
+  }
+
+  public void request(Session session, Channel channel) throws Exception{
+    super.request(session, channel);
+
+    Buffer buf=new Buffer();
+    Packet packet=new Packet(buf);
+
+    packet.reset();
+    buf.putByte((byte) Session.SSH_MSG_CHANNEL_REQUEST);
+    buf.putInt(channel.getRecipient());
+    buf.putString(Util.str2byte("pty-req"));
+    buf.putByte((byte)(waitForReply() ? 1 : 0));
+    buf.putString(Util.str2byte(ttype));
+    buf.putInt(tcol);
+    buf.putInt(trow);
+    buf.putInt(twp);
+    buf.putInt(thp);
+    buf.putString(terminal_mode);
+    write(packet);
+  }
+}
diff --git a/src/com/jcraft/jsch/RequestSftp.java b/src/com/jcraft/jsch/RequestSftp.java
new file mode 100644 (file)
index 0000000..3b171f7
--- /dev/null
@@ -0,0 +1,49 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public class RequestSftp extends Request{
+  RequestSftp(){
+    setReply(true);
+  }
+  public void request(Session session, Channel channel) throws Exception{
+    super.request(session, channel);
+
+    Buffer buf=new Buffer();
+    Packet packet=new Packet(buf);
+    packet.reset();
+    buf.putByte((byte)Session.SSH_MSG_CHANNEL_REQUEST);
+    buf.putInt(channel.getRecipient());
+    buf.putString(Util.str2byte("subsystem"));
+    buf.putByte((byte)(waitForReply() ? 1 : 0));
+    buf.putString(Util.str2byte("sftp"));
+    write(packet);
+  }
+}
diff --git a/src/com/jcraft/jsch/RequestShell.java b/src/com/jcraft/jsch/RequestShell.java
new file mode 100644 (file)
index 0000000..ffc68d7
--- /dev/null
@@ -0,0 +1,51 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+class RequestShell extends Request{
+  public void request(Session session, Channel channel) throws Exception{
+    super.request(session, channel);
+
+    Buffer buf=new Buffer();
+    Packet packet=new Packet(buf);
+
+    // send
+    // byte     SSH_MSG_CHANNEL_REQUEST(98)
+    // uint32 recipient channel
+    // string request type       // "shell"
+    // boolean want reply        // 0
+    packet.reset();
+    buf.putByte((byte) Session.SSH_MSG_CHANNEL_REQUEST);
+    buf.putInt(channel.getRecipient());
+    buf.putString(Util.str2byte("shell"));
+    buf.putByte((byte)(waitForReply() ? 1 : 0));
+    write(packet);
+  }
+}
diff --git a/src/com/jcraft/jsch/RequestSignal.java b/src/com/jcraft/jsch/RequestSignal.java
new file mode 100644 (file)
index 0000000..72baf4e
--- /dev/null
@@ -0,0 +1,49 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+class RequestSignal extends Request{
+  private String signal="KILL";
+  public void setSignal(String foo){ signal=foo; }
+  public void request(Session session, Channel channel) throws Exception{
+    super.request(session, channel);
+
+    Buffer buf=new Buffer();
+    Packet packet=new Packet(buf);
+
+    packet.reset();
+    buf.putByte((byte) Session.SSH_MSG_CHANNEL_REQUEST);
+    buf.putInt(channel.getRecipient());
+    buf.putString(Util.str2byte("signal"));
+    buf.putByte((byte)(waitForReply() ? 1 : 0));
+    buf.putString(Util.str2byte(signal));
+    write(packet);
+  }
+}
diff --git a/src/com/jcraft/jsch/RequestSubsystem.java b/src/com/jcraft/jsch/RequestSubsystem.java
new file mode 100644 (file)
index 0000000..56db414
--- /dev/null
@@ -0,0 +1,53 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2005-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public class RequestSubsystem extends Request{
+  private String subsystem=null;
+  public void request(Session session, Channel channel, String subsystem, boolean want_reply) throws Exception{
+    setReply(want_reply);
+    this.subsystem=subsystem;
+    this.request(session, channel);
+  }
+  public void request(Session session, Channel channel) throws Exception{
+    super.request(session, channel);
+
+    Buffer buf=new Buffer();
+    Packet packet=new Packet(buf);
+
+    packet.reset();
+    buf.putByte((byte)Session.SSH_MSG_CHANNEL_REQUEST);
+    buf.putInt(channel.getRecipient());
+    buf.putString(Util.str2byte("subsystem"));
+    buf.putByte((byte)(waitForReply() ? 1 : 0));
+    buf.putString(Util.str2byte(subsystem));
+    write(packet);
+  }
+}
diff --git a/src/com/jcraft/jsch/RequestWindowChange.java b/src/com/jcraft/jsch/RequestWindowChange.java
new file mode 100644 (file)
index 0000000..34e6172
--- /dev/null
@@ -0,0 +1,68 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+class RequestWindowChange extends Request{
+  int width_columns=80;
+  int height_rows=24;
+  int width_pixels=640;
+  int height_pixels=480;
+  void setSize(int col, int row, int wp, int hp){
+    this.width_columns=col; 
+    this.height_rows=row; 
+    this.width_pixels=wp;
+    this.height_pixels=hp;
+  }
+  public void request(Session session, Channel channel) throws Exception{
+    super.request(session, channel);
+
+    Buffer buf=new Buffer();
+    Packet packet=new Packet(buf);
+
+    //byte      SSH_MSG_CHANNEL_REQUEST
+    //uint32    recipient_channel
+    //string    "window-change"
+    //boolean   FALSE
+    //uint32    terminal width, columns
+    //uint32    terminal height, rows
+    //uint32    terminal width, pixels
+    //uint32    terminal height, pixels
+    packet.reset();
+    buf.putByte((byte) Session.SSH_MSG_CHANNEL_REQUEST);
+    buf.putInt(channel.getRecipient());
+    buf.putString(Util.str2byte("window-change"));
+    buf.putByte((byte)(waitForReply() ? 1 : 0));
+    buf.putInt(width_columns);
+    buf.putInt(height_rows);
+    buf.putInt(width_pixels);
+    buf.putInt(height_pixels);
+    write(packet);
+  }
+}
diff --git a/src/com/jcraft/jsch/RequestX11.java b/src/com/jcraft/jsch/RequestX11.java
new file mode 100644 (file)
index 0000000..748bd32
--- /dev/null
@@ -0,0 +1,63 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+class RequestX11 extends Request{
+  public void setCookie(String cookie){
+    ChannelX11.cookie=Util.str2byte(cookie);
+  }
+  public void request(Session session, Channel channel) throws Exception{
+    super.request(session, channel);
+
+    Buffer buf=new Buffer();
+    Packet packet=new Packet(buf);
+
+    // byte      SSH_MSG_CHANNEL_REQUEST(98)
+    // uint32 recipient channel
+    // string request type        // "x11-req"
+    // boolean want reply         // 0
+    // boolean   single connection
+    // string    x11 authentication protocol // "MIT-MAGIC-COOKIE-1".
+    // string    x11 authentication cookie
+    // uint32    x11 screen number
+    packet.reset();
+    buf.putByte((byte) Session.SSH_MSG_CHANNEL_REQUEST);
+    buf.putInt(channel.getRecipient());
+    buf.putString(Util.str2byte("x11-req"));
+    buf.putByte((byte)(waitForReply() ? 1 : 0));
+    buf.putByte((byte)0);
+    buf.putString(Util.str2byte("MIT-MAGIC-COOKIE-1"));
+    buf.putString(ChannelX11.getFakedCookie(session));
+    buf.putInt(0);
+    write(packet);
+
+    session.x11_forwarding=true;
+  }
+}
diff --git a/src/com/jcraft/jsch/ServerSocketFactory.java b/src/com/jcraft/jsch/ServerSocketFactory.java
new file mode 100644 (file)
index 0000000..3b2d2d7
--- /dev/null
@@ -0,0 +1,37 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.net.*;
+import java.io.*;
+
+public interface ServerSocketFactory{
+  public ServerSocket createServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException;
+}
diff --git a/src/com/jcraft/jsch/Session.java b/src/com/jcraft/jsch/Session.java
new file mode 100644 (file)
index 0000000..daa6f56
--- /dev/null
@@ -0,0 +1,1946 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.io.*;
+import java.net.*;
+
+public class Session implements Runnable{
+  static private final String version="JSCH-0.1.43";
+
+  // http://ietf.org/internet-drafts/draft-ietf-secsh-assignednumbers-01.txt
+  static final int SSH_MSG_DISCONNECT=                      1;
+  static final int SSH_MSG_IGNORE=                          2;
+  static final int SSH_MSG_UNIMPLEMENTED=                   3;
+  static final int SSH_MSG_DEBUG=                           4;
+  static final int SSH_MSG_SERVICE_REQUEST=                 5;
+  static final int SSH_MSG_SERVICE_ACCEPT=                  6;
+  static final int SSH_MSG_KEXINIT=                        20;
+  static final int SSH_MSG_NEWKEYS=                        21;
+  static final int SSH_MSG_KEXDH_INIT=                     30;
+  static final int SSH_MSG_KEXDH_REPLY=                    31;
+  static final int SSH_MSG_KEX_DH_GEX_GROUP=               31;
+  static final int SSH_MSG_KEX_DH_GEX_INIT=                32;
+  static final int SSH_MSG_KEX_DH_GEX_REPLY=               33;
+  static final int SSH_MSG_KEX_DH_GEX_REQUEST=             34;
+  static final int SSH_MSG_GLOBAL_REQUEST=                 80;
+  static final int SSH_MSG_REQUEST_SUCCESS=                81;
+  static final int SSH_MSG_REQUEST_FAILURE=                82;
+  static final int SSH_MSG_CHANNEL_OPEN=                   90;
+  static final int SSH_MSG_CHANNEL_OPEN_CONFIRMATION=      91;
+  static final int SSH_MSG_CHANNEL_OPEN_FAILURE=           92;
+  static final int SSH_MSG_CHANNEL_WINDOW_ADJUST=          93;
+  static final int SSH_MSG_CHANNEL_DATA=                   94;
+  static final int SSH_MSG_CHANNEL_EXTENDED_DATA=          95;
+  static final int SSH_MSG_CHANNEL_EOF=                    96;
+  static final int SSH_MSG_CHANNEL_CLOSE=                  97;
+  static final int SSH_MSG_CHANNEL_REQUEST=                98;
+  static final int SSH_MSG_CHANNEL_SUCCESS=                99;
+  static final int SSH_MSG_CHANNEL_FAILURE=               100;
+
+  private static final int PACKET_MAX_SIZE = 256 * 1024;
+
+  private byte[] V_S;                                 // server version
+  private byte[] V_C=Util.str2byte("SSH-2.0-"+version); // client version
+
+  private byte[] I_C; // the payload of the client's SSH_MSG_KEXINIT
+  private byte[] I_S; // the payload of the server's SSH_MSG_KEXINIT
+  private byte[] K_S; // the host key
+
+  private byte[] session_id;
+
+  private byte[] IVc2s;
+  private byte[] IVs2c;
+  private byte[] Ec2s;
+  private byte[] Es2c;
+  private byte[] MACc2s;
+  private byte[] MACs2c;
+
+  private int seqi=0;
+  private int seqo=0;
+
+  String[] guess=null;
+  private Cipher s2ccipher;
+  private Cipher c2scipher;
+  private MAC s2cmac;
+  private MAC c2smac;
+  //private byte[] mac_buf;
+  private byte[] s2cmac_result1;
+  private byte[] s2cmac_result2;
+
+  private Compression deflater;
+  private Compression inflater;
+
+  private IO io;
+  private Socket socket;
+  private int timeout=0;
+
+  private boolean isConnected=false;
+
+  private boolean isAuthed=false;
+
+  private Thread connectThread=null;
+  private Object lock=new Object();
+
+  boolean x11_forwarding=false;
+  boolean agent_forwarding=false;
+
+  InputStream in=null;
+  OutputStream out=null;
+
+  static Random random;
+
+  Buffer buf;
+  Packet packet;
+
+  SocketFactory socket_factory=null;
+
+  private java.util.Hashtable config=null;
+
+  private Proxy proxy=null;
+  private UserInfo userinfo;
+
+  private String hostKeyAlias=null;
+  private int serverAliveInterval=0;
+  private int serverAliveCountMax=1;
+
+  protected boolean daemon_thread=false;
+
+  private long kex_start_time=0L;
+
+  String host="127.0.0.1";
+  int port=22;
+
+  String username=null;
+  byte[] password=null;
+
+  JSch jsch;
+
+  Session(JSch jsch) throws JSchException{
+    super();
+    this.jsch=jsch;
+    buf=new Buffer();
+    packet=new Packet(buf);
+  }
+
+  public void connect() throws JSchException{
+    connect(timeout);
+  }
+
+  public void connect(int connectTimeout) throws JSchException{
+    if(isConnected){
+      throw new JSchException("session is already connected");
+    }
+
+    io=new IO();
+    if(random==null){
+      try{
+       Class c=Class.forName(getConfig("random"));
+        random=(Random)(c.newInstance());
+      }
+      catch(Exception e){ 
+        throw new JSchException(e.toString(), e);
+      }
+    }
+    Packet.setRandom(random);
+
+    if(JSch.getLogger().isEnabled(Logger.INFO)){
+      JSch.getLogger().log(Logger.INFO, 
+                           "Connecting to "+host+" port "+port);
+    }
+
+    try        {
+      int i, j;
+
+      if(proxy==null){
+        InputStream in;
+        OutputStream out;
+       if(socket_factory==null){
+          socket=Util.createSocket(host, port, connectTimeout);
+         in=socket.getInputStream();
+         out=socket.getOutputStream();
+       }
+       else{
+          socket=socket_factory.createSocket(host, port);
+         in=socket_factory.getInputStream(socket);
+         out=socket_factory.getOutputStream(socket);
+       }
+       //if(timeout>0){ socket.setSoTimeout(timeout); }
+        socket.setTcpNoDelay(true);
+        io.setInputStream(in);
+        io.setOutputStream(out);
+      }
+      else{
+       synchronized(proxy){
+          proxy.connect(socket_factory, host, port, connectTimeout);
+         io.setInputStream(proxy.getInputStream());
+         io.setOutputStream(proxy.getOutputStream());
+          socket=proxy.getSocket();
+       }
+      }
+
+      if(connectTimeout>0 && socket!=null){
+        socket.setSoTimeout(connectTimeout);
+      }
+
+      isConnected=true;
+
+      if(JSch.getLogger().isEnabled(Logger.INFO)){
+        JSch.getLogger().log(Logger.INFO, 
+                             "Connection established");
+      }
+
+      jsch.addSession(this);
+
+      {
+       // Some Cisco devices will miss to read '\n' if it is sent separately.
+       byte[] foo=new byte[V_C.length+1];
+       System.arraycopy(V_C, 0, foo, 0, V_C.length);
+       foo[foo.length-1]=(byte)'\n';
+       io.put(foo, 0, foo.length);
+      }
+
+      while(true){
+        i=0;
+        j=0;
+        while(i<buf.buffer.length){
+          j=io.getByte();
+          if(j<0)break;
+          buf.buffer[i]=(byte)j; i++; 
+          if(j==10)break;
+        }
+        if(j<0){
+          throw new JSchException("connection is closed by foreign host");
+        }
+
+        if(buf.buffer[i-1]==10){    // 0x0a
+          i--;
+          if(i>0 && buf.buffer[i-1]==13){  // 0x0d
+            i--;
+          }
+        }
+
+        if(i<=3 || 
+           ((i!=buf.buffer.length) &&
+            (buf.buffer[0]!='S'||buf.buffer[1]!='S'||
+             buf.buffer[2]!='H'||buf.buffer[3]!='-'))){
+          // It must not start with 'SSH-'
+          //System.err.println(new String(buf.buffer, 0, i);
+          continue;
+        }
+
+        if(i==buf.buffer.length ||
+           i<7 ||                                      // SSH-1.99 or SSH-2.0
+           (buf.buffer[4]=='1' && buf.buffer[6]!='9')  // SSH-1.5
+           ){
+          throw new JSchException("invalid server's version string");
+        }
+        break;
+      }
+
+      V_S=new byte[i]; System.arraycopy(buf.buffer, 0, V_S, 0, i);
+      //System.err.println("V_S: ("+i+") ["+new String(V_S)+"]");
+
+      if(JSch.getLogger().isEnabled(Logger.INFO)){
+        JSch.getLogger().log(Logger.INFO, 
+                             "Remote version string: "+Util.byte2str(V_S));
+        JSch.getLogger().log(Logger.INFO, 
+                             "Local version string: "+Util.byte2str(V_C));
+      }
+
+      send_kexinit();
+
+      buf=read(buf);
+      if(buf.getCommand()!=SSH_MSG_KEXINIT){
+        in_kex=false;
+       throw new JSchException("invalid protocol: "+buf.getCommand());
+      }
+
+      if(JSch.getLogger().isEnabled(Logger.INFO)){
+        JSch.getLogger().log(Logger.INFO, 
+                             "SSH_MSG_KEXINIT received");
+      }
+
+      KeyExchange kex=receive_kexinit(buf);
+
+      while(true){
+       buf=read(buf);
+       if(kex.getState()==buf.getCommand()){
+          kex_start_time=System.currentTimeMillis();
+          boolean result=kex.next(buf);
+         if(!result){
+           //System.err.println("verify: "+result);
+            in_kex=false;
+           throw new JSchException("verify: "+result);
+         }
+       }
+       else{
+          in_kex=false;
+         throw new JSchException("invalid protocol(kex): "+buf.getCommand());
+       }
+       if(kex.getState()==KeyExchange.STATE_END){
+         break;
+       }
+      }
+
+      try{ checkHost(host, port, kex); }
+      catch(JSchException ee){
+        in_kex=false;
+        throw ee;
+      }
+
+      send_newkeys();
+
+      // receive SSH_MSG_NEWKEYS(21)
+      buf=read(buf);
+      //System.err.println("read: 21 ? "+buf.getCommand());
+      if(buf.getCommand()==SSH_MSG_NEWKEYS){
+
+        if(JSch.getLogger().isEnabled(Logger.INFO)){
+          JSch.getLogger().log(Logger.INFO, 
+                               "SSH_MSG_NEWKEYS received");
+        }
+
+       receive_newkeys(buf, kex);
+      }
+      else{
+        in_kex=false;
+       throw new JSchException("invalid protocol(newkyes): "+buf.getCommand());
+      }
+
+      boolean auth=false;
+      boolean auth_cancel=false;
+
+      UserAuth ua=null;
+      try{
+       Class c=Class.forName(getConfig("userauth.none"));
+        ua=(UserAuth)(c.newInstance());
+      }
+      catch(Exception e){ 
+        throw new JSchException(e.toString(), e);
+      }
+
+      auth=ua.start(this);
+
+      String cmethods=getConfig("PreferredAuthentications");
+      String[] cmethoda=Util.split(cmethods, ",");
+
+      String smethods=null;
+      if(!auth){
+        smethods=((UserAuthNone)ua).getMethods();
+        if(smethods!=null){
+          smethods=smethods.toLowerCase();
+        }
+        else{
+          // methods: publickey,password,keyboard-interactive
+          //smethods="publickey,password,keyboard-interactive";
+          smethods=cmethods;
+        }
+      }
+
+      String[] smethoda=Util.split(smethods, ",");
+
+      int methodi=0;
+
+      loop:
+      while(true){
+
+//System.err.println("methods: "+methods);
+
+       while(!auth && 
+             cmethoda!=null && methodi<cmethoda.length){
+
+          String method=cmethoda[methodi++];
+          boolean acceptable=false;
+          for(int k=0; k<smethoda.length; k++){
+            if(smethoda[k].equals(method)){
+              acceptable=true;
+              break;
+            }
+          }
+          if(!acceptable){
+            continue;
+          }
+
+          //System.err.println("  method: "+method);
+
+          if(JSch.getLogger().isEnabled(Logger.INFO)){
+            String str="Authentications that can continue: ";
+            for(int k=methodi-1; k<cmethoda.length; k++){
+              str+=cmethoda[k];
+              if(k+1<cmethoda.length)
+                str+=",";
+            }
+            JSch.getLogger().log(Logger.INFO, 
+                                 str);
+            JSch.getLogger().log(Logger.INFO, 
+                                 "Next authentication method: "+method);
+          }
+
+         ua=null;
+          try{
+            Class c=null;
+            if(getConfig("userauth."+method)!=null){
+              c=Class.forName(getConfig("userauth."+method));
+              ua=(UserAuth)(c.newInstance());
+            }
+          }
+          catch(Exception e){
+            if(JSch.getLogger().isEnabled(Logger.WARN)){
+              JSch.getLogger().log(Logger.WARN, 
+                                   "failed to load "+method+" method");
+            }
+          }
+
+         if(ua!=null){
+            auth_cancel=false;
+           try{ 
+             auth=ua.start(this); 
+              if(auth && 
+                 JSch.getLogger().isEnabled(Logger.INFO)){
+                JSch.getLogger().log(Logger.INFO, 
+                                     "Authentication succeeded ("+method+").");
+              }
+           }
+           catch(JSchAuthCancelException ee){
+             auth_cancel=true;
+           }
+           catch(JSchPartialAuthException ee){
+              String tmp = smethods;
+              smethods=ee.getMethods();
+              smethoda=Util.split(smethods, ",");
+              if(!tmp.equals(smethods)){
+                methodi=0;
+              }
+             //System.err.println("PartialAuth: "+methods);
+             auth_cancel=false;
+             continue loop;
+           }
+           catch(RuntimeException ee){
+             throw ee;
+           }
+           catch(Exception ee){
+             //System.err.println("ee: "+ee); // SSH_MSG_DISCONNECT: 2 Too many authentication failures
+              break loop;
+           }
+         }
+       }
+        break;
+      }
+
+      if(!auth){
+        if(auth_cancel)
+          throw new JSchException("Auth cancel");
+        throw new JSchException("Auth fail");
+      }
+
+      if(connectTimeout>0 || timeout>0){
+        socket.setSoTimeout(timeout);
+      }
+
+      isAuthed=true;
+
+      synchronized(lock){
+        if(isConnected){
+          connectThread=new Thread(this);
+          connectThread.setName("Connect thread "+host+" session");
+          if(daemon_thread){
+            connectThread.setDaemon(daemon_thread);
+          }
+          connectThread.start();
+        }
+        else{
+          // The session has been already down and
+          // we don't have to start new thread.
+        }
+      }
+    }
+    catch(Exception e) {
+      in_kex=false;
+      if(isConnected){
+       try{
+         packet.reset();
+         buf.putByte((byte)SSH_MSG_DISCONNECT);
+         buf.putInt(3);
+         buf.putString(Util.str2byte(e.toString()));
+         buf.putString(Util.str2byte("en"));
+         write(packet);
+         disconnect();
+       }
+       catch(Exception ee){
+       }
+      }
+      isConnected=false;
+      //e.printStackTrace();
+      if(e instanceof RuntimeException) throw (RuntimeException)e;
+      if(e instanceof JSchException) throw (JSchException)e;
+      throw new JSchException("Session.connect: "+e);
+    }
+    finally{
+      Util.bzero(this.password);
+      this.password=null;
+    }
+  }
+
+  private KeyExchange receive_kexinit(Buffer buf) throws Exception {
+    int j=buf.getInt();
+    if(j!=buf.getLength()){    // packet was compressed and
+      buf.getByte();           // j is the size of deflated packet.
+      I_S=new byte[buf.index-5];
+    }
+    else{
+      I_S=new byte[j-1-buf.getByte()];
+    }
+   System.arraycopy(buf.buffer, buf.s, I_S, 0, I_S.length);
+
+   if(!in_kex){     // We are in rekeying activated by the remote!
+     send_kexinit();
+   }
+
+    guess=KeyExchange.guess(I_S, I_C);
+    if(guess==null){
+      throw new JSchException("Algorithm negotiation fail");
+    }
+
+    if(!isAuthed &&
+       (guess[KeyExchange.PROPOSAL_ENC_ALGS_CTOS].equals("none") ||
+        (guess[KeyExchange.PROPOSAL_ENC_ALGS_STOC].equals("none")))){
+      throw new JSchException("NONE Cipher should not be chosen before authentification is successed.");
+    }
+
+    KeyExchange kex=null;
+    try{
+      Class c=Class.forName(getConfig(guess[KeyExchange.PROPOSAL_KEX_ALGS]));
+      kex=(KeyExchange)(c.newInstance());
+    }
+    catch(Exception e){ 
+      throw new JSchException(e.toString(), e);
+    }
+
+    kex.init(this, V_S, V_C, I_S, I_C);
+    return kex;
+  }
+
+  private boolean in_kex=false;
+  public void rekey() throws Exception {
+    send_kexinit();
+  }
+  private void send_kexinit() throws Exception {
+    if(in_kex)
+      return;
+
+    String cipherc2s=getConfig("cipher.c2s");
+    String ciphers2c=getConfig("cipher.s2c");
+
+    String[] not_available=checkCiphers(getConfig("CheckCiphers"));
+    if(not_available!=null && not_available.length>0){
+      cipherc2s=Util.diffString(cipherc2s, not_available);
+      ciphers2c=Util.diffString(ciphers2c, not_available);
+      if(cipherc2s==null || ciphers2c==null){
+        throw new JSchException("There are not any available ciphers.");
+      }
+    }
+
+    in_kex=true;
+    kex_start_time=System.currentTimeMillis();
+
+    // byte      SSH_MSG_KEXINIT(20)
+    // byte[16]  cookie (random bytes)
+    // string    kex_algorithms
+    // string    server_host_key_algorithms
+    // string    encryption_algorithms_client_to_server
+    // string    encryption_algorithms_server_to_client
+    // string    mac_algorithms_client_to_server
+    // string    mac_algorithms_server_to_client
+    // string    compression_algorithms_client_to_server
+    // string    compression_algorithms_server_to_client
+    // string    languages_client_to_server
+    // string    languages_server_to_client
+    Buffer buf = new Buffer();                // send_kexinit may be invoked
+    Packet packet = new Packet(buf);          // by user thread.
+    packet.reset();
+    buf.putByte((byte) SSH_MSG_KEXINIT);
+    synchronized(random){
+      random.fill(buf.buffer, buf.index, 16); buf.skip(16);
+    }
+    buf.putString(Util.str2byte(getConfig("kex")));
+    buf.putString(Util.str2byte(getConfig("server_host_key")));
+    buf.putString(Util.str2byte(cipherc2s));
+    buf.putString(Util.str2byte(ciphers2c));
+    buf.putString(Util.str2byte(getConfig("mac.c2s")));
+    buf.putString(Util.str2byte(getConfig("mac.s2c")));
+    buf.putString(Util.str2byte(getConfig("compression.c2s")));
+    buf.putString(Util.str2byte(getConfig("compression.s2c")));
+    buf.putString(Util.str2byte(getConfig("lang.c2s")));
+    buf.putString(Util.str2byte(getConfig("lang.s2c")));
+    buf.putByte((byte)0);
+    buf.putInt(0);
+
+    buf.setOffSet(5);
+    I_C=new byte[buf.getLength()];
+    buf.getByte(I_C);
+
+    write(packet);
+
+    if(JSch.getLogger().isEnabled(Logger.INFO)){
+      JSch.getLogger().log(Logger.INFO, 
+                           "SSH_MSG_KEXINIT sent");
+    }
+  }
+
+  private void send_newkeys() throws Exception {
+    // send SSH_MSG_NEWKEYS(21)
+    packet.reset();
+    buf.putByte((byte)SSH_MSG_NEWKEYS);
+    write(packet);
+
+    if(JSch.getLogger().isEnabled(Logger.INFO)){
+      JSch.getLogger().log(Logger.INFO, 
+                           "SSH_MSG_NEWKEYS sent");
+    }
+  }
+
+  private void checkHost(String chost, int port, KeyExchange kex) throws JSchException {
+    String shkc=getConfig("StrictHostKeyChecking");
+
+    if(hostKeyAlias!=null){
+      chost=hostKeyAlias;
+    }
+
+    //System.err.println("shkc: "+shkc);
+
+    byte[] K_S=kex.getHostKey();
+    String key_type=kex.getKeyType();
+    String key_fprint=kex.getFingerPrint();
+
+    if(hostKeyAlias==null && port!=22){
+      chost=("["+chost+"]:"+port);
+    }
+
+//    hostkey=new HostKey(chost, K_S);
+
+    HostKeyRepository hkr=jsch.getHostKeyRepository();
+    int i=0;
+    synchronized(hkr){
+      i=hkr.check(chost, K_S);
+    }
+
+    boolean insert=false;
+
+    if((shkc.equals("ask") || shkc.equals("yes")) &&
+       i==HostKeyRepository.CHANGED){
+      String file=null;
+      synchronized(hkr){
+       file=hkr.getKnownHostsRepositoryID();
+      }
+      if(file==null){file="known_hosts";}
+
+      boolean b=false;
+
+      if(userinfo!=null){
+        String message=
+"WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!\n"+
+"IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\n"+
+"Someone could be eavesdropping on you right now (man-in-the-middle attack)!\n"+
+"It is also possible that the "+key_type+" host key has just been changed.\n"+
+"The fingerprint for the "+key_type+" key sent by the remote host is\n"+
+key_fprint+".\n"+
+"Please contact your system administrator.\n"+
+"Add correct host key in "+file+" to get rid of this message.";
+
+        if(shkc.equals("ask")){
+          b=userinfo.promptYesNo(message+
+                                 "\nDo you want to delete the old key and insert the new key?");
+        }
+        else{  // shkc.equals("yes")
+          userinfo.showMessage(message);
+        }
+      }
+
+      if(!b){
+        throw new JSchException("HostKey has been changed: "+chost);
+      }
+
+      synchronized(hkr){
+        hkr.remove(chost, 
+                   (key_type.equals("DSA") ? "ssh-dss" : "ssh-rsa"), 
+                   null);
+        insert=true;
+      }
+    }
+
+    if((shkc.equals("ask") || shkc.equals("yes")) &&
+       (i!=HostKeyRepository.OK) && !insert){
+      if(shkc.equals("yes")){
+       throw new JSchException("reject HostKey: "+host);
+      }
+      //System.err.println("finger-print: "+key_fprint);
+      if(userinfo!=null){
+       boolean foo=userinfo.promptYesNo(
+"The authenticity of host '"+host+"' can't be established.\n"+
+key_type+" key fingerprint is "+key_fprint+".\n"+
+"Are you sure you want to continue connecting?"
+                                        );
+       if(!foo){
+         throw new JSchException("reject HostKey: "+host);
+       }
+       insert=true;
+      }
+      else{
+       if(i==HostKeyRepository.NOT_INCLUDED) 
+         throw new JSchException("UnknownHostKey: "+host+". "+key_type+" key fingerprint is "+key_fprint);
+       else 
+          throw new JSchException("HostKey has been changed: "+host);
+      }
+    }
+
+    if(shkc.equals("no") && 
+       HostKeyRepository.NOT_INCLUDED==i){
+      insert=true;
+    }
+
+    if(i==HostKeyRepository.OK &&
+       JSch.getLogger().isEnabled(Logger.INFO)){
+      JSch.getLogger().log(Logger.INFO, 
+                           "Host '"+host+"' is known and mathces the "+key_type+" host key");
+    }
+
+    if(insert &&
+       JSch.getLogger().isEnabled(Logger.WARN)){
+      JSch.getLogger().log(Logger.WARN, 
+                           "Permanently added '"+host+"' ("+key_type+") to the list of known hosts.");
+    }
+
+    String hkh=getConfig("HashKnownHosts");
+    if(hkh.equals("yes") && (hkr instanceof KnownHosts)){
+      hostkey=((KnownHosts)hkr).createHashedHostKey(chost, K_S);
+    }
+    else{
+      hostkey=new HostKey(chost, K_S);
+    }
+
+    if(insert){
+      synchronized(hkr){
+       hkr.add(hostkey, userinfo);
+      }
+
+    }
+
+  }
+
+//public void start(){ (new Thread(this)).start();  }
+
+  public Channel openChannel(String type) throws JSchException{
+    if(!isConnected){
+      throw new JSchException("session is down");
+    }
+    try{
+      Channel channel=Channel.getChannel(type);
+      addChannel(channel);
+      channel.init();
+      return channel;
+    }
+    catch(Exception e){
+      //e.printStackTrace();
+    }
+    return null;
+  }
+
+  // encode will bin invoked in write with synchronization.
+  public void encode(Packet packet) throws Exception{
+//System.err.println("encode: "+packet.buffer.getCommand());
+//System.err.println("        "+packet.buffer.index);
+//if(packet.buffer.getCommand()==96){
+//Thread.dumpStack();
+//}
+    if(deflater!=null){
+      packet.buffer.index=deflater.compress(packet.buffer.buffer, 
+                                           5, packet.buffer.index);
+    }
+    if(c2scipher!=null){
+      //packet.padding(c2scipher.getIVSize());
+      packet.padding(c2scipher_size);
+      int pad=packet.buffer.buffer[4];
+      synchronized(random){
+       random.fill(packet.buffer.buffer, packet.buffer.index-pad, pad);
+      }
+    }
+    else{
+      packet.padding(8);
+    }
+
+    if(c2smac!=null){
+      c2smac.update(seqo);
+      c2smac.update(packet.buffer.buffer, 0, packet.buffer.index);
+      c2smac.doFinal(packet.buffer.buffer, packet.buffer.index);
+    }
+    if(c2scipher!=null){
+      byte[] buf=packet.buffer.buffer;
+      c2scipher.update(buf, 0, packet.buffer.index, buf, 0);
+    }
+    if(c2smac!=null){
+      packet.buffer.skip(c2smac.getBlockSize());
+    }
+  }
+
+  int[] uncompress_len=new int[1];
+
+  private int s2ccipher_size=8;
+  private int c2scipher_size=8;
+  public Buffer read(Buffer buf) throws Exception{
+    int j=0;
+    while(true){
+      buf.reset();
+      io.getByte(buf.buffer, buf.index, s2ccipher_size); 
+      buf.index+=s2ccipher_size;
+      if(s2ccipher!=null){
+        s2ccipher.update(buf.buffer, 0, s2ccipher_size, buf.buffer, 0);
+      }
+      j=((buf.buffer[0]<<24)&0xff000000)|
+        ((buf.buffer[1]<<16)&0x00ff0000)|
+        ((buf.buffer[2]<< 8)&0x0000ff00)|
+        ((buf.buffer[3]    )&0x000000ff);
+      // RFC 4253 6.1. Maximum Packet Length
+      if(j<5 || j>PACKET_MAX_SIZE){
+        start_discard(buf, s2ccipher, s2cmac, j, PACKET_MAX_SIZE);
+      }
+      int need = j+4-s2ccipher_size;
+      //if(need<0){
+      //  throw new IOException("invalid data");
+      //}
+      if((buf.index+need)>buf.buffer.length){
+        byte[] foo=new byte[buf.index+need];
+        System.arraycopy(buf.buffer, 0, foo, 0, buf.index);
+        buf.buffer=foo;
+      }
+
+      if((need%s2ccipher_size)!=0){
+        String message="Bad packet length "+need;
+        if(JSch.getLogger().isEnabled(Logger.FATAL)){
+          JSch.getLogger().log(Logger.FATAL, message); 
+        }
+        start_discard(buf, s2ccipher, s2cmac, j, PACKET_MAX_SIZE-s2ccipher_size);
+      }
+
+      if(need>0){
+       io.getByte(buf.buffer, buf.index, need); buf.index+=(need);
+       if(s2ccipher!=null){
+         s2ccipher.update(buf.buffer, s2ccipher_size, need, buf.buffer, s2ccipher_size);
+       }
+      }
+
+      if(s2cmac!=null){
+       s2cmac.update(seqi);
+       s2cmac.update(buf.buffer, 0, buf.index);
+
+        s2cmac.doFinal(s2cmac_result1, 0);
+       io.getByte(s2cmac_result2, 0, s2cmac_result2.length);
+        if(!java.util.Arrays.equals(s2cmac_result1, s2cmac_result2)){
+          if(need > PACKET_MAX_SIZE){
+            throw new IOException("MAC Error");
+          }
+          start_discard(buf, s2ccipher, s2cmac, j, PACKET_MAX_SIZE-need);
+          continue;
+       }
+      }
+
+      seqi++;
+
+      if(inflater!=null){
+        //inflater.uncompress(buf);
+       int pad=buf.buffer[4];
+       uncompress_len[0]=buf.index-5-pad;
+       byte[] foo=inflater.uncompress(buf.buffer, 5, uncompress_len);
+       if(foo!=null){
+         buf.buffer=foo;
+         buf.index=5+uncompress_len[0];
+       }
+       else{
+         System.err.println("fail in inflater");
+         break;
+       }
+      }
+
+      int type=buf.getCommand()&0xff;
+      //System.err.println("read: "+type);
+      if(type==SSH_MSG_DISCONNECT){
+        buf.rewind();
+        buf.getInt();buf.getShort();
+       int reason_code=buf.getInt();
+       byte[] description=buf.getString();
+       byte[] language_tag=buf.getString();
+       throw new JSchException("SSH_MSG_DISCONNECT: "+
+                                   reason_code+
+                               " "+Util.byte2str(description)+
+                               " "+Util.byte2str(language_tag));
+       //break;
+      }
+      else if(type==SSH_MSG_IGNORE){
+      }
+      else if(type==SSH_MSG_UNIMPLEMENTED){
+        buf.rewind();
+        buf.getInt();buf.getShort();
+       int reason_id=buf.getInt();
+        if(JSch.getLogger().isEnabled(Logger.INFO)){
+          JSch.getLogger().log(Logger.INFO, 
+                               "Received SSH_MSG_UNIMPLEMENTED for "+reason_id);
+        }
+      }
+      else if(type==SSH_MSG_DEBUG){
+        buf.rewind();
+        buf.getInt();buf.getShort();
+/*
+       byte always_display=(byte)buf.getByte();
+       byte[] message=buf.getString();
+       byte[] language_tag=buf.getString();
+       System.err.println("SSH_MSG_DEBUG:"+
+                          " "+Util.byte2str(message)+
+                          " "+Util.byte2str(language_tag));
+*/
+      }
+      else if(type==SSH_MSG_CHANNEL_WINDOW_ADJUST){
+          buf.rewind();
+          buf.getInt();buf.getShort();
+         Channel c=Channel.getChannel(buf.getInt(), this);
+         if(c==null){
+         }
+         else{
+           c.addRemoteWindowSize(buf.getInt()); 
+         }
+      }
+      else if(type==UserAuth.SSH_MSG_USERAUTH_SUCCESS){
+        isAuthed=true;
+        if(inflater==null && deflater==null){
+          String method;
+          method=guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS];
+          initDeflater(method);
+
+          method=guess[KeyExchange.PROPOSAL_COMP_ALGS_STOC];
+          initInflater(method);
+        }
+        break;
+      }
+      else{
+        break;
+      }
+    }
+    buf.rewind();
+    return buf;
+  }
+
+  private void start_discard(Buffer buf, Cipher cipher, MAC mac, 
+                             int packet_length, int discard) throws JSchException, IOException{
+    MAC discard_mac = null;
+
+    if(!cipher.isCBC()){
+      throw new JSchException("Packet corrupt");
+    }
+
+    if(packet_length!=PACKET_MAX_SIZE && mac != null){
+      discard_mac = mac;
+    }
+
+    discard -= buf.index;
+
+    while(discard>0){
+      buf.reset();
+      int len = discard>buf.buffer.length ? buf.buffer.length : discard;
+      io.getByte(buf.buffer, 0, len);
+      if(discard_mac!=null){
+        discard_mac.update(buf.buffer, 0, len);
+      }
+      discard -= len;
+    }
+
+    if(discard_mac!=null){
+      discard_mac.doFinal(buf.buffer, 0);
+    }
+
+    throw new JSchException("Packet corrupt");
+  }
+
+  byte[] getSessionId(){
+    return session_id;
+  }
+
+  private void receive_newkeys(Buffer buf, KeyExchange kex) throws Exception {
+    updateKeys(kex);
+    in_kex=false;
+  }
+  private void updateKeys(KeyExchange kex) throws Exception{
+    byte[] K=kex.getK();
+    byte[] H=kex.getH();
+    HASH hash=kex.getHash();
+
+//    String[] guess=kex.guess;
+
+    if(session_id==null){
+      session_id=new byte[H.length];
+      System.arraycopy(H, 0, session_id, 0, H.length);
+    }
+
+    /*
+      Initial IV client to server:     HASH (K || H || "A" || session_id)
+      Initial IV server to client:     HASH (K || H || "B" || session_id)
+      Encryption key client to server: HASH (K || H || "C" || session_id)
+      Encryption key server to client: HASH (K || H || "D" || session_id)
+      Integrity key client to server:  HASH (K || H || "E" || session_id)
+      Integrity key server to client:  HASH (K || H || "F" || session_id)
+    */
+
+    buf.reset();
+    buf.putMPInt(K);
+    buf.putByte(H);
+    buf.putByte((byte)0x41);
+    buf.putByte(session_id);
+    hash.update(buf.buffer, 0, buf.index);
+    IVc2s=hash.digest();
+
+    int j=buf.index-session_id.length-1;
+
+    buf.buffer[j]++;
+    hash.update(buf.buffer, 0, buf.index);
+    IVs2c=hash.digest();
+
+    buf.buffer[j]++;
+    hash.update(buf.buffer, 0, buf.index);
+    Ec2s=hash.digest();
+
+    buf.buffer[j]++;
+    hash.update(buf.buffer, 0, buf.index);
+    Es2c=hash.digest();
+
+    buf.buffer[j]++;
+    hash.update(buf.buffer, 0, buf.index);
+    MACc2s=hash.digest();
+
+    buf.buffer[j]++;
+    hash.update(buf.buffer, 0, buf.index);
+    MACs2c=hash.digest();
+
+    try{
+      Class c;
+      String method;
+  
+      method=guess[KeyExchange.PROPOSAL_ENC_ALGS_STOC];
+      c=Class.forName(getConfig(method));
+      s2ccipher=(Cipher)(c.newInstance());
+      while(s2ccipher.getBlockSize()>Es2c.length){
+        buf.reset();
+        buf.putMPInt(K);
+        buf.putByte(H);
+        buf.putByte(Es2c);
+        hash.update(buf.buffer, 0, buf.index);
+        byte[] foo=hash.digest();
+        byte[] bar=new byte[Es2c.length+foo.length];
+       System.arraycopy(Es2c, 0, bar, 0, Es2c.length);
+       System.arraycopy(foo, 0, bar, Es2c.length, foo.length);
+       Es2c=bar;
+      }
+      s2ccipher.init(Cipher.DECRYPT_MODE, Es2c, IVs2c);
+      s2ccipher_size=s2ccipher.getIVSize();
+
+      method=guess[KeyExchange.PROPOSAL_MAC_ALGS_STOC];
+      c=Class.forName(getConfig(method));
+      s2cmac=(MAC)(c.newInstance());
+      s2cmac.init(MACs2c);
+      //mac_buf=new byte[s2cmac.getBlockSize()];
+      s2cmac_result1=new byte[s2cmac.getBlockSize()];
+      s2cmac_result2=new byte[s2cmac.getBlockSize()];
+
+      method=guess[KeyExchange.PROPOSAL_ENC_ALGS_CTOS];
+      c=Class.forName(getConfig(method));
+      c2scipher=(Cipher)(c.newInstance());
+      while(c2scipher.getBlockSize()>Ec2s.length){
+        buf.reset();
+        buf.putMPInt(K);
+        buf.putByte(H);
+        buf.putByte(Ec2s);
+        hash.update(buf.buffer, 0, buf.index);
+        byte[] foo=hash.digest();
+        byte[] bar=new byte[Ec2s.length+foo.length];
+       System.arraycopy(Ec2s, 0, bar, 0, Ec2s.length);
+       System.arraycopy(foo, 0, bar, Ec2s.length, foo.length);
+       Ec2s=bar;
+      }
+      c2scipher.init(Cipher.ENCRYPT_MODE, Ec2s, IVc2s);
+      c2scipher_size=c2scipher.getIVSize();
+
+      method=guess[KeyExchange.PROPOSAL_MAC_ALGS_CTOS];
+      c=Class.forName(getConfig(method));
+      c2smac=(MAC)(c.newInstance());
+      c2smac.init(MACc2s);
+
+      method=guess[KeyExchange.PROPOSAL_COMP_ALGS_CTOS];
+      initDeflater(method);
+
+      method=guess[KeyExchange.PROPOSAL_COMP_ALGS_STOC];
+      initInflater(method);
+    }
+    catch(Exception e){ 
+      if(e instanceof JSchException)
+        throw e;
+      throw new JSchException(e.toString(), e);
+      //System.err.println("updatekeys: "+e); 
+    }
+  }
+
+  /*public*/ /*synchronized*/ void write(Packet packet, Channel c, int length) throws Exception{
+    long t = getTimeout();
+    while(true){
+      if(in_kex){
+        if(t>0L && (System.currentTimeMillis()-kex_start_time)>t){
+          throw new JSchException("timeout in wating for rekeying process.");
+        }
+        try{Thread.sleep(10);}
+        catch(java.lang.InterruptedException e){};
+        continue;
+      }
+      synchronized(c){
+        if(c.rwsize>=length){
+          c.rwsize-=length;
+          break;
+        }
+      }
+      if(c.close || !c.isConnected()){
+       throw new IOException("channel is broken");
+      }
+
+      boolean sendit=false;
+      int s=0;
+      byte command=0;
+      int recipient=-1;
+      synchronized(c){
+       if(c.rwsize>0){
+         long len=c.rwsize;
+          if(len>length){
+            len=length;
+          }
+          if(len!=length){
+            s=packet.shift((int)len, (c2smac!=null ? c2smac.getBlockSize() : 0));
+          }
+         command=packet.buffer.getCommand();
+         recipient=c.getRecipient();
+         length-=len;
+         c.rwsize-=len;
+         sendit=true;
+       }
+      }
+      if(sendit){
+       _write(packet);
+        if(length==0){
+          return;
+        }
+       packet.unshift(command, recipient, s, length);
+      }
+
+      synchronized(c){
+        if(in_kex){
+          continue;
+        }
+        if(c.rwsize>=length){
+          c.rwsize-=length;
+          break;
+        }
+        try{ 
+          c.notifyme++;
+          c.wait(100); 
+        }
+        catch(java.lang.InterruptedException e){
+        }
+        finally{
+          c.notifyme--;
+        }
+      }
+
+    }
+    _write(packet);
+  }
+
+  public void write(Packet packet) throws Exception{
+    // System.err.println("in_kex="+in_kex+" "+(packet.buffer.getCommand()));
+    long t = getTimeout();
+    while(in_kex){
+      if(t>0L && (System.currentTimeMillis()-kex_start_time)>t){
+        throw new JSchException("timeout in wating for rekeying process.");
+      }
+      byte command=packet.buffer.getCommand();
+      //System.err.println("command: "+command);
+      if(command==SSH_MSG_KEXINIT ||
+         command==SSH_MSG_NEWKEYS ||
+         command==SSH_MSG_KEXDH_INIT ||
+         command==SSH_MSG_KEXDH_REPLY ||
+         command==SSH_MSG_KEX_DH_GEX_GROUP ||
+         command==SSH_MSG_KEX_DH_GEX_INIT ||
+         command==SSH_MSG_KEX_DH_GEX_REPLY ||
+         command==SSH_MSG_KEX_DH_GEX_REQUEST ||
+         command==SSH_MSG_DISCONNECT){
+        break;
+      }
+      try{Thread.sleep(10);}
+      catch(java.lang.InterruptedException e){};
+    }
+    _write(packet);
+  }
+
+  private void _write(Packet packet) throws Exception{
+    synchronized(lock){
+      encode(packet);
+      if(io!=null){
+        io.put(packet);
+        seqo++;
+      }
+    }
+  }
+
+  Runnable thread;
+  public void run(){
+    thread=this;
+
+    byte[] foo;
+    Buffer buf=new Buffer();
+    Packet packet=new Packet(buf);
+    int i=0;
+    Channel channel;
+    int[] start=new int[1];
+    int[] length=new int[1];
+    KeyExchange kex=null;
+
+    int stimeout=0;
+    try{
+      while(isConnected &&
+           thread!=null){
+        try{
+          buf=read(buf);
+          stimeout=0;
+        }
+        catch(InterruptedIOException/*SocketTimeoutException*/ ee){
+          if(!in_kex && stimeout<serverAliveCountMax){
+            sendKeepAliveMsg();
+            stimeout++;
+            continue;
+          }
+          throw ee;
+        }
+
+       int msgType=buf.getCommand()&0xff;
+
+       if(kex!=null && kex.getState()==msgType){
+          kex_start_time=System.currentTimeMillis();
+         boolean result=kex.next(buf);
+         if(!result){
+           throw new JSchException("verify: "+result);
+         }
+         continue;
+       }
+
+        switch(msgType){
+       case SSH_MSG_KEXINIT:
+//System.err.println("KEXINIT");
+         kex=receive_kexinit(buf);
+         break;
+
+       case SSH_MSG_NEWKEYS:
+//System.err.println("NEWKEYS");
+          send_newkeys();
+         receive_newkeys(buf, kex);
+         kex=null;
+         break;
+
+       case SSH_MSG_CHANNEL_DATA:
+          buf.getInt(); 
+          buf.getByte(); 
+          buf.getByte(); 
+          i=buf.getInt(); 
+         channel=Channel.getChannel(i, this);
+         foo=buf.getString(start, length);
+         if(channel==null){
+           break;
+         }
+
+          if(length[0]==0){
+           break;
+          }
+
+try{
+         channel.write(foo, start[0], length[0]);
+}
+catch(Exception e){
+//System.err.println(e);
+  try{channel.disconnect();}catch(Exception ee){}
+break;
+}
+         int len=length[0];
+         channel.setLocalWindowSize(channel.lwsize-len);
+         if(channel.lwsize<channel.lwsize_max/2){
+            packet.reset();
+           buf.putByte((byte)SSH_MSG_CHANNEL_WINDOW_ADJUST);
+           buf.putInt(channel.getRecipient());
+           buf.putInt(channel.lwsize_max-channel.lwsize);
+           write(packet);
+           channel.setLocalWindowSize(channel.lwsize_max);
+         }
+         break;
+
+        case SSH_MSG_CHANNEL_EXTENDED_DATA:
+          buf.getInt();
+         buf.getShort();
+         i=buf.getInt();
+         channel=Channel.getChannel(i, this);
+         buf.getInt();                   // data_type_code == 1
+         foo=buf.getString(start, length);
+         //System.err.println("stderr: "+new String(foo,start[0],length[0]));
+         if(channel==null){
+           break;
+         }
+
+          if(length[0]==0){
+           break;
+          }
+
+         channel.write_ext(foo, start[0], length[0]);
+
+         len=length[0];
+         channel.setLocalWindowSize(channel.lwsize-len);
+         if(channel.lwsize<channel.lwsize_max/2){
+            packet.reset();
+           buf.putByte((byte)SSH_MSG_CHANNEL_WINDOW_ADJUST);
+           buf.putInt(channel.getRecipient());
+           buf.putInt(channel.lwsize_max-channel.lwsize);
+           write(packet);
+           channel.setLocalWindowSize(channel.lwsize_max);
+         }
+         break;
+
+       case SSH_MSG_CHANNEL_WINDOW_ADJUST:
+          buf.getInt(); 
+         buf.getShort(); 
+         i=buf.getInt(); 
+         channel=Channel.getChannel(i, this);
+         if(channel==null){
+           break;
+         }
+         channel.addRemoteWindowSize(buf.getInt()); 
+         break;
+
+       case SSH_MSG_CHANNEL_EOF:
+          buf.getInt(); 
+          buf.getShort(); 
+          i=buf.getInt(); 
+         channel=Channel.getChannel(i, this);
+         if(channel!=null){
+           //channel.eof_remote=true;
+           //channel.eof();
+           channel.eof_remote();
+         }
+         /*
+         packet.reset();
+         buf.putByte((byte)SSH_MSG_CHANNEL_EOF);
+         buf.putInt(channel.getRecipient());
+         write(packet);
+         */
+         break;
+       case SSH_MSG_CHANNEL_CLOSE:
+          buf.getInt(); 
+         buf.getShort(); 
+         i=buf.getInt(); 
+         channel=Channel.getChannel(i, this);
+         if(channel!=null){
+//           channel.close();
+           channel.disconnect();
+         }
+         /*
+          if(Channel.pool.size()==0){
+           thread=null;
+         }
+         */
+         break;
+       case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
+          buf.getInt(); 
+         buf.getShort(); 
+         i=buf.getInt(); 
+         channel=Channel.getChannel(i, this);
+         if(channel==null){
+           //break;
+         }
+          int r=buf.getInt();
+          long rws=buf.getUInt();
+          int rps=buf.getInt();
+
+          channel.setRemoteWindowSize(rws);
+          channel.setRemotePacketSize(rps);
+          channel.setRecipient(r);
+          break;
+       case SSH_MSG_CHANNEL_OPEN_FAILURE:
+          buf.getInt(); 
+         buf.getShort(); 
+         i=buf.getInt(); 
+         channel=Channel.getChannel(i, this);
+         if(channel==null){
+           //break;
+         }
+         int reason_code=buf.getInt(); 
+         //foo=buf.getString();  // additional textual information
+         //foo=buf.getString();  // language tag 
+         channel.exitstatus=reason_code;
+         channel.close=true;
+         channel.eof_remote=true;
+         channel.setRecipient(0);
+         break;
+       case SSH_MSG_CHANNEL_REQUEST:
+          buf.getInt(); 
+         buf.getShort(); 
+         i=buf.getInt(); 
+         foo=buf.getString(); 
+          boolean reply=(buf.getByte()!=0);
+         channel=Channel.getChannel(i, this);
+         if(channel!=null){
+           byte reply_type=(byte)SSH_MSG_CHANNEL_FAILURE;
+           if((Util.byte2str(foo)).equals("exit-status")){
+             i=buf.getInt();             // exit-status
+             channel.setExitStatus(i);
+             reply_type=(byte)SSH_MSG_CHANNEL_SUCCESS;
+           }
+           if(reply){
+             packet.reset();
+             buf.putByte(reply_type);
+             buf.putInt(channel.getRecipient());
+             write(packet);
+           }
+         }
+         else{
+         }
+         break;
+       case SSH_MSG_CHANNEL_OPEN:
+          buf.getInt(); 
+         buf.getShort(); 
+         foo=buf.getString(); 
+         String ctyp=Util.byte2str(foo);
+          if(!"forwarded-tcpip".equals(ctyp) &&
+            !("x11".equals(ctyp) && x11_forwarding) &&
+            !("auth-agent@openssh.com".equals(ctyp) && agent_forwarding)){
+            //System.err.println("Session.run: CHANNEL OPEN "+ctyp); 
+           //throw new IOException("Session.run: CHANNEL OPEN "+ctyp);
+           packet.reset();
+           buf.putByte((byte)SSH_MSG_CHANNEL_OPEN_FAILURE);
+           buf.putInt(buf.getInt());
+           buf.putInt(Channel.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED);
+           buf.putString(Util.empty);
+           buf.putString(Util.empty);
+           write(packet);
+         }
+         else{
+           channel=Channel.getChannel(ctyp);
+           addChannel(channel);
+           channel.getData(buf);
+           channel.init();
+
+           Thread tmp=new Thread(channel);
+           tmp.setName("Channel "+ctyp+" "+host);
+            if(daemon_thread){
+              tmp.setDaemon(daemon_thread);
+            }
+           tmp.start();
+           break;
+         }
+       case SSH_MSG_CHANNEL_SUCCESS:
+          buf.getInt(); 
+         buf.getShort(); 
+         i=buf.getInt(); 
+         channel=Channel.getChannel(i, this);
+         if(channel==null){
+           break;
+         }
+         channel.reply=1;
+         break;
+       case SSH_MSG_CHANNEL_FAILURE:
+         buf.getInt(); 
+         buf.getShort(); 
+         i=buf.getInt(); 
+         channel=Channel.getChannel(i, this);
+         if(channel==null){
+           break;
+         }
+         channel.reply=0;
+         break;
+       case SSH_MSG_GLOBAL_REQUEST:
+         buf.getInt(); 
+         buf.getShort(); 
+         foo=buf.getString();       // request name
+         reply=(buf.getByte()!=0);
+         if(reply){
+           packet.reset();
+           buf.putByte((byte)SSH_MSG_REQUEST_FAILURE);
+           write(packet);
+         }
+         break;
+       case SSH_MSG_REQUEST_FAILURE:
+       case SSH_MSG_REQUEST_SUCCESS:
+          Thread t=grr.getThread();
+          if(t!=null){
+            grr.setReply(msgType==SSH_MSG_REQUEST_SUCCESS? 1 : 0);
+            t.interrupt();
+          }
+         break;
+       default:
+          //System.err.println("Session.run: unsupported type "+msgType); 
+         throw new IOException("Unknown SSH message type "+msgType);
+       }
+      }
+    }
+    catch(Exception e){
+      in_kex=false;
+      if(JSch.getLogger().isEnabled(Logger.INFO)){
+        JSch.getLogger().log(Logger.INFO,
+                             "Caught an exception, leaving main loop due to " + e.getMessage());
+      }
+      //System.err.println("# Session.run");
+      //e.printStackTrace();
+    }
+    try{
+      disconnect();
+    }
+    catch(NullPointerException e){
+      //System.err.println("@1");
+      //e.printStackTrace();
+    }
+    catch(Exception e){
+      //System.err.println("@2");
+      //e.printStackTrace();
+    }
+    isConnected=false;
+  }
+
+  public void disconnect(){
+    if(!isConnected) return;
+    //System.err.println(this+": disconnect");
+    //Thread.dumpStack();
+    if(JSch.getLogger().isEnabled(Logger.INFO)){
+      JSch.getLogger().log(Logger.INFO,
+                           "Disconnecting from "+host+" port "+port);
+    }
+    /*
+    for(int i=0; i<Channel.pool.size(); i++){
+      try{
+        Channel c=((Channel)(Channel.pool.elementAt(i)));
+       if(c.session==this) c.eof();
+      }
+      catch(Exception e){
+      }
+    } 
+    */
+
+    Channel.disconnect(this);
+
+    isConnected=false;
+
+    PortWatcher.delPort(this);
+    ChannelForwardedTCPIP.delPort(this);
+
+    synchronized(lock){
+      if(connectThread!=null){
+        Thread.yield();
+        connectThread.interrupt();
+        connectThread=null;
+      }
+    }
+    thread=null;
+    try{
+      if(io!=null){
+       if(io.in!=null) io.in.close();
+       if(io.out!=null) io.out.close();
+       if(io.out_ext!=null) io.out_ext.close();
+      }
+      if(proxy==null){
+        if(socket!=null)
+         socket.close();
+      }
+      else{
+       synchronized(proxy){
+         proxy.close();          
+       }
+       proxy=null;
+      }
+    }
+    catch(Exception e){
+//      e.printStackTrace();
+    }
+    io=null;
+    socket=null;
+//    synchronized(jsch.pool){
+//      jsch.pool.removeElement(this);
+//    }
+
+    jsch.removeSession(this);
+
+    //System.gc();
+  }
+
+  public int setPortForwardingL(int lport, String host, int rport) throws JSchException{
+    return setPortForwardingL("127.0.0.1", lport, host, rport);
+  }
+  public int setPortForwardingL(String boundaddress, int lport, String host, int rport) throws JSchException{
+    return setPortForwardingL(boundaddress, lport, host, rport, null);
+  }
+  public int setPortForwardingL(String boundaddress, int lport, String host, int rport, ServerSocketFactory ssf) throws JSchException{
+    PortWatcher pw=PortWatcher.addPort(this, boundaddress, lport, host, rport, ssf);
+    Thread tmp=new Thread(pw);
+    tmp.setName("PortWatcher Thread for "+host);
+    if(daemon_thread){
+      tmp.setDaemon(daemon_thread);
+    }
+    tmp.start();
+    return pw.lport;
+  }
+  public void delPortForwardingL(int lport) throws JSchException{
+    delPortForwardingL("127.0.0.1", lport);
+  }
+  public void delPortForwardingL(String boundaddress, int lport) throws JSchException{
+    PortWatcher.delPort(this, boundaddress, lport);
+  }
+  public String[] getPortForwardingL() throws JSchException{
+    return PortWatcher.getPortForwarding(this);
+  }
+
+  public void setPortForwardingR(int rport, String host, int lport) throws JSchException{
+    setPortForwardingR(null, rport, host, lport, (SocketFactory)null);
+  }
+  public void setPortForwardingR(String bind_address, int rport, String host, int lport) throws JSchException{
+    setPortForwardingR(bind_address, rport, host, lport, (SocketFactory)null);
+  }
+  public void setPortForwardingR(int rport, String host, int lport, SocketFactory sf) throws JSchException{
+    setPortForwardingR(null, rport, host, lport, sf);
+  }
+  public void setPortForwardingR(String bind_address, int rport, String host, int lport, SocketFactory sf) throws JSchException{
+    ChannelForwardedTCPIP.addPort(this, bind_address, rport, host, lport, sf);
+    setPortForwarding(bind_address, rport);
+  }
+
+  public void setPortForwardingR(int rport, String daemon) throws JSchException{
+    setPortForwardingR(null, rport, daemon, null);
+  }
+  public void setPortForwardingR(int rport, String daemon, Object[] arg) throws JSchException{
+    setPortForwardingR(null, rport, daemon, arg);
+  }
+  public void setPortForwardingR(String bind_address, int rport, String daemon, Object[] arg) throws JSchException{
+    ChannelForwardedTCPIP.addPort(this, bind_address, rport, daemon, arg);
+    setPortForwarding(bind_address, rport);
+  }
+
+  private class GlobalRequestReply{
+    private Thread thread=null;
+    private int reply=-1;
+    void setThread(Thread thread){
+      this.thread=thread;
+      this.reply=-1;
+    }
+    Thread getThread(){ return thread; }
+    void setReply(int reply){ this.reply=reply; }
+    int getReply(){ return this.reply; }
+  }
+  private GlobalRequestReply grr=new GlobalRequestReply();
+  private void setPortForwarding(String bind_address, int rport) throws JSchException{
+    synchronized(grr){
+    Buffer buf=new Buffer(100); // ??
+    Packet packet=new Packet(buf);
+
+    String address_to_bind=ChannelForwardedTCPIP.normalize(bind_address);
+
+    try{
+      // byte SSH_MSG_GLOBAL_REQUEST 80
+      // string "tcpip-forward"
+      // boolean want_reply
+      // string  address_to_bind
+      // uint32  port number to bind
+      packet.reset();
+      buf.putByte((byte) SSH_MSG_GLOBAL_REQUEST);
+      buf.putString(Util.str2byte("tcpip-forward"));
+//      buf.putByte((byte)0);
+      buf.putByte((byte)1);
+      buf.putString(Util.str2byte(address_to_bind));
+      buf.putInt(rport);
+      write(packet);
+    }
+    catch(Exception e){
+      if(e instanceof Throwable)
+        throw new JSchException(e.toString(), (Throwable)e);
+      throw new JSchException(e.toString());
+    }
+
+    grr.setThread(Thread.currentThread());
+    try{ Thread.sleep(10000);}
+    catch(Exception e){
+    }
+    int reply=grr.getReply();
+    grr.setThread(null);
+    if(reply==0){
+      throw new JSchException("remote port forwarding failed for listen port "+rport);
+    }
+    }
+  }
+  public void delPortForwardingR(int rport) throws JSchException{
+    ChannelForwardedTCPIP.delPort(this, rport);
+  }
+
+  private void initDeflater(String method) throws JSchException{
+    if(method.equals("none")){
+      deflater=null;
+      return;
+    }
+    String foo=getConfig(method);
+    if(foo!=null){
+      if(method.equals("zlib") ||
+         (isAuthed && method.equals("zlib@openssh.com"))){
+        try{
+          Class c=Class.forName(foo);
+          deflater=(Compression)(c.newInstance());
+          int level=6;
+          try{ level=Integer.parseInt(getConfig("compression_level"));}
+          catch(Exception ee){ }
+          deflater.init(Compression.DEFLATER, level);
+        }
+        catch(Exception ee){
+          throw new JSchException(ee.toString(), ee);
+          //System.err.println(foo+" isn't accessible.");
+        }
+      }
+    }
+  }
+  private void initInflater(String method) throws JSchException{
+    if(method.equals("none")){
+      inflater=null;
+      return;
+    }
+    String foo=getConfig(method);
+    if(foo!=null){
+      if(method.equals("zlib") ||
+         (isAuthed && method.equals("zlib@openssh.com"))){
+        try{
+          Class c=Class.forName(foo);
+          inflater=(Compression)(c.newInstance());
+          inflater.init(Compression.INFLATER, 0);
+        }
+        catch(Exception ee){
+          throw new JSchException(ee.toString(), ee);
+           //System.err.println(foo+" isn't accessible.");
+        }
+      }
+    }
+  }
+
+  void addChannel(Channel channel){
+    channel.setSession(this);
+  }
+
+  public void setProxy(Proxy proxy){ this.proxy=proxy; }
+  public void setHost(String host){ this.host=host; }
+  public void setPort(int port){ this.port=port; }
+  void setUserName(String username){ this.username=username; }
+  public void setUserInfo(UserInfo userinfo){ this.userinfo=userinfo; }
+  public UserInfo getUserInfo(){ return userinfo; }
+  public void setInputStream(InputStream in){ this.in=in; }
+  public void setOutputStream(OutputStream out){ this.out=out; }
+  public void setX11Host(String host){ ChannelX11.setHost(host); }
+  public void setX11Port(int port){ ChannelX11.setPort(port); }
+  public void setX11Cookie(String cookie){ ChannelX11.setCookie(cookie); }
+  public void setPassword(String password){
+    if(password!=null)
+      this.password=Util.str2byte(password);
+  }
+  public void setPassword(byte[] password){ 
+    if(password!=null){
+      this.password=new byte[password.length];
+      System.arraycopy(password, 0, this.password, 0, password.length);
+    }
+  }
+
+  public void setConfig(java.util.Properties newconf){
+    setConfig((java.util.Hashtable)newconf);
+  }
+  public void setConfig(java.util.Hashtable newconf){
+    synchronized(lock){
+      if(config==null) 
+        config=new java.util.Hashtable();
+      for(java.util.Enumeration e=newconf.keys() ; e.hasMoreElements() ;) {
+        String key=(String)(e.nextElement());
+        config.put(key, (String)(newconf.get(key)));
+      }
+    }
+  }
+
+  public void setConfig(String key, String value){
+    synchronized(lock){ 
+      if(config==null){
+        config=new java.util.Hashtable();
+      }
+      config.put(key, value);
+    }
+  }
+
+  public String getConfig(String key){
+    Object foo=null;
+    if(config!=null){
+      foo=config.get(key);
+      if(foo instanceof String) return (String)foo;
+    }
+    foo=jsch.getConfig(key);
+    if(foo instanceof String) return (String)foo;
+    return null;
+  }
+
+  public void setSocketFactory(SocketFactory sfactory){ 
+    socket_factory=sfactory;
+  }
+  public boolean isConnected(){ return isConnected; }
+  public int getTimeout(){ return timeout; }
+  public void setTimeout(int timeout) throws JSchException {
+    if(socket==null){
+      if(timeout<0){
+        throw new JSchException("invalid timeout value");
+      }
+      this.timeout=timeout;
+      return;
+    }
+    try{
+      socket.setSoTimeout(timeout);
+      this.timeout=timeout;
+    }
+    catch(Exception e){
+      if(e instanceof Throwable)
+        throw new JSchException(e.toString(), (Throwable)e);
+      throw new JSchException(e.toString());
+    }
+  }
+  public String getServerVersion(){
+    return Util.byte2str(V_S);
+  }
+  public String getClientVersion(){
+    return Util.byte2str(V_C);
+  }
+  public void setClientVersion(String cv){
+    V_C=Util.str2byte(cv);
+  }
+
+  public void sendIgnore() throws Exception{
+    Buffer buf=new Buffer();
+    Packet packet=new Packet(buf);
+    packet.reset();
+    buf.putByte((byte)SSH_MSG_IGNORE);
+    write(packet);
+  }
+
+  private static final byte[] keepalivemsg=Util.str2byte("keepalive@jcraft.com");
+  public void sendKeepAliveMsg() throws Exception{
+    Buffer buf=new Buffer();
+    Packet packet=new Packet(buf);
+    packet.reset();
+    buf.putByte((byte)SSH_MSG_GLOBAL_REQUEST);
+    buf.putString(keepalivemsg);
+    buf.putByte((byte)1);
+    write(packet);
+  }
+  
+  private HostKey hostkey=null;
+  public HostKey getHostKey(){ return hostkey; }
+  public String getHost(){return host;}
+  public String getUserName(){return username;}
+  public int getPort(){return port;}
+  public void setHostKeyAlias(String hostKeyAlias){
+    this.hostKeyAlias=hostKeyAlias;
+  }
+  public String getHostKeyAlias(){
+    return hostKeyAlias;
+  }
+
+  public void setServerAliveInterval(int interval) throws JSchException {
+    setTimeout(interval);
+    this.serverAliveInterval=interval;
+  }
+  public void setServerAliveCountMax(int count){
+    this.serverAliveCountMax=count;
+  }
+
+  public int getServerAliveInterval(){
+    return this.serverAliveInterval;
+  }
+  public int getServerAliveCountMax(){
+    return this.serverAliveCountMax;
+  }
+
+  public void setDaemonThread(boolean enable){
+    this.daemon_thread=enable;
+  }
+
+  private String[] checkCiphers(String ciphers){
+    if(ciphers==null || ciphers.length()==0)
+      return null;
+
+    if(JSch.getLogger().isEnabled(Logger.INFO)){
+      JSch.getLogger().log(Logger.INFO, 
+                           "CheckCiphers: "+ciphers);
+    }
+
+    java.util.Vector result=new java.util.Vector();
+    String[] _ciphers=Util.split(ciphers, ",");
+    for(int i=0; i<_ciphers.length; i++){
+      if(!checkCipher(getConfig(_ciphers[i]))){
+        result.addElement(_ciphers[i]);
+      }
+    }
+    if(result.size()==0)
+      return null;
+    String[] foo=new String[result.size()];
+    System.arraycopy(result.toArray(), 0, foo, 0, result.size());
+
+    if(JSch.getLogger().isEnabled(Logger.INFO)){
+      for(int i=0; i<foo.length; i++){
+        JSch.getLogger().log(Logger.INFO, 
+                             foo[i]+" is not available.");
+      }
+    }
+
+    return foo;
+  }
+
+  static boolean checkCipher(String cipher){
+    try{
+      Class c=Class.forName(cipher);
+      Cipher _c=(Cipher)(c.newInstance());
+      _c.init(Cipher.ENCRYPT_MODE,
+              new byte[_c.getBlockSize()],
+              new byte[_c.getIVSize()]);
+      return true;
+    }
+    catch(Exception e){
+      return false;
+    }
+  }
+}
diff --git a/src/com/jcraft/jsch/SftpATTRS.java b/src/com/jcraft/jsch/SftpATTRS.java
new file mode 100644 (file)
index 0000000..a779e69
--- /dev/null
@@ -0,0 +1,263 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/*
+  uint32   flags
+  uint64   size           present only if flag SSH_FILEXFER_ATTR_SIZE
+  uint32   uid            present only if flag SSH_FILEXFER_ATTR_UIDGID
+  uint32   gid            present only if flag SSH_FILEXFER_ATTR_UIDGID
+  uint32   permissions    present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
+  uint32   atime          present only if flag SSH_FILEXFER_ACMODTIME
+  uint32   mtime          present only if flag SSH_FILEXFER_ACMODTIME
+  uint32   extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
+  string   extended_type
+  string   extended_data
+    ...      more extended data (extended_type - extended_data pairs),
+             so that number of pairs equals extended_count
+*/
+public class SftpATTRS {
+
+  static final int S_ISUID = 04000; // set user ID on execution
+  static final int S_ISGID = 02000; // set group ID on execution
+  static final int S_ISVTX = 01000; // sticky bit   ****** NOT DOCUMENTED *****
+
+  static final int S_IRUSR = 00400; // read by owner
+  static final int S_IWUSR = 00200; // write by owner
+  static final int S_IXUSR = 00100; // execute/search by owner
+  static final int S_IREAD = 00400; // read by owner
+  static final int S_IWRITE= 00200; // write by owner
+  static final int S_IEXEC = 00100; // execute/search by owner
+
+  static final int S_IRGRP = 00040; // read by group
+  static final int S_IWGRP = 00020; // write by group
+  static final int S_IXGRP = 00010; // execute/search by group
+
+  static final int S_IROTH = 00004; // read by others
+  static final int S_IWOTH = 00002; // write by others
+  static final int S_IXOTH = 00001; // execute/search by others
+
+  private static final int pmask = 0xFFF;
+
+  public String getPermissionsString() {
+    StringBuffer buf = new StringBuffer(10);
+
+    if(isDir()) buf.append('d');
+    else if(isLink()) buf.append('l');
+    else buf.append('-');
+
+    if((permissions & S_IRUSR)!=0) buf.append('r');
+    else buf.append('-');
+
+    if((permissions & S_IWUSR)!=0) buf.append('w');
+    else buf.append('-');
+
+    if((permissions & S_ISUID)!=0) buf.append('s');
+    else if ((permissions & S_IXUSR)!=0) buf.append('x');
+    else buf.append('-');
+
+    if((permissions & S_IRGRP)!=0) buf.append('r');
+    else buf.append('-');
+
+    if((permissions & S_IWGRP)!=0) buf.append('w');
+    else buf.append('-');
+
+    if((permissions & S_ISGID)!=0) buf.append('s');
+    else if((permissions & S_IXGRP)!=0) buf.append('x');
+    else buf.append('-');
+
+    if((permissions & S_IROTH) != 0) buf.append('r');
+    else buf.append('-');
+
+    if((permissions & S_IWOTH) != 0) buf.append('w');
+    else buf.append('-');
+
+    if((permissions & S_IXOTH) != 0) buf.append('x');
+    else buf.append('-');
+    return (buf.toString());
+  }
+
+  public String  getAtimeString(){
+    SimpleDateFormat locale=new SimpleDateFormat();
+    return (locale.format(new Date(atime)));
+  }
+
+  public String  getMtimeString(){
+    Date date= new Date(((long)mtime)*1000);
+    return (date.toString());
+  }
+
+  public static final int SSH_FILEXFER_ATTR_SIZE=         0x00000001;
+  public static final int SSH_FILEXFER_ATTR_UIDGID=       0x00000002;
+  public static final int SSH_FILEXFER_ATTR_PERMISSIONS=  0x00000004;
+  public static final int SSH_FILEXFER_ATTR_ACMODTIME=    0x00000008;
+  public static final int SSH_FILEXFER_ATTR_EXTENDED=     0x80000000;
+
+  static final int S_IFDIR=0x4000;
+  static final int S_IFLNK=0xa000;
+
+  int flags=0;
+  long size;
+  int uid;
+  int gid;
+  int permissions;
+  int atime;
+  int mtime;
+  String[] extended=null;
+
+  private SftpATTRS(){
+  }
+
+  static SftpATTRS getATTR(Buffer buf){
+    SftpATTRS attr=new SftpATTRS();    
+    attr.flags=buf.getInt();
+    if((attr.flags&SSH_FILEXFER_ATTR_SIZE)!=0){ attr.size=buf.getLong(); }
+    if((attr.flags&SSH_FILEXFER_ATTR_UIDGID)!=0){
+      attr.uid=buf.getInt(); attr.gid=buf.getInt();
+    }
+    if((attr.flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0){ 
+      attr.permissions=buf.getInt();
+    }
+    if((attr.flags&SSH_FILEXFER_ATTR_ACMODTIME)!=0){ 
+      attr.atime=buf.getInt();
+    }
+    if((attr.flags&SSH_FILEXFER_ATTR_ACMODTIME)!=0){ 
+      attr.mtime=buf.getInt(); 
+    }
+    if((attr.flags&SSH_FILEXFER_ATTR_EXTENDED)!=0){
+      int count=buf.getInt();
+      if(count>0){
+       attr.extended=new String[count*2];
+       for(int i=0; i<count; i++){
+         attr.extended[i*2]=Util.byte2str(buf.getString());
+         attr.extended[i*2+1]=Util.byte2str(buf.getString());
+       }
+      }
+    }
+    return attr;
+  } 
+
+  int length(){
+    int len=4;
+
+    if((flags&SSH_FILEXFER_ATTR_SIZE)!=0){ len+=8; }
+    if((flags&SSH_FILEXFER_ATTR_UIDGID)!=0){ len+=8; }
+    if((flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0){ len+=4; }
+    if((flags&SSH_FILEXFER_ATTR_ACMODTIME)!=0){ len+=8; }
+    if((flags&SSH_FILEXFER_ATTR_EXTENDED)!=0){
+      len+=4;
+      int count=extended.length/2;
+      if(count>0){
+       for(int i=0; i<count; i++){
+         len+=4; len+=extended[i*2].length();
+         len+=4; len+=extended[i*2+1].length();
+       }
+      }
+    }
+    return len;
+  }
+
+  void dump(Buffer buf){
+    buf.putInt(flags);
+    if((flags&SSH_FILEXFER_ATTR_SIZE)!=0){ buf.putLong(size); }
+    if((flags&SSH_FILEXFER_ATTR_UIDGID)!=0){
+      buf.putInt(uid); buf.putInt(gid);
+    }
+    if((flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0){ 
+      buf.putInt(permissions);
+    }
+    if((flags&SSH_FILEXFER_ATTR_ACMODTIME)!=0){ buf.putInt(atime); }
+    if((flags&SSH_FILEXFER_ATTR_ACMODTIME)!=0){ buf.putInt(mtime); }
+    if((flags&SSH_FILEXFER_ATTR_EXTENDED)!=0){
+      int count=extended.length/2;
+      if(count>0){
+       for(int i=0; i<count; i++){
+         buf.putString(Util.str2byte(extended[i*2]));
+         buf.putString(Util.str2byte(extended[i*2+1]));
+       }
+      }
+    }
+  }
+  void setFLAGS(int flags){
+    this.flags=flags;
+  }
+  public void setSIZE(long size){
+    flags|=SSH_FILEXFER_ATTR_SIZE;
+    this.size=size;
+  }
+  public void setUIDGID(int uid, int gid){
+    flags|=SSH_FILEXFER_ATTR_UIDGID;
+    this.uid=uid;
+    this.gid=gid;
+  }
+  public void setACMODTIME(int atime, int mtime){
+    flags|=SSH_FILEXFER_ATTR_ACMODTIME;
+    this.atime=atime;
+    this.mtime=mtime;
+  }
+  public void setPERMISSIONS(int permissions){
+    flags|=SSH_FILEXFER_ATTR_PERMISSIONS;
+    permissions=(this.permissions&~pmask)|(permissions&pmask);
+    this.permissions=permissions;
+  }
+
+  public boolean isDir(){
+    return ((flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0 && 
+           ((permissions&S_IFDIR)==S_IFDIR));
+  }      
+  public boolean isLink(){
+    return ((flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0 && 
+           ((permissions&S_IFLNK)==S_IFLNK));
+  }      
+  public int getFlags() { return flags; }
+  public long getSize() { return size; }
+  public int getUId() { return uid; }
+  public int getGId() { return gid; }
+  public int getPermissions() { return permissions; }
+  public int getATime() { return atime; }
+  public int getMTime() { return mtime; }
+  public String[] getExtended() { return extended; }
+
+  public String toString() {
+    return (getPermissionsString()+" "+getUId()+" "+getGId()+" "+getSize()+" "+getMtimeString());
+  }
+  /*
+  public String toString(){
+    return (((flags&SSH_FILEXFER_ATTR_SIZE)!=0) ? ("size:"+size+" ") : "")+
+           (((flags&SSH_FILEXFER_ATTR_UIDGID)!=0) ? ("uid:"+uid+",gid:"+gid+" ") : "")+
+           (((flags&SSH_FILEXFER_ATTR_PERMISSIONS)!=0) ? ("permissions:0x"+Integer.toHexString(permissions)+" ") : "")+
+           (((flags&SSH_FILEXFER_ATTR_ACMODTIME)!=0) ? ("atime:"+atime+",mtime:"+mtime+" ") : "")+
+           (((flags&SSH_FILEXFER_ATTR_EXTENDED)!=0) ? ("extended:?"+" ") : "");
+  }
+  */
+}
diff --git a/src/com/jcraft/jsch/SftpException.java b/src/com/jcraft/jsch/SftpException.java
new file mode 100644 (file)
index 0000000..8df0e5d
--- /dev/null
@@ -0,0 +1,51 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public class SftpException extends Exception{
+  //private static final long serialVersionUID=-5616888495583253811L;
+  public int id;
+  private Throwable cause=null;
+  public SftpException (int id, String message) {
+    super(message);
+    this.id=id;
+  }
+  public SftpException (int id, String message, Throwable e) {
+    super(message);
+    this.id=id;
+    this.cause=e;
+  }
+  public String toString(){
+    return id+": "+getMessage();
+  }
+  public Throwable getCause(){
+    return this.cause;
+  }
+}
diff --git a/src/com/jcraft/jsch/SftpProgressMonitor.java b/src/com/jcraft/jsch/SftpProgressMonitor.java
new file mode 100644 (file)
index 0000000..c4fa65b
--- /dev/null
@@ -0,0 +1,38 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface SftpProgressMonitor{
+  public static final int PUT=0;
+  public static final int GET=1;
+  void init(int op, String src, String dest, long max);
+  boolean count(long count);
+  void end();
+}
diff --git a/src/com/jcraft/jsch/SignatureDSA.java b/src/com/jcraft/jsch/SignatureDSA.java
new file mode 100644 (file)
index 0000000..f9068eb
--- /dev/null
@@ -0,0 +1,39 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface SignatureDSA{
+  void init() throws Exception;
+  void setPubKey(byte[] y, byte[] p, byte[] q, byte[] g) throws Exception;
+  void setPrvKey(byte[] x, byte[] p, byte[] q, byte[] g) throws Exception;
+  void update(byte[] H) throws Exception;
+  boolean verify(byte[] sig) throws Exception;
+  byte[] sign() throws Exception;
+}
diff --git a/src/com/jcraft/jsch/SignatureRSA.java b/src/com/jcraft/jsch/SignatureRSA.java
new file mode 100644 (file)
index 0000000..e1e8ed0
--- /dev/null
@@ -0,0 +1,39 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface SignatureRSA{
+  void init() throws Exception;
+  void setPubKey(byte[] e, byte[] n) throws Exception;
+  void setPrvKey(byte[] d, byte[] n) throws Exception;
+  void update(byte[] H) throws Exception;
+  boolean verify(byte[] sig) throws Exception;
+  byte[] sign() throws Exception;
+}
diff --git a/src/com/jcraft/jsch/SocketFactory.java b/src/com/jcraft/jsch/SocketFactory.java
new file mode 100644 (file)
index 0000000..70f922d
--- /dev/null
@@ -0,0 +1,40 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.net.*;
+import java.io.*;
+
+public interface SocketFactory{
+  public Socket createSocket(String host, int port)throws IOException,
+                                                         UnknownHostException;
+  public InputStream getInputStream(Socket socket)throws IOException;
+  public OutputStream getOutputStream(Socket socket)throws IOException;
+}
diff --git a/src/com/jcraft/jsch/UIKeyboardInteractive.java b/src/com/jcraft/jsch/UIKeyboardInteractive.java
new file mode 100644 (file)
index 0000000..6ff281d
--- /dev/null
@@ -0,0 +1,38 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface UIKeyboardInteractive{
+  String[] promptKeyboardInteractive(String destination,
+                                    String name,
+                                    String instruction,
+                                    String[] prompt,
+                                    boolean[] echo);
+}
diff --git a/src/com/jcraft/jsch/UserAuth.java b/src/com/jcraft/jsch/UserAuth.java
new file mode 100644 (file)
index 0000000..c9a990a
--- /dev/null
@@ -0,0 +1,53 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public abstract class UserAuth{
+  protected static final int SSH_MSG_USERAUTH_REQUEST=               50;
+  protected static final int SSH_MSG_USERAUTH_FAILURE=               51;
+  protected static final int SSH_MSG_USERAUTH_SUCCESS=               52;
+  protected static final int SSH_MSG_USERAUTH_BANNER=                53;
+  protected static final int SSH_MSG_USERAUTH_INFO_REQUEST=          60;
+  protected static final int SSH_MSG_USERAUTH_INFO_RESPONSE=         61;
+  protected static final int SSH_MSG_USERAUTH_PK_OK=                 60;
+
+  protected UserInfo userinfo;
+  protected Packet packet;
+  protected Buffer buf;
+  protected String username;
+
+  public boolean start(Session session) throws Exception{
+    this.userinfo=session.getUserInfo();
+    this.packet=session.packet;
+    this.buf=packet.getBuffer();
+    this.username=session.getUserName();
+    return true;
+  }
+}
diff --git a/src/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java b/src/com/jcraft/jsch/UserAuthGSSAPIWithMIC.java
new file mode 100644 (file)
index 0000000..6b20713
--- /dev/null
@@ -0,0 +1,227 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public class UserAuthGSSAPIWithMIC extends UserAuth {
+  private static final int SSH_MSG_USERAUTH_GSSAPI_RESPONSE=         60;
+  private static final int SSH_MSG_USERAUTH_GSSAPI_TOKEN=            61;
+  private static final int SSH_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE=63;
+  private static final int SSH_MSG_USERAUTH_GSSAPI_ERROR=            64;
+  private static final int SSH_MSG_USERAUTH_GSSAPI_ERRTOK=           65;
+  private static final int SSH_MSG_USERAUTH_GSSAPI_MIC=              66;
+
+  private static final byte[][] supported_oid={
+    // OID 1.2.840.113554.1.2.2 in DER
+    {(byte)0x6,(byte)0x9,(byte)0x2a,(byte)0x86,(byte)0x48,
+     (byte)0x86,(byte)0xf7,(byte)0x12,(byte)0x1,(byte)0x2,
+     (byte)0x2}
+  };
+
+  private static final String[] supported_method={
+    "gssapi-with-mic.krb5"
+  };
+
+  public boolean start(Session session)throws Exception{
+    super.start(session);
+
+    byte[] _username=Util.str2byte(username);
+
+    packet.reset();
+
+    // byte            SSH_MSG_USERAUTH_REQUEST(50)
+    // string          user name(in ISO-10646 UTF-8 encoding)
+    // string          service name(in US-ASCII)
+    // string          "gssapi"(US-ASCII)
+    // uint32          n, the number of OIDs client supports
+    // string[n]       mechanism OIDS
+    buf.putByte((byte)SSH_MSG_USERAUTH_REQUEST);
+    buf.putString(_username);
+    buf.putString(Util.str2byte("ssh-connection"));
+    buf.putString(Util.str2byte("gssapi-with-mic"));
+    buf.putInt(supported_oid.length);
+    for(int i=0; i<supported_oid.length; i++){
+      buf.putString(supported_oid[i]);
+    }
+    session.write(packet);
+
+    String method=null;
+    int command;
+    while(true){
+      buf=session.read(buf);
+      command=buf.getCommand()&0xff;
+
+      if(command==SSH_MSG_USERAUTH_FAILURE){
+        return false;
+      }
+      
+      if(command==SSH_MSG_USERAUTH_GSSAPI_RESPONSE){
+        buf.getInt(); buf.getByte(); buf.getByte();
+        byte[] message=buf.getString();
+
+        for(int i=0; i<supported_oid.length; i++){
+          if(Util.array_equals(message, supported_oid[i])){
+            method=supported_method[i];
+            break;
+          }
+        }
+
+        if(method==null){
+          return false;
+        }
+
+        break; // success
+      }
+
+      if(command==SSH_MSG_USERAUTH_BANNER){
+        buf.getInt(); buf.getByte(); buf.getByte();
+        byte[] _message=buf.getString();
+        byte[] lang=buf.getString();
+        String message=Util.byte2str(_message);
+        if(userinfo!=null){
+          userinfo.showMessage(message);
+        }
+        continue;
+      }
+      return false;
+    }
+
+    GSSContext context=null;
+    try{
+      Class c=Class.forName(session.getConfig(method));
+      context=(GSSContext)(c.newInstance());
+    }
+    catch(Exception e){ 
+      return false;
+    }
+
+    try{
+      context.create(username, session.host);
+    }
+    catch(JSchException e){
+      return false;
+    }
+
+    byte[] token=new byte[0];
+
+    while(!context.isEstablished()){
+      try{
+        token=context.init(token, 0, token.length);
+      }
+      catch(JSchException e){
+        // TODO
+        // ERRTOK should be sent?
+        // byte        SSH_MSG_USERAUTH_GSSAPI_ERRTOK
+        // string      error token
+        return false;
+      }
+
+      if(token!=null){
+        packet.reset();
+        buf.putByte((byte)SSH_MSG_USERAUTH_GSSAPI_TOKEN);
+        buf.putString(token);
+        session.write(packet);
+      }
+
+      if(!context.isEstablished()){
+        buf=session.read(buf);
+        command=buf.getCommand()&0xff;
+        if(command==SSH_MSG_USERAUTH_GSSAPI_ERROR){
+          // uint32    major_status
+          // uint32    minor_status
+          // string    message
+          // string    language tag
+
+          buf=session.read(buf);
+          command=buf.getCommand()&0xff;
+          //return false;
+        }
+        else if(command==SSH_MSG_USERAUTH_GSSAPI_ERRTOK){
+          // string error token
+
+          buf=session.read(buf);
+          command=buf.getCommand()&0xff;
+          //return false;
+        }
+
+        if(command==SSH_MSG_USERAUTH_FAILURE){
+          return false;
+        }
+
+        buf.getInt(); buf.getByte(); buf.getByte();
+        token=buf.getString();
+      }
+    }
+
+    Buffer mbuf=new Buffer();
+    // string    session identifier
+    // byte      SSH_MSG_USERAUTH_REQUEST
+    // string    user name
+    // string    service
+    // string    "gssapi-with-mic"
+    mbuf.putString(session.getSessionId());
+    mbuf.putByte((byte)SSH_MSG_USERAUTH_REQUEST);
+    mbuf.putString(_username);
+    mbuf.putString(Util.str2byte("ssh-connection"));
+    mbuf.putString(Util.str2byte("gssapi-with-mic"));
+
+    byte[] mic=context.getMIC(mbuf.buffer, 0, mbuf.getLength());
+
+    if(mic==null){
+      return false;
+    }
+
+    packet.reset();
+    buf.putByte((byte)SSH_MSG_USERAUTH_GSSAPI_MIC);
+    buf.putString(mic);
+    session.write(packet);
+
+    context.dispose();
+
+    buf=session.read(buf);
+    command=buf.getCommand()&0xff;
+
+    if(command==SSH_MSG_USERAUTH_SUCCESS){
+      return true;
+    }
+    else if(command==SSH_MSG_USERAUTH_FAILURE){
+      buf.getInt(); buf.getByte(); buf.getByte(); 
+      byte[] foo=buf.getString();
+      int partial_success=buf.getByte();
+      //System.err.println(new String(foo)+
+      //                " partial_success:"+(partial_success!=0));
+      if(partial_success!=0){
+        throw new JSchPartialAuthException(Util.byte2str(foo));
+      }
+    }
+    return false;
+  }
+}
+
+
diff --git a/src/com/jcraft/jsch/UserAuthKeyboardInteractive.java b/src/com/jcraft/jsch/UserAuthKeyboardInteractive.java
new file mode 100644 (file)
index 0000000..0334fb2
--- /dev/null
@@ -0,0 +1,197 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+class UserAuthKeyboardInteractive extends UserAuth{
+  public boolean start(Session session) throws Exception{
+    super.start(session);
+
+    if(userinfo!=null && !(userinfo instanceof UIKeyboardInteractive)){
+      return false;
+    }
+
+    String dest=username+"@"+session.host;
+    if(session.port!=22){
+      dest+=(":"+session.port);
+    }
+    byte[] password=session.password;
+
+    boolean cancel=false;
+
+    byte[] _username=null;
+    _username=Util.str2byte(username);
+
+    while(true){
+      // send
+      // byte      SSH_MSG_USERAUTH_REQUEST(50)
+      // string    user name (ISO-10646 UTF-8, as defined in [RFC-2279])
+      // string    service name (US-ASCII) "ssh-userauth" ? "ssh-connection"
+      // string    "keyboard-interactive" (US-ASCII)
+      // string    language tag (as defined in [RFC-3066])
+      // string    submethods (ISO-10646 UTF-8)
+      packet.reset();
+      buf.putByte((byte)SSH_MSG_USERAUTH_REQUEST);
+      buf.putString(_username);
+      buf.putString(Util.str2byte("ssh-connection"));
+      //buf.putString("ssh-userauth".getBytes());
+      buf.putString(Util.str2byte("keyboard-interactive"));
+      buf.putString(Util.empty);
+      buf.putString(Util.empty);
+      session.write(packet);
+
+      boolean firsttime=true;
+      loop:
+      while(true){
+        buf=session.read(buf);
+        int command=buf.getCommand()&0xff;
+
+       if(command==SSH_MSG_USERAUTH_SUCCESS){
+         return true;
+       }
+       if(command==SSH_MSG_USERAUTH_BANNER){
+         buf.getInt(); buf.getByte(); buf.getByte();
+         byte[] _message=buf.getString();
+         byte[] lang=buf.getString();
+         String message=Util.byte2str(_message);
+         if(userinfo!=null){
+           userinfo.showMessage(message);
+         }
+         continue loop;
+       }
+       if(command==SSH_MSG_USERAUTH_FAILURE){
+         buf.getInt(); buf.getByte(); buf.getByte(); 
+         byte[] foo=buf.getString();
+         int partial_success=buf.getByte();
+//       System.err.println(new String(foo)+
+//                          " partial_success:"+(partial_success!=0));
+
+         if(partial_success!=0){
+           throw new JSchPartialAuthException(Util.byte2str(foo));
+         }
+
+         if(firsttime){
+           return false;
+           //throw new JSchException("USERAUTH KI is not supported");
+           //cancel=true;  // ??
+         }
+         break;
+       }
+       if(command==SSH_MSG_USERAUTH_INFO_REQUEST){
+         firsttime=false;
+         buf.getInt(); buf.getByte(); buf.getByte();
+         String name=Util.byte2str(buf.getString());
+         String instruction=Util.byte2str(buf.getString());
+         String languate_tag=Util.byte2str(buf.getString());
+         int num=buf.getInt();
+         String[] prompt=new String[num];
+         boolean[] echo=new boolean[num];
+         for(int i=0; i<num; i++){
+           prompt[i]=Util.byte2str(buf.getString());
+           echo[i]=(buf.getByte()!=0);
+         }
+
+         byte[][] response=null;
+
+          if(password!=null && 
+             prompt.length==1 &&
+             !echo[0] &&
+             prompt[0].toLowerCase().startsWith("password:")){
+            response=new byte[1][];
+            response[0]=password;
+            password=null;
+          }
+          else if(num>0
+            ||(name.length()>0 || instruction.length()>0)
+            ){
+           if(userinfo!=null){
+              UIKeyboardInteractive kbi=(UIKeyboardInteractive)userinfo;
+              String[] _response=kbi.promptKeyboardInteractive(dest,
+                                                               name,
+                                                               instruction,
+                                                               prompt,
+                                                               echo);
+              if(_response!=null){
+                response=new byte[_response.length][];
+                for(int i=0; i<_response.length; i++){
+                  response[i]=Util.str2byte(_response[i]);
+                }
+              }
+           }
+         }
+
+         // byte      SSH_MSG_USERAUTH_INFO_RESPONSE(61)
+         // int       num-responses
+         // string    response[1] (ISO-10646 UTF-8)
+         // ...
+         // string    response[num-responses] (ISO-10646 UTF-8)
+         packet.reset();
+         buf.putByte((byte)SSH_MSG_USERAUTH_INFO_RESPONSE);
+         if(num>0 &&
+            (response==null ||  // cancel
+             num!=response.length)){
+
+            if(response==null){  
+              // working around the bug in OpenSSH ;-<
+              buf.putInt(num);
+              for(int i=0; i<num; i++){
+                buf.putString(Util.empty);
+              }
+            }
+            else{
+              buf.putInt(0);
+            }
+
+           if(response==null)
+             cancel=true;
+         }
+         else{
+           buf.putInt(num);
+           for(int i=0; i<num; i++){
+             buf.putString(response[i]);
+           }
+         }
+         session.write(packet);
+          /*
+         if(cancel)
+           break;
+          */
+         continue loop;
+       }
+       //throw new JSchException("USERAUTH fail ("+command+")");
+       return false;
+      }
+      if(cancel){
+       throw new JSchAuthCancelException("keyboard-interactive");
+       //break;
+      }
+    }
+    //return false;
+  }
+}
diff --git a/src/com/jcraft/jsch/UserAuthNone.java b/src/com/jcraft/jsch/UserAuthNone.java
new file mode 100644 (file)
index 0000000..c5cacd5
--- /dev/null
@@ -0,0 +1,129 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+class UserAuthNone extends UserAuth{
+  private static final int SSH_MSG_SERVICE_ACCEPT=                  6;
+  private String methods=null;
+
+  public boolean start(Session session) throws Exception{
+    super.start(session);
+
+
+    // send
+    // byte      SSH_MSG_SERVICE_REQUEST(5)
+    // string    service name "ssh-userauth"
+    packet.reset();
+    buf.putByte((byte)Session.SSH_MSG_SERVICE_REQUEST);
+    buf.putString(Util.str2byte("ssh-userauth"));
+    session.write(packet);
+
+    if(JSch.getLogger().isEnabled(Logger.INFO)){
+      JSch.getLogger().log(Logger.INFO, 
+                           "SSH_MSG_SERVICE_REQUEST sent");
+    }
+
+    // receive
+    // byte      SSH_MSG_SERVICE_ACCEPT(6)
+    // string    service name
+    buf=session.read(buf);
+    int command=buf.getCommand();
+
+    boolean result=(command==SSH_MSG_SERVICE_ACCEPT);
+
+    if(JSch.getLogger().isEnabled(Logger.INFO)){
+      JSch.getLogger().log(Logger.INFO, 
+                           "SSH_MSG_SERVICE_ACCEPT received");
+    }
+    if(!result)
+      return false;
+
+    byte[] _username=null;
+    _username=Util.str2byte(username);
+
+    // send
+    // byte      SSH_MSG_USERAUTH_REQUEST(50)
+    // string    user name
+    // string    service name ("ssh-connection")
+    // string    "none"
+    packet.reset();
+    buf.putByte((byte)SSH_MSG_USERAUTH_REQUEST);
+    buf.putString(_username);
+    buf.putString(Util.str2byte("ssh-connection"));
+    buf.putString(Util.str2byte("none"));
+    session.write(packet);
+
+    loop:
+    while(true){
+      buf=session.read(buf);
+      command=buf.getCommand()&0xff;
+
+      if(command==SSH_MSG_USERAUTH_SUCCESS){
+       return true;
+      }
+      if(command==SSH_MSG_USERAUTH_BANNER){
+       buf.getInt(); buf.getByte(); buf.getByte();
+       byte[] _message=buf.getString();
+       byte[] lang=buf.getString();
+       String message=Util.byte2str(_message);
+       if(userinfo!=null){
+          try{
+            userinfo.showMessage(message);
+          }
+          catch(RuntimeException ee){
+          }
+       }
+       continue loop;
+      }
+      if(command==SSH_MSG_USERAUTH_FAILURE){
+       buf.getInt(); buf.getByte(); buf.getByte(); 
+       byte[] foo=buf.getString();
+       int partial_success=buf.getByte();
+       methods=Util.byte2str(foo);
+//System.err.println("UserAuthNONE: "+methods+
+//                " partial_success:"+(partial_success!=0));
+//     if(partial_success!=0){
+//       throw new JSchPartialAuthException(new String(foo));
+//     }
+
+        break;
+      }
+      else{
+//      System.err.println("USERAUTH fail ("+command+")");
+       throw new JSchException("USERAUTH fail ("+command+")");
+      }
+    }
+   //throw new JSchException("USERAUTH fail");
+    return false;
+  }
+  String getMethods(){
+    return methods;
+  }
+}
diff --git a/src/com/jcraft/jsch/UserAuthPassword.java b/src/com/jcraft/jsch/UserAuthPassword.java
new file mode 100644 (file)
index 0000000..41b499a
--- /dev/null
@@ -0,0 +1,187 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+class UserAuthPassword extends UserAuth{
+  private final int SSH_MSG_USERAUTH_PASSWD_CHANGEREQ=60;
+
+  public boolean start(Session session) throws Exception{
+    super.start(session);
+
+    byte[] password=session.password;
+    String dest=username+"@"+session.host;
+    if(session.port!=22){
+      dest+=(":"+session.port);
+    }
+
+    try{
+
+    while(true){
+      if(password==null){
+       if(userinfo==null){
+         //throw new JSchException("USERAUTH fail");
+         return false;
+       }
+       if(!userinfo.promptPassword("Password for "+dest)){
+         throw new JSchAuthCancelException("password");
+         //break;
+       }
+
+       String _password=userinfo.getPassword();
+       if(_password==null){
+         throw new JSchAuthCancelException("password");
+         //break;
+       }
+        password=Util.str2byte(_password);
+      }
+
+      byte[] _username=null;
+      _username=Util.str2byte(username);
+
+      // send
+      // byte      SSH_MSG_USERAUTH_REQUEST(50)
+      // string    user name
+      // string    service name ("ssh-connection")
+      // string    "password"
+      // boolen    FALSE
+      // string    plaintext password (ISO-10646 UTF-8)
+      packet.reset();
+      buf.putByte((byte)SSH_MSG_USERAUTH_REQUEST);
+      buf.putString(_username);
+      buf.putString(Util.str2byte("ssh-connection"));
+      buf.putString(Util.str2byte("password"));
+      buf.putByte((byte)0);
+      buf.putString(password);
+      session.write(packet);
+
+      loop:
+      while(true){
+       buf=session.read(buf);
+        int command=buf.getCommand()&0xff;
+
+       if(command==SSH_MSG_USERAUTH_SUCCESS){
+         return true;
+       }
+       if(command==SSH_MSG_USERAUTH_BANNER){
+         buf.getInt(); buf.getByte(); buf.getByte();
+         byte[] _message=buf.getString();
+         byte[] lang=buf.getString();
+          String message=Util.byte2str(_message);
+         if(userinfo!=null){
+           userinfo.showMessage(message);
+         }
+         continue loop;
+       }
+       if(command==SSH_MSG_USERAUTH_PASSWD_CHANGEREQ){
+         buf.getInt(); buf.getByte(); buf.getByte(); 
+         byte[] instruction=buf.getString();
+         byte[] tag=buf.getString();
+         if(userinfo==null || 
+             !(userinfo instanceof UIKeyboardInteractive)){
+            if(userinfo!=null){
+              userinfo.showMessage("Password must be changed.");
+            }
+            return false;
+          }
+
+          UIKeyboardInteractive kbi=(UIKeyboardInteractive)userinfo;
+          String[] response;
+          String name="Password Change Required";
+          String[] prompt={"New Password: "};
+          boolean[] echo={false};
+          response=kbi.promptKeyboardInteractive(dest,
+                                                 name,
+                                                 Util.byte2str(instruction),
+                                                 prompt,
+                                                 echo);
+          if(response==null){
+            throw new JSchAuthCancelException("password");
+          }
+
+          byte[] newpassword=Util.str2byte(response[0]);
+
+          // send
+          // byte      SSH_MSG_USERAUTH_REQUEST(50)
+          // string    user name
+          // string    service name ("ssh-connection")
+          // string    "password"
+          // boolen    TRUE
+          // string    plaintext old password (ISO-10646 UTF-8)
+          // string    plaintext new password (ISO-10646 UTF-8)
+          packet.reset();
+          buf.putByte((byte)SSH_MSG_USERAUTH_REQUEST);
+          buf.putString(_username);
+          buf.putString(Util.str2byte("ssh-connection"));
+          buf.putString(Util.str2byte("password"));
+          buf.putByte((byte)1);
+          buf.putString(password);
+          buf.putString(newpassword);
+          Util.bzero(newpassword);
+          response=null;
+          session.write(packet);
+         continue loop;
+        }
+       if(command==SSH_MSG_USERAUTH_FAILURE){
+         buf.getInt(); buf.getByte(); buf.getByte(); 
+         byte[] foo=buf.getString();
+         int partial_success=buf.getByte();
+         //System.err.println(new String(foo)+
+         //             " partial_success:"+(partial_success!=0));
+         if(partial_success!=0){
+           throw new JSchPartialAuthException(Util.byte2str(foo));
+         }
+         break;
+       }
+       else{
+          //System.err.println("USERAUTH fail ("+buf.getCommand()+")");
+//       throw new JSchException("USERAUTH fail ("+buf.getCommand()+")");
+         return false;
+       }
+      }
+
+      if(password!=null){
+        Util.bzero(password);
+        password=null;
+      }
+
+    }
+
+    }
+    finally{
+      if(password!=null){
+        Util.bzero(password);
+        password=null;
+      }
+    }
+
+    //throw new JSchException("USERAUTH fail");
+    //return false;
+  }
+}
diff --git a/src/com/jcraft/jsch/UserAuthPublicKey.java b/src/com/jcraft/jsch/UserAuthPublicKey.java
new file mode 100644 (file)
index 0000000..b5866ab
--- /dev/null
@@ -0,0 +1,222 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+import java.util.Vector;
+
+class UserAuthPublicKey extends UserAuth{
+
+  public boolean start(Session session) throws Exception{
+    super.start(session);
+
+    Vector identities=session.jsch.identities;
+
+    byte[] passphrase=null;
+    byte[] _username=null;
+
+    int command;
+
+    synchronized(identities){
+      if(identities.size()<=0){
+        return false;
+      }
+
+      _username=Util.str2byte(username);
+
+      for(int i=0; i<identities.size(); i++){
+        Identity identity=(Identity)(identities.elementAt(i));
+        byte[] pubkeyblob=identity.getPublicKeyBlob();
+
+//System.err.println("UserAuthPublicKey: "+identity+" "+pubkeyblob);
+
+        if(pubkeyblob!=null){
+          // send
+          // byte      SSH_MSG_USERAUTH_REQUEST(50)
+          // string    user name
+          // string    service name ("ssh-connection")
+          // string    "publickey"
+          // boolen    FALSE
+          // string    plaintext password (ISO-10646 UTF-8)
+          packet.reset();
+          buf.putByte((byte)SSH_MSG_USERAUTH_REQUEST);
+          buf.putString(_username);
+          buf.putString(Util.str2byte("ssh-connection"));
+          buf.putString(Util.str2byte("publickey"));
+          buf.putByte((byte)0);
+          buf.putString(Util.str2byte(identity.getAlgName()));
+          buf.putString(pubkeyblob);
+          session.write(packet);
+
+          loop1:
+          while(true){
+            buf=session.read(buf);
+            command=buf.getCommand()&0xff;
+
+            if(command==SSH_MSG_USERAUTH_PK_OK){
+              break;
+            }
+            else if(command==SSH_MSG_USERAUTH_FAILURE){
+              break;
+            }
+            else if(command==SSH_MSG_USERAUTH_BANNER){
+              buf.getInt(); buf.getByte(); buf.getByte();
+              byte[] _message=buf.getString();
+              byte[] lang=buf.getString();
+              String message=Util.byte2str(_message);
+              if(userinfo!=null){
+                userinfo.showMessage(message);
+              }
+              continue loop1;
+            }
+            else{
+           //System.err.println("USERAUTH fail ("+command+")");
+           //throw new JSchException("USERAUTH fail ("+command+")");
+              break;
+            }
+          }
+
+          if(command!=SSH_MSG_USERAUTH_PK_OK){
+            continue;
+          }
+        }
+
+//System.err.println("UserAuthPublicKey: identity.isEncrypted()="+identity.isEncrypted());
+
+        int count=5;
+        while(true){
+          if((identity.isEncrypted() && passphrase==null)){
+            if(userinfo==null) throw new JSchException("USERAUTH fail");
+            if(identity.isEncrypted() &&
+               !userinfo.promptPassphrase("Passphrase for "+identity.getName())){
+              throw new JSchAuthCancelException("publickey");
+              //throw new JSchException("USERAUTH cancel");
+              //break;
+            }
+            String _passphrase=userinfo.getPassphrase();
+            if(_passphrase!=null){
+              passphrase=Util.str2byte(_passphrase);
+            }
+          }
+
+          if(!identity.isEncrypted() || passphrase!=null){
+            if(identity.setPassphrase(passphrase))
+              break;
+          }
+          Util.bzero(passphrase);
+          passphrase=null;
+          count--;
+          if(count==0)break;
+        }
+
+        Util.bzero(passphrase);
+        passphrase=null;
+//System.err.println("UserAuthPublicKey: identity.isEncrypted()="+identity.isEncrypted());
+
+        if(identity.isEncrypted()) continue;
+        if(pubkeyblob==null) pubkeyblob=identity.getPublicKeyBlob();
+
+//System.err.println("UserAuthPublicKey: pubkeyblob="+pubkeyblob);
+
+        if(pubkeyblob==null) continue;
+
+      // send
+      // byte      SSH_MSG_USERAUTH_REQUEST(50)
+      // string    user name
+      // string    service name ("ssh-connection")
+      // string    "publickey"
+      // boolen    TRUE
+      // string    plaintext password (ISO-10646 UTF-8)
+        packet.reset();
+        buf.putByte((byte)SSH_MSG_USERAUTH_REQUEST);
+        buf.putString(_username);
+        buf.putString(Util.str2byte("ssh-connection"));
+        buf.putString(Util.str2byte("publickey"));
+        buf.putByte((byte)1);
+        buf.putString(Util.str2byte(identity.getAlgName()));
+        buf.putString(pubkeyblob);
+
+//      byte[] tmp=new byte[buf.index-5];
+//      System.arraycopy(buf.buffer, 5, tmp, 0, tmp.length);
+//      buf.putString(signature);
+
+        byte[] sid=session.getSessionId();
+        int sidlen=sid.length;
+        byte[] tmp=new byte[4+sidlen+buf.index-5];
+        tmp[0]=(byte)(sidlen>>>24);
+        tmp[1]=(byte)(sidlen>>>16);
+        tmp[2]=(byte)(sidlen>>>8);
+        tmp[3]=(byte)(sidlen);
+        System.arraycopy(sid, 0, tmp, 4, sidlen);
+        System.arraycopy(buf.buffer, 5, tmp, 4+sidlen, buf.index-5);
+        byte[] signature=identity.getSignature(tmp);
+        if(signature==null){  // for example, too long key length.
+          break;
+        }
+        buf.putString(signature);
+        session.write(packet);
+
+        loop2:
+        while(true){
+          buf=session.read(buf);
+          command=buf.getCommand()&0xff;
+
+          if(command==SSH_MSG_USERAUTH_SUCCESS){
+            return true;
+          }
+          else if(command==SSH_MSG_USERAUTH_BANNER){
+            buf.getInt(); buf.getByte(); buf.getByte();
+            byte[] _message=buf.getString();
+            byte[] lang=buf.getString();
+            String message=Util.byte2str(_message);
+            if(userinfo!=null){
+              userinfo.showMessage(message);
+            }
+            continue loop2;
+          }
+          else if(command==SSH_MSG_USERAUTH_FAILURE){
+            buf.getInt(); buf.getByte(); buf.getByte(); 
+            byte[] foo=buf.getString();
+            int partial_success=buf.getByte();
+         //System.err.println(new String(foo)+
+         //                   " partial_success:"+(partial_success!=0));
+            if(partial_success!=0){
+              throw new JSchPartialAuthException(Util.byte2str(foo));
+            }
+            break;
+          }
+          //System.err.println("USERAUTH fail ("+command+")");
+          //throw new JSchException("USERAUTH fail ("+command+")");
+          break;
+        }
+      }
+    }
+    return false;
+  }
+}
diff --git a/src/com/jcraft/jsch/UserInfo.java b/src/com/jcraft/jsch/UserInfo.java
new file mode 100644 (file)
index 0000000..6939f22
--- /dev/null
@@ -0,0 +1,39 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+
+public interface UserInfo{
+  String getPassphrase();
+  String getPassword();
+  boolean promptPassword(String message);
+  boolean promptPassphrase(String message);
+  boolean promptYesNo(String message);
+  void showMessage(String message);
+}
diff --git a/src/com/jcraft/jsch/Util.java b/src/com/jcraft/jsch/Util.java
new file mode 100644 (file)
index 0000000..6b8170d
--- /dev/null
@@ -0,0 +1,474 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch;
+import java.net.Socket;
+
+class Util{
+
+  private static final byte[] b64 =Util.str2byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=");
+  private static byte val(byte foo){
+    if(foo == '=') return 0;
+    for(int j=0; j<b64.length; j++){
+      if(foo==b64[j]) return (byte)j;
+    }
+    return 0;
+  }
+  static byte[] fromBase64(byte[] buf, int start, int length){
+    byte[] foo=new byte[length];
+    int j=0;
+    for (int i=start;i<start+length;i+=4){
+      foo[j]=(byte)((val(buf[i])<<2)|((val(buf[i+1])&0x30)>>>4));
+      if(buf[i+2]==(byte)'='){ j++; break;}
+      foo[j+1]=(byte)(((val(buf[i+1])&0x0f)<<4)|((val(buf[i+2])&0x3c)>>>2));
+      if(buf[i+3]==(byte)'='){ j+=2; break;}
+      foo[j+2]=(byte)(((val(buf[i+2])&0x03)<<6)|(val(buf[i+3])&0x3f));
+      j+=3;
+    }
+    byte[] bar=new byte[j];
+    System.arraycopy(foo, 0, bar, 0, j);
+    return bar;
+  }
+  static byte[] toBase64(byte[] buf, int start, int length){
+
+    byte[] tmp=new byte[length*2];
+    int i,j,k;
+    
+    int foo=(length/3)*3+start;
+    i=0;
+    for(j=start; j<foo; j+=3){
+      k=(buf[j]>>>2)&0x3f;
+      tmp[i++]=b64[k];
+      k=(buf[j]&0x03)<<4|(buf[j+1]>>>4)&0x0f;
+      tmp[i++]=b64[k];
+      k=(buf[j+1]&0x0f)<<2|(buf[j+2]>>>6)&0x03;
+      tmp[i++]=b64[k];
+      k=buf[j+2]&0x3f;
+      tmp[i++]=b64[k];
+    }
+
+    foo=(start+length)-foo;
+    if(foo==1){
+      k=(buf[j]>>>2)&0x3f;
+      tmp[i++]=b64[k];
+      k=((buf[j]&0x03)<<4)&0x3f;
+      tmp[i++]=b64[k];
+      tmp[i++]=(byte)'=';
+      tmp[i++]=(byte)'=';
+    }
+    else if(foo==2){
+      k=(buf[j]>>>2)&0x3f;
+      tmp[i++]=b64[k];
+      k=(buf[j]&0x03)<<4|(buf[j+1]>>>4)&0x0f;
+      tmp[i++]=b64[k];
+      k=((buf[j+1]&0x0f)<<2)&0x3f;
+      tmp[i++]=b64[k];
+      tmp[i++]=(byte)'=';
+    }
+    byte[] bar=new byte[i];
+    System.arraycopy(tmp, 0, bar, 0, i);
+    return bar;
+
+//    return sun.misc.BASE64Encoder().encode(buf);
+  }
+
+  static String[] split(String foo, String split){
+    if(foo==null)
+      return null;
+    byte[] buf=Util.str2byte(foo);
+    java.util.Vector bar=new java.util.Vector();
+    int start=0;
+    int index;
+    while(true){
+      index=foo.indexOf(split, start);
+      if(index>=0){
+       bar.addElement(Util.byte2str(buf, start, index-start));
+       start=index+1;
+       continue;
+      }
+      bar.addElement(Util.byte2str(buf, start, buf.length-start));
+      break;
+    }
+    String[] result=new String[bar.size()];
+    for(int i=0; i<result.length; i++){
+      result[i]=(String)(bar.elementAt(i));
+    }
+    return result;
+  }
+  static boolean glob(byte[] pattern, byte[] name){
+    return glob0(pattern, 0, name, 0);
+  }
+  static private boolean glob0(byte[] pattern, int pattern_index,
+                             byte[] name, int name_index){
+    if(name.length>0 && name[0]=='.'){
+      if(pattern.length>0 && pattern[0]=='.'){
+        if(pattern.length==2 && pattern[1]=='*') return true;
+        return glob(pattern, pattern_index+1, name, name_index+1);
+      }
+      return false;
+    }
+    return glob(pattern, pattern_index, name, name_index);
+  }
+  static private boolean glob(byte[] pattern, int pattern_index,
+                             byte[] name, int name_index){
+    //System.err.println("glob: "+new String(pattern)+", "+pattern_index+" "+new String(name)+", "+name_index);
+
+    int patternlen=pattern.length;
+    if(patternlen==0)
+      return false;
+
+    int namelen=name.length;
+    int i=pattern_index;
+    int j=name_index;
+
+    while(i<patternlen && j<namelen){
+      if(pattern[i]=='\\'){
+       if(i+1==patternlen)
+         return false;
+       i++;
+       if(pattern[i]!=name[j]) 
+          return false;
+        i+=skipUTF8Char(pattern[i]);
+        j+=skipUTF8Char(name[j]);
+       continue;
+      }
+
+      if(pattern[i]=='*'){
+        while(i<patternlen){
+          if(pattern[i]=='*'){
+            i++;
+            continue;
+          }
+          break;
+        }
+       if(patternlen==i)
+          return true;
+
+       byte foo=pattern[i];
+        if(foo=='?'){
+          while(j<namelen){
+           if(glob(pattern, i, name, j)){
+             return true;
+            }
+            j+=skipUTF8Char(name[j]);
+          }
+          return false;
+        }
+        else if(foo=='\\'){
+          if(i+1==patternlen)
+            return false;
+          i++;
+          foo=pattern[i];
+          while(j<namelen){
+            if(foo==name[j]){
+              if(glob(pattern, i+skipUTF8Char(foo),
+                      name, j+skipUTF8Char(name[j]))){
+                return true;
+              }
+            }
+            j+=skipUTF8Char(name[j]);
+          }
+          return false;
+        }
+
+       while(j<namelen){
+         if(foo==name[j]){
+           if(glob(pattern, i, name, j)){
+             return true;
+           }
+         }
+          j+=skipUTF8Char(name[j]);
+       }
+       return false;
+      }
+
+      if(pattern[i]=='?'){
+        i++;
+        j+=skipUTF8Char(name[j]);
+       continue;
+      }
+
+      if(pattern[i]!=name[j])
+        return false;
+
+      i+=skipUTF8Char(pattern[i]);
+      j+=skipUTF8Char(name[j]);
+
+      if(!(j<namelen)){         // name is end
+        if(!(i<patternlen)){    // pattern is end
+         return true;
+       }
+       if(pattern[i]=='*'){    
+          break;
+       }
+      }
+      continue;
+    }
+
+    if(i==patternlen && j==namelen) 
+      return true;
+
+    if(!(j<namelen) &&  // name is end
+       pattern[i]=='*'){
+      boolean ok=true;
+      while(i<patternlen){
+        if(pattern[i++]!='*'){
+          ok=false;
+          break;
+        }
+      }
+      return ok;
+    }
+
+    return false;
+  }
+
+  static String quote(String path){
+    byte[] _path=str2byte(path);
+    int count=0;
+    for(int i=0;i<_path.length; i++){
+      byte b=_path[i];
+      if(b=='\\' || b=='?' || b=='*')
+        count++;
+    }
+    if(count==0)
+      return path;
+    byte[] _path2=new byte[_path.length+count];
+    for(int i=0, j=0; i<_path.length; i++){
+      byte b=_path[i];
+      if(b=='\\' || b=='?' || b=='*'){
+        _path2[j++]='\\';
+      }
+      _path2[j++]=b;
+    }
+    return byte2str(_path2);
+  }
+
+  static String unquote(String path){
+    byte[] foo=str2byte(path);
+    byte[] bar=unquote(foo);
+    if(foo.length==bar.length)
+      return path;
+    return byte2str(bar);
+  }
+  static byte[] unquote(byte[] path){
+    int pathlen=path.length;
+    int i=0;
+    while(i<pathlen){
+      if(path[i]=='\\'){
+        if(i+1==pathlen)
+          break;
+        System.arraycopy(path, i+1, path, i, path.length-(i+1));
+        pathlen--;
+        i++;
+        continue;
+      }
+      i++;
+    }
+    if(pathlen==path.length)
+      return path;
+    byte[] foo=new byte[pathlen];
+    System.arraycopy(path, 0, foo, 0, pathlen);
+    return foo;
+  }
+
+  private static String[] chars={
+    "0","1","2","3","4","5","6","7","8","9", "a","b","c","d","e","f"
+  };
+  static String getFingerPrint(HASH hash, byte[] data){
+    try{
+      hash.init();
+      hash.update(data, 0, data.length);
+      byte[] foo=hash.digest();
+      StringBuffer sb=new StringBuffer();
+      int bar;
+      for(int i=0; i<foo.length;i++){
+        bar=foo[i]&0xff;
+        sb.append(chars[(bar>>>4)&0xf]);
+        sb.append(chars[(bar)&0xf]);
+        if(i+1<foo.length)
+          sb.append(":");
+      }
+      return sb.toString();
+    }
+    catch(Exception e){
+      return "???";
+    }
+  }
+  static boolean array_equals(byte[] foo, byte bar[]){
+    int i=foo.length;
+    if(i!=bar.length) return false;
+    for(int j=0; j<i; j++){ if(foo[j]!=bar[j]) return false; }
+    //try{while(true){i--; if(foo[i]!=bar[i])return false;}}catch(Exception e){}
+    return true;
+  }
+  static Socket createSocket(String host, int port, int timeout) throws JSchException{
+    Socket socket=null;
+    if(timeout==0){
+      try{
+        socket=new Socket(host, port);
+        return socket;
+      }
+      catch(Exception e){
+        String message=e.toString();
+        if(e instanceof Throwable)
+          throw new JSchException(message, (Throwable)e);
+        throw new JSchException(message);
+      }
+    }
+    final String _host=host;
+    final int _port=port;
+    final Socket[] sockp=new Socket[1];
+    final Exception[] ee=new Exception[1];
+    String message="";
+    Thread tmp=new Thread(new Runnable(){
+        public void run(){
+          sockp[0]=null;
+          try{
+            sockp[0]=new Socket(_host, _port);
+          }
+          catch(Exception e){
+            ee[0]=e;
+            if(sockp[0]!=null && sockp[0].isConnected()){
+              try{
+                sockp[0].close();
+              }
+              catch(Exception eee){}
+            }
+            sockp[0]=null;
+          }
+        }
+      });
+    tmp.setName("Opening Socket "+host);
+    tmp.start();
+    try{ 
+      tmp.join(timeout);
+      message="timeout: ";
+    }
+    catch(java.lang.InterruptedException eee){
+    }
+    if(sockp[0]!=null && sockp[0].isConnected()){
+      socket=sockp[0];
+    }
+    else{
+      message+="socket is not established";
+      if(ee[0]!=null){
+        message=ee[0].toString();
+      }
+      tmp.interrupt();
+      tmp=null;
+      throw new JSchException(message);
+    }
+    return socket;
+  } 
+
+  static byte[] str2byte(String str, String encoding){
+    if(str==null) 
+      return null;
+    try{ return str.getBytes(encoding); }
+    catch(java.io.UnsupportedEncodingException e){
+      return str.getBytes();
+    }
+  }
+
+  static byte[] str2byte(String str){
+    return str2byte(str, "UTF-8");
+  }
+
+  static String byte2str(byte[] str, String encoding){
+    return byte2str(str, 0, str.length, encoding);
+  }
+
+  static String byte2str(byte[] str, int s, int l, String encoding){
+    try{ return new String(str, s, l, encoding); }
+    catch(java.io.UnsupportedEncodingException e){
+      return new String(str, s, l);
+    }
+  }
+
+  static String byte2str(byte[] str){
+    return byte2str(str, 0, str.length, "UTF-8");
+  }
+
+  static String byte2str(byte[] str, int s, int l){
+    return byte2str(str, s, l, "UTF-8");
+  }
+
+  static final byte[] empty = str2byte("");
+
+  /*
+  static byte[] char2byte(char[] foo){
+    int len=0;
+    for(int i=0; i<foo.length; i++){
+      if((foo[i]&0xff00)==0) len++;
+      else len+=2;
+    }
+    byte[] bar=new byte[len];
+    for(int i=0, j=0; i<foo.length; i++){
+      if((foo[i]&0xff00)==0){
+        bar[j++]=(byte)foo[i];
+      }
+      else{
+        bar[j++]=(byte)(foo[i]>>>8);
+        bar[j++]=(byte)foo[i];
+      }
+    }
+    return bar;
+  }
+  */
+  static void bzero(byte[] foo){
+    if(foo==null)
+      return;
+    for(int i=0; i<foo.length; i++)
+      foo[i]=0;
+  }
+
+  static String diffString(String str, String[] not_available){
+    String[] stra=Util.split(str, ",");
+    String result=null;
+    loop:
+    for(int i=0; i<stra.length; i++){
+      for(int j=0; j<not_available.length; j++){
+        if(stra[i].equals(not_available[j])){
+          continue loop;
+        }
+      }
+      if(result==null){ result=stra[i]; }
+      else{ result=result+","+stra[i]; }
+    }
+    return result;
+  }
+
+  private static int skipUTF8Char(byte b){
+    if((byte)(b&0x80)==0) return 1;
+    if((byte)(b&0xe0)==(byte)0xc0) return 2;
+    if((byte)(b&0xf0)==(byte)0xe0) return 3;
+    return 1;
+  }
+}
diff --git a/src/com/jcraft/jsch/jce/AES128CBC.java b/src/com/jcraft/jsch/jce/AES128CBC.java
new file mode 100644 (file)
index 0000000..d894a7c
--- /dev/null
@@ -0,0 +1,73 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2005-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.Cipher;
+import javax.crypto.spec.*;
+
+public class AES128CBC implements Cipher{
+  private static final int ivsize=16;
+  private static final int bsize=16;
+  private javax.crypto.Cipher cipher;    
+  public int getIVSize(){return ivsize;} 
+  public int getBlockSize(){return bsize;}
+  public void init(int mode, byte[] key, byte[] iv) throws Exception{
+    String pad="NoPadding";      
+    byte[] tmp;
+    if(iv.length>ivsize){
+      tmp=new byte[ivsize];
+      System.arraycopy(iv, 0, tmp, 0, tmp.length);
+      iv=tmp;
+    }
+    if(key.length>bsize){
+      tmp=new byte[bsize];
+      System.arraycopy(key, 0, tmp, 0, tmp.length);
+      key=tmp;
+    }
+
+    try{
+      SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
+      cipher=javax.crypto.Cipher.getInstance("AES/CBC/"+pad);
+      cipher.init((mode==ENCRYPT_MODE?
+                   javax.crypto.Cipher.ENCRYPT_MODE:
+                   javax.crypto.Cipher.DECRYPT_MODE),
+                  keyspec, new IvParameterSpec(iv));
+    }
+    catch(Exception e){
+      cipher=null;
+      throw e;
+    }
+  }
+  public void update(byte[] foo, int s1, int len, byte[] bar, int s2) throws Exception{
+    cipher.update(foo, s1, len, bar, s2);
+  }
+
+  public boolean isCBC(){return true; }
+}
diff --git a/src/com/jcraft/jsch/jce/AES128CTR.java b/src/com/jcraft/jsch/jce/AES128CTR.java
new file mode 100644 (file)
index 0000000..55c8715
--- /dev/null
@@ -0,0 +1,73 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2008-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.Cipher;
+import javax.crypto.spec.*;
+
+public class AES128CTR implements Cipher{
+  private static final int ivsize=16;
+  private static final int bsize=16;
+  private javax.crypto.Cipher cipher;    
+  public int getIVSize(){return ivsize;} 
+  public int getBlockSize(){return bsize;}
+  public void init(int mode, byte[] key, byte[] iv) throws Exception{
+    String pad="NoPadding";      
+    byte[] tmp;
+    if(iv.length>ivsize){
+      tmp=new byte[ivsize];
+      System.arraycopy(iv, 0, tmp, 0, tmp.length);
+      iv=tmp;
+    }
+    if(key.length>bsize){
+      tmp=new byte[bsize];
+      System.arraycopy(key, 0, tmp, 0, tmp.length);
+      key=tmp;
+    }
+
+    try{
+      SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
+      cipher=javax.crypto.Cipher.getInstance("AES/CTR/"+pad);
+      cipher.init((mode==ENCRYPT_MODE?
+                   javax.crypto.Cipher.ENCRYPT_MODE:
+                   javax.crypto.Cipher.DECRYPT_MODE),
+                  keyspec, new IvParameterSpec(iv));
+    }
+    catch(Exception e){
+      cipher=null;
+      throw e;
+    }
+  }
+  public void update(byte[] foo, int s1, int len, byte[] bar, int s2) throws Exception{
+    cipher.update(foo, s1, len, bar, s2);
+  }
+
+  public boolean isCBC(){return false; }
+}
diff --git a/src/com/jcraft/jsch/jce/AES192CBC.java b/src/com/jcraft/jsch/jce/AES192CBC.java
new file mode 100644 (file)
index 0000000..850d207
--- /dev/null
@@ -0,0 +1,71 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2005-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.Cipher;
+import javax.crypto.spec.*;
+
+public class AES192CBC implements Cipher{
+  private static final int ivsize=16;
+  private static final int bsize=24;
+  private javax.crypto.Cipher cipher;    
+  public int getIVSize(){return ivsize;} 
+  public int getBlockSize(){return bsize;}
+  public void init(int mode, byte[] key, byte[] iv) throws Exception{
+    String pad="NoPadding";      
+    byte[] tmp;
+    if(iv.length>ivsize){
+      tmp=new byte[ivsize];
+      System.arraycopy(iv, 0, tmp, 0, tmp.length);
+      iv=tmp;
+    }
+    if(key.length>bsize){
+      tmp=new byte[bsize];
+      System.arraycopy(key, 0, tmp, 0, tmp.length);
+      key=tmp;
+    }
+    try{
+      SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
+      cipher=javax.crypto.Cipher.getInstance("AES/CBC/"+pad);
+      cipher.init((mode==ENCRYPT_MODE?
+                   javax.crypto.Cipher.ENCRYPT_MODE:
+                   javax.crypto.Cipher.DECRYPT_MODE),
+                  keyspec, new IvParameterSpec(iv));
+    }
+    catch(Exception e){
+      cipher=null;
+      throw e;
+    }
+  }
+  public void update(byte[] foo, int s1, int len, byte[] bar, int s2) throws Exception{
+    cipher.update(foo, s1, len, bar, s2);
+  }
+  public boolean isCBC(){return true; }
+}
diff --git a/src/com/jcraft/jsch/jce/AES192CTR.java b/src/com/jcraft/jsch/jce/AES192CTR.java
new file mode 100644 (file)
index 0000000..fe7a310
--- /dev/null
@@ -0,0 +1,71 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2008-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.Cipher;
+import javax.crypto.spec.*;
+
+public class AES192CTR implements Cipher{
+  private static final int ivsize=16;
+  private static final int bsize=24;
+  private javax.crypto.Cipher cipher;    
+  public int getIVSize(){return ivsize;} 
+  public int getBlockSize(){return bsize;}
+  public void init(int mode, byte[] key, byte[] iv) throws Exception{
+    String pad="NoPadding";      
+    byte[] tmp;
+    if(iv.length>ivsize){
+      tmp=new byte[ivsize];
+      System.arraycopy(iv, 0, tmp, 0, tmp.length);
+      iv=tmp;
+    }
+    if(key.length>bsize){
+      tmp=new byte[bsize];
+      System.arraycopy(key, 0, tmp, 0, tmp.length);
+      key=tmp;
+    }
+    try{
+      SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
+      cipher=javax.crypto.Cipher.getInstance("AES/CTR/"+pad);
+      cipher.init((mode==ENCRYPT_MODE?
+                   javax.crypto.Cipher.ENCRYPT_MODE:
+                   javax.crypto.Cipher.DECRYPT_MODE),
+                  keyspec, new IvParameterSpec(iv));
+    }
+    catch(Exception e){
+      cipher=null;
+      throw e;
+    }
+  }
+  public void update(byte[] foo, int s1, int len, byte[] bar, int s2) throws Exception{
+    cipher.update(foo, s1, len, bar, s2);
+  }
+  public boolean isCBC(){return false; }
+}
diff --git a/src/com/jcraft/jsch/jce/AES256CBC.java b/src/com/jcraft/jsch/jce/AES256CBC.java
new file mode 100644 (file)
index 0000000..559b41e
--- /dev/null
@@ -0,0 +1,71 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2005-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.Cipher;
+import javax.crypto.spec.*;
+
+public class AES256CBC implements Cipher{
+  private static final int ivsize=16;
+  private static final int bsize=32;
+  private javax.crypto.Cipher cipher;    
+  public int getIVSize(){return ivsize;} 
+  public int getBlockSize(){return bsize;}
+  public void init(int mode, byte[] key, byte[] iv) throws Exception{
+    String pad="NoPadding";      
+    byte[] tmp;
+    if(iv.length>ivsize){
+      tmp=new byte[ivsize];
+      System.arraycopy(iv, 0, tmp, 0, tmp.length);
+      iv=tmp;
+    }
+    if(key.length>bsize){
+      tmp=new byte[bsize];
+      System.arraycopy(key, 0, tmp, 0, tmp.length);
+      key=tmp;
+    }
+    try{
+      SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
+      cipher=javax.crypto.Cipher.getInstance("AES/CBC/"+pad);
+      cipher.init((mode==ENCRYPT_MODE?
+                   javax.crypto.Cipher.ENCRYPT_MODE:
+                   javax.crypto.Cipher.DECRYPT_MODE),
+                  keyspec, new IvParameterSpec(iv));
+    }
+    catch(Exception e){
+      cipher=null;
+      throw e;
+    }
+  }
+  public void update(byte[] foo, int s1, int len, byte[] bar, int s2) throws Exception{
+    cipher.update(foo, s1, len, bar, s2);
+  }
+  public boolean isCBC(){return true; }
+}
diff --git a/src/com/jcraft/jsch/jce/AES256CTR.java b/src/com/jcraft/jsch/jce/AES256CTR.java
new file mode 100644 (file)
index 0000000..5ff963e
--- /dev/null
@@ -0,0 +1,71 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2008-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.Cipher;
+import javax.crypto.spec.*;
+
+public class AES256CTR implements Cipher{
+  private static final int ivsize=16;
+  private static final int bsize=32;
+  private javax.crypto.Cipher cipher;    
+  public int getIVSize(){return ivsize;} 
+  public int getBlockSize(){return bsize;}
+  public void init(int mode, byte[] key, byte[] iv) throws Exception{
+    String pad="NoPadding";      
+    byte[] tmp;
+    if(iv.length>ivsize){
+      tmp=new byte[ivsize];
+      System.arraycopy(iv, 0, tmp, 0, tmp.length);
+      iv=tmp;
+    }
+    if(key.length>bsize){
+      tmp=new byte[bsize];
+      System.arraycopy(key, 0, tmp, 0, tmp.length);
+      key=tmp;
+    }
+    try{
+      SecretKeySpec keyspec=new SecretKeySpec(key, "AES");
+      cipher=javax.crypto.Cipher.getInstance("AES/CTR/"+pad);
+      cipher.init((mode==ENCRYPT_MODE?
+                   javax.crypto.Cipher.ENCRYPT_MODE:
+                   javax.crypto.Cipher.DECRYPT_MODE),
+                  keyspec, new IvParameterSpec(iv));
+    }
+    catch(Exception e){
+      cipher=null;
+      throw e;
+    }
+  }
+  public void update(byte[] foo, int s1, int len, byte[] bar, int s2) throws Exception{
+    cipher.update(foo, s1, len, bar, s2);
+  }
+  public boolean isCBC(){return false; }
+}
diff --git a/src/com/jcraft/jsch/jce/ARCFOUR.java b/src/com/jcraft/jsch/jce/ARCFOUR.java
new file mode 100644 (file)
index 0000000..8f465f2
--- /dev/null
@@ -0,0 +1,68 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2008-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.Cipher;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class ARCFOUR implements Cipher{
+  private static final int ivsize=8;
+  private static final int bsize=16;
+  private javax.crypto.Cipher cipher;    
+  public int getIVSize(){return ivsize;} 
+  public int getBlockSize(){return bsize;}
+  public void init(int mode, byte[] key, byte[] iv) throws Exception{
+    String pad="NoPadding";      
+    byte[] tmp;
+    if(key.length>bsize){
+      tmp=new byte[bsize];
+      System.arraycopy(key, 0, tmp, 0, tmp.length);
+      key=tmp;
+    }
+
+    try{
+      cipher=javax.crypto.Cipher.getInstance("RC4");
+      SecretKeySpec _key = new SecretKeySpec(key, "RC4");
+      cipher.init((mode==ENCRYPT_MODE?
+                  javax.crypto.Cipher.ENCRYPT_MODE:
+                  javax.crypto.Cipher.DECRYPT_MODE),
+                 _key);
+    }
+    catch(Exception e){
+      cipher=null;
+      throw e;
+    }
+  }
+  public void update(byte[] foo, int s1, int len, byte[] bar, int s2) throws Exception{
+    cipher.update(foo, s1, len, bar, s2);
+  }
+  public boolean isCBC(){return false; }
+}
diff --git a/src/com/jcraft/jsch/jce/ARCFOUR128.java b/src/com/jcraft/jsch/jce/ARCFOUR128.java
new file mode 100644 (file)
index 0000000..501ab35
--- /dev/null
@@ -0,0 +1,71 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2008-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.Cipher;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class ARCFOUR128 implements Cipher{
+  private static final int ivsize=8;
+  private static final int bsize=16;
+  private static final int skip=1536; 
+  private javax.crypto.Cipher cipher;    
+  public int getIVSize(){return ivsize;} 
+  public int getBlockSize(){return bsize;}
+  public void init(int mode, byte[] key, byte[] iv) throws Exception{
+    byte[] tmp;
+    if(key.length>bsize){
+      tmp=new byte[bsize];
+      System.arraycopy(key, 0, tmp, 0, tmp.length);
+      key=tmp;
+    }
+    try{
+      cipher=javax.crypto.Cipher.getInstance("RC4");
+      SecretKeySpec _key = new SecretKeySpec(key, "RC4");
+      cipher.init((mode==ENCRYPT_MODE?
+                  javax.crypto.Cipher.ENCRYPT_MODE:
+                  javax.crypto.Cipher.DECRYPT_MODE),
+                 _key);
+      byte[] foo=new byte[1];
+      for(int i=0; i<skip; i++){
+        cipher.update(foo, 0, 1, foo, 0);
+      }
+    }
+    catch(Exception e){
+      cipher=null;
+      throw e;
+    }
+  }
+  public void update(byte[] foo, int s1, int len, byte[] bar, int s2) throws Exception{
+    cipher.update(foo, s1, len, bar, s2);
+  }
+  public boolean isCBC(){return false; }
+}
diff --git a/src/com/jcraft/jsch/jce/ARCFOUR256.java b/src/com/jcraft/jsch/jce/ARCFOUR256.java
new file mode 100644 (file)
index 0000000..c6bc6bc
--- /dev/null
@@ -0,0 +1,71 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2008-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.Cipher;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class ARCFOUR256 implements Cipher{
+  private static final int ivsize=8;
+  private static final int bsize=32;
+  private static final int skip=1536; 
+  private javax.crypto.Cipher cipher;    
+  public int getIVSize(){return ivsize;} 
+  public int getBlockSize(){return bsize;}
+  public void init(int mode, byte[] key, byte[] iv) throws Exception{
+    byte[] tmp;
+    if(key.length>bsize){
+      tmp=new byte[bsize];
+      System.arraycopy(key, 0, tmp, 0, tmp.length);
+      key=tmp;
+    }
+    try{
+      cipher=javax.crypto.Cipher.getInstance("RC4");
+      SecretKeySpec _key = new SecretKeySpec(key, "RC4");
+      cipher.init((mode==ENCRYPT_MODE?
+                  javax.crypto.Cipher.ENCRYPT_MODE:
+                  javax.crypto.Cipher.DECRYPT_MODE),
+                 _key);
+      byte[] foo=new byte[1];
+      for(int i=0; i<skip; i++){
+        cipher.update(foo, 0, 1, foo, 0);
+      }
+    }
+    catch(Exception e){
+      cipher=null;
+      throw e;
+    }
+  }
+  public void update(byte[] foo, int s1, int len, byte[] bar, int s2) throws Exception{
+    cipher.update(foo, s1, len, bar, s2);
+  }
+  public boolean isCBC(){return false; }
+}
diff --git a/src/com/jcraft/jsch/jce/BlowfishCBC.java b/src/com/jcraft/jsch/jce/BlowfishCBC.java
new file mode 100644 (file)
index 0000000..50fc271
--- /dev/null
@@ -0,0 +1,71 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.Cipher;
+import javax.crypto.spec.*;
+
+public class BlowfishCBC implements Cipher{
+  private static final int ivsize=8;
+  private static final int bsize=16;
+  private javax.crypto.Cipher cipher;    
+  public int getIVSize(){return ivsize;} 
+  public int getBlockSize(){return bsize;}
+  public void init(int mode, byte[] key, byte[] iv) throws Exception{
+    String pad="NoPadding";      
+//  if(padding) pad="PKCS5Padding";
+    byte[] tmp;
+    if(iv.length>ivsize){
+      tmp=new byte[ivsize];
+      System.arraycopy(iv, 0, tmp, 0, tmp.length);
+      iv=tmp;
+    }
+    if(key.length>bsize){
+      tmp=new byte[bsize];
+      System.arraycopy(key, 0, tmp, 0, tmp.length);
+      key=tmp;
+    }
+    try{
+      SecretKeySpec skeySpec = new SecretKeySpec(key, "Blowfish");
+      cipher=javax.crypto.Cipher.getInstance("Blowfish/CBC/"+pad);
+      cipher.init((mode==ENCRYPT_MODE?
+                  javax.crypto.Cipher.ENCRYPT_MODE:
+                  javax.crypto.Cipher.DECRYPT_MODE),
+                 skeySpec, new IvParameterSpec(iv));
+    }
+    catch(Exception e){
+      throw e;
+    }
+  }
+  public void update(byte[] foo, int s1, int len, byte[] bar, int s2) throws Exception{
+    cipher.update(foo, s1, len, bar, s2);
+  }
+  public boolean isCBC(){return true; }
+}
diff --git a/src/com/jcraft/jsch/jce/DH.java b/src/com/jcraft/jsch/jce/DH.java
new file mode 100644 (file)
index 0000000..19cddd8
--- /dev/null
@@ -0,0 +1,91 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import java.math.BigInteger;
+import java.security.*;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class DH implements com.jcraft.jsch.DH{
+  BigInteger p;
+  BigInteger g;
+  BigInteger e;  // my public key
+  byte[] e_array;
+  BigInteger f;  // your public key
+  BigInteger K;  // shared secret key
+  byte[] K_array;
+
+  private KeyPairGenerator myKpairGen;
+  private KeyAgreement myKeyAgree;
+  public void init() throws Exception{
+    myKpairGen=KeyPairGenerator.getInstance("DH");
+//    myKpairGen=KeyPairGenerator.getInstance("DiffieHellman");
+    myKeyAgree=KeyAgreement.getInstance("DH");
+//    myKeyAgree=KeyAgreement.getInstance("DiffieHellman");
+  }
+  public byte[] getE() throws Exception{
+    if(e==null){
+      DHParameterSpec dhSkipParamSpec=new DHParameterSpec(p, g);
+      myKpairGen.initialize(dhSkipParamSpec);
+      KeyPair myKpair=myKpairGen.generateKeyPair();
+      myKeyAgree.init(myKpair.getPrivate());
+//    BigInteger x=((javax.crypto.interfaces.DHPrivateKey)(myKpair.getPrivate())).getX();
+      byte[] myPubKeyEnc=myKpair.getPublic().getEncoded();
+      e=((javax.crypto.interfaces.DHPublicKey)(myKpair.getPublic())).getY();
+      e_array=e.toByteArray();
+    }
+    return e_array;
+  }
+  public byte[] getK() throws Exception{
+    if(K==null){
+      KeyFactory myKeyFac=KeyFactory.getInstance("DH");
+      DHPublicKeySpec keySpec=new DHPublicKeySpec(f, p, g);
+      PublicKey yourPubKey=myKeyFac.generatePublic(keySpec);
+      myKeyAgree.doPhase(yourPubKey, true);
+      byte[] mySharedSecret=myKeyAgree.generateSecret();
+      K=new BigInteger(mySharedSecret);
+      K_array=K.toByteArray();
+
+//System.err.println("K.signum(): "+K.signum()+
+//                " "+Integer.toHexString(mySharedSecret[0]&0xff)+
+//                " "+Integer.toHexString(K_array[0]&0xff));
+
+      K_array=mySharedSecret;
+    }
+    return K_array;
+  }
+  public void setP(byte[] p){ setP(new BigInteger(p)); }
+  public void setG(byte[] g){ setG(new BigInteger(g)); }
+  public void setF(byte[] f){ setF(new BigInteger(f)); }
+  void setP(BigInteger p){this.p=p;}
+  void setG(BigInteger g){this.g=g;}
+  void setF(BigInteger f){this.f=f;}
+}
diff --git a/src/com/jcraft/jsch/jce/HMACMD5.java b/src/com/jcraft/jsch/jce/HMACMD5.java
new file mode 100644 (file)
index 0000000..77a1542
--- /dev/null
@@ -0,0 +1,75 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.MAC;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class HMACMD5 implements MAC{
+  private static final String name="hmac-md5";
+  private static final int BSIZE=16;
+  private Mac mac;
+  public int getBlockSize(){return BSIZE;};
+  public void init(byte[] key) throws Exception{
+    if(key.length>BSIZE){
+      byte[] tmp=new byte[BSIZE];
+      System.arraycopy(key, 0, tmp, 0, BSIZE);   
+      key=tmp;
+    }
+
+    SecretKeySpec skey=new SecretKeySpec(key, "HmacMD5");
+    mac=Mac.getInstance("HmacMD5");
+    mac.init(skey);
+  } 
+
+  private final byte[] tmp=new byte[4];
+  public void update(int i){
+    tmp[0]=(byte)(i>>>24);
+    tmp[1]=(byte)(i>>>16);
+    tmp[2]=(byte)(i>>>8);
+    tmp[3]=(byte)i;
+    update(tmp, 0, 4);
+  }
+  public void update(byte foo[], int s, int l){
+    mac.update(foo, s, l);      
+  }
+  public void doFinal(byte[] buf, int offset){
+    try{
+      mac.doFinal(buf, offset);
+    }
+    catch(ShortBufferException e){
+    }
+  }
+
+  public String getName(){
+    return name;
+  }
+}
diff --git a/src/com/jcraft/jsch/jce/HMACMD596.java b/src/com/jcraft/jsch/jce/HMACMD596.java
new file mode 100644 (file)
index 0000000..a31a82b
--- /dev/null
@@ -0,0 +1,77 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.MAC;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class HMACMD596 implements MAC{
+  private static final String name="hmac-md5-96";
+  private static final int bsize=12;
+  private Mac mac;
+  public int getBlockSize(){return bsize;};
+  public void init(byte[] key) throws Exception{
+    if(key.length>16){
+      byte[] tmp=new byte[16];
+      System.arraycopy(key, 0, tmp, 0, 16);      
+      key=tmp;
+    }
+    SecretKeySpec skey=new SecretKeySpec(key, "HmacMD5");
+    mac=Mac.getInstance("HmacMD5");
+    mac.init(skey);
+  } 
+  private final byte[] tmp=new byte[4];
+  public void update(int i){
+    tmp[0]=(byte)(i>>>24);
+    tmp[1]=(byte)(i>>>16);
+    tmp[2]=(byte)(i>>>8);
+    tmp[3]=(byte)i;
+    update(tmp, 0, 4);
+  }
+
+  public void update(byte foo[], int s, int l){
+    mac.update(foo, s, l);      
+  }
+
+  private final byte[] _buf16=new byte[16];
+  public void doFinal(byte[] buf, int offset){
+    try{
+      mac.doFinal(_buf16, 0);
+    }
+    catch(ShortBufferException e){
+    }
+    System.arraycopy(_buf16, 0, buf, 0, 12);
+  }
+
+  public String getName(){
+    return name;
+  }
+}
diff --git a/src/com/jcraft/jsch/jce/HMACSHA1.java b/src/com/jcraft/jsch/jce/HMACSHA1.java
new file mode 100644 (file)
index 0000000..9b80bb6
--- /dev/null
@@ -0,0 +1,75 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.MAC;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class HMACSHA1 implements MAC{
+  private static final String name="hmac-sha1";
+  private static final int bsize=20;
+  private Mac mac;
+  public int getBlockSize(){return bsize;};
+  public void init(byte[] key) throws Exception{
+    if(key.length>bsize){
+      byte[] tmp=new byte[bsize];
+      System.arraycopy(key, 0, tmp, 0, bsize);   
+      key=tmp;
+    }
+    SecretKeySpec skey=new SecretKeySpec(key, "HmacSHA1");
+    mac=Mac.getInstance("HmacSHA1");
+    mac.init(skey);
+  } 
+  private final byte[] tmp=new byte[4];
+  public void update(int i){
+    tmp[0]=(byte)(i>>>24);
+    tmp[1]=(byte)(i>>>16);
+    tmp[2]=(byte)(i>>>8);
+    tmp[3]=(byte)i;
+    update(tmp, 0, 4);
+  }
+
+  public void update(byte foo[], int s, int l){
+    mac.update(foo, s, l);      
+  }
+
+  public void doFinal(byte[] buf, int offset){
+    try{
+      mac.doFinal(buf, offset);
+    }
+    catch(ShortBufferException e){
+    }
+  }
+
+  public String getName(){
+    return name;
+  }
+}
diff --git a/src/com/jcraft/jsch/jce/HMACSHA196.java b/src/com/jcraft/jsch/jce/HMACSHA196.java
new file mode 100644 (file)
index 0000000..641b788
--- /dev/null
@@ -0,0 +1,76 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.MAC;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class HMACSHA196 implements MAC{
+  private static final String name="hmac-sha1-96";
+  private static final int bsize=12;
+  private Mac mac;
+  public int getBlockSize(){return bsize;};
+  public void init(byte[] key) throws Exception{
+    if(key.length>20){
+      byte[] tmp=new byte[20];
+      System.arraycopy(key, 0, tmp, 0, 20);      
+      key=tmp;
+    }
+    SecretKeySpec skey=new SecretKeySpec(key, "HmacSHA1");
+    mac=Mac.getInstance("HmacSHA1");
+    mac.init(skey);
+  } 
+  private final byte[] tmp=new byte[4];
+  public void update(int i){
+    tmp[0]=(byte)(i>>>24);
+    tmp[1]=(byte)(i>>>16);
+    tmp[2]=(byte)(i>>>8);
+    tmp[3]=(byte)i;
+    update(tmp, 0, 4);
+  }
+  public void update(byte foo[], int s, int l){
+    mac.update(foo, s, l);      
+  }
+
+  private final byte[] _buf20=new byte[20];
+  public void doFinal(byte[] buf, int offset){
+    try{
+      mac.doFinal(_buf20, 0);
+    }
+    catch(ShortBufferException e){
+    }
+    System.arraycopy(_buf20, 0, buf, 0, 12);
+  }
+
+  public String getName(){
+    return name;
+  }
+}
diff --git a/src/com/jcraft/jsch/jce/KeyPairGenDSA.java b/src/com/jcraft/jsch/jce/KeyPairGenDSA.java
new file mode 100644 (file)
index 0000000..79e11c6
--- /dev/null
@@ -0,0 +1,62 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import java.security.*;
+import java.security.interfaces.*;
+
+public class KeyPairGenDSA implements com.jcraft.jsch.KeyPairGenDSA{
+  byte[] x;  // private
+  byte[] y;  // public
+  byte[] p;
+  byte[] q;
+  byte[] g;
+
+  public void init(int key_size) throws Exception{
+    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
+    keyGen.initialize(key_size, new SecureRandom());
+    KeyPair pair = keyGen.generateKeyPair();
+    PublicKey pubKey=pair.getPublic();
+    PrivateKey prvKey=pair.getPrivate();
+
+    x=((DSAPrivateKey)prvKey).getX().toByteArray();
+    y=((DSAPublicKey)pubKey).getY().toByteArray();
+
+    DSAParams params=((DSAKey)prvKey).getParams();
+    p=params.getP().toByteArray();
+    q=params.getQ().toByteArray();
+    g=params.getG().toByteArray();
+  }
+  public byte[] getX(){return x;}
+  public byte[] getY(){return y;}
+  public byte[] getP(){return p;}
+  public byte[] getQ(){return q;}
+  public byte[] getG(){return g;}
+}
diff --git a/src/com/jcraft/jsch/jce/KeyPairGenRSA.java b/src/com/jcraft/jsch/jce/KeyPairGenRSA.java
new file mode 100644 (file)
index 0000000..aff5ed5
--- /dev/null
@@ -0,0 +1,72 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import java.security.*;
+import java.security.interfaces.*;
+
+public class KeyPairGenRSA implements com.jcraft.jsch.KeyPairGenRSA{
+  byte[] d;  // private
+  byte[] e;  // public
+  byte[] n;
+
+  byte[] c; //  coefficient
+  byte[] ep; // exponent p
+  byte[] eq; // exponent q
+  byte[] p;  // prime p
+  byte[] q;  // prime q
+
+  public void init(int key_size) throws Exception{
+    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+    keyGen.initialize(key_size, new SecureRandom());
+    KeyPair pair = keyGen.generateKeyPair();
+
+    PublicKey pubKey=pair.getPublic();
+    PrivateKey prvKey=pair.getPrivate();
+
+    d=((RSAPrivateKey)prvKey).getPrivateExponent().toByteArray();
+    e=((RSAPublicKey)pubKey).getPublicExponent().toByteArray();
+    n=((RSAPrivateKey)prvKey).getModulus().toByteArray();
+
+    c=((RSAPrivateCrtKey)prvKey).getCrtCoefficient().toByteArray();
+    ep=((RSAPrivateCrtKey)prvKey).getPrimeExponentP().toByteArray();
+    eq=((RSAPrivateCrtKey)prvKey).getPrimeExponentQ().toByteArray();
+    p=((RSAPrivateCrtKey)prvKey).getPrimeP().toByteArray();
+    q=((RSAPrivateCrtKey)prvKey).getPrimeQ().toByteArray();
+  }
+  public byte[] getD(){return d;}
+  public byte[] getE(){return e;}
+  public byte[] getN(){return n;}
+  public byte[] getC(){return c;}
+  public byte[] getEP(){return ep;}
+  public byte[] getEQ(){return eq;}
+  public byte[] getP(){return p;}
+  public byte[] getQ(){return q;}
+}
diff --git a/src/com/jcraft/jsch/jce/MD5.java b/src/com/jcraft/jsch/jce/MD5.java
new file mode 100644 (file)
index 0000000..f19c72b
--- /dev/null
@@ -0,0 +1,51 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.HASH;
+
+import java.security.*;
+
+public class MD5 implements HASH{
+  MessageDigest md;
+  public int getBlockSize(){return 16;}
+  public void init() throws Exception{
+    try{ md=MessageDigest.getInstance("MD5"); }
+    catch(Exception e){
+      System.err.println(e);
+    }
+  }
+  public void update(byte[] foo, int start, int len) throws Exception{
+    md.update(foo, start, len);
+  }
+  public byte[] digest() throws Exception{
+    return md.digest();
+  }
+}
diff --git a/src/com/jcraft/jsch/jce/Random.java b/src/com/jcraft/jsch/jce/Random.java
new file mode 100644 (file)
index 0000000..e7eda20
--- /dev/null
@@ -0,0 +1,81 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import java.security.SecureRandom;
+
+public class Random implements com.jcraft.jsch.Random{
+  private byte[] tmp=new byte[16];
+  private SecureRandom random=null;
+  public Random(){
+
+    // We hope that 'new SecureRandom()' will use NativePRNG algorithm
+    // on Sun's Java5 for GNU/Linux and Solaris.
+    // It seems NativePRNG refers to /dev/urandom and it must not be blocked,
+    // but NativePRNG is slower than SHA1PRNG ;-<
+    // TIPS: By adding option '-Djava.security.egd=file:/dev/./urandom'
+    //       SHA1PRNG will be used instead of NativePRNG.
+    // On MacOSX, 'new SecureRandom()' will use NativePRNG algorithm and
+    // it is also slower than SHA1PRNG.
+    // On Windows, 'new SecureRandom()' will use SHA1PRNG algorithm.
+    random=new SecureRandom();
+
+    /*
+    try{ 
+      random=SecureRandom.getInstance("SHA1PRNG"); 
+      return;
+    }
+    catch(java.security.NoSuchAlgorithmException e){ 
+      // System.err.println(e); 
+    }
+
+    // The following code is for IBM's JCE
+    try{ 
+      random=SecureRandom.getInstance("IBMSecureRandom"); 
+      return;
+    }
+    catch(java.security.NoSuchAlgorithmException ee){ 
+      //System.err.println(ee); 
+    }
+    */
+  }
+  public void fill(byte[] foo, int start, int len){
+    /*
+    // This case will not become true in our usage.
+    if(start==0 && foo.length==len){
+      random.nextBytes(foo);
+      return;
+    }
+    */
+    if(len>tmp.length){ tmp=new byte[len]; }
+    random.nextBytes(tmp);
+    System.arraycopy(tmp, 0, foo, start, len);
+  }
+}
diff --git a/src/com/jcraft/jsch/jce/SHA1.java b/src/com/jcraft/jsch/jce/SHA1.java
new file mode 100644 (file)
index 0000000..b1c571a
--- /dev/null
@@ -0,0 +1,51 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.HASH;
+
+import java.security.*;
+
+public class SHA1 implements HASH{
+  MessageDigest md;
+  public int getBlockSize(){return 20;}
+  public void init() throws Exception{
+    try{ md=MessageDigest.getInstance("SHA-1"); }
+    catch(Exception e){
+      System.err.println(e);
+    }
+  }
+  public void update(byte[] foo, int start, int len) throws Exception{
+    md.update(foo, start, len);
+  }
+  public byte[] digest() throws Exception{
+    return md.digest();
+  }
+}
diff --git a/src/com/jcraft/jsch/jce/SignatureDSA.java b/src/com/jcraft/jsch/jce/SignatureDSA.java
new file mode 100644 (file)
index 0000000..b33fb9b
--- /dev/null
@@ -0,0 +1,147 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import java.math.BigInteger;
+import java.security.*;
+import java.security.spec.*;
+
+public class SignatureDSA implements com.jcraft.jsch.SignatureDSA{
+
+  java.security.Signature signature;
+  KeyFactory keyFactory;
+
+  public void init() throws Exception{
+    signature=java.security.Signature.getInstance("SHA1withDSA");
+    keyFactory=KeyFactory.getInstance("DSA");
+  }     
+  public void setPubKey(byte[] y, byte[] p, byte[] q, byte[] g) throws Exception{
+    DSAPublicKeySpec dsaPubKeySpec = 
+       new DSAPublicKeySpec(new BigInteger(y),
+                            new BigInteger(p),
+                            new BigInteger(q),
+                            new BigInteger(g));
+    PublicKey pubKey=keyFactory.generatePublic(dsaPubKeySpec);
+    signature.initVerify(pubKey);
+  }
+  public void setPrvKey(byte[] x, byte[] p, byte[] q, byte[] g) throws Exception{
+    DSAPrivateKeySpec dsaPrivKeySpec = 
+       new DSAPrivateKeySpec(new BigInteger(x),
+                             new BigInteger(p),
+                             new BigInteger(q),
+                             new BigInteger(g));
+    PrivateKey prvKey = keyFactory.generatePrivate(dsaPrivKeySpec);
+    signature.initSign(prvKey);
+  }
+  public byte[] sign() throws Exception{
+    byte[] sig=signature.sign();      
+/*
+System.err.print("sign["+sig.length+"] ");
+for(int i=0; i<sig.length;i++){
+System.err.print(Integer.toHexString(sig[i]&0xff)+":");
+}
+System.err.println("");
+*/
+    // sig is in ASN.1
+    // SEQUENCE::={ r INTEGER, s INTEGER }
+    int len=0; 
+    int index=3;
+    len=sig[index++]&0xff;
+//System.err.println("! len="+len);
+    byte[] r=new byte[len];
+    System.arraycopy(sig, index, r, 0, r.length);
+    index=index+len+1;
+    len=sig[index++]&0xff;
+//System.err.println("!! len="+len);
+    byte[] s=new byte[len];
+    System.arraycopy(sig, index, s, 0, s.length);
+
+    byte[] result=new byte[40];
+
+    // result must be 40 bytes, but length of r and s may not be 20 bytes  
+
+    System.arraycopy(r, (r.length>20)?1:0,
+                    result, (r.length>20)?0:20-r.length,
+                    (r.length>20)?20:r.length);
+    System.arraycopy(s, (s.length>20)?1:0,
+                    result, (s.length>20)?20:40-s.length,
+                    (s.length>20)?20:s.length);
+//  System.arraycopy(sig, (sig[3]==20?4:5), result, 0, 20);
+//  System.arraycopy(sig, sig.length-20, result, 20, 20);
+
+    return result;
+  }
+  public void update(byte[] foo) throws Exception{
+   signature.update(foo);
+  }
+  public boolean verify(byte[] sig) throws Exception{
+    int i=0;
+    int j=0;
+    byte[] tmp;
+
+    if(sig[0]==0 && sig[1]==0 && sig[2]==0){
+    j=((sig[i++]<<24)&0xff000000)|((sig[i++]<<16)&0x00ff0000)|
+       ((sig[i++]<<8)&0x0000ff00)|((sig[i++])&0x000000ff);
+    i+=j;
+    j=((sig[i++]<<24)&0xff000000)|((sig[i++]<<16)&0x00ff0000)|
+       ((sig[i++]<<8)&0x0000ff00)|((sig[i++])&0x000000ff);
+    tmp=new byte[j]; 
+    System.arraycopy(sig, i, tmp, 0, j); sig=tmp;
+    }
+
+    // ASN.1
+    int frst=((sig[0]&0x80)!=0?1:0);
+    int scnd=((sig[20]&0x80)!=0?1:0);
+    //System.err.println("frst: "+frst+", scnd: "+scnd);
+
+    int length=sig.length+6+frst+scnd;
+    tmp=new byte[length];
+    tmp[0]=(byte)0x30; tmp[1]=(byte)0x2c; 
+    tmp[1]+=frst; tmp[1]+=scnd;
+    tmp[2]=(byte)0x02; tmp[3]=(byte)0x14;
+    tmp[3]+=frst;
+    System.arraycopy(sig, 0, tmp, 4+frst, 20);
+    tmp[4+tmp[3]]=(byte)0x02; tmp[5+tmp[3]]=(byte)0x14;
+    tmp[5+tmp[3]]+=scnd;
+    System.arraycopy(sig, 20, tmp, 6+tmp[3]+scnd, 20);
+    sig=tmp;
+
+/*
+    tmp=new byte[sig.length+6];
+    tmp[0]=(byte)0x30; tmp[1]=(byte)0x2c; 
+    tmp[2]=(byte)0x02; tmp[3]=(byte)0x14;
+    System.arraycopy(sig, 0, tmp, 4, 20);
+    tmp[24]=(byte)0x02; tmp[25]=(byte)0x14;
+    System.arraycopy(sig, 20, tmp, 26, 20); sig=tmp;
+*/  
+    return signature.verify(sig);
+  }
+}
diff --git a/src/com/jcraft/jsch/jce/SignatureRSA.java b/src/com/jcraft/jsch/jce/SignatureRSA.java
new file mode 100644 (file)
index 0000000..1e344b9
--- /dev/null
@@ -0,0 +1,83 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import java.math.BigInteger;
+import java.security.*;
+import java.security.spec.*;
+
+public class SignatureRSA implements com.jcraft.jsch.SignatureRSA{
+
+  java.security.Signature signature;
+  KeyFactory keyFactory;
+
+  public void init() throws Exception{
+    signature=java.security.Signature.getInstance("SHA1withRSA");
+    keyFactory=KeyFactory.getInstance("RSA");
+  }     
+  public void setPubKey(byte[] e, byte[] n) throws Exception{
+    RSAPublicKeySpec rsaPubKeySpec = 
+       new RSAPublicKeySpec(new BigInteger(n),
+                            new BigInteger(e));
+    PublicKey pubKey=keyFactory.generatePublic(rsaPubKeySpec);
+    signature.initVerify(pubKey);
+  }
+  public void setPrvKey(byte[] d, byte[] n) throws Exception{
+    RSAPrivateKeySpec rsaPrivKeySpec = 
+       new RSAPrivateKeySpec(new BigInteger(n),
+                             new BigInteger(d));
+    PrivateKey prvKey = keyFactory.generatePrivate(rsaPrivKeySpec);
+    signature.initSign(prvKey);
+  }
+  public byte[] sign() throws Exception{
+    byte[] sig=signature.sign();      
+    return sig;
+  }
+  public void update(byte[] foo) throws Exception{
+   signature.update(foo);
+  }
+  public boolean verify(byte[] sig) throws Exception{
+    int i=0;
+    int j=0;
+    byte[] tmp;
+
+    if(sig[0]==0 && sig[1]==0 && sig[2]==0){
+    j=((sig[i++]<<24)&0xff000000)|((sig[i++]<<16)&0x00ff0000)|
+       ((sig[i++]<<8)&0x0000ff00)|((sig[i++])&0x000000ff);
+    i+=j;
+    j=((sig[i++]<<24)&0xff000000)|((sig[i++]<<16)&0x00ff0000)|
+       ((sig[i++]<<8)&0x0000ff00)|((sig[i++])&0x000000ff);
+    tmp=new byte[j]; 
+    System.arraycopy(sig, i, tmp, 0, j); sig=tmp;
+    }
+//System.err.println("j="+j+" "+Integer.toHexString(sig[0]&0xff));
+    return signature.verify(sig);
+  }
+}
diff --git a/src/com/jcraft/jsch/jce/TripleDESCBC.java b/src/com/jcraft/jsch/jce/TripleDESCBC.java
new file mode 100644 (file)
index 0000000..a5ada9c
--- /dev/null
@@ -0,0 +1,84 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.Cipher;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class TripleDESCBC implements Cipher{
+  private static final int ivsize=8;
+  private static final int bsize=24;
+  private javax.crypto.Cipher cipher;    
+  public int getIVSize(){return ivsize;} 
+  public int getBlockSize(){return bsize;}
+  public void init(int mode, byte[] key, byte[] iv) throws Exception{
+    String pad="NoPadding";      
+    //if(padding) pad="PKCS5Padding";
+    byte[] tmp;
+    if(iv.length>ivsize){
+      tmp=new byte[ivsize];
+      System.arraycopy(iv, 0, tmp, 0, tmp.length);
+      iv=tmp;
+    }
+    if(key.length>bsize){
+      tmp=new byte[bsize];
+      System.arraycopy(key, 0, tmp, 0, tmp.length);
+      key=tmp;
+    }
+
+    try{
+      cipher=javax.crypto.Cipher.getInstance("DESede/CBC/"+pad);
+/*
+      // The following code does not work on IBM's JDK 1.4.1
+      SecretKeySpec skeySpec = new SecretKeySpec(key, "DESede");
+      cipher.init((mode==ENCRYPT_MODE?
+                  javax.crypto.Cipher.ENCRYPT_MODE:
+                  javax.crypto.Cipher.DECRYPT_MODE),
+                 skeySpec, new IvParameterSpec(iv));
+*/
+      DESedeKeySpec keyspec=new DESedeKeySpec(key);
+      SecretKeyFactory keyfactory=SecretKeyFactory.getInstance("DESede");
+      SecretKey _key=keyfactory.generateSecret(keyspec);
+      cipher.init((mode==ENCRYPT_MODE?
+                  javax.crypto.Cipher.ENCRYPT_MODE:
+                  javax.crypto.Cipher.DECRYPT_MODE),
+                 _key, new IvParameterSpec(iv));
+    }
+    catch(Exception e){
+      cipher=null;
+      throw e;
+    }
+  }
+  public void update(byte[] foo, int s1, int len, byte[] bar, int s2) throws Exception{
+    cipher.update(foo, s1, len, bar, s2);
+  }
+  public boolean isCBC(){return true; }
+}
diff --git a/src/com/jcraft/jsch/jce/TripleDESCTR.java b/src/com/jcraft/jsch/jce/TripleDESCTR.java
new file mode 100644 (file)
index 0000000..d511852
--- /dev/null
@@ -0,0 +1,84 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2008-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jce;
+
+import com.jcraft.jsch.Cipher;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class TripleDESCTR implements Cipher{
+  private static final int ivsize=8;
+  private static final int bsize=24;
+  private javax.crypto.Cipher cipher;    
+  public int getIVSize(){return ivsize;} 
+  public int getBlockSize(){return bsize;}
+  public void init(int mode, byte[] key, byte[] iv) throws Exception{
+    String pad="NoPadding";      
+    //if(padding) pad="PKCS5Padding";
+    byte[] tmp;
+    if(iv.length>ivsize){
+      tmp=new byte[ivsize];
+      System.arraycopy(iv, 0, tmp, 0, tmp.length);
+      iv=tmp;
+    }
+    if(key.length>bsize){
+      tmp=new byte[bsize];
+      System.arraycopy(key, 0, tmp, 0, tmp.length);
+      key=tmp;
+    }
+
+    try{
+      cipher=javax.crypto.Cipher.getInstance("DESede/CTR/"+pad);
+/*
+      // The following code does not work on IBM's JDK 1.4.1
+      SecretKeySpec skeySpec = new SecretKeySpec(key, "DESede");
+      cipher.init((mode==ENCRYPT_MODE?
+                  javax.crypto.Cipher.ENCRYPT_MODE:
+                  javax.crypto.Cipher.DECRYPT_MODE),
+                 skeySpec, new IvParameterSpec(iv));
+*/
+      DESedeKeySpec keyspec=new DESedeKeySpec(key);
+      SecretKeyFactory keyfactory=SecretKeyFactory.getInstance("DESede");
+      SecretKey _key=keyfactory.generateSecret(keyspec);
+      cipher.init((mode==ENCRYPT_MODE?
+                  javax.crypto.Cipher.ENCRYPT_MODE:
+                  javax.crypto.Cipher.DECRYPT_MODE),
+                 _key, new IvParameterSpec(iv));
+    }
+    catch(Exception e){
+      cipher=null;
+      throw e;
+    }
+  }
+  public void update(byte[] foo, int s1, int len, byte[] bar, int s2) throws Exception{
+    cipher.update(foo, s1, len, bar, s2);
+  }
+  public boolean isCBC(){return false; }
+}
diff --git a/src/com/jcraft/jsch/jcraft/Compression.java b/src/com/jcraft/jsch/jcraft/Compression.java
new file mode 100644 (file)
index 0000000..d06976e
--- /dev/null
@@ -0,0 +1,145 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jcraft;
+import com.jcraft.jzlib.*;
+import com.jcraft.jsch.*;
+
+public class Compression implements com.jcraft.jsch.Compression {
+  static private final int BUF_SIZE=4096;
+
+  private int type;
+  private ZStream stream;
+  private byte[] tmpbuf=new byte[BUF_SIZE];
+
+  public Compression(){
+    stream=new ZStream();
+  }
+
+  public void init(int type, int level){
+    if(type==DEFLATER){
+      stream.deflateInit(level);
+      this.type=DEFLATER;
+    }
+    else if(type==INFLATER){
+      stream.inflateInit();
+      inflated_buf=new byte[BUF_SIZE];
+      this.type=INFLATER;
+    }
+  }
+  /*
+  static Compression getDeflater(int level){
+    Compression foo=new Compression();
+    foo.stream.deflateInit(level);
+    foo.type=DEFLATER;
+    return foo;
+  }
+  */
+  private byte[] inflated_buf;
+  /*
+  static Compression getInflater(){
+    Compression foo=new Compression();
+    foo.stream.inflateInit();
+    foo.inflated_buf=new byte[BUF_SIZE];
+    foo.type=INFLATER;
+    return foo;
+  }
+  */
+
+  public int compress(byte[] buf, int start, int len){
+    stream.next_in=buf;
+    stream.next_in_index=start;
+    stream.avail_in=len-start;
+    int status;
+    int outputlen=start;
+
+    do{
+      stream.next_out=tmpbuf;
+      stream.next_out_index=0;
+      stream.avail_out=BUF_SIZE;
+      status=stream.deflate(JZlib.Z_PARTIAL_FLUSH);
+      switch(status){
+        case JZlib.Z_OK:
+           System.arraycopy(tmpbuf, 0,
+                            buf, outputlen,
+                            BUF_SIZE-stream.avail_out);
+           outputlen+=(BUF_SIZE-stream.avail_out);
+           break;
+        default:
+           System.err.println("compress: deflate returnd "+status);
+      }
+    }
+    while(stream.avail_out==0);
+    return outputlen;
+  }
+
+  public byte[] uncompress(byte[] buffer, int start, int[] length){
+    int inflated_end=0;
+
+    stream.next_in=buffer;
+    stream.next_in_index=start;
+    stream.avail_in=length[0];
+
+    while(true){
+      stream.next_out=tmpbuf;
+      stream.next_out_index=0;
+      stream.avail_out=BUF_SIZE;
+      int status=stream.inflate(JZlib.Z_PARTIAL_FLUSH);
+      switch(status){
+        case JZlib.Z_OK:
+         if(inflated_buf.length<inflated_end+BUF_SIZE-stream.avail_out){
+            byte[] foo=new byte[inflated_end+BUF_SIZE-stream.avail_out];
+           System.arraycopy(inflated_buf, 0, foo, 0, inflated_end);
+           inflated_buf=foo;
+         }
+         System.arraycopy(tmpbuf, 0,
+                          inflated_buf, inflated_end,
+                          BUF_SIZE-stream.avail_out);
+         inflated_end+=(BUF_SIZE-stream.avail_out);
+          length[0]=inflated_end;
+         break;
+        case JZlib.Z_BUF_ERROR:
+          if(inflated_end>buffer.length-start){
+            byte[] foo=new byte[inflated_end+start];
+            System.arraycopy(buffer, 0, foo, 0, start);
+            System.arraycopy(inflated_buf, 0, foo, start, inflated_end);
+           buffer=foo;
+         }
+         else{
+            System.arraycopy(inflated_buf, 0, buffer, start, inflated_end);
+         }
+          length[0]=inflated_end;
+         return buffer;
+       default:
+         System.err.println("uncompress: inflate returnd "+status);
+          return null;
+      }
+    }
+  }
+}
diff --git a/src/com/jcraft/jsch/jcraft/HMAC.java b/src/com/jcraft/jsch/jcraft/HMAC.java
new file mode 100644 (file)
index 0000000..1610df1
--- /dev/null
@@ -0,0 +1,107 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jcraft;
+
+import java.security.*;
+
+class HMAC{
+
+  /*
+   * Refer to RFC2104.
+   *
+   * H(K XOR opad, H(K XOR ipad, text))
+   *
+   * where K is an n byte key
+   * ipad is the byte 0x36 repeated 64 times
+   * opad is the byte 0x5c repeated 64 times
+   * and text is the data being protected
+   */
+  private static final int B=64;
+  private byte[] k_ipad=null;
+  private byte[] k_opad=null;
+
+  private MessageDigest md=null;
+
+  private int bsize=0;
+
+  protected void setH(MessageDigest md){
+    this.md=md;
+    bsize=md.getDigestLength();
+  }
+
+  public int getBlockSize(){return bsize;};
+  public void init(byte[] key) throws Exception{
+    if(key.length>bsize){
+      byte[] tmp=new byte[bsize];
+      System.arraycopy(key, 0, tmp, 0, bsize);   
+      key=tmp;
+    }
+
+    /* if key is longer than B bytes reset it to key=MD5(key) */
+    if(key.length>B){
+      md.update(key, 0, key.length);
+      key=md.digest();
+    }
+
+    k_ipad=new byte[B];
+    System.arraycopy(key, 0, k_ipad, 0, key.length);
+    k_opad=new byte[B];
+    System.arraycopy(key, 0, k_opad, 0, key.length);
+
+    /* XOR key with ipad and opad values */
+    for(int i=0; i<B; i++) {
+      k_ipad[i]^=(byte)0x36;
+      k_opad[i]^=(byte)0x5c;
+    }
+
+    md.update(k_ipad, 0, B);
+  }
+
+  private final byte[] tmp=new byte[4];
+  public void update(int i){
+    tmp[0]=(byte)(i>>>24);
+    tmp[1]=(byte)(i>>>16);
+    tmp[2]=(byte)(i>>>8);
+    tmp[3]=(byte)i;
+    update(tmp, 0, 4);
+  }
+
+  public void update(byte foo[], int s, int l){
+    md.update(foo, s, l);
+  }
+
+  public void doFinal(byte[] buf, int offset){
+    byte[] result=md.digest();
+    md.update(k_opad, 0, B);
+    md.update(result, 0, bsize);
+    try{md.digest(buf, offset, bsize);}catch(Exception e){}
+    md.update(k_ipad, 0, B);
+  }
+}
diff --git a/src/com/jcraft/jsch/jcraft/HMACMD5.java b/src/com/jcraft/jsch/jcraft/HMACMD5.java
new file mode 100644 (file)
index 0000000..69bbe63
--- /dev/null
@@ -0,0 +1,51 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jcraft;
+
+import com.jcraft.jsch.MAC;
+import java.security.*;
+
+public class HMACMD5 extends HMAC implements MAC{
+  private static final String name="hmac-md5";
+
+  public HMACMD5(){
+    super();
+    MessageDigest md=null;
+    try{ md=MessageDigest.getInstance("MD5"); }
+    catch(Exception e){
+      System.err.println(e);
+    }
+    setH(md);
+  }
+
+  public String getName(){
+    return name;
+  }
+}
diff --git a/src/com/jcraft/jsch/jcraft/HMACMD596.java b/src/com/jcraft/jsch/jcraft/HMACMD596.java
new file mode 100644 (file)
index 0000000..a36ef47
--- /dev/null
@@ -0,0 +1,50 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jcraft;
+
+import com.jcraft.jsch.MAC;
+
+public class HMACMD596 extends HMACMD5{
+
+  private static final String name="hmac-md5-96";
+  private static final int BSIZE=12;
+
+  public int getBlockSize(){return BSIZE;};
+
+  private final byte[] _buf16=new byte[16];
+  public void doFinal(byte[] buf, int offset){
+    super.doFinal(_buf16, 0);
+    System.arraycopy(_buf16, 0, buf, offset, BSIZE);
+  }
+
+  public String getName(){
+    return name;
+  }
+}
diff --git a/src/com/jcraft/jsch/jcraft/HMACSHA1.java b/src/com/jcraft/jsch/jcraft/HMACSHA1.java
new file mode 100644 (file)
index 0000000..f3ed188
--- /dev/null
@@ -0,0 +1,51 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jcraft;
+
+import com.jcraft.jsch.MAC;
+import java.security.*;
+
+public class HMACSHA1 extends HMAC implements MAC{
+  private static final String name="hmac-sha1";
+
+  public HMACSHA1(){
+    super();
+    MessageDigest md=null;
+    try{ md=MessageDigest.getInstance("SHA-1"); }
+    catch(Exception e){
+      System.err.println(e);
+    }
+    setH(md);
+  }
+
+  public String getName(){
+    return name;
+  }
+}
diff --git a/src/com/jcraft/jsch/jcraft/HMACSHA196.java b/src/com/jcraft/jsch/jcraft/HMACSHA196.java
new file mode 100644 (file)
index 0000000..c9d333e
--- /dev/null
@@ -0,0 +1,50 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2006-2010 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
+*/
+
+package com.jcraft.jsch.jcraft;
+
+import com.jcraft.jsch.MAC;
+
+public class HMACSHA196 extends HMACSHA1{
+
+  private static final String name="hmac-sha1-96";
+  private static final int BSIZE=12;
+
+  public int getBlockSize(){return BSIZE;};
+
+  private final byte[] _buf16=new byte[20];
+  public void doFinal(byte[] buf, int offset){
+    super.doFinal(_buf16, 0);
+    System.arraycopy(_buf16, 0, buf, offset, BSIZE);
+  }
+
+  public String getName(){
+    return name;
+  }
+}
diff --git a/src/com/jcraft/jzlib/Adler32.java b/src/com/jcraft/jzlib/Adler32.java
new file mode 100644 (file)
index 0000000..d8b6ef8
--- /dev/null
@@ -0,0 +1,94 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/*
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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 program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+final class Adler32{
+
+  // largest prime smaller than 65536
+  static final private int BASE=65521; 
+  // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
+  static final private int NMAX=5552;
+
+  long adler32(long adler, byte[] buf, int index, int len){
+    if(buf == null){ return 1L; }
+
+    long s1=adler&0xffff;
+    long s2=(adler>>16)&0xffff;
+    int k;
+
+    while(len > 0) {
+      k=len<NMAX?len:NMAX;
+      len-=k;
+      while(k>=16){
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        s1+=buf[index++]&0xff; s2+=s1;
+        k-=16;
+      }
+      if(k!=0){
+        do{
+          s1+=buf[index++]&0xff; s2+=s1;
+        }
+        while(--k!=0);
+      }
+      s1%=BASE;
+      s2%=BASE;
+    }
+    return (s2<<16)|s1;
+  }
+
+  /*
+  private java.util.zip.Adler32 adler=new java.util.zip.Adler32();
+  long adler32(long value, byte[] buf, int index, int len){
+    if(value==1) {adler.reset();}
+    if(buf==null) {adler.reset();}
+    else{adler.update(buf, index, len);}
+    return adler.getValue();
+  }
+  */
+}
diff --git a/src/com/jcraft/jzlib/Deflate.java b/src/com/jcraft/jzlib/Deflate.java
new file mode 100644 (file)
index 0000000..9978802
--- /dev/null
@@ -0,0 +1,1623 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/*
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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 program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+public 
+final class Deflate{
+
+  static final private int MAX_MEM_LEVEL=9;
+
+  static final private int Z_DEFAULT_COMPRESSION=-1;
+
+  static final private int MAX_WBITS=15;            // 32K LZ77 window
+  static final private int DEF_MEM_LEVEL=8;
+
+  static class Config{
+    int good_length; // reduce lazy search above this match length
+    int max_lazy;    // do not perform lazy search above this match length
+    int nice_length; // quit search above this match length
+    int max_chain;
+    int func;
+    Config(int good_length, int max_lazy, 
+          int nice_length, int max_chain, int func){
+      this.good_length=good_length;
+      this.max_lazy=max_lazy;
+      this.nice_length=nice_length;
+      this.max_chain=max_chain;
+      this.func=func;
+    }
+  }
+  
+  static final private int STORED=0;
+  static final private int FAST=1;
+  static final private int SLOW=2;
+  static final private Config[] config_table;    
+  static{
+    config_table=new Config[10];
+    //                         good  lazy  nice  chain
+    config_table[0]=new Config(0,    0,    0,    0, STORED);
+    config_table[1]=new Config(4,    4,    8,    4, FAST);
+    config_table[2]=new Config(4,    5,   16,    8, FAST);
+    config_table[3]=new Config(4,    6,   32,   32, FAST);
+
+    config_table[4]=new Config(4,    4,   16,   16, SLOW);
+    config_table[5]=new Config(8,   16,   32,   32, SLOW);
+    config_table[6]=new Config(8,   16,  128,  128, SLOW);
+    config_table[7]=new Config(8,   32,  128,  256, SLOW);
+    config_table[8]=new Config(32, 128,  258, 1024, SLOW);
+    config_table[9]=new Config(32, 258,  258, 4096, SLOW);
+  }
+
+  static final private String[] z_errmsg = {
+    "need dictionary",     // Z_NEED_DICT       2
+    "stream end",          // Z_STREAM_END      1
+    "",                    // Z_OK              0
+    "file error",          // Z_ERRNO         (-1)
+    "stream error",        // Z_STREAM_ERROR  (-2)
+    "data error",          // Z_DATA_ERROR    (-3)
+    "insufficient memory", // Z_MEM_ERROR     (-4)
+    "buffer error",        // Z_BUF_ERROR     (-5)
+    "incompatible version",// Z_VERSION_ERROR (-6)
+    ""
+  };
+
+  // block not completed, need more input or more output
+  static final private int NeedMore=0; 
+
+  // block flush performed
+  static final private int BlockDone=1; 
+
+  // finish started, need only more output at next deflate
+  static final private int FinishStarted=2;
+
+  // finish done, accept no more input or output
+  static final private int FinishDone=3;
+
+  // preset dictionary flag in zlib header
+  static final private int PRESET_DICT=0x20;
+
+  static final private int Z_FILTERED=1;
+  static final private int Z_HUFFMAN_ONLY=2;
+  static final private int Z_DEFAULT_STRATEGY=0;
+
+  static final private int Z_NO_FLUSH=0;
+  static final private int Z_PARTIAL_FLUSH=1;
+  static final private int Z_SYNC_FLUSH=2;
+  static final private int Z_FULL_FLUSH=3;
+  static final private int Z_FINISH=4;
+
+  static final private int Z_OK=0;
+  static final private int Z_STREAM_END=1;
+  static final private int Z_NEED_DICT=2;
+  static final private int Z_ERRNO=-1;
+  static final private int Z_STREAM_ERROR=-2;
+  static final private int Z_DATA_ERROR=-3;
+  static final private int Z_MEM_ERROR=-4;
+  static final private int Z_BUF_ERROR=-5;
+  static final private int Z_VERSION_ERROR=-6;
+
+  static final private int INIT_STATE=42;
+  static final private int BUSY_STATE=113;
+  static final private int FINISH_STATE=666;
+
+  // The deflate compression method
+  static final private int Z_DEFLATED=8;
+
+  static final private int STORED_BLOCK=0;
+  static final private int STATIC_TREES=1;
+  static final private int DYN_TREES=2;
+
+  // The three kinds of block type
+  static final private int Z_BINARY=0;
+  static final private int Z_ASCII=1;
+  static final private int Z_UNKNOWN=2;
+
+  static final private int Buf_size=8*2;
+
+  // repeat previous bit length 3-6 times (2 bits of repeat count)
+  static final private int REP_3_6=16; 
+
+  // repeat a zero length 3-10 times  (3 bits of repeat count)
+  static final private int REPZ_3_10=17; 
+
+  // repeat a zero length 11-138 times  (7 bits of repeat count)
+  static final private int REPZ_11_138=18; 
+
+  static final private int MIN_MATCH=3;
+  static final private int MAX_MATCH=258;
+  static final private int MIN_LOOKAHEAD=(MAX_MATCH+MIN_MATCH+1);
+
+  static final private int MAX_BITS=15;
+  static final private int D_CODES=30;
+  static final private int BL_CODES=19;
+  static final private int LENGTH_CODES=29;
+  static final private int LITERALS=256;
+  static final private int L_CODES=(LITERALS+1+LENGTH_CODES);
+  static final private int HEAP_SIZE=(2*L_CODES+1);
+
+  static final private int END_BLOCK=256;
+
+  ZStream strm;         // pointer back to this zlib stream
+  int status;           // as the name implies
+  byte[] pending_buf;   // output still pending
+  int pending_buf_size; // size of pending_buf
+  int pending_out;      // next pending byte to output to the stream
+  int pending;          // nb of bytes in the pending buffer
+  int noheader;         // suppress zlib header and adler32
+  byte data_type;       // UNKNOWN, BINARY or ASCII
+  byte method;          // STORED (for zip only) or DEFLATED
+  int last_flush;       // value of flush param for previous deflate call
+
+  int w_size;           // LZ77 window size (32K by default)
+  int w_bits;           // log2(w_size)  (8..16)
+  int w_mask;           // w_size - 1
+
+  byte[] window;
+  // Sliding window. Input bytes are read into the second half of the window,
+  // and move to the first half later to keep a dictionary of at least wSize
+  // bytes. With this organization, matches are limited to a distance of
+  // wSize-MAX_MATCH bytes, but this ensures that IO is always
+  // performed with a length multiple of the block size. Also, it limits
+  // the window size to 64K, which is quite useful on MSDOS.
+  // To do: use the user input buffer as sliding window.
+
+  int window_size;
+  // Actual size of window: 2*wSize, except when the user input buffer
+  // is directly used as sliding window.
+
+  short[] prev;
+  // Link to older string with same hash index. To limit the size of this
+  // array to 64K, this link is maintained only for the last 32K strings.
+  // An index in this array is thus a window index modulo 32K.
+
+  short[] head; // Heads of the hash chains or NIL.
+
+  int ins_h;          // hash index of string to be inserted
+  int hash_size;      // number of elements in hash table
+  int hash_bits;      // log2(hash_size)
+  int hash_mask;      // hash_size-1
+
+  // Number of bits by which ins_h must be shifted at each input
+  // step. It must be such that after MIN_MATCH steps, the oldest
+  // byte no longer takes part in the hash key, that is:
+  // hash_shift * MIN_MATCH >= hash_bits
+  int hash_shift;
+
+  // Window position at the beginning of the current output block. Gets
+  // negative when the window is moved backwards.
+
+  int block_start;
+
+  int match_length;           // length of best match
+  int prev_match;             // previous match
+  int match_available;        // set if previous match exists
+  int strstart;               // start of string to insert
+  int match_start;            // start of matching string
+  int lookahead;              // number of valid bytes ahead in window
+
+  // Length of the best match at previous step. Matches not greater than this
+  // are discarded. This is used in the lazy match evaluation.
+  int prev_length;
+
+  // To speed up deflation, hash chains are never searched beyond this
+  // length.  A higher limit improves compression ratio but degrades the speed.
+  int max_chain_length;
+
+  // Attempt to find a better match only when the current match is strictly
+  // smaller than this value. This mechanism is used only for compression
+  // levels >= 4.
+  int max_lazy_match;
+
+  // Insert new strings in the hash table only if the match length is not
+  // greater than this length. This saves time but degrades compression.
+  // max_insert_length is used only for compression levels <= 3.
+
+  int level;    // compression level (1..9)
+  int strategy; // favor or force Huffman coding
+
+  // Use a faster search when the previous match is longer than this
+  int good_match;
+
+  // Stop searching when current match exceeds this
+  int nice_match;
+
+  short[] dyn_ltree;       // literal and length tree
+  short[] dyn_dtree;       // distance tree
+  short[] bl_tree;         // Huffman tree for bit lengths
+
+  Tree l_desc=new Tree();  // desc for literal tree
+  Tree d_desc=new Tree();  // desc for distance tree
+  Tree bl_desc=new Tree(); // desc for bit length tree
+
+  // number of codes at each bit length for an optimal tree
+  short[] bl_count=new short[MAX_BITS+1];
+
+  // heap used to build the Huffman trees
+  int[] heap=new int[2*L_CODES+1];
+
+  int heap_len;               // number of elements in the heap
+  int heap_max;               // element of largest frequency
+  // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+  // The same heap array is used to build all trees.
+
+  // Depth of each subtree used as tie breaker for trees of equal frequency
+  byte[] depth=new byte[2*L_CODES+1];
+
+  int l_buf;               // index for literals or lengths */
+
+  // Size of match buffer for literals/lengths.  There are 4 reasons for
+  // limiting lit_bufsize to 64K:
+  //   - frequencies can be kept in 16 bit counters
+  //   - if compression is not successful for the first block, all input
+  //     data is still in the window so we can still emit a stored block even
+  //     when input comes from standard input.  (This can also be done for
+  //     all blocks if lit_bufsize is not greater than 32K.)
+  //   - if compression is not successful for a file smaller than 64K, we can
+  //     even emit a stored file instead of a stored block (saving 5 bytes).
+  //     This is applicable only for zip (not gzip or zlib).
+  //   - creating new Huffman trees less frequently may not provide fast
+  //     adaptation to changes in the input data statistics. (Take for
+  //     example a binary file with poorly compressible code followed by
+  //     a highly compressible string table.) Smaller buffer sizes give
+  //     fast adaptation but have of course the overhead of transmitting
+  //     trees more frequently.
+  //   - I can't count above 4
+  int lit_bufsize;
+
+  int last_lit;      // running index in l_buf
+
+  // Buffer for distances. To simplify the code, d_buf and l_buf have
+  // the same number of elements. To use different lengths, an extra flag
+  // array would be necessary.
+
+  int d_buf;         // index of pendig_buf
+
+  int opt_len;        // bit length of current block with optimal trees
+  int static_len;     // bit length of current block with static trees
+  int matches;        // number of string matches in current block
+  int last_eob_len;   // bit length of EOB code for last block
+
+  // Output buffer. bits are inserted starting at the bottom (least
+  // significant bits).
+  short bi_buf;
+
+  // Number of valid bits in bi_buf.  All bits above the last valid bit
+  // are always zero.
+  int bi_valid;
+
+  Deflate(){
+    dyn_ltree=new short[HEAP_SIZE*2];
+    dyn_dtree=new short[(2*D_CODES+1)*2]; // distance tree
+    bl_tree=new short[(2*BL_CODES+1)*2];  // Huffman tree for bit lengths
+  }
+
+  void lm_init() {
+    window_size=2*w_size;
+
+    head[hash_size-1]=0;
+    for(int i=0; i<hash_size-1; i++){
+      head[i]=0;
+    }
+
+    // Set the default configuration parameters:
+    max_lazy_match   = Deflate.config_table[level].max_lazy;
+    good_match       = Deflate.config_table[level].good_length;
+    nice_match       = Deflate.config_table[level].nice_length;
+    max_chain_length = Deflate.config_table[level].max_chain;
+
+    strstart = 0;
+    block_start = 0;
+    lookahead = 0;
+    match_length = prev_length = MIN_MATCH-1;
+    match_available = 0;
+    ins_h = 0;
+  }
+
+  // Initialize the tree data structures for a new zlib stream.
+  void tr_init(){
+
+    l_desc.dyn_tree = dyn_ltree;
+    l_desc.stat_desc = StaticTree.static_l_desc;
+
+    d_desc.dyn_tree = dyn_dtree;
+    d_desc.stat_desc = StaticTree.static_d_desc;
+
+    bl_desc.dyn_tree = bl_tree;
+    bl_desc.stat_desc = StaticTree.static_bl_desc;
+
+    bi_buf = 0;
+    bi_valid = 0;
+    last_eob_len = 8; // enough lookahead for inflate
+
+    // Initialize the first block of the first file:
+    init_block();
+  }
+
+  void init_block(){
+    // Initialize the trees.
+    for(int i = 0; i < L_CODES; i++) dyn_ltree[i*2] = 0;
+    for(int i= 0; i < D_CODES; i++) dyn_dtree[i*2] = 0;
+    for(int i= 0; i < BL_CODES; i++) bl_tree[i*2] = 0;
+
+    dyn_ltree[END_BLOCK*2] = 1;
+    opt_len = static_len = 0;
+    last_lit = matches = 0;
+  }
+
+  // Restore the heap property by moving down the tree starting at node k,
+  // exchanging a node with the smallest of its two sons if necessary, stopping
+  // when the heap property is re-established (each father smaller than its
+  // two sons).
+  void pqdownheap(short[] tree,  // the tree to restore
+                 int k          // node to move down
+                 ){
+    int v = heap[k];
+    int j = k << 1;  // left son of k
+    while (j <= heap_len) {
+      // Set j to the smallest of the two sons:
+      if (j < heap_len &&
+         smaller(tree, heap[j+1], heap[j], depth)){
+       j++;
+      }
+      // Exit if v is smaller than both sons
+      if(smaller(tree, v, heap[j], depth)) break;
+
+      // Exchange v with the smallest son
+      heap[k]=heap[j];  k = j;
+      // And continue down the tree, setting j to the left son of k
+      j <<= 1;
+    }
+    heap[k] = v;
+  }
+
+  static boolean smaller(short[] tree, int n, int m, byte[] depth){
+    short tn2=tree[n*2];
+    short tm2=tree[m*2];
+    return (tn2<tm2 ||
+           (tn2==tm2 && depth[n] <= depth[m]));
+  }
+
+  // Scan a literal or distance tree to determine the frequencies of the codes
+  // in the bit length tree.
+  void scan_tree (short[] tree,// the tree to be scanned
+                 int max_code // and its largest code of non zero frequency
+                 ){
+    int n;                     // iterates over all tree elements
+    int prevlen = -1;          // last emitted length
+    int curlen;                // length of current code
+    int nextlen = tree[0*2+1]; // length of next code
+    int count = 0;             // repeat count of the current code
+    int max_count = 7;         // max repeat count
+    int min_count = 4;         // min repeat count
+
+    if (nextlen == 0){ max_count = 138; min_count = 3; }
+    tree[(max_code+1)*2+1] = (short)0xffff; // guard
+
+    for(n = 0; n <= max_code; n++) {
+      curlen = nextlen; nextlen = tree[(n+1)*2+1];
+      if(++count < max_count && curlen == nextlen) {
+       continue;
+      }
+      else if(count < min_count) {
+       bl_tree[curlen*2] += count;
+      }
+      else if(curlen != 0) {
+       if(curlen != prevlen) bl_tree[curlen*2]++;
+       bl_tree[REP_3_6*2]++;
+      }
+      else if(count <= 10) {
+       bl_tree[REPZ_3_10*2]++;
+      }
+      else{
+       bl_tree[REPZ_11_138*2]++;
+      }
+      count = 0; prevlen = curlen;
+      if(nextlen == 0) {
+       max_count = 138; min_count = 3;
+      }
+      else if(curlen == nextlen) {
+       max_count = 6; min_count = 3;
+      }
+      else{
+       max_count = 7; min_count = 4;
+      }
+    }
+  }
+
+  // Construct the Huffman tree for the bit lengths and return the index in
+  // bl_order of the last bit length code to send.
+  int build_bl_tree(){
+    int max_blindex;  // index of last bit length code of non zero freq
+
+    // Determine the bit length frequencies for literal and distance trees
+    scan_tree(dyn_ltree, l_desc.max_code);
+    scan_tree(dyn_dtree, d_desc.max_code);
+
+    // Build the bit length tree:
+    bl_desc.build_tree(this);
+    // opt_len now includes the length of the tree representations, except
+    // the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+
+    // Determine the number of bit length codes to send. The pkzip format
+    // requires that at least 4 bit length codes be sent. (appnote.txt says
+    // 3 but the actual value used is 4.)
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+      if (bl_tree[Tree.bl_order[max_blindex]*2+1] != 0) break;
+    }
+    // Update opt_len to include the bit length tree and counts
+    opt_len += 3*(max_blindex+1) + 5+5+4;
+
+    return max_blindex;
+  }
+
+
+  // Send the header for a block using dynamic Huffman trees: the counts, the
+  // lengths of the bit length codes, the literal tree and the distance tree.
+  // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+  void send_all_trees(int lcodes, int dcodes, int blcodes){
+    int rank;                    // index in bl_order
+
+    send_bits(lcodes-257, 5); // not +255 as stated in appnote.txt
+    send_bits(dcodes-1,   5);
+    send_bits(blcodes-4,  4); // not -3 as stated in appnote.txt
+    for (rank = 0; rank < blcodes; rank++) {
+      send_bits(bl_tree[Tree.bl_order[rank]*2+1], 3);
+    }
+    send_tree(dyn_ltree, lcodes-1); // literal tree
+    send_tree(dyn_dtree, dcodes-1); // distance tree
+  }
+
+  // Send a literal or distance tree in compressed form, using the codes in
+  // bl_tree.
+  void send_tree (short[] tree,// the tree to be sent
+                 int max_code // and its largest code of non zero frequency
+                 ){
+    int n;                     // iterates over all tree elements
+    int prevlen = -1;          // last emitted length
+    int curlen;                // length of current code
+    int nextlen = tree[0*2+1]; // length of next code
+    int count = 0;             // repeat count of the current code
+    int max_count = 7;         // max repeat count
+    int min_count = 4;         // min repeat count
+
+    if (nextlen == 0){ max_count = 138; min_count = 3; }
+
+    for (n = 0; n <= max_code; n++) {
+      curlen = nextlen; nextlen = tree[(n+1)*2+1];
+      if(++count < max_count && curlen == nextlen) {
+       continue;
+      }
+      else if(count < min_count) {
+       do { send_code(curlen, bl_tree); } while (--count != 0);
+      }
+      else if(curlen != 0){
+       if(curlen != prevlen){
+         send_code(curlen, bl_tree); count--;
+       }
+       send_code(REP_3_6, bl_tree); 
+       send_bits(count-3, 2);
+      }
+      else if(count <= 10){
+       send_code(REPZ_3_10, bl_tree); 
+       send_bits(count-3, 3);
+      }
+      else{
+       send_code(REPZ_11_138, bl_tree);
+       send_bits(count-11, 7);
+      }
+      count = 0; prevlen = curlen;
+      if(nextlen == 0){
+       max_count = 138; min_count = 3;
+      }
+      else if(curlen == nextlen){
+       max_count = 6; min_count = 3;
+      }
+      else{
+       max_count = 7; min_count = 4;
+      }
+    }
+  }
+
+  // Output a byte on the stream.
+  // IN assertion: there is enough room in pending_buf.
+  final void put_byte(byte[] p, int start, int len){
+    System.arraycopy(p, start, pending_buf, pending, len);
+    pending+=len;
+  }
+
+  final void put_byte(byte c){
+    pending_buf[pending++]=c;
+  }
+  final void put_short(int w) {
+    put_byte((byte)(w/*&0xff*/));
+    put_byte((byte)(w>>>8));
+  }
+  final void putShortMSB(int b){
+    put_byte((byte)(b>>8));
+    put_byte((byte)(b/*&0xff*/));
+  }   
+
+  final void send_code(int c, short[] tree){
+    int c2=c*2;
+    send_bits((tree[c2]&0xffff), (tree[c2+1]&0xffff));
+  }
+
+  void send_bits(int value, int length){
+    int len = length;
+    if (bi_valid > (int)Buf_size - len) {
+      int val = value;
+//      bi_buf |= (val << bi_valid);
+      bi_buf |= ((val << bi_valid)&0xffff);
+      put_short(bi_buf);
+      bi_buf = (short)(val >>> (Buf_size - bi_valid));
+      bi_valid += len - Buf_size;
+    } else {
+//      bi_buf |= (value) << bi_valid;
+      bi_buf |= (((value) << bi_valid)&0xffff);
+      bi_valid += len;
+    }
+  }
+
+  // Send one empty static block to give enough lookahead for inflate.
+  // This takes 10 bits, of which 7 may remain in the bit buffer.
+  // The current inflate code requires 9 bits of lookahead. If the
+  // last two codes for the previous block (real code plus EOB) were coded
+  // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+  // the last real code. In this case we send two empty static blocks instead
+  // of one. (There are no problems if the previous block is stored or fixed.)
+  // To simplify the code, we assume the worst case of last real code encoded
+  // on one bit only.
+  void _tr_align(){
+    send_bits(STATIC_TREES<<1, 3);
+    send_code(END_BLOCK, StaticTree.static_ltree);
+
+    bi_flush();
+
+    // Of the 10 bits for the empty block, we have already sent
+    // (10 - bi_valid) bits. The lookahead for the last real code (before
+    // the EOB of the previous block) was thus at least one plus the length
+    // of the EOB plus what we have just sent of the empty static block.
+    if (1 + last_eob_len + 10 - bi_valid < 9) {
+      send_bits(STATIC_TREES<<1, 3);
+      send_code(END_BLOCK, StaticTree.static_ltree);
+      bi_flush();
+    }
+    last_eob_len = 7;
+  }
+
+
+  // Save the match info and tally the frequency counts. Return true if
+  // the current block must be flushed.
+  boolean _tr_tally (int dist, // distance of matched string
+                    int lc // match length-MIN_MATCH or unmatched char (if dist==0)
+                    ){
+
+    pending_buf[d_buf+last_lit*2] = (byte)(dist>>>8);
+    pending_buf[d_buf+last_lit*2+1] = (byte)dist;
+
+    pending_buf[l_buf+last_lit] = (byte)lc; last_lit++;
+
+    if (dist == 0) {
+      // lc is the unmatched char
+      dyn_ltree[lc*2]++;
+    } 
+    else {
+      matches++;
+      // Here, lc is the match length - MIN_MATCH
+      dist--;             // dist = match distance - 1
+      dyn_ltree[(Tree._length_code[lc]+LITERALS+1)*2]++;
+      dyn_dtree[Tree.d_code(dist)*2]++;
+    }
+
+    if ((last_lit & 0x1fff) == 0 && level > 2) {
+      // Compute an upper bound for the compressed length
+      int out_length = last_lit*8;
+      int in_length = strstart - block_start;
+      int dcode;
+      for (dcode = 0; dcode < D_CODES; dcode++) {
+       out_length += (int)dyn_dtree[dcode*2] *
+         (5L+Tree.extra_dbits[dcode]);
+      }
+      out_length >>>= 3;
+      if ((matches < (last_lit/2)) && out_length < in_length/2) return true;
+    }
+
+    return (last_lit == lit_bufsize-1);
+    // We avoid equality with lit_bufsize because of wraparound at 64K
+    // on 16 bit machines and because stored blocks are restricted to
+    // 64K-1 bytes.
+  }
+
+  // Send the block data compressed using the given Huffman trees
+  void compress_block(short[] ltree, short[] dtree){
+    int  dist;      // distance of matched string
+    int lc;         // match length or unmatched char (if dist == 0)
+    int lx = 0;     // running index in l_buf
+    int code;       // the code to send
+    int extra;      // number of extra bits to send
+
+    if (last_lit != 0){
+      do{
+       dist=((pending_buf[d_buf+lx*2]<<8)&0xff00)|
+         (pending_buf[d_buf+lx*2+1]&0xff);
+       lc=(pending_buf[l_buf+lx])&0xff; lx++;
+
+       if(dist == 0){
+         send_code(lc, ltree); // send a literal byte
+       } 
+       else{
+         // Here, lc is the match length - MIN_MATCH
+         code = Tree._length_code[lc];
+
+         send_code(code+LITERALS+1, ltree); // send the length code
+         extra = Tree.extra_lbits[code];
+         if(extra != 0){
+           lc -= Tree.base_length[code];
+           send_bits(lc, extra);       // send the extra length bits
+         }
+         dist--; // dist is now the match distance - 1
+         code = Tree.d_code(dist);
+
+         send_code(code, dtree);       // send the distance code
+         extra = Tree.extra_dbits[code];
+         if (extra != 0) {
+           dist -= Tree.base_dist[code];
+           send_bits(dist, extra);   // send the extra distance bits
+         }
+       } // literal or match pair ?
+
+       // Check that the overlay between pending_buf and d_buf+l_buf is ok:
+      }
+      while (lx < last_lit);
+    }
+
+    send_code(END_BLOCK, ltree);
+    last_eob_len = ltree[END_BLOCK*2+1];
+  }
+
+  // Set the data type to ASCII or BINARY, using a crude approximation:
+  // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+  // IN assertion: the fields freq of dyn_ltree are set and the total of all
+  // frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+  void set_data_type(){
+    int n = 0;
+    int  ascii_freq = 0;
+    int  bin_freq = 0;
+    while(n<7){ bin_freq += dyn_ltree[n*2]; n++;}
+    while(n<128){ ascii_freq += dyn_ltree[n*2]; n++;}
+    while(n<LITERALS){ bin_freq += dyn_ltree[n*2]; n++;}
+    data_type=(byte)(bin_freq > (ascii_freq >>> 2) ? Z_BINARY : Z_ASCII);
+  }
+
+  // Flush the bit buffer, keeping at most 7 bits in it.
+  void bi_flush(){
+    if (bi_valid == 16) {
+      put_short(bi_buf);
+      bi_buf=0;
+      bi_valid=0;
+    }
+    else if (bi_valid >= 8) {
+      put_byte((byte)bi_buf);
+      bi_buf>>>=8;
+      bi_valid-=8;
+    }
+  }
+
+  // Flush the bit buffer and align the output on a byte boundary
+  void bi_windup(){
+    if (bi_valid > 8) {
+      put_short(bi_buf);
+    } else if (bi_valid > 0) {
+      put_byte((byte)bi_buf);
+    }
+    bi_buf = 0;
+    bi_valid = 0;
+  }
+
+  // Copy a stored block, storing first the length and its
+  // one's complement if requested.
+  void copy_block(int buf,         // the input data
+                 int len,         // its length
+                 boolean header   // true if block header must be written
+                 ){
+    int index=0;
+    bi_windup();      // align on byte boundary
+    last_eob_len = 8; // enough lookahead for inflate
+
+    if (header) {
+      put_short((short)len);   
+      put_short((short)~len);
+    }
+
+    //  while(len--!=0) {
+    //    put_byte(window[buf+index]);
+    //    index++;
+    //  }
+    put_byte(window, buf, len);
+  }
+
+  void flush_block_only(boolean eof){
+    _tr_flush_block(block_start>=0 ? block_start : -1,
+                   strstart-block_start,
+                   eof);
+    block_start=strstart;
+    strm.flush_pending();
+  }
+
+  // Copy without compression as much as possible from the input stream, return
+  // the current block state.
+  // This function does not insert new strings in the dictionary since
+  // uncompressible data is probably not useful. This function is used
+  // only for the level=0 compression option.
+  // NOTE: this function should be optimized to avoid extra copying from
+  // window to pending_buf.
+  int deflate_stored(int flush){
+    // Stored blocks are limited to 0xffff bytes, pending_buf is limited
+    // to pending_buf_size, and each stored block has a 5 byte header:
+
+    int max_block_size = 0xffff;
+    int max_start;
+
+    if(max_block_size > pending_buf_size - 5) {
+      max_block_size = pending_buf_size - 5;
+    }
+
+    // Copy as much as possible from input to output:
+    while(true){
+      // Fill the window as much as possible:
+      if(lookahead<=1){
+       fill_window();
+       if(lookahead==0 && flush==Z_NO_FLUSH) return NeedMore;
+       if(lookahead==0) break; // flush the current block
+      }
+
+      strstart+=lookahead;
+      lookahead=0;
+
+      // Emit a stored block if pending_buf will be full:
+      max_start=block_start+max_block_size;
+      if(strstart==0|| strstart>=max_start) {
+       // strstart == 0 is possible when wraparound on 16-bit machine
+       lookahead = (int)(strstart-max_start);
+       strstart = (int)max_start;
+      
+       flush_block_only(false);
+       if(strm.avail_out==0) return NeedMore;
+
+      }
+
+      // Flush if we may have to slide, otherwise block_start may become
+      // negative and the data will be gone:
+      if(strstart-block_start >= w_size-MIN_LOOKAHEAD) {
+       flush_block_only(false);
+       if(strm.avail_out==0) return NeedMore;
+      }
+    }
+
+    flush_block_only(flush == Z_FINISH);
+    if(strm.avail_out==0)
+      return (flush == Z_FINISH) ? FinishStarted : NeedMore;
+
+    return flush == Z_FINISH ? FinishDone : BlockDone;
+  }
+
+  // Send a stored block
+  void _tr_stored_block(int buf,        // input block
+                       int stored_len, // length of input block
+                       boolean eof     // true if this is the last block for a file
+                       ){
+    send_bits((STORED_BLOCK<<1)+(eof?1:0), 3);  // send block type
+    copy_block(buf, stored_len, true);          // with header
+  }
+
+  // Determine the best encoding for the current block: dynamic trees, static
+  // trees or store, and output the encoded block to the zip file.
+  void _tr_flush_block(int buf,        // input block, or NULL if too old
+                      int stored_len, // length of input block
+                      boolean eof     // true if this is the last block for a file
+                      ) {
+    int opt_lenb, static_lenb;// opt_len and static_len in bytes
+    int max_blindex = 0;      // index of last bit length code of non zero freq
+
+    // Build the Huffman trees unless a stored block is forced
+    if(level > 0) {
+      // Check if the file is ascii or binary
+      if(data_type == Z_UNKNOWN) set_data_type();
+
+      // Construct the literal and distance trees
+      l_desc.build_tree(this);
+
+      d_desc.build_tree(this);
+
+      // At this point, opt_len and static_len are the total bit lengths of
+      // the compressed block data, excluding the tree representations.
+
+      // Build the bit length tree for the above two trees, and get the index
+      // in bl_order of the last bit length code to send.
+      max_blindex=build_bl_tree();
+
+      // Determine the best encoding. Compute first the block length in bytes
+      opt_lenb=(opt_len+3+7)>>>3;
+      static_lenb=(static_len+3+7)>>>3;
+
+      if(static_lenb<=opt_lenb) opt_lenb=static_lenb;
+    }
+    else {
+      opt_lenb=static_lenb=stored_len+5; // force a stored block
+    }
+
+    if(stored_len+4<=opt_lenb && buf != -1){
+      // 4: two words for the lengths
+      // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+      // Otherwise we can't have processed more than WSIZE input bytes since
+      // the last block flush, because compression would have been
+      // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+      // transform a block into a stored block.
+      _tr_stored_block(buf, stored_len, eof);
+    }
+    else if(static_lenb == opt_lenb){
+      send_bits((STATIC_TREES<<1)+(eof?1:0), 3);
+      compress_block(StaticTree.static_ltree, StaticTree.static_dtree);
+    }
+    else{
+      send_bits((DYN_TREES<<1)+(eof?1:0), 3);
+      send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1);
+      compress_block(dyn_ltree, dyn_dtree);
+    }
+
+    // The above check is made mod 2^32, for files larger than 512 MB
+    // and uLong implemented on 32 bits.
+
+    init_block();
+
+    if(eof){
+      bi_windup();
+    }
+  }
+
+  // Fill the window when the lookahead becomes insufficient.
+  // Updates strstart and lookahead.
+  //
+  // IN assertion: lookahead < MIN_LOOKAHEAD
+  // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+  //    At least one byte has been read, or avail_in == 0; reads are
+  //    performed for at least two bytes (required for the zip translate_eol
+  //    option -- not supported here).
+  void fill_window(){
+    int n, m;
+    int p;
+    int more;    // Amount of free space at the end of the window.
+
+    do{
+      more = (window_size-lookahead-strstart);
+
+      // Deal with !@#$% 64K limit:
+      if(more==0 && strstart==0 && lookahead==0){
+       more = w_size;
+      } 
+      else if(more==-1) {
+       // Very unlikely, but possible on 16 bit machine if strstart == 0
+       // and lookahead == 1 (input done one byte at time)
+       more--;
+
+       // If the window is almost full and there is insufficient lookahead,
+       // move the upper half to the lower one to make room in the upper half.
+      }
+      else if(strstart >= w_size+ w_size-MIN_LOOKAHEAD) {
+       System.arraycopy(window, w_size, window, 0, w_size);
+       match_start-=w_size;
+       strstart-=w_size; // we now have strstart >= MAX_DIST
+       block_start-=w_size;
+
+       // Slide the hash table (could be avoided with 32 bit values
+       // at the expense of memory usage). We slide even when level == 0
+       // to keep the hash table consistent if we switch back to level > 0
+       // later. (Using level 0 permanently is not an optimal usage of
+       // zlib, so we don't care about this pathological case.)
+
+       n = hash_size;
+       p=n;
+       do {
+         m = (head[--p]&0xffff);
+         head[p]=(m>=w_size ? (short)(m-w_size) : 0);
+       }
+       while (--n != 0);
+
+       n = w_size;
+       p = n;
+       do {
+         m = (prev[--p]&0xffff);
+         prev[p] = (m >= w_size ? (short)(m-w_size) : 0);
+         // If n is not on any hash chain, prev[n] is garbage but
+         // its value will never be used.
+       }
+       while (--n!=0);
+       more += w_size;
+      }
+
+      if (strm.avail_in == 0) return;
+
+      // If there was no sliding:
+      //    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+      //    more == window_size - lookahead - strstart
+      // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+      // => more >= window_size - 2*WSIZE + 2
+      // In the BIG_MEM or MMAP case (not yet supported),
+      //   window_size == input_size + MIN_LOOKAHEAD  &&
+      //   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+      // Otherwise, window_size == 2*WSIZE so more >= 2.
+      // If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+
+      n = strm.read_buf(window, strstart + lookahead, more);
+      lookahead += n;
+
+      // Initialize the hash value now that we have some input:
+      if(lookahead >= MIN_MATCH) {
+       ins_h = window[strstart]&0xff;
+       ins_h=(((ins_h)<<hash_shift)^(window[strstart+1]&0xff))&hash_mask;
+      }
+      // If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+      // but this is not important since only literal bytes will be emitted.
+    }
+    while (lookahead < MIN_LOOKAHEAD && strm.avail_in != 0);
+  }
+
+  // Compress as much as possible from the input stream, return the current
+  // block state.
+  // This function does not perform lazy evaluation of matches and inserts
+  // new strings in the dictionary only for unmatched strings or for short
+  // matches. It is used only for the fast compression options.
+  int deflate_fast(int flush){
+//    short hash_head = 0; // head of the hash chain
+    int hash_head = 0; // head of the hash chain
+    boolean bflush;      // set if current block must be flushed
+
+    while(true){
+      // Make sure that we always have enough lookahead, except
+      // at the end of the input file. We need MAX_MATCH bytes
+      // for the next match, plus MIN_MATCH bytes to insert the
+      // string following the next match.
+      if(lookahead < MIN_LOOKAHEAD){
+       fill_window();
+       if(lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH){
+         return NeedMore;
+       }
+       if(lookahead == 0) break; // flush the current block
+      }
+
+      // Insert the string window[strstart .. strstart+2] in the
+      // dictionary, and set hash_head to the head of the hash chain:
+      if(lookahead >= MIN_MATCH){
+       ins_h=(((ins_h)<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff))&hash_mask;
+
+//     prev[strstart&w_mask]=hash_head=head[ins_h];
+        hash_head=(head[ins_h]&0xffff);
+       prev[strstart&w_mask]=head[ins_h];
+       head[ins_h]=(short)strstart;
+      }
+
+      // Find the longest match, discarding those <= prev_length.
+      // At this point we have always match_length < MIN_MATCH
+
+      if(hash_head!=0L && 
+        ((strstart-hash_head)&0xffff) <= w_size-MIN_LOOKAHEAD
+        ){
+       // To simplify the code, we prevent matches with the string
+       // of window index 0 (in particular we have to avoid a match
+       // of the string with itself at the start of the input file).
+       if(strategy != Z_HUFFMAN_ONLY){
+         match_length=longest_match (hash_head);
+       }
+       // longest_match() sets match_start
+      }
+      if(match_length>=MIN_MATCH){
+       //        check_match(strstart, match_start, match_length);
+
+       bflush=_tr_tally(strstart-match_start, match_length-MIN_MATCH);
+
+       lookahead -= match_length;
+
+       // Insert new strings in the hash table only if the match length
+       // is not too large. This saves time but degrades compression.
+       if(match_length <= max_lazy_match &&
+          lookahead >= MIN_MATCH) {
+         match_length--; // string at strstart already in hash table
+         do{
+           strstart++;
+
+           ins_h=((ins_h<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff))&hash_mask;
+//         prev[strstart&w_mask]=hash_head=head[ins_h];
+           hash_head=(head[ins_h]&0xffff);
+           prev[strstart&w_mask]=head[ins_h];
+           head[ins_h]=(short)strstart;
+
+           // strstart never exceeds WSIZE-MAX_MATCH, so there are
+           // always MIN_MATCH bytes ahead.
+         }
+         while (--match_length != 0);
+         strstart++; 
+       }
+       else{
+         strstart += match_length;
+         match_length = 0;
+         ins_h = window[strstart]&0xff;
+
+         ins_h=(((ins_h)<<hash_shift)^(window[strstart+1]&0xff))&hash_mask;
+         // If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+         // matter since it will be recomputed at next deflate call.
+       }
+      }
+      else {
+       // No match, output a literal byte
+
+       bflush=_tr_tally(0, window[strstart]&0xff);
+       lookahead--;
+       strstart++; 
+      }
+      if (bflush){
+
+       flush_block_only(false);
+       if(strm.avail_out==0) return NeedMore;
+      }
+    }
+
+    flush_block_only(flush == Z_FINISH);
+    if(strm.avail_out==0){
+      if(flush == Z_FINISH) return FinishStarted;
+      else return NeedMore;
+    }
+    return flush==Z_FINISH ? FinishDone : BlockDone;
+  }
+
+  // Same as above, but achieves better compression. We use a lazy
+  // evaluation for matches: a match is finally adopted only if there is
+  // no better match at the next window position.
+  int deflate_slow(int flush){
+//    short hash_head = 0;    // head of hash chain
+    int hash_head = 0;    // head of hash chain
+    boolean bflush;         // set if current block must be flushed
+
+    // Process the input block.
+    while(true){
+      // Make sure that we always have enough lookahead, except
+      // at the end of the input file. We need MAX_MATCH bytes
+      // for the next match, plus MIN_MATCH bytes to insert the
+      // string following the next match.
+
+      if (lookahead < MIN_LOOKAHEAD) {
+       fill_window();
+       if(lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+         return NeedMore;
+       }
+       if(lookahead == 0) break; // flush the current block
+      }
+
+      // Insert the string window[strstart .. strstart+2] in the
+      // dictionary, and set hash_head to the head of the hash chain:
+
+      if(lookahead >= MIN_MATCH) {
+       ins_h=(((ins_h)<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff)) & hash_mask;
+//     prev[strstart&w_mask]=hash_head=head[ins_h];
+       hash_head=(head[ins_h]&0xffff);
+       prev[strstart&w_mask]=head[ins_h];
+       head[ins_h]=(short)strstart;
+      }
+
+      // Find the longest match, discarding those <= prev_length.
+      prev_length = match_length; prev_match = match_start;
+      match_length = MIN_MATCH-1;
+
+      if (hash_head != 0 && prev_length < max_lazy_match &&
+         ((strstart-hash_head)&0xffff) <= w_size-MIN_LOOKAHEAD
+         ){
+       // To simplify the code, we prevent matches with the string
+       // of window index 0 (in particular we have to avoid a match
+       // of the string with itself at the start of the input file).
+
+       if(strategy != Z_HUFFMAN_ONLY) {
+         match_length = longest_match(hash_head);
+       }
+       // longest_match() sets match_start
+
+       if (match_length <= 5 && (strategy == Z_FILTERED ||
+                                 (match_length == MIN_MATCH &&
+                                  strstart - match_start > 4096))) {
+
+         // If prev_match is also MIN_MATCH, match_start is garbage
+         // but we will ignore the current match anyway.
+         match_length = MIN_MATCH-1;
+       }
+      }
+
+      // If there was a match at the previous step and the current
+      // match is not better, output the previous match:
+      if(prev_length >= MIN_MATCH && match_length <= prev_length) {
+       int max_insert = strstart + lookahead - MIN_MATCH;
+       // Do not insert strings in hash table beyond this.
+
+       //          check_match(strstart-1, prev_match, prev_length);
+
+       bflush=_tr_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
+
+       // Insert in hash table all strings up to the end of the match.
+       // strstart-1 and strstart are already inserted. If there is not
+       // enough lookahead, the last two strings are not inserted in
+       // the hash table.
+       lookahead -= prev_length-1;
+       prev_length -= 2;
+       do{
+         if(++strstart <= max_insert) {
+           ins_h=(((ins_h)<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff))&hash_mask;
+           //prev[strstart&w_mask]=hash_head=head[ins_h];
+           hash_head=(head[ins_h]&0xffff);
+           prev[strstart&w_mask]=head[ins_h];
+           head[ins_h]=(short)strstart;
+         }
+       }
+       while(--prev_length != 0);
+       match_available = 0;
+       match_length = MIN_MATCH-1;
+       strstart++;
+
+       if (bflush){
+         flush_block_only(false);
+         if(strm.avail_out==0) return NeedMore;
+       }
+      } else if (match_available!=0) {
+
+       // If there was no match at the previous position, output a
+       // single literal. If there was a match but the current match
+       // is longer, truncate the previous match to a single literal.
+
+       bflush=_tr_tally(0, window[strstart-1]&0xff);
+
+       if (bflush) {
+         flush_block_only(false);
+       }
+       strstart++;
+       lookahead--;
+       if(strm.avail_out == 0) return NeedMore;
+      } else {
+       // There is no previous match to compare with, wait for
+       // the next step to decide.
+
+       match_available = 1;
+       strstart++;
+       lookahead--;
+      }
+    }
+
+    if(match_available!=0) {
+      bflush=_tr_tally(0, window[strstart-1]&0xff);
+      match_available = 0;
+    }
+    flush_block_only(flush == Z_FINISH);
+
+    if(strm.avail_out==0){
+      if(flush == Z_FINISH) return FinishStarted;
+      else return NeedMore;
+    }
+
+    return flush == Z_FINISH ? FinishDone : BlockDone;
+  }
+
+  int longest_match(int cur_match){
+    int chain_length = max_chain_length; // max hash chain length
+    int scan = strstart;                 // current string
+    int match;                           // matched string
+    int len;                             // length of current match
+    int best_len = prev_length;          // best match length so far
+    int limit = strstart>(w_size-MIN_LOOKAHEAD) ?
+      strstart-(w_size-MIN_LOOKAHEAD) : 0;
+    int nice_match=this.nice_match;
+
+    // Stop when cur_match becomes <= limit. To simplify the code,
+    // we prevent matches with the string of window index 0.
+
+    int wmask = w_mask;
+
+    int strend = strstart + MAX_MATCH;
+    byte scan_end1 = window[scan+best_len-1];
+    byte scan_end = window[scan+best_len];
+
+    // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+    // It is easy to get rid of this optimization if necessary.
+
+    // Do not waste too much time if we already have a good match:
+    if (prev_length >= good_match) {
+      chain_length >>= 2;
+    }
+
+    // Do not look for matches beyond the end of the input. This is necessary
+    // to make deflate deterministic.
+    if (nice_match > lookahead) nice_match = lookahead;
+
+    do {
+      match = cur_match;
+
+      // Skip to next match if the match length cannot increase
+      // or if the match length is less than 2:
+      if (window[match+best_len]   != scan_end  ||
+         window[match+best_len-1] != scan_end1 ||
+         window[match]       != window[scan]     ||
+         window[++match]     != window[scan+1])      continue;
+
+      // The check at best_len-1 can be removed because it will be made
+      // again later. (This heuristic is not always a win.)
+      // It is not necessary to compare scan[2] and match[2] since they
+      // are always equal when the other bytes match, given that
+      // the hash keys are equal and that HASH_BITS >= 8.
+      scan += 2; match++;
+
+      // We check for insufficient lookahead only every 8th comparison;
+      // the 256th check will be made at strstart+258.
+      do {
+      } while (window[++scan] == window[++match] &&
+              window[++scan] == window[++match] &&
+              window[++scan] == window[++match] &&
+              window[++scan] == window[++match] &&
+              window[++scan] == window[++match] &&
+              window[++scan] == window[++match] &&
+              window[++scan] == window[++match] &&
+              window[++scan] == window[++match] &&
+              scan < strend);
+
+      len = MAX_MATCH - (int)(strend - scan);
+      scan = strend - MAX_MATCH;
+
+      if(len>best_len) {
+       match_start = cur_match;
+       best_len = len;
+       if (len >= nice_match) break;
+       scan_end1  = window[scan+best_len-1];
+       scan_end   = window[scan+best_len];
+      }
+
+    } while ((cur_match = (prev[cur_match & wmask]&0xffff)) > limit
+            && --chain_length != 0);
+
+    if (best_len <= lookahead) return best_len;
+    return lookahead;
+  }
+    
+  int deflateInit(ZStream strm, int level, int bits){
+    return deflateInit2(strm, level, Z_DEFLATED, bits, DEF_MEM_LEVEL,
+                       Z_DEFAULT_STRATEGY);
+  }
+  int deflateInit(ZStream strm, int level){
+    return deflateInit(strm, level, MAX_WBITS);
+  }
+  int deflateInit2(ZStream strm, int level, int method,  int windowBits,
+                  int memLevel, int strategy){
+    int noheader = 0;
+    //    byte[] my_version=ZLIB_VERSION;
+
+    //
+    //  if (version == null || version[0] != my_version[0]
+    //  || stream_size != sizeof(z_stream)) {
+    //  return Z_VERSION_ERROR;
+    //  }
+
+    strm.msg = null;
+
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+    if (windowBits < 0) { // undocumented feature: suppress zlib header
+      noheader = 1;
+      windowBits = -windowBits;
+    }
+
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || 
+       method != Z_DEFLATED ||
+       windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
+        strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+      return Z_STREAM_ERROR;
+    }
+
+    strm.dstate = (Deflate)this;
+
+    this.noheader = noheader;
+    w_bits = windowBits;
+    w_size = 1 << w_bits;
+    w_mask = w_size - 1;
+
+    hash_bits = memLevel + 7;
+    hash_size = 1 << hash_bits;
+    hash_mask = hash_size - 1;
+    hash_shift = ((hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    window = new byte[w_size*2];
+    prev = new short[w_size];
+    head = new short[hash_size];
+
+    lit_bufsize = 1 << (memLevel + 6); // 16K elements by default
+
+    // We overlay pending_buf and d_buf+l_buf. This works since the average
+    // output size for (length,distance) codes is <= 24 bits.
+    pending_buf = new byte[lit_bufsize*4];
+    pending_buf_size = lit_bufsize*4;
+
+    d_buf = lit_bufsize/2;
+    l_buf = (1+2)*lit_bufsize;
+
+    this.level = level;
+
+//System.out.println("level="+level);
+
+    this.strategy = strategy;
+    this.method = (byte)method;
+
+    return deflateReset(strm);
+  }
+
+  int deflateReset(ZStream strm){
+    strm.total_in = strm.total_out = 0;
+    strm.msg = null; //
+    strm.data_type = Z_UNKNOWN;
+
+    pending = 0;
+    pending_out = 0;
+
+    if(noheader < 0) {
+      noheader = 0; // was set to -1 by deflate(..., Z_FINISH);
+    }
+    status = (noheader!=0) ? BUSY_STATE : INIT_STATE;
+    strm.adler=strm._adler.adler32(0, null, 0, 0);
+
+    last_flush = Z_NO_FLUSH;
+
+    tr_init();
+    lm_init();
+    return Z_OK;
+  }
+
+  int deflateEnd(){
+    if(status!=INIT_STATE && status!=BUSY_STATE && status!=FINISH_STATE){
+      return Z_STREAM_ERROR;
+    }
+    // Deallocate in reverse order of allocations:
+    pending_buf=null;
+    head=null;
+    prev=null;
+    window=null;
+    // free
+    // dstate=null;
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+  }
+
+  int deflateParams(ZStream strm, int _level, int _strategy){
+    int err=Z_OK;
+
+    if(_level == Z_DEFAULT_COMPRESSION){
+      _level = 6;
+    }
+    if(_level < 0 || _level > 9 || 
+       _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) {
+      return Z_STREAM_ERROR;
+    }
+
+    if(config_table[level].func!=config_table[_level].func &&
+       strm.total_in != 0) {
+      // Flush the last buffer:
+      err = strm.deflate(Z_PARTIAL_FLUSH);
+    }
+
+    if(level != _level) {
+      level = _level;
+      max_lazy_match   = config_table[level].max_lazy;
+      good_match       = config_table[level].good_length;
+      nice_match       = config_table[level].nice_length;
+      max_chain_length = config_table[level].max_chain;
+    }
+    strategy = _strategy;
+    return err;
+  }
+
+  int deflateSetDictionary (ZStream strm, byte[] dictionary, int dictLength){
+    int length = dictLength;
+    int index=0;
+
+    if(dictionary == null || status != INIT_STATE)
+      return Z_STREAM_ERROR;
+
+    strm.adler=strm._adler.adler32(strm.adler, dictionary, 0, dictLength);
+
+    if(length < MIN_MATCH) return Z_OK;
+    if(length > w_size-MIN_LOOKAHEAD){
+      length = w_size-MIN_LOOKAHEAD;
+      index=dictLength-length; // use the tail of the dictionary
+    }
+    System.arraycopy(dictionary, index, window, 0, length);
+    strstart = length;
+    block_start = length;
+
+    // Insert all strings in the hash table (except for the last two bytes).
+    // s->lookahead stays null, so s->ins_h will be recomputed at the next
+    // call of fill_window.
+
+    ins_h = window[0]&0xff;
+    ins_h=(((ins_h)<<hash_shift)^(window[1]&0xff))&hash_mask;
+
+    for(int n=0; n<=length-MIN_MATCH; n++){
+      ins_h=(((ins_h)<<hash_shift)^(window[(n)+(MIN_MATCH-1)]&0xff))&hash_mask;
+      prev[n&w_mask]=head[ins_h];
+      head[ins_h]=(short)n;
+    }
+    return Z_OK;
+  }
+
+  int deflate(ZStream strm, int flush){
+    int old_flush;
+
+    if(flush>Z_FINISH || flush<0){
+      return Z_STREAM_ERROR;
+    }
+
+    if(strm.next_out == null ||
+       (strm.next_in == null && strm.avail_in != 0) ||
+       (status == FINISH_STATE && flush != Z_FINISH)) {
+      strm.msg=z_errmsg[Z_NEED_DICT-(Z_STREAM_ERROR)];
+      return Z_STREAM_ERROR;
+    }
+    if(strm.avail_out == 0){
+      strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
+      return Z_BUF_ERROR;
+    }
+
+    this.strm = strm; // just in case
+    old_flush = last_flush;
+    last_flush = flush;
+
+    // Write the zlib header
+    if(status == INIT_STATE) {
+      int header = (Z_DEFLATED+((w_bits-8)<<4))<<8;
+      int level_flags=((level-1)&0xff)>>1;
+
+      if(level_flags>3) level_flags=3;
+      header |= (level_flags<<6);
+      if(strstart!=0) header |= PRESET_DICT;
+      header+=31-(header % 31);
+
+      status=BUSY_STATE;
+      putShortMSB(header);
+
+
+      // Save the adler32 of the preset dictionary:
+      if(strstart!=0){
+        putShortMSB((int)(strm.adler>>>16));
+        putShortMSB((int)(strm.adler&0xffff));
+      }
+      strm.adler=strm._adler.adler32(0, null, 0, 0);
+    }
+
+    // Flush as much pending output as possible
+    if(pending != 0) {
+      strm.flush_pending();
+      if(strm.avail_out == 0) {
+       //System.out.println("  avail_out==0");
+       // Since avail_out is 0, deflate will be called again with
+       // more output space, but possibly with both pending and
+       // avail_in equal to zero. There won't be anything to do,
+       // but this is not an error situation so make sure we
+       // return OK instead of BUF_ERROR at next call of deflate:
+       last_flush = -1;
+       return Z_OK;
+      }
+
+      // Make sure there is something to do and avoid duplicate consecutive
+      // flushes. For repeated and useless calls with Z_FINISH, we keep
+      // returning Z_STREAM_END instead of Z_BUFF_ERROR.
+    }
+    else if(strm.avail_in==0 && flush <= old_flush &&
+           flush != Z_FINISH) {
+      strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
+      return Z_BUF_ERROR;
+    }
+
+    // User must not provide more input after the first FINISH:
+    if(status == FINISH_STATE && strm.avail_in != 0) {
+      strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
+      return Z_BUF_ERROR;
+    }
+
+    // Start a new block or continue the current one.
+    if(strm.avail_in!=0 || lookahead!=0 ||
+       (flush != Z_NO_FLUSH && status != FINISH_STATE)) {
+      int bstate=-1;
+      switch(config_table[level].func){
+      case STORED: 
+       bstate = deflate_stored(flush);
+       break;
+      case FAST: 
+       bstate = deflate_fast(flush);
+       break;
+      case SLOW: 
+       bstate = deflate_slow(flush);
+       break;
+      default:
+      }
+
+      if (bstate==FinishStarted || bstate==FinishDone) {
+       status = FINISH_STATE;
+      }
+      if (bstate==NeedMore || bstate==FinishStarted) {
+       if(strm.avail_out == 0) {
+         last_flush = -1; // avoid BUF_ERROR next call, see above
+       }
+       return Z_OK;
+       // If flush != Z_NO_FLUSH && avail_out == 0, the next call
+       // of deflate should use the same flush parameter to make sure
+       // that the flush is complete. So we don't have to output an
+       // empty block here, this will be done at next call. This also
+       // ensures that for a very small output buffer, we emit at most
+       // one empty block.
+      }
+
+      if (bstate==BlockDone) {
+       if(flush == Z_PARTIAL_FLUSH) {
+         _tr_align();
+       } 
+       else { // FULL_FLUSH or SYNC_FLUSH
+         _tr_stored_block(0, 0, false);
+         // For a full flush, this empty block will be recognized
+         // as a special marker by inflate_sync().
+         if(flush == Z_FULL_FLUSH) {
+           //state.head[s.hash_size-1]=0;
+           for(int i=0; i<hash_size/*-1*/; i++)  // forget history
+             head[i]=0;
+         }
+       }
+       strm.flush_pending();
+       if(strm.avail_out == 0) {
+         last_flush = -1; // avoid BUF_ERROR at next call, see above
+         return Z_OK;
+       }
+      }
+    }
+
+    if(flush!=Z_FINISH) return Z_OK;
+    if(noheader!=0) return Z_STREAM_END;
+
+    // Write the zlib trailer (adler32)
+    putShortMSB((int)(strm.adler>>>16));
+    putShortMSB((int)(strm.adler&0xffff));
+    strm.flush_pending();
+
+    // If avail_out is zero, the application will call deflate again
+    // to flush the rest.
+    noheader = -1; // write the trailer only once!
+    return pending != 0 ? Z_OK : Z_STREAM_END;
+  }
+}
diff --git a/src/com/jcraft/jzlib/InfBlocks.java b/src/com/jcraft/jzlib/InfBlocks.java
new file mode 100644 (file)
index 0000000..f6997fc
--- /dev/null
@@ -0,0 +1,614 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/*
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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 program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+final class InfBlocks{
+  static final private int MANY=1440;
+
+  // And'ing with mask[n] masks the lower n bits
+  static final private int[] inflate_mask = {
+    0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+    0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff,
+    0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
+    0x00007fff, 0x0000ffff
+  };
+
+  // Table for deflate from PKZIP's appnote.txt.
+  static final int[] border = { // Order of the bit length code lengths
+    16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+  };
+
+  static final private int Z_OK=0;
+  static final private int Z_STREAM_END=1;
+  static final private int Z_NEED_DICT=2;
+  static final private int Z_ERRNO=-1;
+  static final private int Z_STREAM_ERROR=-2;
+  static final private int Z_DATA_ERROR=-3;
+  static final private int Z_MEM_ERROR=-4;
+  static final private int Z_BUF_ERROR=-5;
+  static final private int Z_VERSION_ERROR=-6;
+
+  static final private int TYPE=0;  // get type bits (3, including end bit)
+  static final private int LENS=1;  // get lengths for stored
+  static final private int STORED=2;// processing stored block
+  static final private int TABLE=3; // get table lengths
+  static final private int BTREE=4; // get bit lengths tree for a dynamic block
+  static final private int DTREE=5; // get length, distance trees for a dynamic block
+  static final private int CODES=6; // processing fixed or dynamic block
+  static final private int DRY=7;   // output remaining window bytes
+  static final private int DONE=8;  // finished last block, done
+  static final private int BAD=9;   // ot a data error--stuck here
+
+  int mode;            // current inflate_block mode 
+
+  int left;            // if STORED, bytes left to copy 
+
+  int table;           // table lengths (14 bits) 
+  int index;           // index into blens (or border) 
+  int[] blens;         // bit lengths of codes 
+  int[] bb=new int[1]; // bit length tree depth 
+  int[] tb=new int[1]; // bit length decoding tree 
+
+  InfCodes codes=new InfCodes();      // if CODES, current state 
+
+  int last;            // true if this block is the last block 
+
+  // mode independent information 
+  int bitk;            // bits in bit buffer 
+  int bitb;            // bit buffer 
+  int[] hufts;         // single malloc for tree space 
+  byte[] window;       // sliding window 
+  int end;             // one byte after sliding window 
+  int read;            // window read pointer 
+  int write;           // window write pointer 
+  Object checkfn;      // check function 
+  long check;          // check on output 
+
+  InfTree inftree=new InfTree();
+
+  InfBlocks(ZStream z, Object checkfn, int w){
+    hufts=new int[MANY*3];
+    window=new byte[w];
+    end=w;
+    this.checkfn = checkfn;
+    mode = TYPE;
+    reset(z, null);
+  }
+
+  void reset(ZStream z, long[] c){
+    if(c!=null) c[0]=check;
+    if(mode==BTREE || mode==DTREE){
+    }
+    if(mode==CODES){
+      codes.free(z);
+    }
+    mode=TYPE;
+    bitk=0;
+    bitb=0;
+    read=write=0;
+
+    if(checkfn != null)
+      z.adler=check=z._adler.adler32(0L, null, 0, 0);
+  }
+
+  int proc(ZStream z, int r){
+    int t;              // temporary storage
+    int b;              // bit buffer
+    int k;              // bits in bit buffer
+    int p;              // input data pointer
+    int n;              // bytes available there
+    int q;              // output window write pointer
+    int m;              // bytes to end of window or read pointer
+
+    // copy input/output information to locals (UPDATE macro restores)
+    {p=z.next_in_index;n=z.avail_in;b=bitb;k=bitk;}
+    {q=write;m=(int)(q<read?read-q-1:end-q);}
+
+    // process input based on current state
+    while(true){
+      switch (mode){
+      case TYPE:
+
+       while(k<(3)){
+         if(n!=0){
+           r=Z_OK;
+         }
+         else{
+           bitb=b; bitk=k; 
+           z.avail_in=n;
+           z.total_in+=p-z.next_in_index;z.next_in_index=p;
+           write=q;
+           return inflate_flush(z,r);
+         };
+         n--;
+         b|=(z.next_in[p++]&0xff)<<k;
+         k+=8;
+       }
+       t = (int)(b & 7);
+       last = t & 1;
+
+       switch (t >>> 1){
+        case 0:                         // stored 
+          {b>>>=(3);k-=(3);}
+          t = k & 7;                    // go to byte boundary
+
+          {b>>>=(t);k-=(t);}
+          mode = LENS;                  // get length of stored block
+          break;
+        case 1:                         // fixed
+          {
+            int[] bl=new int[1];
+           int[] bd=new int[1];
+            int[][] tl=new int[1][];
+           int[][] td=new int[1][];
+
+           InfTree.inflate_trees_fixed(bl, bd, tl, td, z);
+            codes.init(bl[0], bd[0], tl[0], 0, td[0], 0, z);
+          }
+
+          {b>>>=(3);k-=(3);}
+
+          mode = CODES;
+          break;
+        case 2:                         // dynamic
+
+          {b>>>=(3);k-=(3);}
+
+          mode = TABLE;
+          break;
+        case 3:                         // illegal
+
+          {b>>>=(3);k-=(3);}
+          mode = BAD;
+          z.msg = "invalid block type";
+          r = Z_DATA_ERROR;
+
+         bitb=b; bitk=k; 
+         z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+         write=q;
+         return inflate_flush(z,r);
+       }
+       break;
+      case LENS:
+
+       while(k<(32)){
+         if(n!=0){
+           r=Z_OK;
+         }
+         else{
+           bitb=b; bitk=k; 
+           z.avail_in=n;
+           z.total_in+=p-z.next_in_index;z.next_in_index=p;
+           write=q;
+           return inflate_flush(z,r);
+         };
+         n--;
+         b|=(z.next_in[p++]&0xff)<<k;
+         k+=8;
+       }
+
+       if ((((~b) >>> 16) & 0xffff) != (b & 0xffff)){
+         mode = BAD;
+         z.msg = "invalid stored block lengths";
+         r = Z_DATA_ERROR;
+
+         bitb=b; bitk=k; 
+         z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+         write=q;
+         return inflate_flush(z,r);
+       }
+       left = (b & 0xffff);
+       b = k = 0;                       // dump bits
+       mode = left!=0 ? STORED : (last!=0 ? DRY : TYPE);
+       break;
+      case STORED:
+       if (n == 0){
+         bitb=b; bitk=k; 
+         z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+         write=q;
+         return inflate_flush(z,r);
+       }
+
+       if(m==0){
+         if(q==end&&read!=0){
+           q=0; m=(int)(q<read?read-q-1:end-q);
+         }
+         if(m==0){
+           write=q; 
+           r=inflate_flush(z,r);
+           q=write;m=(int)(q<read?read-q-1:end-q);
+           if(q==end&&read!=0){
+             q=0; m=(int)(q<read?read-q-1:end-q);
+           }
+           if(m==0){
+             bitb=b; bitk=k; 
+             z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+             write=q;
+             return inflate_flush(z,r);
+           }
+         }
+       }
+       r=Z_OK;
+
+       t = left;
+       if(t>n) t = n;
+       if(t>m) t = m;
+       System.arraycopy(z.next_in, p, window, q, t);
+       p += t;  n -= t;
+       q += t;  m -= t;
+       if ((left -= t) != 0)
+         break;
+       mode = last!=0 ? DRY : TYPE;
+       break;
+      case TABLE:
+
+       while(k<(14)){
+         if(n!=0){
+           r=Z_OK;
+         }
+         else{
+           bitb=b; bitk=k; 
+           z.avail_in=n;
+           z.total_in+=p-z.next_in_index;z.next_in_index=p;
+           write=q;
+           return inflate_flush(z,r);
+         };
+         n--;
+         b|=(z.next_in[p++]&0xff)<<k;
+         k+=8;
+       }
+
+       table = t = (b & 0x3fff);
+       if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+         {
+           mode = BAD;
+           z.msg = "too many length or distance symbols";
+           r = Z_DATA_ERROR;
+
+           bitb=b; bitk=k; 
+           z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+           write=q;
+           return inflate_flush(z,r);
+         }
+       t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+       if(blens==null || blens.length<t){
+         blens=new int[t];
+       }
+       else{
+         for(int i=0; i<t; i++){blens[i]=0;}
+       }
+
+       {b>>>=(14);k-=(14);}
+
+       index = 0;
+       mode = BTREE;
+      case BTREE:
+       while (index < 4 + (table >>> 10)){
+         while(k<(3)){
+           if(n!=0){
+             r=Z_OK;
+           }
+           else{
+             bitb=b; bitk=k; 
+             z.avail_in=n;
+             z.total_in+=p-z.next_in_index;z.next_in_index=p;
+             write=q;
+             return inflate_flush(z,r);
+           };
+           n--;
+           b|=(z.next_in[p++]&0xff)<<k;
+           k+=8;
+         }
+
+         blens[border[index++]] = b&7;
+
+         {b>>>=(3);k-=(3);}
+       }
+
+       while(index < 19){
+         blens[border[index++]] = 0;
+       }
+
+       bb[0] = 7;
+       t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z);
+       if (t != Z_OK){
+         r = t;
+         if (r == Z_DATA_ERROR){
+           blens=null;
+           mode = BAD;
+         }
+
+         bitb=b; bitk=k; 
+         z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+         write=q;
+         return inflate_flush(z,r);
+       }
+
+       index = 0;
+       mode = DTREE;
+      case DTREE:
+       while (true){
+         t = table;
+         if(!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))){
+           break;
+         }
+
+         int[] h;
+         int i, j, c;
+
+         t = bb[0];
+
+         while(k<(t)){
+           if(n!=0){
+             r=Z_OK;
+           }
+           else{
+             bitb=b; bitk=k; 
+             z.avail_in=n;
+             z.total_in+=p-z.next_in_index;z.next_in_index=p;
+             write=q;
+             return inflate_flush(z,r);
+           };
+           n--;
+           b|=(z.next_in[p++]&0xff)<<k;
+           k+=8;
+         }
+
+         if(tb[0]==-1){
+            //System.err.println("null...");
+         }
+
+         t=hufts[(tb[0]+(b&inflate_mask[t]))*3+1];
+         c=hufts[(tb[0]+(b&inflate_mask[t]))*3+2];
+
+         if (c < 16){
+           b>>>=(t);k-=(t);
+           blens[index++] = c;
+         }
+         else { // c == 16..18
+           i = c == 18 ? 7 : c - 14;
+           j = c == 18 ? 11 : 3;
+
+           while(k<(t+i)){
+             if(n!=0){
+               r=Z_OK;
+             }
+             else{
+               bitb=b; bitk=k; 
+               z.avail_in=n;
+               z.total_in+=p-z.next_in_index;z.next_in_index=p;
+               write=q;
+               return inflate_flush(z,r);
+             };
+             n--;
+             b|=(z.next_in[p++]&0xff)<<k;
+             k+=8;
+           }
+
+           b>>>=(t);k-=(t);
+
+           j += (b & inflate_mask[i]);
+
+           b>>>=(i);k-=(i);
+
+           i = index;
+           t = table;
+           if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+               (c == 16 && i < 1)){
+             blens=null;
+             mode = BAD;
+             z.msg = "invalid bit length repeat";
+             r = Z_DATA_ERROR;
+
+             bitb=b; bitk=k; 
+             z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+             write=q;
+             return inflate_flush(z,r);
+           }
+
+           c = c == 16 ? blens[i-1] : 0;
+           do{
+             blens[i++] = c;
+           }
+           while (--j!=0);
+           index = i;
+         }
+       }
+
+       tb[0]=-1;
+       {
+         int[] bl=new int[1];
+         int[] bd=new int[1];
+         int[] tl=new int[1];
+         int[] td=new int[1];
+         bl[0] = 9;         // must be <= 9 for lookahead assumptions
+         bd[0] = 6;         // must be <= 9 for lookahead assumptions
+
+         t = table;
+         t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), 
+                                           1 + ((t >> 5) & 0x1f),
+                                           blens, bl, bd, tl, td, hufts, z);
+
+         if (t != Z_OK){
+           if (t == Z_DATA_ERROR){
+             blens=null;
+             mode = BAD;
+           }
+           r = t;
+
+           bitb=b; bitk=k; 
+           z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+           write=q;
+           return inflate_flush(z,r);
+         }
+         codes.init(bl[0], bd[0], hufts, tl[0], hufts, td[0], z);
+       }
+       mode = CODES;
+      case CODES:
+       bitb=b; bitk=k;
+       z.avail_in=n; z.total_in+=p-z.next_in_index;z.next_in_index=p;
+       write=q;
+
+       if ((r = codes.proc(this, z, r)) != Z_STREAM_END){
+         return inflate_flush(z, r);
+       }
+       r = Z_OK;
+       codes.free(z);
+
+       p=z.next_in_index; n=z.avail_in;b=bitb;k=bitk;
+       q=write;m=(int)(q<read?read-q-1:end-q);
+
+       if (last==0){
+         mode = TYPE;
+         break;
+       }
+       mode = DRY;
+      case DRY:
+       write=q; 
+       r=inflate_flush(z, r); 
+       q=write; m=(int)(q<read?read-q-1:end-q);
+       if (read != write){
+         bitb=b; bitk=k; 
+         z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+         write=q;
+         return inflate_flush(z, r);
+       }
+       mode = DONE;
+      case DONE:
+       r = Z_STREAM_END;
+
+       bitb=b; bitk=k; 
+       z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+       write=q;
+       return inflate_flush(z, r);
+      case BAD:
+       r = Z_DATA_ERROR;
+
+       bitb=b; bitk=k; 
+       z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+       write=q;
+       return inflate_flush(z, r);
+
+      default:
+       r = Z_STREAM_ERROR;
+
+       bitb=b; bitk=k; 
+       z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+       write=q;
+       return inflate_flush(z, r);
+      }
+    }
+  }
+
+  void free(ZStream z){
+    reset(z, null);
+    window=null;
+    hufts=null;
+    //ZFREE(z, s);
+  }
+
+  void set_dictionary(byte[] d, int start, int n){
+    System.arraycopy(d, start, window, 0, n);
+    read = write = n;
+  }
+
+  // Returns true if inflate is currently at the end of a block generated
+  // by Z_SYNC_FLUSH or Z_FULL_FLUSH. 
+  int sync_point(){
+    return mode == LENS ? 1 : 0;
+  }
+
+  // copy as much as possible from the sliding window to the output area
+  int inflate_flush(ZStream z, int r){
+    int n;
+    int p;
+    int q;
+
+    // local copies of source and destination pointers
+    p = z.next_out_index;
+    q = read;
+
+    // compute number of bytes to copy as far as end of window
+    n = (int)((q <= write ? write : end) - q);
+    if (n > z.avail_out) n = z.avail_out;
+    if (n!=0 && r == Z_BUF_ERROR) r = Z_OK;
+
+    // update counters
+    z.avail_out -= n;
+    z.total_out += n;
+
+    // update check information
+    if(checkfn != null)
+      z.adler=check=z._adler.adler32(check, window, q, n);
+
+    // copy as far as end of window
+    System.arraycopy(window, q, z.next_out, p, n);
+    p += n;
+    q += n;
+
+    // see if more to copy at beginning of window
+    if (q == end){
+      // wrap pointers
+      q = 0;
+      if (write == end)
+        write = 0;
+
+      // compute bytes to copy
+      n = write - q;
+      if (n > z.avail_out) n = z.avail_out;
+      if (n!=0 && r == Z_BUF_ERROR) r = Z_OK;
+
+      // update counters
+      z.avail_out -= n;
+      z.total_out += n;
+
+      // update check information
+      if(checkfn != null)
+       z.adler=check=z._adler.adler32(check, window, q, n);
+
+      // copy
+      System.arraycopy(window, q, z.next_out, p, n);
+      p += n;
+      q += n;
+    }
+
+    // update pointers
+    z.next_out_index = p;
+    read = q;
+
+    // done
+    return r;
+  }
+}
diff --git a/src/com/jcraft/jzlib/InfCodes.java b/src/com/jcraft/jzlib/InfCodes.java
new file mode 100644 (file)
index 0000000..c768fb1
--- /dev/null
@@ -0,0 +1,605 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/*
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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 program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+final class InfCodes{
+
+  static final private int[] inflate_mask = {
+    0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+    0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff,
+    0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
+    0x00007fff, 0x0000ffff
+  };
+
+  static final private int Z_OK=0;
+  static final private int Z_STREAM_END=1;
+  static final private int Z_NEED_DICT=2;
+  static final private int Z_ERRNO=-1;
+  static final private int Z_STREAM_ERROR=-2;
+  static final private int Z_DATA_ERROR=-3;
+  static final private int Z_MEM_ERROR=-4;
+  static final private int Z_BUF_ERROR=-5;
+  static final private int Z_VERSION_ERROR=-6;
+
+  // waiting for "i:"=input,
+  //             "o:"=output,
+  //             "x:"=nothing
+  static final private int START=0;  // x: set up for LEN
+  static final private int LEN=1;    // i: get length/literal/eob next
+  static final private int LENEXT=2; // i: getting length extra (have base)
+  static final private int DIST=3;   // i: get distance next
+  static final private int DISTEXT=4;// i: getting distance extra
+  static final private int COPY=5;   // o: copying bytes in window, waiting for space
+  static final private int LIT=6;    // o: got literal, waiting for output space
+  static final private int WASH=7;   // o: got eob, possibly still output waiting
+  static final private int END=8;    // x: got eob and all data flushed
+  static final private int BADCODE=9;// x: got error
+
+  int mode;      // current inflate_codes mode
+
+  // mode dependent information
+  int len;
+
+  int[] tree; // pointer into tree
+  int tree_index=0;
+  int need;   // bits needed
+
+  int lit;
+
+  // if EXT or COPY, where and how much
+  int get;              // bits to get for extra
+  int dist;             // distance back to copy from
+
+  byte lbits;           // ltree bits decoded per branch
+  byte dbits;           // dtree bits decoder per branch
+  int[] ltree;          // literal/length/eob tree
+  int ltree_index;      // literal/length/eob tree
+  int[] dtree;          // distance tree
+  int dtree_index;      // distance tree
+
+  InfCodes(){
+  }
+  void init(int bl, int bd,
+          int[] tl, int tl_index,
+          int[] td, int td_index, ZStream z){
+    mode=START;
+    lbits=(byte)bl;
+    dbits=(byte)bd;
+    ltree=tl;
+    ltree_index=tl_index;
+    dtree = td;
+    dtree_index=td_index;
+    tree=null;
+  }
+
+  int proc(InfBlocks s, ZStream z, int r){ 
+    int j;              // temporary storage
+    int[] t;            // temporary pointer
+    int tindex;         // temporary pointer
+    int e;              // extra bits or operation
+    int b=0;            // bit buffer
+    int k=0;            // bits in bit buffer
+    int p=0;            // input data pointer
+    int n;              // bytes available there
+    int q;              // output window write pointer
+    int m;              // bytes to end of window or read pointer
+    int f;              // pointer to copy strings from
+
+    // copy input/output information to locals (UPDATE macro restores)
+    p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
+    q=s.write;m=q<s.read?s.read-q-1:s.end-q;
+
+    // process input and output based on current state
+    while (true){
+      switch (mode){
+       // waiting for "i:"=input, "o:"=output, "x:"=nothing
+      case START:         // x: set up for LEN
+       if (m >= 258 && n >= 10){
+
+         s.bitb=b;s.bitk=k;
+         z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+         s.write=q;
+         r = inflate_fast(lbits, dbits, 
+                          ltree, ltree_index, 
+                          dtree, dtree_index,
+                          s, z);
+
+         p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
+         q=s.write;m=q<s.read?s.read-q-1:s.end-q;
+
+         if (r != Z_OK){
+           mode = r == Z_STREAM_END ? WASH : BADCODE;
+           break;
+         }
+       }
+       need = lbits;
+       tree = ltree;
+       tree_index=ltree_index;
+
+       mode = LEN;
+      case LEN:           // i: get length/literal/eob next
+       j = need;
+
+       while(k<(j)){
+         if(n!=0)r=Z_OK;
+         else{
+
+           s.bitb=b;s.bitk=k;
+           z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+           s.write=q;
+           return s.inflate_flush(z,r);
+         }
+         n--;
+         b|=(z.next_in[p++]&0xff)<<k;
+         k+=8;
+       }
+
+       tindex=(tree_index+(b&inflate_mask[j]))*3;
+
+       b>>>=(tree[tindex+1]);
+       k-=(tree[tindex+1]);
+
+       e=tree[tindex];
+
+       if(e == 0){               // literal
+         lit = tree[tindex+2];
+         mode = LIT;
+         break;
+       }
+       if((e & 16)!=0 ){          // length
+         get = e & 15;
+         len = tree[tindex+2];
+         mode = LENEXT;
+         break;
+       }
+       if ((e & 64) == 0){        // next table
+         need = e;
+         tree_index = tindex/3+tree[tindex+2];
+         break;
+       }
+       if ((e & 32)!=0){               // end of block
+         mode = WASH;
+         break;
+       }
+       mode = BADCODE;        // invalid code
+       z.msg = "invalid literal/length code";
+       r = Z_DATA_ERROR;
+
+       s.bitb=b;s.bitk=k;
+       z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+       s.write=q;
+       return s.inflate_flush(z,r);
+
+      case LENEXT:        // i: getting length extra (have base)
+       j = get;
+
+       while(k<(j)){
+         if(n!=0)r=Z_OK;
+         else{
+
+           s.bitb=b;s.bitk=k;
+           z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+           s.write=q;
+           return s.inflate_flush(z,r);
+         }
+         n--; b|=(z.next_in[p++]&0xff)<<k;
+         k+=8;
+       }
+
+       len += (b & inflate_mask[j]);
+
+       b>>=j;
+       k-=j;
+
+       need = dbits;
+       tree = dtree;
+       tree_index=dtree_index;
+       mode = DIST;
+      case DIST:          // i: get distance next
+       j = need;
+
+       while(k<(j)){
+         if(n!=0)r=Z_OK;
+         else{
+
+           s.bitb=b;s.bitk=k;
+           z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+           s.write=q;
+           return s.inflate_flush(z,r);
+         }
+         n--; b|=(z.next_in[p++]&0xff)<<k;
+         k+=8;
+       }
+
+       tindex=(tree_index+(b & inflate_mask[j]))*3;
+
+       b>>=tree[tindex+1];
+       k-=tree[tindex+1];
+
+       e = (tree[tindex]);
+       if((e & 16)!=0){               // distance
+         get = e & 15;
+         dist = tree[tindex+2];
+         mode = DISTEXT;
+         break;
+       }
+       if ((e & 64) == 0){        // next table
+         need = e;
+         tree_index = tindex/3 + tree[tindex+2];
+         break;
+       }
+       mode = BADCODE;        // invalid code
+       z.msg = "invalid distance code";
+       r = Z_DATA_ERROR;
+
+       s.bitb=b;s.bitk=k;
+       z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+       s.write=q;
+       return s.inflate_flush(z,r);
+
+      case DISTEXT:       // i: getting distance extra
+       j = get;
+
+       while(k<(j)){
+         if(n!=0)r=Z_OK;
+         else{
+
+           s.bitb=b;s.bitk=k;
+           z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+           s.write=q;
+           return s.inflate_flush(z,r);
+         }
+         n--; b|=(z.next_in[p++]&0xff)<<k;
+         k+=8;
+       }
+
+       dist += (b & inflate_mask[j]);
+
+       b>>=j;
+       k-=j;
+
+       mode = COPY;
+      case COPY:          // o: copying bytes in window, waiting for space
+        f = q - dist;
+        while(f < 0){     // modulo window size-"while" instead
+          f += s.end;     // of "if" handles invalid distances
+       }
+       while (len!=0){
+
+         if(m==0){
+           if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
+           if(m==0){
+             s.write=q; r=s.inflate_flush(z,r);
+             q=s.write;m=q<s.read?s.read-q-1:s.end-q;
+
+             if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
+
+             if(m==0){
+               s.bitb=b;s.bitk=k;
+               z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+               s.write=q;
+               return s.inflate_flush(z,r);
+             }  
+           }
+         }
+
+         s.window[q++]=s.window[f++]; m--;
+
+         if (f == s.end)
+            f = 0;
+         len--;
+       }
+       mode = START;
+       break;
+      case LIT:           // o: got literal, waiting for output space
+       if(m==0){
+         if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
+         if(m==0){
+           s.write=q; r=s.inflate_flush(z,r);
+           q=s.write;m=q<s.read?s.read-q-1:s.end-q;
+
+           if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
+           if(m==0){
+             s.bitb=b;s.bitk=k;
+             z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+             s.write=q;
+             return s.inflate_flush(z,r);
+           }
+         }
+       }
+       r=Z_OK;
+
+       s.window[q++]=(byte)lit; m--;
+
+       mode = START;
+       break;
+      case WASH:           // o: got eob, possibly more output
+       if (k > 7){        // return unused byte, if any
+         k -= 8;
+         n++;
+         p--;             // can always return one
+       }
+
+       s.write=q; r=s.inflate_flush(z,r);
+       q=s.write;m=q<s.read?s.read-q-1:s.end-q;
+
+       if (s.read != s.write){
+         s.bitb=b;s.bitk=k;
+         z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+         s.write=q;
+         return s.inflate_flush(z,r);
+       }
+       mode = END;
+      case END:
+       r = Z_STREAM_END;
+       s.bitb=b;s.bitk=k;
+       z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+       s.write=q;
+       return s.inflate_flush(z,r);
+
+      case BADCODE:       // x: got error
+
+       r = Z_DATA_ERROR;
+
+       s.bitb=b;s.bitk=k;
+       z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+       s.write=q;
+       return s.inflate_flush(z,r);
+
+      default:
+       r = Z_STREAM_ERROR;
+
+       s.bitb=b;s.bitk=k;
+       z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+       s.write=q;
+       return s.inflate_flush(z,r);
+      }
+    }
+  }
+
+  void free(ZStream z){
+    //  ZFREE(z, c);
+  }
+
+  // Called with number of bytes left to write in window at least 258
+  // (the maximum string length) and number of input bytes available
+  // at least ten.  The ten bytes are six bytes for the longest length/
+  // distance pair plus four bytes for overloading the bit buffer.
+
+  int inflate_fast(int bl, int bd, 
+                  int[] tl, int tl_index,
+                  int[] td, int td_index,
+                  InfBlocks s, ZStream z){
+    int t;                // temporary pointer
+    int[] tp;             // temporary pointer
+    int tp_index;         // temporary pointer
+    int e;                // extra bits or operation
+    int b;                // bit buffer
+    int k;                // bits in bit buffer
+    int p;                // input data pointer
+    int n;                // bytes available there
+    int q;                // output window write pointer
+    int m;                // bytes to end of window or read pointer
+    int ml;               // mask for literal/length tree
+    int md;               // mask for distance tree
+    int c;                // bytes to copy
+    int d;                // distance back to copy from
+    int r;                // copy source pointer
+
+    int tp_index_t_3;     // (tp_index+t)*3
+
+    // load input, output, bit values
+    p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
+    q=s.write;m=q<s.read?s.read-q-1:s.end-q;
+
+    // initialize masks
+    ml = inflate_mask[bl];
+    md = inflate_mask[bd];
+
+    // do until not enough input or output space for fast loop
+    do {                          // assume called with m >= 258 && n >= 10
+      // get literal/length code
+      while(k<(20)){              // max bits for literal/length code
+       n--;
+       b|=(z.next_in[p++]&0xff)<<k;k+=8;
+      }
+
+      t= b&ml;
+      tp=tl; 
+      tp_index=tl_index;
+      tp_index_t_3=(tp_index+t)*3;
+      if ((e = tp[tp_index_t_3]) == 0){
+       b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+       s.window[q++] = (byte)tp[tp_index_t_3+2];
+       m--;
+       continue;
+      }
+      do {
+
+       b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+       if((e&16)!=0){
+         e &= 15;
+         c = tp[tp_index_t_3+2] + ((int)b & inflate_mask[e]);
+
+         b>>=e; k-=e;
+
+         // decode distance base of block to copy
+         while(k<(15)){           // max bits for distance code
+           n--;
+           b|=(z.next_in[p++]&0xff)<<k;k+=8;
+         }
+
+         t= b&md;
+         tp=td;
+         tp_index=td_index;
+          tp_index_t_3=(tp_index+t)*3;
+         e = tp[tp_index_t_3];
+
+         do {
+
+           b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+           if((e&16)!=0){
+             // get extra bits to add to distance base
+             e &= 15;
+             while(k<(e)){         // get extra bits (up to 13)
+               n--;
+               b|=(z.next_in[p++]&0xff)<<k;k+=8;
+             }
+
+             d = tp[tp_index_t_3+2] + (b&inflate_mask[e]);
+
+             b>>=(e); k-=(e);
+
+             // do the copy
+             m -= c;
+             if (q >= d){                // offset before dest
+               //  just copy
+               r=q-d;
+               if(q-r>0 && 2>(q-r)){           
+                 s.window[q++]=s.window[r++]; // minimum count is three,
+                 s.window[q++]=s.window[r++]; // so unroll loop a little
+                 c-=2;
+               }
+               else{
+                 System.arraycopy(s.window, r, s.window, q, 2);
+                 q+=2; r+=2; c-=2;
+               }
+             }
+             else{                  // else offset after destination
+                r=q-d;
+                do{
+                  r+=s.end;          // force pointer in window
+                }while(r<0);         // covers invalid distances
+               e=s.end-r;
+               if(c>e){             // if source crosses,
+                 c-=e;              // wrapped copy
+                 if(q-r>0 && e>(q-r)){           
+                   do{s.window[q++] = s.window[r++];}
+                   while(--e!=0);
+                 }
+                 else{
+                   System.arraycopy(s.window, r, s.window, q, e);
+                   q+=e; r+=e; e=0;
+                 }
+                 r = 0;                  // copy rest from start of window
+               }
+
+             }
+
+             // copy all or what's left
+             if(q-r>0 && c>(q-r)){           
+               do{s.window[q++] = s.window[r++];}
+               while(--c!=0);
+             }
+             else{
+               System.arraycopy(s.window, r, s.window, q, c);
+               q+=c; r+=c; c=0;
+             }
+             break;
+           }
+           else if((e&64)==0){
+             t+=tp[tp_index_t_3+2];
+             t+=(b&inflate_mask[e]);
+             tp_index_t_3=(tp_index+t)*3;
+             e=tp[tp_index_t_3];
+           }
+           else{
+             z.msg = "invalid distance code";
+
+             c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
+
+             s.bitb=b;s.bitk=k;
+             z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+             s.write=q;
+
+             return Z_DATA_ERROR;
+           }
+         }
+         while(true);
+         break;
+       }
+
+       if((e&64)==0){
+         t+=tp[tp_index_t_3+2];
+         t+=(b&inflate_mask[e]);
+         tp_index_t_3=(tp_index+t)*3;
+         if((e=tp[tp_index_t_3])==0){
+
+           b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+           s.window[q++]=(byte)tp[tp_index_t_3+2];
+           m--;
+           break;
+         }
+       }
+       else if((e&32)!=0){
+
+         c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
+         s.bitb=b;s.bitk=k;
+         z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+         s.write=q;
+
+         return Z_STREAM_END;
+       }
+       else{
+         z.msg="invalid literal/length code";
+
+         c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
+
+         s.bitb=b;s.bitk=k;
+         z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+         s.write=q;
+
+         return Z_DATA_ERROR;
+       }
+      } 
+      while(true);
+    } 
+    while(m>=258 && n>= 10);
+
+    // not enough input or output--restore pointers and return
+    c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
+
+    s.bitb=b;s.bitk=k;
+    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+    s.write=q;
+
+    return Z_OK;
+  }
+}
diff --git a/src/com/jcraft/jzlib/InfTree.java b/src/com/jcraft/jzlib/InfTree.java
new file mode 100644 (file)
index 0000000..cbca436
--- /dev/null
@@ -0,0 +1,520 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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 program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+final class InfTree{
+
+  static final private int MANY=1440;
+
+  static final private int Z_OK=0;
+  static final private int Z_STREAM_END=1;
+  static final private int Z_NEED_DICT=2;
+  static final private int Z_ERRNO=-1;
+  static final private int Z_STREAM_ERROR=-2;
+  static final private int Z_DATA_ERROR=-3;
+  static final private int Z_MEM_ERROR=-4;
+  static final private int Z_BUF_ERROR=-5;
+  static final private int Z_VERSION_ERROR=-6;
+
+  static final int fixed_bl = 9;
+  static final int fixed_bd = 5;
+
+  static final int[] fixed_tl = {
+    96,7,256, 0,8,80, 0,8,16, 84,8,115,
+    82,7,31, 0,8,112, 0,8,48, 0,9,192,
+    80,7,10, 0,8,96, 0,8,32, 0,9,160,
+    0,8,0, 0,8,128, 0,8,64, 0,9,224,
+    80,7,6, 0,8,88, 0,8,24, 0,9,144,
+    83,7,59, 0,8,120, 0,8,56, 0,9,208,
+    81,7,17, 0,8,104, 0,8,40, 0,9,176,
+    0,8,8, 0,8,136, 0,8,72, 0,9,240,
+    80,7,4, 0,8,84, 0,8,20, 85,8,227,
+    83,7,43, 0,8,116, 0,8,52, 0,9,200,
+    81,7,13, 0,8,100, 0,8,36, 0,9,168,
+    0,8,4, 0,8,132, 0,8,68, 0,9,232,
+    80,7,8, 0,8,92, 0,8,28, 0,9,152,
+    84,7,83, 0,8,124, 0,8,60, 0,9,216,
+    82,7,23, 0,8,108, 0,8,44, 0,9,184,
+    0,8,12, 0,8,140, 0,8,76, 0,9,248,
+    80,7,3, 0,8,82, 0,8,18, 85,8,163,
+    83,7,35, 0,8,114, 0,8,50, 0,9,196,
+    81,7,11, 0,8,98, 0,8,34, 0,9,164,
+    0,8,2, 0,8,130, 0,8,66, 0,9,228,
+    80,7,7, 0,8,90, 0,8,26, 0,9,148,
+    84,7,67, 0,8,122, 0,8,58, 0,9,212,
+    82,7,19, 0,8,106, 0,8,42, 0,9,180,
+    0,8,10, 0,8,138, 0,8,74, 0,9,244,
+    80,7,5, 0,8,86, 0,8,22, 192,8,0,
+    83,7,51, 0,8,118, 0,8,54, 0,9,204,
+    81,7,15, 0,8,102, 0,8,38, 0,9,172,
+    0,8,6, 0,8,134, 0,8,70, 0,9,236,
+    80,7,9, 0,8,94, 0,8,30, 0,9,156,
+    84,7,99, 0,8,126, 0,8,62, 0,9,220,
+    82,7,27, 0,8,110, 0,8,46, 0,9,188,
+    0,8,14, 0,8,142, 0,8,78, 0,9,252,
+    96,7,256, 0,8,81, 0,8,17, 85,8,131,
+    82,7,31, 0,8,113, 0,8,49, 0,9,194,
+    80,7,10, 0,8,97, 0,8,33, 0,9,162,
+    0,8,1, 0,8,129, 0,8,65, 0,9,226,
+    80,7,6, 0,8,89, 0,8,25, 0,9,146,
+    83,7,59, 0,8,121, 0,8,57, 0,9,210,
+    81,7,17, 0,8,105, 0,8,41, 0,9,178,
+    0,8,9, 0,8,137, 0,8,73, 0,9,242,
+    80,7,4, 0,8,85, 0,8,21, 80,8,258,
+    83,7,43, 0,8,117, 0,8,53, 0,9,202,
+    81,7,13, 0,8,101, 0,8,37, 0,9,170,
+    0,8,5, 0,8,133, 0,8,69, 0,9,234,
+    80,7,8, 0,8,93, 0,8,29, 0,9,154,
+    84,7,83, 0,8,125, 0,8,61, 0,9,218,
+    82,7,23, 0,8,109, 0,8,45, 0,9,186,
+    0,8,13, 0,8,141, 0,8,77, 0,9,250,
+    80,7,3, 0,8,83, 0,8,19, 85,8,195,
+    83,7,35, 0,8,115, 0,8,51, 0,9,198,
+    81,7,11, 0,8,99, 0,8,35, 0,9,166,
+    0,8,3, 0,8,131, 0,8,67, 0,9,230,
+    80,7,7, 0,8,91, 0,8,27, 0,9,150,
+    84,7,67, 0,8,123, 0,8,59, 0,9,214,
+    82,7,19, 0,8,107, 0,8,43, 0,9,182,
+    0,8,11, 0,8,139, 0,8,75, 0,9,246,
+    80,7,5, 0,8,87, 0,8,23, 192,8,0,
+    83,7,51, 0,8,119, 0,8,55, 0,9,206,
+    81,7,15, 0,8,103, 0,8,39, 0,9,174,
+    0,8,7, 0,8,135, 0,8,71, 0,9,238,
+    80,7,9, 0,8,95, 0,8,31, 0,9,158,
+    84,7,99, 0,8,127, 0,8,63, 0,9,222,
+    82,7,27, 0,8,111, 0,8,47, 0,9,190,
+    0,8,15, 0,8,143, 0,8,79, 0,9,254,
+    96,7,256, 0,8,80, 0,8,16, 84,8,115,
+    82,7,31, 0,8,112, 0,8,48, 0,9,193,
+
+    80,7,10, 0,8,96, 0,8,32, 0,9,161,
+    0,8,0, 0,8,128, 0,8,64, 0,9,225,
+    80,7,6, 0,8,88, 0,8,24, 0,9,145,
+    83,7,59, 0,8,120, 0,8,56, 0,9,209,
+    81,7,17, 0,8,104, 0,8,40, 0,9,177,
+    0,8,8, 0,8,136, 0,8,72, 0,9,241,
+    80,7,4, 0,8,84, 0,8,20, 85,8,227,
+    83,7,43, 0,8,116, 0,8,52, 0,9,201,
+    81,7,13, 0,8,100, 0,8,36, 0,9,169,
+    0,8,4, 0,8,132, 0,8,68, 0,9,233,
+    80,7,8, 0,8,92, 0,8,28, 0,9,153,
+    84,7,83, 0,8,124, 0,8,60, 0,9,217,
+    82,7,23, 0,8,108, 0,8,44, 0,9,185,
+    0,8,12, 0,8,140, 0,8,76, 0,9,249,
+    80,7,3, 0,8,82, 0,8,18, 85,8,163,
+    83,7,35, 0,8,114, 0,8,50, 0,9,197,
+    81,7,11, 0,8,98, 0,8,34, 0,9,165,
+    0,8,2, 0,8,130, 0,8,66, 0,9,229,
+    80,7,7, 0,8,90, 0,8,26, 0,9,149,
+    84,7,67, 0,8,122, 0,8,58, 0,9,213,
+    82,7,19, 0,8,106, 0,8,42, 0,9,181,
+    0,8,10, 0,8,138, 0,8,74, 0,9,245,
+    80,7,5, 0,8,86, 0,8,22, 192,8,0,
+    83,7,51, 0,8,118, 0,8,54, 0,9,205,
+    81,7,15, 0,8,102, 0,8,38, 0,9,173,
+    0,8,6, 0,8,134, 0,8,70, 0,9,237,
+    80,7,9, 0,8,94, 0,8,30, 0,9,157,
+    84,7,99, 0,8,126, 0,8,62, 0,9,221,
+    82,7,27, 0,8,110, 0,8,46, 0,9,189,
+    0,8,14, 0,8,142, 0,8,78, 0,9,253,
+    96,7,256, 0,8,81, 0,8,17, 85,8,131,
+    82,7,31, 0,8,113, 0,8,49, 0,9,195,
+    80,7,10, 0,8,97, 0,8,33, 0,9,163,
+    0,8,1, 0,8,129, 0,8,65, 0,9,227,
+    80,7,6, 0,8,89, 0,8,25, 0,9,147,
+    83,7,59, 0,8,121, 0,8,57, 0,9,211,
+    81,7,17, 0,8,105, 0,8,41, 0,9,179,
+    0,8,9, 0,8,137, 0,8,73, 0,9,243,
+    80,7,4, 0,8,85, 0,8,21, 80,8,258,
+    83,7,43, 0,8,117, 0,8,53, 0,9,203,
+    81,7,13, 0,8,101, 0,8,37, 0,9,171,
+    0,8,5, 0,8,133, 0,8,69, 0,9,235,
+    80,7,8, 0,8,93, 0,8,29, 0,9,155,
+    84,7,83, 0,8,125, 0,8,61, 0,9,219,
+    82,7,23, 0,8,109, 0,8,45, 0,9,187,
+    0,8,13, 0,8,141, 0,8,77, 0,9,251,
+    80,7,3, 0,8,83, 0,8,19, 85,8,195,
+    83,7,35, 0,8,115, 0,8,51, 0,9,199,
+    81,7,11, 0,8,99, 0,8,35, 0,9,167,
+    0,8,3, 0,8,131, 0,8,67, 0,9,231,
+    80,7,7, 0,8,91, 0,8,27, 0,9,151,
+    84,7,67, 0,8,123, 0,8,59, 0,9,215,
+    82,7,19, 0,8,107, 0,8,43, 0,9,183,
+    0,8,11, 0,8,139, 0,8,75, 0,9,247,
+    80,7,5, 0,8,87, 0,8,23, 192,8,0,
+    83,7,51, 0,8,119, 0,8,55, 0,9,207,
+    81,7,15, 0,8,103, 0,8,39, 0,9,175,
+    0,8,7, 0,8,135, 0,8,71, 0,9,239,
+    80,7,9, 0,8,95, 0,8,31, 0,9,159,
+    84,7,99, 0,8,127, 0,8,63, 0,9,223,
+    82,7,27, 0,8,111, 0,8,47, 0,9,191,
+    0,8,15, 0,8,143, 0,8,79, 0,9,255
+  };
+  static final int[] fixed_td = {
+    80,5,1, 87,5,257, 83,5,17, 91,5,4097,
+    81,5,5, 89,5,1025, 85,5,65, 93,5,16385,
+    80,5,3, 88,5,513, 84,5,33, 92,5,8193,
+    82,5,9, 90,5,2049, 86,5,129, 192,5,24577,
+    80,5,2, 87,5,385, 83,5,25, 91,5,6145,
+    81,5,7, 89,5,1537, 85,5,97, 93,5,24577,
+    80,5,4, 88,5,769, 84,5,49, 92,5,12289,
+    82,5,13, 90,5,3073, 86,5,193, 192,5,24577
+  };
+
+  // Tables for deflate from PKZIP's appnote.txt.
+  static final int[] cplens = { // Copy lengths for literal codes 257..285
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+  };
+
+  // see note #13 above about 258
+  static final int[] cplext = { // Extra bits for literal codes 257..285
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112  // 112==invalid
+  };
+
+  static final int[] cpdist = { // Copy offsets for distance codes 0..29
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577
+  };
+
+  static final int[] cpdext = { // Extra bits for distance codes
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+  // If BMAX needs to be larger than 16, then h and x[] should be uLong.
+  static final int BMAX=15;         // maximum bit length of any code
+
+  int[] hn = null;  // hufts used in space
+  int[] v = null;   // work area for huft_build 
+  int[] c = null;   // bit length count table
+  int[] r = null;   // table entry for structure assignment
+  int[] u = null;   // table stack
+  int[] x = null;   // bit offsets, then code stack
+
+  private int huft_build(int[] b, // code lengths in bits (all assumed <= BMAX)
+                         int bindex, 
+                         int n,   // number of codes (assumed <= 288)
+                         int s,   // number of simple-valued codes (0..s-1)
+                         int[] d, // list of base values for non-simple codes
+                         int[] e, // list of extra bits for non-simple codes
+                         int[] t, // result: starting table
+                         int[] m, // maximum lookup bits, returns actual
+                         int[] hp,// space for trees
+                         int[] hn,// hufts used in space
+                         int[] v  // working area: values in order of bit length
+                         ){
+    // Given a list of code lengths and a maximum table size, make a set of
+    // tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+    // if the given code set is incomplete (the tables are still built in this
+    // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+    // lengths), or Z_MEM_ERROR if not enough memory.
+
+    int a;                       // counter for codes of length k
+    int f;                       // i repeats in table every f entries
+    int g;                       // maximum code length
+    int h;                       // table level
+    int i;                       // counter, current code
+    int j;                       // counter
+    int k;                       // number of bits in current code
+    int l;                       // bits per table (returned in m)
+    int mask;                    // (1 << w) - 1, to avoid cc -O bug on HP
+    int p;                       // pointer into c[], b[], or v[]
+    int q;                       // points to current table
+    int w;                       // bits before this table == (l * h)
+    int xp;                      // pointer into x
+    int y;                       // number of dummy codes added
+    int z;                       // number of entries in current table
+
+    // Generate counts for each bit length
+
+    p = 0; i = n;
+    do {
+      c[b[bindex+p]]++; p++; i--;   // assume all entries <= BMAX
+    }while(i!=0);
+
+    if(c[0] == n){                // null input--all zero length codes
+      t[0] = -1;
+      m[0] = 0;
+      return Z_OK;
+    }
+
+    // Find minimum and maximum length, bound *m by those
+    l = m[0];
+    for (j = 1; j <= BMAX; j++)
+      if(c[j]!=0) break;
+    k = j;                        // minimum code length
+    if(l < j){
+      l = j;
+    }
+    for (i = BMAX; i!=0; i--){
+      if(c[i]!=0) break;
+    }
+    g = i;                        // maximum code length
+    if(l > i){
+      l = i;
+    }
+    m[0] = l;
+
+    // Adjust last length count to fill out codes, if needed
+    for (y = 1 << j; j < i; j++, y <<= 1){
+      if ((y -= c[j]) < 0){
+        return Z_DATA_ERROR;
+      }
+    }
+    if ((y -= c[i]) < 0){
+      return Z_DATA_ERROR;
+    }
+    c[i] += y;
+
+    // Generate starting offsets into the value table for each length
+    x[1] = j = 0;
+    p = 1;  xp = 2;
+    while (--i!=0) {                 // note that i == g from above
+      x[xp] = (j += c[p]);
+      xp++;
+      p++;
+    }
+
+    // Make a table of values in order of bit lengths
+    i = 0; p = 0;
+    do {
+      if ((j = b[bindex+p]) != 0){
+        v[x[j]++] = i;
+      }
+      p++;
+    }
+    while (++i < n);
+    n = x[g];                     // set n to length of v
+
+    // Generate the Huffman codes and for each, make the table entries
+    x[0] = i = 0;                 // first Huffman code is zero
+    p = 0;                        // grab values in bit order
+    h = -1;                       // no tables yet--level -1
+    w = -l;                       // bits decoded == (l * h)
+    u[0] = 0;                     // just to keep compilers happy
+    q = 0;                        // ditto
+    z = 0;                        // ditto
+
+    // go through the bit lengths (k already is bits in shortest code)
+    for (; k <= g; k++){
+      a = c[k];
+      while (a--!=0){
+       // here i is the Huffman code of length k bits for value *p
+       // make tables up to required level
+        while (k > w + l){
+          h++;
+          w += l;                 // previous table always l bits
+         // compute minimum size table less than or equal to l bits
+          z = g - w;
+          z = (z > l) ? l : z;        // table size upper limit
+          if((f=1<<(j=k-w))>a+1){     // try a k-w bit table
+                                      // too few codes for k-w bit table
+            f -= a + 1;               // deduct codes from patterns left
+            xp = k;
+            if(j < z){
+              while (++j < z){        // try smaller tables up to z bits
+                if((f <<= 1) <= c[++xp])
+                  break;              // enough codes to use up j bits
+                f -= c[xp];           // else deduct codes from patterns
+              }
+           }
+          }
+          z = 1 << j;                 // table entries for j-bit table
+
+         // allocate new table
+          if (hn[0] + z > MANY){       // (note: doesn't matter for fixed)
+            return Z_DATA_ERROR;       // overflow of MANY
+          }
+          u[h] = q = /*hp+*/ hn[0];   // DEBUG
+          hn[0] += z;
+         // connect to last table, if there is one
+         if(h!=0){
+            x[h]=i;           // save pattern for backing up
+            r[0]=(byte)j;     // bits in this table
+            r[1]=(byte)l;     // bits to dump before this table
+            j=i>>>(w - l);
+            r[2] = (int)(q - u[h-1] - j);               // offset to this table
+            System.arraycopy(r, 0, hp, (u[h-1]+j)*3, 3); // connect to last table
+          }
+          else{
+            t[0] = q;               // first table is returned result
+         }
+        }
+
+       // set up table entry in r
+        r[1] = (byte)(k - w);
+        if (p >= n){
+          r[0] = 128 + 64;      // out of values--invalid code
+       }
+        else if (v[p] < s){
+          r[0] = (byte)(v[p] < 256 ? 0 : 32 + 64);  // 256 is end-of-block
+          r[2] = v[p++];          // simple code is just the value
+        }
+        else{
+          r[0]=(byte)(e[v[p]-s]+16+64); // non-simple--look up in lists
+          r[2]=d[v[p++] - s];
+        }
+
+        // fill code-like entries with r
+        f=1<<(k-w);
+        for (j=i>>>w;j<z;j+=f){
+          System.arraycopy(r, 0, hp, (q+j)*3, 3);
+       }
+
+       // backwards increment the k-bit code i
+        for (j = 1 << (k - 1); (i & j)!=0; j >>>= 1){
+          i ^= j;
+       }
+        i ^= j;
+
+       // backup over finished tables
+        mask = (1 << w) - 1;      // needed on HP, cc -O bug
+        while ((i & mask) != x[h]){
+          h--;                    // don't need to update q
+          w -= l;
+          mask = (1 << w) - 1;
+        }
+      }
+    }
+    // Return Z_BUF_ERROR if we were given an incomplete table
+    return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+  }
+
+  int inflate_trees_bits(int[] c,  // 19 code lengths
+                         int[] bb, // bits tree desired/actual depth
+                         int[] tb, // bits tree result
+                         int[] hp, // space for trees
+                         ZStream z // for messages
+                         ){
+    int result;
+    initWorkArea(19);
+    hn[0]=0;
+    result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);
+
+    if(result == Z_DATA_ERROR){
+      z.msg = "oversubscribed dynamic bit lengths tree";
+    }
+    else if(result == Z_BUF_ERROR || bb[0] == 0){
+      z.msg = "incomplete dynamic bit lengths tree";
+      result = Z_DATA_ERROR;
+    }
+    return result;
+  }
+
+  int inflate_trees_dynamic(int nl,   // number of literal/length codes
+                            int nd,   // number of distance codes
+                            int[] c,  // that many (total) code lengths
+                            int[] bl, // literal desired/actual bit depth
+                            int[] bd, // distance desired/actual bit depth 
+                            int[] tl, // literal/length tree result
+                            int[] td, // distance tree result
+                            int[] hp, // space for trees
+                            ZStream z // for messages
+                            ){
+    int result;
+
+    // build literal/length tree
+    initWorkArea(288);
+    hn[0]=0;
+    result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
+    if (result != Z_OK || bl[0] == 0){
+      if(result == Z_DATA_ERROR){
+        z.msg = "oversubscribed literal/length tree";
+      }
+      else if (result != Z_MEM_ERROR){
+        z.msg = "incomplete literal/length tree";
+        result = Z_DATA_ERROR;
+      }
+      return result;
+    }
+
+    // build distance tree
+    initWorkArea(288);
+    result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);
+
+    if (result != Z_OK || (bd[0] == 0 && nl > 257)){
+      if (result == Z_DATA_ERROR){
+        z.msg = "oversubscribed distance tree";
+      }
+      else if (result == Z_BUF_ERROR) {
+        z.msg = "incomplete distance tree";
+        result = Z_DATA_ERROR;
+      }
+      else if (result != Z_MEM_ERROR){
+        z.msg = "empty distance tree with lengths";
+        result = Z_DATA_ERROR;
+      }
+      return result;
+    }
+
+    return Z_OK;
+  }
+
+  static int inflate_trees_fixed(int[] bl,  //literal desired/actual bit depth
+                                 int[] bd,  //distance desired/actual bit depth
+                                 int[][] tl,//literal/length tree result
+                                 int[][] td,//distance tree result 
+                                 ZStream z  //for memory allocation
+                                ){
+    bl[0]=fixed_bl;
+    bd[0]=fixed_bd;
+    tl[0]=fixed_tl;
+    td[0]=fixed_td;
+    return Z_OK;
+  }
+
+  private void initWorkArea(int vsize){
+    if(hn==null){
+      hn=new int[1];
+      v=new int[vsize];
+      c=new int[BMAX+1];
+      r=new int[3];
+      u=new int[BMAX];
+      x=new int[BMAX+1];
+    }
+    if(v.length<vsize){ v=new int[vsize]; }
+    for(int i=0; i<vsize; i++){v[i]=0;}
+    for(int i=0; i<BMAX+1; i++){c[i]=0;}
+    for(int i=0; i<3; i++){r[i]=0;}
+//  for(int i=0; i<BMAX; i++){u[i]=0;}
+    System.arraycopy(c, 0, u, 0, BMAX);
+//  for(int i=0; i<BMAX+1; i++){x[i]=0;}
+    System.arraycopy(c, 0, x, 0, BMAX+1);
+  }
+}
diff --git a/src/com/jcraft/jzlib/Inflate.java b/src/com/jcraft/jzlib/Inflate.java
new file mode 100644 (file)
index 0000000..30310f6
--- /dev/null
@@ -0,0 +1,374 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/*
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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 program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+final class Inflate{
+  
+  static final private int MAX_WBITS=15; // 32K LZ77 window
+
+  // preset dictionary flag in zlib header
+  static final private int PRESET_DICT=0x20;
+
+  static final int Z_NO_FLUSH=0;
+  static final int Z_PARTIAL_FLUSH=1;
+  static final int Z_SYNC_FLUSH=2;
+  static final int Z_FULL_FLUSH=3;
+  static final int Z_FINISH=4;
+
+  static final private int Z_DEFLATED=8;
+
+  static final private int Z_OK=0;
+  static final private int Z_STREAM_END=1;
+  static final private int Z_NEED_DICT=2;
+  static final private int Z_ERRNO=-1;
+  static final private int Z_STREAM_ERROR=-2;
+  static final private int Z_DATA_ERROR=-3;
+  static final private int Z_MEM_ERROR=-4;
+  static final private int Z_BUF_ERROR=-5;
+  static final private int Z_VERSION_ERROR=-6;
+
+  static final private int METHOD=0;   // waiting for method byte
+  static final private int FLAG=1;     // waiting for flag byte
+  static final private int DICT4=2;    // four dictionary check bytes to go
+  static final private int DICT3=3;    // three dictionary check bytes to go
+  static final private int DICT2=4;    // two dictionary check bytes to go
+  static final private int DICT1=5;    // one dictionary check byte to go
+  static final private int DICT0=6;    // waiting for inflateSetDictionary
+  static final private int BLOCKS=7;   // decompressing blocks
+  static final private int CHECK4=8;   // four check bytes to go
+  static final private int CHECK3=9;   // three check bytes to go
+  static final private int CHECK2=10;  // two check bytes to go
+  static final private int CHECK1=11;  // one check byte to go
+  static final private int DONE=12;    // finished check, done
+  static final private int BAD=13;     // got an error--stay here
+
+  int mode;                            // current inflate mode
+
+  // mode dependent information
+  int method;        // if FLAGS, method byte
+
+  // if CHECK, check values to compare
+  long[] was=new long[1] ; // computed check value
+  long need;               // stream check value
+
+  // if BAD, inflateSync's marker bytes count
+  int marker;
+
+  // mode independent information
+  int  nowrap;          // flag for no wrapper
+  int wbits;            // log2(window size)  (8..15, defaults to 15)
+
+  InfBlocks blocks;     // current inflate_blocks state
+
+  int inflateReset(ZStream z){
+    if(z == null || z.istate == null) return Z_STREAM_ERROR;
+    
+    z.total_in = z.total_out = 0;
+    z.msg = null;
+    z.istate.mode = z.istate.nowrap!=0 ? BLOCKS : METHOD;
+    z.istate.blocks.reset(z, null);
+    return Z_OK;
+  }
+
+  int inflateEnd(ZStream z){
+    if(blocks != null)
+      blocks.free(z);
+    blocks=null;
+    //    ZFREE(z, z->state);
+    return Z_OK;
+  }
+
+  int inflateInit(ZStream z, int w){
+    z.msg = null;
+    blocks = null;
+
+    // handle undocumented nowrap option (no zlib header or check)
+    nowrap = 0;
+    if(w < 0){
+      w = - w;
+      nowrap = 1;
+    }
+
+    // set window size
+    if(w<8 ||w>15){
+      inflateEnd(z);
+      return Z_STREAM_ERROR;
+    }
+    wbits=w;
+
+    z.istate.blocks=new InfBlocks(z, 
+                                 z.istate.nowrap!=0 ? null : this,
+                                 1<<w);
+
+    // reset state
+    inflateReset(z);
+    return Z_OK;
+  }
+
+  int inflate(ZStream z, int f){
+    int r;
+    int b;
+
+    if(z == null || z.istate == null || z.next_in == null)
+      return Z_STREAM_ERROR;
+    f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+    r = Z_BUF_ERROR;
+    while (true){
+//System.out.println("mode: "+z.istate.mode);
+      switch (z.istate.mode){
+      case METHOD:
+
+        if(z.avail_in==0)return r;r=f;
+
+        z.avail_in--; z.total_in++;
+        if(((z.istate.method = z.next_in[z.next_in_index++])&0xf)!=Z_DEFLATED){
+          z.istate.mode = BAD;
+          z.msg="unknown compression method";
+          z.istate.marker = 5;       // can't try inflateSync
+          break;
+        }
+        if((z.istate.method>>4)+8>z.istate.wbits){
+          z.istate.mode = BAD;
+          z.msg="invalid window size";
+          z.istate.marker = 5;       // can't try inflateSync
+          break;
+        }
+        z.istate.mode=FLAG;
+      case FLAG:
+
+        if(z.avail_in==0)return r;r=f;
+
+        z.avail_in--; z.total_in++;
+        b = (z.next_in[z.next_in_index++])&0xff;
+
+        if((((z.istate.method << 8)+b) % 31)!=0){
+          z.istate.mode = BAD;
+          z.msg = "incorrect header check";
+          z.istate.marker = 5;       // can't try inflateSync
+          break;
+        }
+
+        if((b&PRESET_DICT)==0){
+          z.istate.mode = BLOCKS;
+          break;
+        }
+        z.istate.mode = DICT4;
+      case DICT4:
+
+        if(z.avail_in==0)return r;r=f;
+
+        z.avail_in--; z.total_in++;
+        z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
+        z.istate.mode=DICT3;
+      case DICT3:
+
+        if(z.avail_in==0)return r;r=f;
+
+        z.avail_in--; z.total_in++;
+        z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
+        z.istate.mode=DICT2;
+      case DICT2:
+
+        if(z.avail_in==0)return r;r=f;
+
+        z.avail_in--; z.total_in++;
+        z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
+        z.istate.mode=DICT1;
+      case DICT1:
+
+        if(z.avail_in==0)return r;r=f;
+
+        z.avail_in--; z.total_in++;
+        z.istate.need += (z.next_in[z.next_in_index++]&0xffL);
+        z.adler = z.istate.need;
+        z.istate.mode = DICT0;
+        return Z_NEED_DICT;
+      case DICT0:
+        z.istate.mode = BAD;
+        z.msg = "need dictionary";
+        z.istate.marker = 0;       // can try inflateSync
+        return Z_STREAM_ERROR;
+      case BLOCKS:
+
+        r = z.istate.blocks.proc(z, r);
+        if(r == Z_DATA_ERROR){
+          z.istate.mode = BAD;
+          z.istate.marker = 0;     // can try inflateSync
+          break;
+        }
+        if(r == Z_OK){
+          r = f;
+        }
+        if(r != Z_STREAM_END){
+          return r;
+        }
+        r = f;
+        z.istate.blocks.reset(z, z.istate.was);
+        if(z.istate.nowrap!=0){
+          z.istate.mode=DONE;
+          break;
+        }
+        z.istate.mode=CHECK4;
+      case CHECK4:
+
+        if(z.avail_in==0)return r;r=f;
+
+        z.avail_in--; z.total_in++;
+        z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
+        z.istate.mode=CHECK3;
+      case CHECK3:
+
+        if(z.avail_in==0)return r;r=f;
+
+        z.avail_in--; z.total_in++;
+        z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
+        z.istate.mode = CHECK2;
+      case CHECK2:
+
+        if(z.avail_in==0)return r;r=f;
+
+        z.avail_in--; z.total_in++;
+        z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
+        z.istate.mode = CHECK1;
+      case CHECK1:
+
+        if(z.avail_in==0)return r;r=f;
+
+        z.avail_in--; z.total_in++;
+        z.istate.need+=(z.next_in[z.next_in_index++]&0xffL);
+
+        if(((int)(z.istate.was[0])) != ((int)(z.istate.need))){
+          z.istate.mode = BAD;
+          z.msg = "incorrect data check";
+          z.istate.marker = 5;       // can't try inflateSync
+          break;
+        }
+
+        z.istate.mode = DONE;
+      case DONE:
+        return Z_STREAM_END;
+      case BAD:
+        return Z_DATA_ERROR;
+      default:
+        return Z_STREAM_ERROR;
+      }
+    }
+  }
+
+
+  int inflateSetDictionary(ZStream z, byte[] dictionary, int dictLength){
+    int index=0;
+    int length = dictLength;
+    if(z==null || z.istate == null|| z.istate.mode != DICT0)
+      return Z_STREAM_ERROR;
+
+    if(z._adler.adler32(1L, dictionary, 0, dictLength)!=z.adler){
+      return Z_DATA_ERROR;
+    }
+
+    z.adler = z._adler.adler32(0, null, 0, 0);
+
+    if(length >= (1<<z.istate.wbits)){
+      length = (1<<z.istate.wbits)-1;
+      index=dictLength - length;
+    }
+    z.istate.blocks.set_dictionary(dictionary, index, length);
+    z.istate.mode = BLOCKS;
+    return Z_OK;
+  }
+
+  static private byte[] mark = {(byte)0, (byte)0, (byte)0xff, (byte)0xff};
+
+  int inflateSync(ZStream z){
+    int n;       // number of bytes to look at
+    int p;       // pointer to bytes
+    int m;       // number of marker bytes found in a row
+    long r, w;   // temporaries to save total_in and total_out
+
+    // set up
+    if(z == null || z.istate == null)
+      return Z_STREAM_ERROR;
+    if(z.istate.mode != BAD){
+      z.istate.mode = BAD;
+      z.istate.marker = 0;
+    }
+    if((n=z.avail_in)==0)
+      return Z_BUF_ERROR;
+    p=z.next_in_index;
+    m=z.istate.marker;
+
+    // search
+    while (n!=0 && m < 4){
+      if(z.next_in[p] == mark[m]){
+        m++;
+      }
+      else if(z.next_in[p]!=0){
+        m = 0;
+      }
+      else{
+        m = 4 - m;
+      }
+      p++; n--;
+    }
+
+    // restore
+    z.total_in += p-z.next_in_index;
+    z.next_in_index = p;
+    z.avail_in = n;
+    z.istate.marker = m;
+
+    // return no joy or set up to restart on a new block
+    if(m != 4){
+      return Z_DATA_ERROR;
+    }
+    r=z.total_in;  w=z.total_out;
+    inflateReset(z);
+    z.total_in=r;  z.total_out = w;
+    z.istate.mode = BLOCKS;
+    return Z_OK;
+  }
+
+  // Returns true if inflate is currently at the end of a block generated
+  // by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+  // implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
+  // but removes the length bytes of the resulting empty stored block. When
+  // decompressing, PPP checks that at the end of input packet, inflate is
+  // waiting for these length bytes.
+  int inflateSyncPoint(ZStream z){
+    if(z == null || z.istate == null || z.istate.blocks == null)
+      return Z_STREAM_ERROR;
+    return z.istate.blocks.sync_point();
+  }
+}
diff --git a/src/com/jcraft/jzlib/JZlib.java b/src/com/jcraft/jzlib/JZlib.java
new file mode 100644 (file)
index 0000000..b84d7a1
--- /dev/null
@@ -0,0 +1,67 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/*
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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 program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+final public class JZlib{
+  private static final String version="1.0.2";
+  public static String version(){return version;}
+
+  // compression levels
+  static final public int Z_NO_COMPRESSION=0;
+  static final public int Z_BEST_SPEED=1;
+  static final public int Z_BEST_COMPRESSION=9;
+  static final public int Z_DEFAULT_COMPRESSION=(-1);
+
+  // compression strategy
+  static final public int Z_FILTERED=1;
+  static final public int Z_HUFFMAN_ONLY=2;
+  static final public int Z_DEFAULT_STRATEGY=0;
+
+  static final public int Z_NO_FLUSH=0;
+  static final public int Z_PARTIAL_FLUSH=1;
+  static final public int Z_SYNC_FLUSH=2;
+  static final public int Z_FULL_FLUSH=3;
+  static final public int Z_FINISH=4;
+
+  static final public int Z_OK=0;
+  static final public int Z_STREAM_END=1;
+  static final public int Z_NEED_DICT=2;
+  static final public int Z_ERRNO=-1;
+  static final public int Z_STREAM_ERROR=-2;
+  static final public int Z_DATA_ERROR=-3;
+  static final public int Z_MEM_ERROR=-4;
+  static final public int Z_BUF_ERROR=-5;
+  static final public int Z_VERSION_ERROR=-6;
+}
diff --git a/src/com/jcraft/jzlib/StaticTree.java b/src/com/jcraft/jzlib/StaticTree.java
new file mode 100644 (file)
index 0000000..0f7f577
--- /dev/null
@@ -0,0 +1,149 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/*
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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 program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+final class StaticTree{
+  static final private int MAX_BITS=15;
+
+  static final private int BL_CODES=19;
+  static final private int D_CODES=30;
+  static final private int LITERALS=256;
+  static final private int LENGTH_CODES=29;
+  static final private int L_CODES=(LITERALS+1+LENGTH_CODES);
+
+  // Bit length codes must not exceed MAX_BL_BITS bits
+  static final int MAX_BL_BITS=7; 
+
+  static final short[] static_ltree = {
+    12,  8, 140,  8,  76,  8, 204,  8,  44,  8,
+    172,  8, 108,  8, 236,  8,  28,  8, 156,  8,
+    92,  8, 220,  8,  60,  8, 188,  8, 124,  8,
+    252,  8,   2,  8, 130,  8,  66,  8, 194,  8,
+    34,  8, 162,  8,  98,  8, 226,  8,  18,  8,
+    146,  8,  82,  8, 210,  8,  50,  8, 178,  8,
+    114,  8, 242,  8,  10,  8, 138,  8,  74,  8,
+    202,  8,  42,  8, 170,  8, 106,  8, 234,  8,
+    26,  8, 154,  8,  90,  8, 218,  8,  58,  8,
+    186,  8, 122,  8, 250,  8,   6,  8, 134,  8,
+    70,  8, 198,  8,  38,  8, 166,  8, 102,  8,
+    230,  8,  22,  8, 150,  8,  86,  8, 214,  8,
+    54,  8, 182,  8, 118,  8, 246,  8,  14,  8,
+    142,  8,  78,  8, 206,  8,  46,  8, 174,  8,
+    110,  8, 238,  8,  30,  8, 158,  8,  94,  8,
+    222,  8,  62,  8, 190,  8, 126,  8, 254,  8,
+    1,  8, 129,  8,  65,  8, 193,  8,  33,  8,
+    161,  8,  97,  8, 225,  8,  17,  8, 145,  8,
+    81,  8, 209,  8,  49,  8, 177,  8, 113,  8,
+    241,  8,   9,  8, 137,  8,  73,  8, 201,  8,
+    41,  8, 169,  8, 105,  8, 233,  8,  25,  8,
+    153,  8,  89,  8, 217,  8,  57,  8, 185,  8,
+    121,  8, 249,  8,   5,  8, 133,  8,  69,  8,
+    197,  8,  37,  8, 165,  8, 101,  8, 229,  8,
+    21,  8, 149,  8,  85,  8, 213,  8,  53,  8,
+    181,  8, 117,  8, 245,  8,  13,  8, 141,  8,
+    77,  8, 205,  8,  45,  8, 173,  8, 109,  8,
+    237,  8,  29,  8, 157,  8,  93,  8, 221,  8,
+    61,  8, 189,  8, 125,  8, 253,  8,  19,  9,
+    275,  9, 147,  9, 403,  9,  83,  9, 339,  9,
+    211,  9, 467,  9,  51,  9, 307,  9, 179,  9,
+    435,  9, 115,  9, 371,  9, 243,  9, 499,  9,
+    11,  9, 267,  9, 139,  9, 395,  9,  75,  9,
+    331,  9, 203,  9, 459,  9,  43,  9, 299,  9,
+    171,  9, 427,  9, 107,  9, 363,  9, 235,  9,
+    491,  9,  27,  9, 283,  9, 155,  9, 411,  9,
+    91,  9, 347,  9, 219,  9, 475,  9,  59,  9,
+    315,  9, 187,  9, 443,  9, 123,  9, 379,  9,
+    251,  9, 507,  9,   7,  9, 263,  9, 135,  9,
+    391,  9,  71,  9, 327,  9, 199,  9, 455,  9,
+    39,  9, 295,  9, 167,  9, 423,  9, 103,  9,
+    359,  9, 231,  9, 487,  9,  23,  9, 279,  9,
+    151,  9, 407,  9,  87,  9, 343,  9, 215,  9,
+    471,  9,  55,  9, 311,  9, 183,  9, 439,  9,
+    119,  9, 375,  9, 247,  9, 503,  9,  15,  9,
+    271,  9, 143,  9, 399,  9,  79,  9, 335,  9,
+    207,  9, 463,  9,  47,  9, 303,  9, 175,  9,
+    431,  9, 111,  9, 367,  9, 239,  9, 495,  9,
+    31,  9, 287,  9, 159,  9, 415,  9,  95,  9,
+    351,  9, 223,  9, 479,  9,  63,  9, 319,  9,
+    191,  9, 447,  9, 127,  9, 383,  9, 255,  9,
+    511,  9,   0,  7,  64,  7,  32,  7,  96,  7,
+    16,  7,  80,  7,  48,  7, 112,  7,   8,  7,
+    72,  7,  40,  7, 104,  7,  24,  7,  88,  7,
+    56,  7, 120,  7,   4,  7,  68,  7,  36,  7,
+    100,  7,  20,  7,  84,  7,  52,  7, 116,  7,
+    3,  8, 131,  8,  67,  8, 195,  8,  35,  8,
+    163,  8,  99,  8, 227,  8
+  };
+
+  static final short[] static_dtree = {
+    0, 5, 16, 5,  8, 5, 24, 5,  4, 5,
+    20, 5, 12, 5, 28, 5,  2, 5, 18, 5,
+    10, 5, 26, 5,  6, 5, 22, 5, 14, 5,
+    30, 5,  1, 5, 17, 5,  9, 5, 25, 5,
+    5, 5, 21, 5, 13, 5, 29, 5,  3, 5,
+    19, 5, 11, 5, 27, 5,  7, 5, 23, 5
+  };
+
+  static StaticTree static_l_desc =
+    new StaticTree(static_ltree, Tree.extra_lbits,
+                  LITERALS+1, L_CODES, MAX_BITS);
+
+  static StaticTree static_d_desc =
+    new StaticTree(static_dtree, Tree.extra_dbits,
+                  0,  D_CODES, MAX_BITS);
+
+  static StaticTree static_bl_desc =
+    new StaticTree(null, Tree.extra_blbits,
+                  0, BL_CODES, MAX_BL_BITS);
+
+  short[] static_tree;     // static tree or null
+  int[] extra_bits;        // extra bits for each code or null
+  int extra_base;          // base index for extra_bits
+  int elems;               // max number of elements in the tree
+  int max_length;          // max bit length for the codes
+
+  StaticTree(short[] static_tree,
+            int[] extra_bits,
+            int extra_base,
+            int elems,
+            int max_length
+            ){
+    this.static_tree=static_tree;
+    this.extra_bits=extra_bits;
+    this.extra_base=extra_base;
+    this.elems=elems;
+    this.max_length=max_length;
+  }
+}
diff --git a/src/com/jcraft/jzlib/Tree.java b/src/com/jcraft/jzlib/Tree.java
new file mode 100644 (file)
index 0000000..8103897
--- /dev/null
@@ -0,0 +1,365 @@
+/* -*-mode:java; c-basic-offset:2; -*- */
+/*
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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 program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+final class Tree{
+  static final private int MAX_BITS=15;
+  static final private int BL_CODES=19;
+  static final private int D_CODES=30;
+  static final private int LITERALS=256;
+  static final private int LENGTH_CODES=29;
+  static final private int L_CODES=(LITERALS+1+LENGTH_CODES);
+  static final private int HEAP_SIZE=(2*L_CODES+1);
+
+  // Bit length codes must not exceed MAX_BL_BITS bits
+  static final int MAX_BL_BITS=7; 
+
+  // end of block literal code
+  static final int END_BLOCK=256; 
+
+  // repeat previous bit length 3-6 times (2 bits of repeat count)
+  static final int REP_3_6=16; 
+
+  // repeat a zero length 3-10 times  (3 bits of repeat count)
+  static final int REPZ_3_10=17; 
+
+  // repeat a zero length 11-138 times  (7 bits of repeat count)
+  static final int REPZ_11_138=18; 
+
+  // extra bits for each length code
+  static final int[] extra_lbits={
+    0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0
+  };
+
+  // extra bits for each distance code
+  static final int[] extra_dbits={
+    0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13
+  };
+
+  // extra bits for each bit length code
+  static final int[] extra_blbits={
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7
+  };
+
+  static final byte[] bl_order={
+    16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+
+
+  // The lengths of the bit length codes are sent in order of decreasing
+  // probability, to avoid transmitting the lengths for unused bit
+  // length codes.
+
+  static final int Buf_size=8*2;
+
+  // see definition of array dist_code below
+  static final int DIST_CODE_LEN=512;
+
+  static final byte[] _dist_code = {
+    0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
+    8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+    11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+    13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+    15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+    15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+    15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
+    18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+    23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+    24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+    26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+    26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+    27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+    28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+    28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+    29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+    29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+    29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+  };
+
+  static final byte[] _length_code={
+    0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
+    13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+    17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+    19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+    21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+    22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+    23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+    24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+    25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+    25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+    26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+    26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+  };
+
+  static final int[] base_length = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+    64, 80, 96, 112, 128, 160, 192, 224, 0
+  };
+
+  static final int[] base_dist = {
+       0,   1,      2,     3,     4,    6,     8,    12,    16,     24,
+      32,  48,     64,    96,   128,  192,   256,   384,   512,    768,
+    1024, 1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
+  };
+
+  // Mapping from a distance to a distance code. dist is the distance - 1 and
+  // must not have side effects. _dist_code[256] and _dist_code[257] are never
+  // used.
+  static int d_code(int dist){
+    return ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>>7)]);
+  }
+
+  short[] dyn_tree;      // the dynamic tree
+  int     max_code;      // largest code with non zero frequency
+  StaticTree stat_desc;  // the corresponding static tree
+
+  // Compute the optimal bit lengths for a tree and update the total bit length
+  // for the current block.
+  // IN assertion: the fields freq and dad are set, heap[heap_max] and
+  //    above are the tree nodes sorted by increasing frequency.
+  // OUT assertions: the field len is set to the optimal bit length, the
+  //     array bl_count contains the frequencies for each bit length.
+  //     The length opt_len is updated; static_len is also updated if stree is
+  //     not null.
+  void gen_bitlen(Deflate s){
+    short[] tree = dyn_tree;
+    short[] stree = stat_desc.static_tree;
+    int[] extra = stat_desc.extra_bits;
+    int base = stat_desc.extra_base;
+    int max_length = stat_desc.max_length;
+    int h;              // heap index
+    int n, m;           // iterate over the tree elements
+    int bits;           // bit length
+    int xbits;          // extra bits
+    short f;            // frequency
+    int overflow = 0;   // number of elements with bit length too large
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s.bl_count[bits] = 0;
+
+    // In a first pass, compute the optimal bit lengths (which may
+    // overflow in the case of the bit length tree).
+    tree[s.heap[s.heap_max]*2+1] = 0; // root of the heap
+
+    for(h=s.heap_max+1; h<HEAP_SIZE; h++){
+      n = s.heap[h];
+      bits = tree[tree[n*2+1]*2+1] + 1;
+      if (bits > max_length){ bits = max_length; overflow++; }
+      tree[n*2+1] = (short)bits;
+      // We overwrite tree[n*2+1] which is no longer needed
+
+      if (n > max_code) continue;  // not a leaf node
+
+      s.bl_count[bits]++;
+      xbits = 0;
+      if (n >= base) xbits = extra[n-base];
+      f = tree[n*2];
+      s.opt_len += f * (bits + xbits);
+      if (stree!=null) s.static_len += f * (stree[n*2+1] + xbits);
+    }
+    if (overflow == 0) return;
+
+    // This happens for example on obj2 and pic of the Calgary corpus
+    // Find the first bit length which could increase:
+    do {
+      bits = max_length-1;
+      while(s.bl_count[bits]==0) bits--;
+      s.bl_count[bits]--;      // move one leaf down the tree
+      s.bl_count[bits+1]+=2;   // move one overflow item as its brother
+      s.bl_count[max_length]--;
+      // The brother of the overflow item also moves one step up,
+      // but this does not affect bl_count[max_length]
+      overflow -= 2;
+    }
+    while (overflow > 0);
+
+    for (bits = max_length; bits != 0; bits--) {
+      n = s.bl_count[bits];
+      while (n != 0) {
+       m = s.heap[--h];
+       if (m > max_code) continue;
+       if (tree[m*2+1] != bits) {
+         s.opt_len += ((long)bits - (long)tree[m*2+1])*(long)tree[m*2];
+         tree[m*2+1] = (short)bits;
+       }
+       n--;
+      }
+    }
+  }
+
+  // Construct one Huffman tree and assigns the code bit strings and lengths.
+  // Update the total bit length for the current block.
+  // IN assertion: the field freq is set for all tree elements.
+  // OUT assertions: the fields len and code are set to the optimal bit length
+  //     and corresponding code. The length opt_len is updated; static_len is
+  //     also updated if stree is not null. The field max_code is set.
+  void build_tree(Deflate s){
+    short[] tree=dyn_tree;
+    short[] stree=stat_desc.static_tree;
+    int elems=stat_desc.elems;
+    int n, m;          // iterate over heap elements
+    int max_code=-1;   // largest code with non zero frequency
+    int node;          // new node being created
+
+    // Construct the initial heap, with least frequent element in
+    // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+    // heap[0] is not used.
+    s.heap_len = 0;
+    s.heap_max = HEAP_SIZE;
+
+    for(n=0; n<elems; n++) {
+      if(tree[n*2] != 0) {
+       s.heap[++s.heap_len] = max_code = n;
+       s.depth[n] = 0;
+      }
+      else{
+       tree[n*2+1] = 0;
+      }
+    }
+
+    // The pkzip format requires that at least one distance code exists,
+    // and that at least one bit should be sent even if there is only one
+    // possible code. So to avoid special checks later on we force at least
+    // two codes of non zero frequency.
+    while (s.heap_len < 2) {
+      node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
+      tree[node*2] = 1;
+      s.depth[node] = 0;
+      s.opt_len--; if (stree!=null) s.static_len -= stree[node*2+1];
+      // node is 0 or 1 so it does not have extra bits
+    }
+    this.max_code = max_code;
+
+    // The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+    // establish sub-heaps of increasing lengths:
+
+    for(n=s.heap_len/2;n>=1; n--)
+      s.pqdownheap(tree, n);
+
+    // Construct the Huffman tree by repeatedly combining the least two
+    // frequent nodes.
+
+    node=elems;                 // next internal node of the tree
+    do{
+      // n = node of least frequency
+      n=s.heap[1];
+      s.heap[1]=s.heap[s.heap_len--];
+      s.pqdownheap(tree, 1);
+      m=s.heap[1];                // m = node of next least frequency
+
+      s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
+      s.heap[--s.heap_max] = m;
+
+      // Create a new node father of n and m
+      tree[node*2] = (short)(tree[n*2] + tree[m*2]);
+      s.depth[node] = (byte)(Math.max(s.depth[n],s.depth[m])+1);
+      tree[n*2+1] = tree[m*2+1] = (short)node;
+
+      // and insert the new node in the heap
+      s.heap[1] = node++;
+      s.pqdownheap(tree, 1);
+    }
+    while(s.heap_len>=2);
+
+    s.heap[--s.heap_max] = s.heap[1];
+
+    // At this point, the fields freq and dad are set. We can now
+    // generate the bit lengths.
+
+    gen_bitlen(s);
+
+    // The field len is now set, we can generate the bit codes
+    gen_codes(tree, max_code, s.bl_count);
+  }
+
+  // Generate the codes for a given tree and bit counts (which need not be
+  // optimal).
+  // IN assertion: the array bl_count contains the bit length statistics for
+  // the given tree and the field len is set for all tree elements.
+  // OUT assertion: the field code is set for all tree elements of non
+  //     zero code length.
+  static void gen_codes(short[] tree, // the tree to decorate
+                       int max_code, // largest code with non zero frequency
+                       short[] bl_count // number of codes at each bit length
+                       ){
+    short[] next_code=new short[MAX_BITS+1]; // next code value for each bit length
+    short code = 0;            // running code value
+    int bits;                  // bit index
+    int n;                     // code index
+
+    // The distribution counts are first used to generate the code values
+    // without bit reversal.
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+      next_code[bits] = code = (short)((code + bl_count[bits-1]) << 1);
+    }
+
+    // Check that the bit counts in bl_count are consistent. The last code
+    // must be all ones.
+    //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+    //        "inconsistent bit counts");
+    //Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+      int len = tree[n*2+1];
+      if (len == 0) continue;
+      // Now reverse the bits
+      tree[n*2] = (short)(bi_reverse(next_code[len]++, len));
+    }
+  }
+
+  // Reverse the first len bits of a code, using straightforward code (a faster
+  // method would use a table)
+  // IN assertion: 1 <= len <= 15
+  static int bi_reverse(int code, // the value to invert
+                       int len   // its bit length
+                       ){
+    int res = 0;
+    do{
+      res|=code&1;
+      code>>>=1;
+      res<<=1;
+    } 
+    while(--len>0);
+    return res>>>1;
+  }
+}
+
diff --git a/src/com/jcraft/jzlib/ZInputStream.java b/src/com/jcraft/jzlib/ZInputStream.java
new file mode 100644 (file)
index 0000000..3f97c44
--- /dev/null
@@ -0,0 +1,149 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2001 Lapo Luchini.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 AUTHORS
+OR ANY CONTRIBUTORS TO THIS SOFTWARE 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 program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+import java.io.*;
+
+public class ZInputStream extends FilterInputStream {
+
+  protected ZStream z=new ZStream();
+  protected int bufsize=512;
+  protected int flush=JZlib.Z_NO_FLUSH;
+  protected byte[] buf=new byte[bufsize],
+                   buf1=new byte[1];
+  protected boolean compress;
+
+  protected InputStream in=null;
+
+  public ZInputStream(InputStream in) {
+    this(in, false);
+  }
+  public ZInputStream(InputStream in, boolean nowrap) {
+    super(in);
+    this.in=in;
+    z.inflateInit(nowrap);
+    compress=false;
+    z.next_in=buf;
+    z.next_in_index=0;
+    z.avail_in=0;
+  }
+
+  public ZInputStream(InputStream in, int level) {
+    super(in);
+    this.in=in;
+    z.deflateInit(level);
+    compress=true;
+    z.next_in=buf;
+    z.next_in_index=0;
+    z.avail_in=0;
+  }
+
+  /*public int available() throws IOException {
+    return inf.finished() ? 0 : 1;
+  }*/
+
+  public int read() throws IOException {
+    if(read(buf1, 0, 1)==-1)
+      return(-1);
+    return(buf1[0]&0xFF);
+  }
+
+  private boolean nomoreinput=false;
+
+  public int read(byte[] b, int off, int len) throws IOException {
+    if(len==0)
+      return(0);
+    int err;
+    z.next_out=b;
+    z.next_out_index=off;
+    z.avail_out=len;
+    do {
+      if((z.avail_in==0)&&(!nomoreinput)) { // if buffer is empty and more input is avaiable, refill it
+       z.next_in_index=0;
+       z.avail_in=in.read(buf, 0, bufsize);//(bufsize<z.avail_out ? bufsize : z.avail_out));
+       if(z.avail_in==-1) {
+         z.avail_in=0;
+         nomoreinput=true;
+       }
+      }
+      if(compress)
+       err=z.deflate(flush);
+      else
+       err=z.inflate(flush);
+      if(nomoreinput&&(err==JZlib.Z_BUF_ERROR))
+        return(-1);
+      if(err!=JZlib.Z_OK && err!=JZlib.Z_STREAM_END)
+       throw new ZStreamException((compress ? "de" : "in")+"flating: "+z.msg);
+      if((nomoreinput||err==JZlib.Z_STREAM_END)&&(z.avail_out==len))
+       return(-1);
+    } 
+    while(z.avail_out==len&&err==JZlib.Z_OK);
+    //System.err.print("("+(len-z.avail_out)+")");
+    return(len-z.avail_out);
+  }
+
+  public long skip(long n) throws IOException {
+    int len=512;
+    if(n<len)
+      len=(int)n;
+    byte[] tmp=new byte[len];
+    return((long)read(tmp));
+  }
+
+  public int getFlushMode() {
+    return(flush);
+  }
+
+  public void setFlushMode(int flush) {
+    this.flush=flush;
+  }
+
+  /**
+   * Returns the total number of bytes input so far.
+   */
+  public long getTotalIn() {
+    return z.total_in;
+  }
+
+  /**
+   * Returns the total number of bytes output so far.
+   */
+  public long getTotalOut() {
+    return z.total_out;
+  }
+
+  public void close() throws IOException{
+    in.close();
+  }
+}
diff --git a/src/com/jcraft/jzlib/ZOutputStream.java b/src/com/jcraft/jzlib/ZOutputStream.java
new file mode 100644 (file)
index 0000000..afee65b
--- /dev/null
@@ -0,0 +1,156 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2001 Lapo Luchini.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 AUTHORS
+OR ANY CONTRIBUTORS TO THIS SOFTWARE 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 program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+import java.io.*;
+
+public class ZOutputStream extends OutputStream {
+
+  protected ZStream z=new ZStream();
+  protected int bufsize=512;
+  protected int flush=JZlib.Z_NO_FLUSH;
+  protected byte[] buf=new byte[bufsize],
+                   buf1=new byte[1];
+  protected boolean compress;
+
+  protected OutputStream out;
+
+  public ZOutputStream(OutputStream out) {
+    super();
+    this.out=out;
+    z.inflateInit();
+    compress=false;
+  }
+
+  public ZOutputStream(OutputStream out, int level) {
+    this(out, level, false);
+  }
+  public ZOutputStream(OutputStream out, int level, boolean nowrap) {
+    super();
+    this.out=out;
+    z.deflateInit(level, nowrap);
+    compress=true;
+  }
+
+  public void write(int b) throws IOException {
+    buf1[0]=(byte)b;
+    write(buf1, 0, 1);
+  }
+
+  public void write(byte b[], int off, int len) throws IOException {
+    if(len==0)
+      return;
+    int err;
+    z.next_in=b;
+    z.next_in_index=off;
+    z.avail_in=len;
+    do{
+      z.next_out=buf;
+      z.next_out_index=0;
+      z.avail_out=bufsize;
+      if(compress)
+        err=z.deflate(flush);
+      else
+        err=z.inflate(flush);
+      if(err!=JZlib.Z_OK)
+        throw new ZStreamException((compress?"de":"in")+"flating: "+z.msg);
+      out.write(buf, 0, bufsize-z.avail_out);
+    } 
+    while(z.avail_in>0 || z.avail_out==0);
+  }
+
+  public int getFlushMode() {
+    return(flush);
+  }
+
+  public void setFlushMode(int flush) {
+    this.flush=flush;
+  }
+
+  public void finish() throws IOException {
+    int err;
+    do{
+      z.next_out=buf;
+      z.next_out_index=0;
+      z.avail_out=bufsize;
+      if(compress){ err=z.deflate(JZlib.Z_FINISH);  }
+      else{ err=z.inflate(JZlib.Z_FINISH); }
+      if(err!=JZlib.Z_STREAM_END && err != JZlib.Z_OK)
+      throw new ZStreamException((compress?"de":"in")+"flating: "+z.msg);
+      if(bufsize-z.avail_out>0){
+       out.write(buf, 0, bufsize-z.avail_out);
+      }
+    }
+    while(z.avail_in>0 || z.avail_out==0);
+    flush();
+  }
+  public void end() {
+    if(z==null)
+      return;
+    if(compress){ z.deflateEnd(); }
+    else{ z.inflateEnd(); }
+    z.free();
+    z=null;
+  }
+  public void close() throws IOException {
+    try{
+      try{finish();}
+      catch (IOException ignored) {}
+    }
+    finally{
+      end();
+      out.close();
+      out=null;
+    }
+  }
+
+  /**
+   * Returns the total number of bytes input so far.
+   */
+  public long getTotalIn() {
+    return z.total_in;
+  }
+
+  /**
+   * Returns the total number of bytes output so far.
+   */
+  public long getTotalOut() {
+    return z.total_out;
+  }
+
+  public void flush() throws IOException {
+    out.flush();
+  }
+
+}
diff --git a/src/com/jcraft/jzlib/ZStream.java b/src/com/jcraft/jzlib/ZStream.java
new file mode 100644 (file)
index 0000000..334475e
--- /dev/null
@@ -0,0 +1,211 @@
+/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
+/*
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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 program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+package com.jcraft.jzlib;
+
+final public class ZStream{
+
+  static final private int MAX_WBITS=15;        // 32K LZ77 window
+  static final private int DEF_WBITS=MAX_WBITS;
+
+  static final private int Z_NO_FLUSH=0;
+  static final private int Z_PARTIAL_FLUSH=1;
+  static final private int Z_SYNC_FLUSH=2;
+  static final private int Z_FULL_FLUSH=3;
+  static final private int Z_FINISH=4;
+
+  static final private int MAX_MEM_LEVEL=9;
+
+  static final private int Z_OK=0;
+  static final private int Z_STREAM_END=1;
+  static final private int Z_NEED_DICT=2;
+  static final private int Z_ERRNO=-1;
+  static final private int Z_STREAM_ERROR=-2;
+  static final private int Z_DATA_ERROR=-3;
+  static final private int Z_MEM_ERROR=-4;
+  static final private int Z_BUF_ERROR=-5;
+  static final private int Z_VERSION_ERROR=-6;
+
+  public byte[] next_in;     // next input byte
+  public int next_in_index;
+  public int avail_in;       // number of bytes available at next_in
+  public long total_in;      // total nb of input bytes read so far
+
+  public byte[] next_out;    // next output byte should be put there
+  public int next_out_index;
+  public int avail_out;      // remaining free space at next_out
+  public long total_out;     // total nb of bytes output so far
+
+  public String msg;
+
+  Deflate dstate; 
+  Inflate istate; 
+
+  int data_type; // best guess about the data type: ascii or binary
+
+  public long adler;
+  Adler32 _adler=new Adler32();
+
+  public int inflateInit(){
+    return inflateInit(DEF_WBITS);
+  }
+  public int inflateInit(boolean nowrap){
+    return inflateInit(DEF_WBITS, nowrap);
+  }
+  public int inflateInit(int w){
+    return inflateInit(w, false);
+  }
+
+  public int inflateInit(int w, boolean nowrap){
+    istate=new Inflate();
+    return istate.inflateInit(this, nowrap?-w:w);
+  }
+
+  public int inflate(int f){
+    if(istate==null) return Z_STREAM_ERROR;
+    return istate.inflate(this, f);
+  }
+  public int inflateEnd(){
+    if(istate==null) return Z_STREAM_ERROR;
+    int ret=istate.inflateEnd(this);
+    istate = null;
+    return ret;
+  }
+  public int inflateSync(){
+    if(istate == null)
+      return Z_STREAM_ERROR;
+    return istate.inflateSync(this);
+  }
+  public int inflateSetDictionary(byte[] dictionary, int dictLength){
+    if(istate == null)
+      return Z_STREAM_ERROR;
+    return istate.inflateSetDictionary(this, dictionary, dictLength);
+  }
+
+  public int deflateInit(int level){
+    return deflateInit(level, MAX_WBITS);
+  }
+  public int deflateInit(int level, boolean nowrap){
+    return deflateInit(level, MAX_WBITS, nowrap);
+  }
+  public int deflateInit(int level, int bits){
+    return deflateInit(level, bits, false);
+  }
+  public int deflateInit(int level, int bits, boolean nowrap){
+    dstate=new Deflate();
+    return dstate.deflateInit(this, level, nowrap?-bits:bits);
+  }
+  public int deflate(int flush){
+    if(dstate==null){
+      return Z_STREAM_ERROR;
+    }
+    return dstate.deflate(this, flush);
+  }
+  public int deflateEnd(){
+    if(dstate==null) return Z_STREAM_ERROR;
+    int ret=dstate.deflateEnd();
+    dstate=null;
+    return ret;
+  }
+  public int deflateParams(int level, int strategy){
+    if(dstate==null) return Z_STREAM_ERROR;
+    return dstate.deflateParams(this, level, strategy);
+  }
+  public int deflateSetDictionary (byte[] dictionary, int dictLength){
+    if(dstate == null)
+      return Z_STREAM_ERROR;
+    return dstate.deflateSetDictionary(this, dictionary, dictLength);
+  }
+
+  // Flush as much pending output as possible. All deflate() output goes
+  // through this function so some applications may wish to modify it
+  // to avoid allocating a large strm->next_out buffer and copying into it.
+  // (See also read_buf()).
+  void flush_pending(){
+    int len=dstate.pending;
+
+    if(len>avail_out) len=avail_out;
+    if(len==0) return;
+
+    if(dstate.pending_buf.length<=dstate.pending_out ||
+       next_out.length<=next_out_index ||
+       dstate.pending_buf.length<(dstate.pending_out+len) ||
+       next_out.length<(next_out_index+len)){
+      System.out.println(dstate.pending_buf.length+", "+dstate.pending_out+
+                        ", "+next_out.length+", "+next_out_index+", "+len);
+      System.out.println("avail_out="+avail_out);
+    }
+
+    System.arraycopy(dstate.pending_buf, dstate.pending_out,
+                    next_out, next_out_index, len);
+
+    next_out_index+=len;
+    dstate.pending_out+=len;
+    total_out+=len;
+    avail_out-=len;
+    dstate.pending-=len;
+    if(dstate.pending==0){
+      dstate.pending_out=0;
+    }
+  }
+
+  // Read a new buffer from the current input stream, update the adler32
+  // and total number of bytes read.  All deflate() input goes through
+  // this function so some applications may wish to modify it to avoid
+  // allocating a large strm->next_in buffer and copying from it.
+  // (See also flush_pending()).
+  int read_buf(byte[] buf, int start, int size) {
+    int len=avail_in;
+
+    if(len>size) len=size;
+    if(len==0) return 0;
+
+    avail_in-=len;
+
+    if(dstate.noheader==0) {
+      adler=_adler.adler32(adler, next_in, next_in_index, len);
+    }
+    System.arraycopy(next_in, next_in_index, buf, start, len);
+    next_in_index  += len;
+    total_in += len;
+    return len;
+  }
+
+  public void free(){
+    next_in=null;
+    next_out=null;
+    msg=null;
+    _adler=null;
+  }
+}
diff --git a/src/com/jcraft/jzlib/ZStreamException.java b/src/com/jcraft/jzlib/ZStreamException.java
new file mode 100644 (file)
index 0000000..424b74b
--- /dev/null
@@ -0,0 +1,44 @@
+/* -*-mode:java; c-basic-offset:2; -*- */\r
+/*\r
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.\r
+\r
+Redistribution and use in source and binary forms, with or without\r
+modification, are permitted provided that the following conditions are met:\r
+\r
+  1. Redistributions of source code must retain the above copyright notice,\r
+     this list of conditions and the following disclaimer.\r
+\r
+  2. Redistributions in binary form must reproduce the above copyright \r
+     notice, this list of conditions and the following disclaimer in \r
+     the documentation and/or other materials provided with the distribution.\r
+\r
+  3. The names of the authors may not be used to endorse or promote products\r
+     derived from this software without specific prior written permission.\r
+\r
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,\r
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\r
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,\r
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+/*\r
+ * This program is based on zlib-1.1.3, so all credit should go authors\r
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)\r
+ * and contributors of zlib.\r
+ */\r
+\r
+package com.jcraft.jzlib;\r
+\r
+public class ZStreamException extends java.io.IOException {\r
+  public ZStreamException() {\r
+    super();\r
+  }\r
+  public ZStreamException(String s) {\r
+    super(s);\r
+  }\r
+}\r
diff --git a/src/com/joshuawise/dumload/Dumload.java b/src/com/joshuawise/dumload/Dumload.java
new file mode 100644 (file)
index 0000000..0905ac9
--- /dev/null
@@ -0,0 +1,54 @@
+package com.joshuawise.dumload;
+
+import java.io.InputStream;
+
+import android.app.Activity;
+import android.app.Service;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.util.Log;
+
+public class Dumload extends Activity {
+       /** Called when the activity is first created. */
+       @Override
+       public void onCreate(Bundle savedInstanceState) {
+               super.onCreate(savedInstanceState);
+               setContentView(R.layout.main);
+               TextView tv = (TextView)findViewById(R.id.suckit);
+               tv.setText("Suck it.");
+       }
+       
+       private void say(String s) {
+               Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show();
+       }
+       
+       public void onStart() {
+               super.onStart();
+               
+               Intent i = getIntent(); /* i *am* not an intent! */
+               if (i.getAction().equals(Intent.ACTION_SEND))
+               {
+                       Bundle extras = i.getExtras();
+                       Uri uri = (Uri)extras.getParcelable(Intent.EXTRA_STREAM);
+                       
+                       Log.e("Dumload", "Got a send -- starting service.");
+                       // Never let an ML programmer touch Java.
+                       android.content.ComponentName cn = getApplicationContext().startService(new Intent().setClass(getApplicationContext(), Uploader.class).setData(uri));
+                       
+                       if (cn == null)
+                               say("Fuuuuuuuuuck.");
+                       else
+                               Log.e("Dumload", "Started service " + cn.toString() + ".");
+                       
+                       TextView tv = (TextView)findViewById(R.id.suckit);
+                       tv.setText("Action was send: "+uri.toString());
+               } else {
+                       TextView tv = (TextView)findViewById(R.id.suckit);
+                       tv.setText("Action was something else");
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/com/joshuawise/dumload/NotifSlave.java b/src/com/joshuawise/dumload/NotifSlave.java
new file mode 100644 (file)
index 0000000..21af25e
--- /dev/null
@@ -0,0 +1,171 @@
+package com.joshuawise.dumload;
+
+import java.io.InputStream;
+
+import android.app.Activity;
+import android.app.Service;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.widget.TextView;
+import android.widget.Button;
+import android.view.View;
+import android.widget.Toast;
+import android.util.Log;
+import android.os.Messenger;
+import android.os.Message;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+
+public class NotifSlave extends Activity {
+       /** Called when the activity is first created. */
+       @Override
+       public void onCreate(Bundle savedInstanceState) {
+               super.onCreate(savedInstanceState);
+//             setContentView(R.layout.main);
+//             TextView tv = (TextView)findViewById(R.id.suckit);
+//             tv.setText("Suck it.");
+       }
+       
+       private void say(String s) {
+               Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show();
+       }
+       
+       private int _nextdialog = 0;
+       private Dialog _hell_ass_balls = null;
+       
+       @Override
+       protected Dialog onCreateDialog(int id)
+       {
+               Log.e("DumLoad.NotifSlave", "Create for dialog "+(Integer.toString(id)));
+               if (id != _nextdialog)
+                       return null;
+               return _hell_ass_balls;
+       }
+       
+       private void showDialog(Dialog d)
+       {
+               _nextdialog++;
+               _hell_ass_balls = d;
+               Log.e("DumLoad.NotifSlave", "Attempting to show dialog "+(Integer.toString(_nextdialog)));
+               showDialog(_nextdialog);
+       }
+       
+       public void onStart() {
+               super.onStart();
+       
+               Intent i = getIntent(); /* i *am* not an intent! */
+               final Activity thisact = this;
+               
+               final Messenger m = (Messenger)i.getParcelableExtra("com.joshuawise.dumload.returnmessenger");
+               String reqtype = i.getStringExtra("com.joshuawise.dumload.reqtype");
+               String prompt = i.getStringExtra("com.joshuawise.dumload.prompt");
+               /* If any of these were null, we'll just take the exception. */
+       
+               if (reqtype.equals("yesno")) {
+                       AlertDialog.Builder builder = new AlertDialog.Builder(this);
+                       builder.setTitle("Dumload");
+                       builder.setMessage(prompt);
+                       builder.setCancelable(false);
+                       builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
+                               public void onClick(DialogInterface dialog, int id) {
+                                       Log.e("Dumload.NotifSlave", "Responding with a 1.");
+                                       try {
+                                               Message me = Message.obtain();
+                                               me.arg1 = 1;
+                                               m.send(me);
+                                       } catch (Exception e) {
+                                               Log.e("Dumload.NotifSlave", "Failed to send a message back to my buddy.");
+                                       }
+                                       dialog.cancel();
+                                       thisact.finish();
+                               }
+                       });
+                       builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
+                               public void onClick(DialogInterface dialog, int id) {
+                                       Log.e("Dumload.NotifSlave", "Responding with a 1.");
+                                       try {
+                                               Message me = Message.obtain();
+                                               me.arg1 = 0;
+                                               m.send(me);
+                                       } catch (Exception e) {
+                                               Log.e("Dumload.NotifSlave", "Failed to send a message back to my buddy.");
+                                       }
+                                       dialog.cancel();
+                                       thisact.finish();
+                               }
+                       });
+                       AlertDialog alert = builder.create();
+                       showDialog(alert);
+               } else if (reqtype.equals("message")) {
+                       AlertDialog.Builder builder = new AlertDialog.Builder(this);
+                       builder.setTitle("Dumload");
+                       builder.setMessage(prompt);
+                       builder.setCancelable(false);
+                       builder.setNeutralButton("OK", new DialogInterface.OnClickListener() {
+                               public void onClick(DialogInterface dialog, int id) {
+                                       try {
+                                               Message me = Message.obtain();
+                                               m.send(me);
+                                       } catch (Exception e) {
+                                               Log.e("Dumload.NotifSlave", "Failed to send a message back to my buddy.");
+                                       }
+                                       dialog.cancel();
+                                       thisact.finish();
+                               }
+                       });
+                       AlertDialog alert = builder.create();
+                       showDialog(alert);
+               } else if (reqtype.equals("password")) {
+                       final Dialog d = new Dialog(this);
+                       
+                       d.setContentView(R.layout.passwd);
+                       d.setTitle("Dumload");
+                       d.setCancelable(false);
+                       
+                       TextView text = (TextView) d.findViewById(R.id.prompt);
+                       text.setText(prompt);
+                       
+                       Button ok = (Button) d.findViewById(R.id.ok);
+                       ok.setOnClickListener(new View.OnClickListener() {
+                               public void onClick(View v) {
+                                       try {
+                                               Message me = Message.obtain();
+                                               me.arg1 = 1;
+                                               TextView entry = (TextView) d.findViewById(R.id.entry);
+                                               Bundle b = new Bundle(1);
+                                               b.putString("response", entry.getText().toString());
+                                               me.setData(b);
+                                               m.send(me);
+                                       } catch (Exception e) {
+                                               Log.e("Dumload.NotifSlave", "Failed to send a message back to my buddy.");
+                                       }
+                                       d.cancel();
+                                       thisact.finish();
+                               }
+                       });
+                       
+                       Button cancel = (Button) d.findViewById(R.id.cancel);
+                       cancel.setOnClickListener(new View.OnClickListener() {
+                               public void onClick(View v) {
+                                       try {
+                                               Message me = Message.obtain();
+                                               me.arg1 = 0;
+                                               m.send(me);
+                                       } catch (Exception e) {
+                                               Log.e("Dumload.NotifSlave", "Failed to send a message back to my buddy.");
+                                       }
+                                       d.cancel();
+                                       thisact.finish();
+                               }
+                       });
+                       
+                       
+                       showDialog(d);
+               } else {
+                       Log.e("Dumload.NotifSlave", "What's a "+reqtype+"?");
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/com/joshuawise/dumload/Uploader.java b/src/com/joshuawise/dumload/Uploader.java
new file mode 100644 (file)
index 0000000..489040b
--- /dev/null
@@ -0,0 +1,216 @@
+package com.joshuawise.dumload;
+
+import java.io.InputStream;
+
+import com.jcraft.jsch.*;
+import java.lang.Boolean;
+
+import android.app.Activity;
+import android.app.Service;
+import android.content.Intent;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.util.Log;
+import android.app.NotificationManager;
+import android.app.Notification;
+import android.os.Handler;
+import android.os.Messenger;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+
+public class Uploader extends Service implements Runnable, UserInfo, UIKeyboardInteractive {
+       private Uri uri;
+       private String homedir;
+       private Thread me;
+       private static final int HELPME_ID = 1;
+       
+       public Object _theObject;
+
+       private Object /* pick one type, and fixate on it */ dance(final String type, final String text)        /* for inside the thread */
+       {
+               final Uploader thisupl = this;
+               final Message msg = Message.obtain();
+               
+               /* t(*A*t) */
+               Thread t = new Thread() {
+                       public void run() {
+                               Looper.prepare();
+                               int bogon = (int)SystemClock.elapsedRealtime();
+                               
+                               NotificationManager mNotificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
+                               Notification notification = new Notification(R.drawable.icon, "Dumload prompt", System.currentTimeMillis());
+                               
+                               Handler h = new Handler() {
+                                       public void handleMessage(Message M) {
+                                               msg.copyFrom(M);
+                                               Looper.myLooper().quit();
+                                       }
+                               };
+                               Messenger m = new Messenger(h);
+                               
+                               Intent intent = new Intent(thisupl, NotifSlave.class);
+                                       
+                               intent.setAction("com.joshuawise.dumload.NotifSlave");
+                               intent.putExtra("com.joshuawise.dumload.returnmessenger", m);
+                               intent.putExtra("com.joshuawise.dumload.reqtype", type);
+                               intent.putExtra("com.joshuawise.dumload.prompt", text);
+                               intent.setData((Uri.parse("suckit://"+SystemClock.elapsedRealtime())));
+                               
+                               PendingIntent contentIntent = PendingIntent.getActivity(thisupl, 0, intent, 0);
+                               notification.defaults |= Notification.DEFAULT_VIBRATE;
+                               notification.flags |= Notification.FLAG_AUTO_CANCEL | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
+                               notification.setLatestEventInfo(getApplicationContext(), "I've been had!", "Dumload needs your input.", contentIntent);
+                               
+                               Log.e("Dumload.Uploader[thread]", "Notifying...");
+                               
+                               mNotificationManager.notify(bogon, notification);
+                               
+                               Log.e("Dumload.Uploader[thread]", "About to go to 'sleep'...");
+                               Looper.loop();
+                               Log.e("Dumload.Uploader[thread]", "And we're alive!");
+                                       
+                               Log.e("Dumload.Uploader[thread]", "result was: "+(Integer.toString(msg.arg1)));
+                               
+                               mNotificationManager.cancel(bogon);
+                       }
+               };
+               
+               t.start();
+               try {
+                       t.join();
+               } catch (Exception e) {
+                       return null;
+               }
+               
+               if (type.equals("yesno"))
+                       return new Boolean(msg.arg1 == 1);
+               else if (type.equals("message"))
+                       return null;
+               else if (type.equals("password")) {
+                       if (msg.arg1 == 0)
+                               return null;
+                       Bundle b = msg.getData();
+                       return b.getString("response");
+               } else
+                       return null;
+       }
+       
+       /* UserInfo bits */
+       String _password = null;
+       public String getPassword()
+       {
+               return _password;
+       }
+       public boolean promptPassword(String message)
+       {
+               _password = (String)dance("password", message); 
+               return (_password != null);
+       }
+       
+       String _passphrase = null;
+       public String getPassphrase()
+       {
+               return _passphrase;
+       }
+       public boolean promptPassphrase(String message)
+       {
+               _passphrase = (String)dance("password", message); 
+               return (_passphrase != null);
+       }
+       
+       public boolean promptYesNo(String str)
+       {
+               return ((Boolean)dance("yesno", str)).booleanValue();
+       }
+       
+       public void showMessage(String str)
+       {
+               dance("message", str);
+       }
+       
+       public String[] promptKeyboardInteractive(String dest, String name, String instr, String[] prompt, boolean[] echo)
+       {
+               int i;
+               String [] responses = new String[prompt.length];
+               
+               Log.e("Dumload.Uploader", "dest: "+dest);
+               Log.e("Dumload.Uploader", "name: "+name);
+               Log.e("Dumload.Uploader", "instr: "+instr);
+               for (i = 0; i < prompt.length; i++)
+               {
+                       responses[i] = (String) dance("password", "[" + dest + "]\n" + prompt[i]);
+               }
+               return responses;
+       }
+       
+       @Override
+       public void run()
+       {
+               Looper.prepare();
+               
+               Log.e("Dumload.Uploader[thread]", "This brought to you from the new thread.");
+               
+               try {
+                       JSch jsch = new JSch();
+                       jsch.setKnownHosts(homedir + "/known_hosts");
+                       Session s = jsch.getSession("joshua", "nyus.joshuawise.com", 22);
+                       s.setUserInfo(this);
+                       s.connect();
+                       
+                       Channel channel = s.openChannel("exec");
+                       ((ChannelExec)channel).setCommand("echo foo > /tmp/lol");
+                       channel.connect();
+                       
+                       dance("message", "done");
+
+                       channel.disconnect();
+                       s.disconnect();
+               } catch (JSchException e) {
+                       Log.e("Dumload.uploader[thread]", "JSchException: "+(e.toString()));
+               }
+               
+               
+               Log.e("Dumload.uploader[thread]", "And now I'm back to life!");
+       }
+       
+       private void say(String s) {
+               Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show();
+       }
+       
+       @Override
+       public void onStart(Intent i, int startId)
+       {
+               uri = i.getData();
+               homedir = getApplicationContext().getFilesDir().getAbsolutePath();
+               int shits = 0;
+               
+               super.onStart(i, startId);
+               
+               Log.e("Dumload.Uploader", "Started.");
+               Log.e("Dumload.Uploader", "My path is "+homedir);
+               
+               try {
+                       InputStream is = getContentResolver().openInputStream(uri);
+                       shits = is.available();
+               } catch (Exception e) {
+               }
+               
+               say("Your shit was "+(Integer.toString(shits))+" bytes long");
+               
+               me = new Thread(this, "Uploader thread");
+               me.start();
+       }
+       
+       @Override
+       public IBinder onBind(Intent i) {
+               Log.e("Dumload.Uploader", "bound");
+               
+               return null;
+       }
+}
This page took 0.729137 seconds and 4 git commands to generate.