1diff -Naur mindbright/Makefile mindbright-compression/Makefile
2--- mindbright/Makefile	Tue Aug  1 20:37:08 2000
3+++ mindbright-compression/Makefile	Tue Dec 19 05:49:00 2000
4@@ -56,6 +56,7 @@
5 	ssh/SSHTxChannel.class \
6 	ssh/SSHTunnel.class \
7 	ssh/SSHProtocolPlugin.class \
8+	ssh/SSHCompression.class \
9 	ssh/SSHPdu.class \
10 	ssh/SSHDataInputStream.class \
11 	ssh/SSHDataOutputStream.class \
12diff -Naur mindbright/ssh/SSH.java mindbright-compression/ssh/SSH.java
13--- mindbright/ssh/SSH.java	Tue Aug  1 22:30:52 2000
14+++ mindbright-compression/ssh/SSH.java	Tue Dec 19 05:59:45 2000
15@@ -206,6 +206,8 @@
16   protected Cipher rcvCipher;
17   protected int    cipherType;
18
19+  protected static int compressionLevel=0;
20+
21   // Server data fields
22   //
23   protected byte[]  srvCookie;
24diff -Naur mindbright/ssh/SSHClient.java mindbright-compression/ssh/SSHClient.java
25--- mindbright/ssh/SSHClient.java	Tue Apr  4 09:34:12 2000
26+++ mindbright-compression/ssh/SSHClient.java	Tue Dec 19 05:31:57 2000
27@@ -481,6 +481,10 @@
28   protected void disconnect(boolean graceful) {
29     if(!isConnected)
30       return;
31+    if(SSH.compressionLevel!=0){
32+      SSHCompression.uninit();
33+      SSH.compressionLevel=0;
34+    }
35     isConnected   = false;
36     isOpened      = false;
37     gracefulExit  = graceful;
38@@ -897,7 +901,7 @@
39   void initiateSession() throws IOException {
40     // !!! java.util.zip.Deflater/Inflater can't be used since we can't give
41     // the native inflate/deflate methods the Z_PARTIAL_FLUSH flag
42-    // requestCompression(3);
43+    requestCompression(user.getCompressionLevel());
44
45     if(user.wantPTY())
46       requestPTY();
47@@ -939,11 +943,20 @@
48   }
49
50   void requestCompression(int level) throws IOException {
51+    if(level==0) return;
52+    if(level<0 || level>9){
53+      if(interactor!=null)
54+	interactor.report("Error requesting invalid compression level: " + level);
55+      return;
56+    }
57+
58     SSHPduOutputStream outpdu = new SSHPduOutputStream(CMSG_REQUEST_COMPRESSION, sndCipher);
59     outpdu.writeInt(level);
60     outpdu.writeTo(sshOut);
61     if(!isSuccess() && interactor != null)
62 	interactor.report("Error requesting compression level: " + level);
63+    SSH.compressionLevel=level;
64+    SSHCompression.init(level);
65   }
66
67   void requestMaxPacketSz(int sz) throws IOException {
68diff -Naur mindbright/ssh/SSHClientUser.java mindbright-compression/ssh/SSHClientUser.java
69--- mindbright/ssh/SSHClientUser.java	Sat Feb 26 12:28:51 2000
70+++ mindbright-compression/ssh/SSHClientUser.java	Mon Dec 18 05:23:28 2000
71@@ -30,6 +30,7 @@
72   public String  getDisplay();
73   public int     getMaxPacketSz();
74   public int     getAliveInterval();
75+  public int     getCompressionLevel();
76
77   public boolean wantX11Forward();
78   public boolean wantPrivileged();
79diff -Naur mindbright/ssh/SSHClientUserAdaptor.java mindbright-compression/ssh/SSHClientUserAdaptor.java
80--- mindbright/ssh/SSHClientUserAdaptor.java	Sat Feb 26 12:28:51 2000
81+++ mindbright-compression/ssh/SSHClientUserAdaptor.java	Mon Dec 18 06:07:33 2000
82@@ -62,6 +62,10 @@
83     return 0;
84   }
85
86+  public int getCompressionLevel() {
87+    return 0;
88+  }
89+
90   public boolean wantX11Forward() {
91     return false;
92   }
93diff -Naur mindbright/ssh/SSHCompression.java mindbright-compression/ssh/SSHCompression.java
94--- mindbright/ssh/SSHCompression.java	Thu Jan  1 00:00:00 1970
95+++ mindbright-compression/ssh/SSHCompression.java	Wed Dec 20 03:13:52 2000
96@@ -0,0 +1,145 @@
97+/******************************************************************************
98+ *
99+ * Copyright (c) 1998,99 by Mindbright Technology AB, Stockholm, Sweden.
100+ *                 www.mindbright.se, info@mindbright.se
101+ *
102+ * This program is free software; you can redistribute it and/or modify
103+ * it under the terms of the GNU General Public License as published by
104+ * the Free Software Foundation; either version 2 of the License, or
105+ * (at your option) any later version.
106+ *
107+ * This program is distributed in the hope that it will be useful,
108+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
109+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
110+ * GNU General Public License for more details.
111+ *
112+ *****************************************************************************
113+ * $Author: ymnk@jcraft.com $
114+ * $Date: 2000/12/18 17:13:50 $
115+ * $Name: rel0-0-0 $
116+ *****************************************************************************/
117+package mindbright.ssh;
118+
119+import mindbright.ssh.*;
120+import com.jcraft.jzlib.*;
121+
122+final class SSHCompression{
123+  static private ZStream deflate_stream=null;
124+  static private ZStream inflate_stream=null;
125+
126+  static void init(int level){
127+    deflate_stream=new ZStream();
128+    inflate_stream=new ZStream();
129+    deflate_stream.deflateInit(level);
130+    inflate_stream.inflateInit();
131+  }
132+
133+  static void uninit(){
134+    if(SSH.DEBUGMORE){
135+    if(deflate_stream!=null)
136+    System.out.println("compress outgoing: raw data "+deflate_stream.total_in+
137+		       ", compressed "+deflate_stream.total_out+
138+		       ", factor "+(deflate_stream.total_in == 0 ?
139+				    0.0 :
140+				    ((double)deflate_stream.total_out) /
141+				    ((double)deflate_stream.total_in)));
142+    if(inflate_stream!=null)
143+    System.out.println("compress incoming: raw data "+inflate_stream.total_out+
144+		       ", compressed "+inflate_stream.total_in+
145+		       ", factor "+(inflate_stream.total_out == 0 ?
146+				    0.0 :
147+				    ((double)inflate_stream.total_in) /
148+				    ((double)inflate_stream.total_out)));
149+    }
150+    if(deflate_stream!=null){
151+      deflate_stream.deflateEnd();
152+      deflate_stream.free();
153+      deflate_stream=null;
154+    }
155+    if(inflate_stream!=null){
156+      inflate_stream.inflateEnd();
157+      inflate_stream.free();
158+      inflate_stream=null;
159+    }
160+  }
161+
162+  static private final int BUF_SIZE=4096;
163+  static private byte[] d_buf=new byte[BUF_SIZE];
164+  static private byte[] i_buf=new byte[BUF_SIZE];
165+
166+  static int compress(byte[] buf, int len){
167+
168+    deflate_stream.next_in=buf;
169+    deflate_stream.next_in_index=8;
170+    deflate_stream.avail_in=len-8;
171+
172+    int status;
173+    int outputlen=8;
174+
175+    do{
176+      deflate_stream.next_out=d_buf;
177+      deflate_stream.next_out_index=0;
178+      deflate_stream.avail_out=BUF_SIZE;
179+      status=deflate_stream.deflate(JZlib.Z_PARTIAL_FLUSH);
180+      switch(status){
181+      case JZlib.Z_OK:
182+	System.arraycopy(d_buf, 0,
183+			 buf, outputlen,
184+			 BUF_SIZE-deflate_stream.avail_out);
185+	outputlen+=(BUF_SIZE-deflate_stream.avail_out);
186+	break;
187+      default:
188+	System.err.println("SSHCompression.compress: deflate returnd "+status);
189+      }
190+    }
191+    while(deflate_stream.avail_out==0);
192+    return outputlen;
193+  }
194+
195+  static private byte[] out_buf = new byte[BUF_SIZE];
196+  static void uncompress(SSHPduInputStream input){
197+    int pad=(8-(input.length%8));
198+    int out_end=0;
199+
200+    inflate_stream.next_in=input.bytes;
201+    inflate_stream.next_in_index=pad;
202+    inflate_stream.avail_in=input.length - 4; // chop checksum field
203+
204+    while(true){
205+      inflate_stream.next_out=i_buf;
206+      inflate_stream.next_out_index=0;
207+      inflate_stream.avail_out=BUF_SIZE;
208+
209+      int status=inflate_stream.inflate(JZlib.Z_PARTIAL_FLUSH);
210+      switch(status){
211+      case JZlib.Z_OK:
212+        if(out_buf.length<out_end+BUF_SIZE-inflate_stream.avail_out){
213+	  byte[] foo=new byte[out_end+BUF_SIZE-inflate_stream.avail_out];
214+          System.arraycopy(out_buf, 0, foo, 0, out_end);
215+          out_buf=foo;
216+	}
217+	System.arraycopy(i_buf, 0,
218+			 out_buf, out_end,
219+			 BUF_SIZE-inflate_stream.avail_out);
220+	out_end+=(BUF_SIZE-inflate_stream.avail_out);
221+	break;
222+      case JZlib.Z_BUF_ERROR:
223+	if(out_end>input.bytes.length){
224+	  byte[] foo=new byte[out_end];
225+          System.arraycopy(out_buf, 0, foo, 0, out_end);
226+          input.bytes=foo;
227+	}
228+	else{
229+          System.arraycopy(out_buf, 0, input.bytes, 0, out_end);
230+	}
231+	input.length=out_end;
232+	try{ input.reset(); }
233+	catch(Exception e){}
234+	return;
235+      default:
236+	System.err.println("SSHCompression.uncompress: inflate returnd "+status);
237+	return; // humm..
238+      }
239+    }
240+  }
241+}
242diff -Naur mindbright/ssh/SSHMenuHandlerFull.java mindbright-compression/ssh/SSHMenuHandlerFull.java
243--- mindbright/ssh/SSHMenuHandlerFull.java	Tue Aug  1 20:37:08 2000
244+++ mindbright-compression/ssh/SSHMenuHandlerFull.java	Tue Dec 19 05:26:02 2000
245@@ -544,6 +544,7 @@
246
247   Dialog     settingsDialog = null;
248   Choice     choiceCipher, choiceAuthTyp;
249+  Choice     choiceCompressionLevel;
250   Checkbox   cbX11, cbPrvPrt, cbRemFwd, cbIdHost, cbPortFtp, cbLocHst, cbMTU, cbAlive, cbForcPty;
251   TextField  textPort, textUser, textId, textDisp, textMtu, textAlive, textSrv,
252       textRealAddr, textAuthList, textLocHost;
253@@ -801,6 +802,17 @@
254       grid2.setConstraints(cbRemFwd, gridc2);
255       ap.add(cbRemFwd);
256
257+      gridc2.gridy = 7;
258+      lbl = new Label("CompressionLevel:");
259+      grid2.setConstraints(lbl, gridc2);
260+      ap.add(lbl);
261+      choiceCompressionLevel = new Choice();
262+      for(i = 0; i < 10; i++) {
263+	choiceCompressionLevel.add(new Integer(i).toString());
264+      }
265+      grid2.setConstraints(choiceCompressionLevel, gridc2);
266+      ap.add(choiceCompressionLevel);
267+
268       gridc.gridy = 7;
269       gridc.insets = new Insets(0, 0, 0, 0);
270       gridc.anchor = GridBagConstraints.CENTER;
271@@ -844,6 +856,8 @@
272 	    } else {
273 	      client.propsHandler.setProperty("authtyp", authType);
274 	    }
275+	    String level = choiceCompressionLevel.getSelectedItem();
276+	    client.propsHandler.setProperty("compression", level);
277 	    client.propsHandler.setProperty("port", textPort.getText());
278 	    client.propsHandler.setProperty("usrname", textUser.getText());
279 	    client.propsHandler.setProperty("cipher", cipher[choiceCipher.getSelectedIndex()]);
280@@ -924,6 +938,9 @@
281       choiceAuthTyp.select("custom...");
282       textAuthList.setText(at);
283     }
284+
285+    at = client.propsHandler.getProperty("compression");
286+    choiceCompressionLevel.select(at);
287
288     textId.setText(client.propsHandler.getProperty("idfile"));
289
290diff -Naur mindbright/ssh/SSHPduInputStream.java mindbright-compression/ssh/SSHPduInputStream.java
291--- mindbright/ssh/SSHPduInputStream.java	Mon Jul 19 17:13:50 1999
292+++ mindbright-compression/ssh/SSHPduInputStream.java	Tue Dec 19 05:32:08 2000
293@@ -102,6 +102,17 @@
294       throw new IOException("Invalid checksum in packet");
295
296     this.skip(8 - (len % 8));
297+
298+    if(SSH.compressionLevel!=0){
299+      //System.out.print("readFrom: length="+length);
300+      byte[] foo=bytes;
301+      SSHCompression.uncompress(this);
302+      if(foo!=bytes){
303+        this.in = new PduByteArrayInputStream(bytes);
304+      }
305+      //System.out.println(" -> length="+length);
306+    }
307+
308     type = (int)this.readByte();
309
310     if(type == SSH.MSG_DEBUG) {
311diff -Naur mindbright/ssh/SSHPduOutputStream.java mindbright-compression/ssh/SSHPduOutputStream.java
312--- mindbright/ssh/SSHPduOutputStream.java	Mon Jul 19 17:13:50 1999
313+++ mindbright-compression/ssh/SSHPduOutputStream.java	Tue Dec 19 05:32:14 2000
314@@ -126,6 +126,13 @@
315     int                      padSz;
316     int                      off = 0;
317
318+    if(SSH.compressionLevel!=0){
319+      //System.out.print("writeTo: size="+bytes.size());
320+      int size=SSHCompression.compress(bytes.getBuf(), bytes.size());
321+      bytes.setCount(size);
322+      //System.out.println(" -> size="+bytes.size());
323+    }
324+
325     iSz   = bytes.size();
326     pad   = (iSz + 4) % 8;
327     crc32 = (int)CRC32.getValue(bytes.getBuf(), pad, iSz - pad);
328diff -Naur mindbright/ssh/SSHPropertyHandler.java mindbright-compression/ssh/SSHPropertyHandler.java
329--- mindbright/ssh/SSHPropertyHandler.java	Tue Aug  1 20:37:08 2000
330+++ mindbright-compression/ssh/SSHPropertyHandler.java	Tue Dec 19 05:23:39 2000
331@@ -84,6 +84,7 @@
332 	{ "secrand",  "0",           "level of security in random seed (for generating session key)",
333 	  "(0-2, 0=low and 2=high)" },
334 	{ "alive",    "0",           "Connection keep-alive interval in seconds (0 means none)", "(0-600)" },
335+	{ "compression",    "0",     "Compression Level (0 means none, 1=fast, 9=slow,best )", "(0-9)" },
336 	{ "x11fwd",   "false",       "indicates whether X11 display is forwarded or not", "(true/false)" },
337 	{ "prvport",  "false",       "indicates whether to use a privileged port or not (locally)", "(true/false)" },
338 	{ "forcpty",  "true",        "indicates whether to allocate a pty or not", "(true/false)" },
339@@ -295,7 +296,7 @@
340 	    if(!(value.equals("true") || value.equals("false")))
341 		throw new IllegalArgumentException("Value for " + key + " must be 'true' or 'false'");
342 	    //
343-	} else if(key.equals("port") || key.equals("proxyport") || key.equals("mtu") ||
344+	} else if(key.equals("port") || key.equals("proxyport") || key.equals("mtu") || key.equals("compression") ||
345 		  key.equals("secrand") || key.equals("alive")) {
346 	    try {
347 		int val = Integer.valueOf(value).intValue();
348@@ -309,6 +310,9 @@
349 		} else if(key.equals("secrand")) {
350 		    if(val < 0 || val > 2)
351 			throw new IllegalArgumentException("Secrand must be 0-2");
352+		} else if(key.equals("compression")) {
353+		    if(val < 0 || val > 9)
354+			throw new IllegalArgumentException("Compression Level must be 0-9");
355 		}
356 	    } catch (NumberFormatException e) {
357 		throw new IllegalArgumentException("Value for " + key + " must be an integer");
358@@ -1203,6 +1207,10 @@
359
360     public int getAliveInterval() {
361 	return Integer.valueOf(getProperty("alive")).intValue();
362+    }
363+
364+    public int getCompressionLevel() {
365+	return Integer.valueOf(getProperty("compression")).intValue();
366     }
367
368     public boolean wantX11Forward() {
369