+// This is surprisingly fast, for pure Java. On a SPARC 20, wrapped +// in Acme.Crypto.EncryptedOutputStream or Acme.Crypto.EncryptedInputStream, +// it does around 7000 bytes/second. +//
+// Most of this code is by Dave Zimmerman
+// Fetch the software.
+// @see Des3Cipher
+// @see EncryptedOutputStream
+// @see EncryptedInputStream
+
+package android.androidVNC;
+
+//- import java.io.*;
+
+
+public class DesCipher
+ {
+
+ // Constructor, byte-array key.
+ public DesCipher( byte[] key )
+ {
+ setKey( key );
+ }
+
+ // Key routines.
+
+ private int[] encryptKeys = new int[32];
+ private int[] decryptKeys = new int[32];
+
+ /// Set the key.
+ public void setKey( byte[] key )
+ {
+ deskey( key, true, encryptKeys );
+ deskey( key, false, decryptKeys );
+ }
+
+ // Turn an 8-byte key into internal keys.
+ private void deskey( byte[] keyBlock, boolean encrypting, int[] KnL )
+ {
+ int i, j, l, m, n;
+ int[] pc1m = new int[56];
+ int[] pcr = new int[56];
+ int[] kn = new int[32];
+
+ for ( j = 0; j < 56; ++j )
+ {
+ l = pc1[j];
+ m = l & 07;
+ pc1m[j] = ( (keyBlock[l >>> 3] & bytebit[m]) != 0 )? 1: 0;
+ }
+
+ for ( i = 0; i < 16; ++i )
+ {
+ if ( encrypting )
+ m = i << 1;
+ else
+ m = (15-i) << 1;
+ n = m+1;
+ kn[m] = kn[n] = 0;
+ for ( j = 0; j < 28; ++j )
+ {
+ l = j+totrot[i];
+ if ( l < 28 )
+ pcr[j] = pc1m[l];
+ else
+ pcr[j] = pc1m[l-28];
+ }
+ for ( j=28; j < 56; ++j )
+ {
+ l = j+totrot[i];
+ if ( l < 56 )
+ pcr[j] = pc1m[l];
+ else
+ pcr[j] = pc1m[l-28];
+ }
+ for ( j = 0; j < 24; ++j )
+ {
+ if ( pcr[pc2[j]] != 0 )
+ kn[m] |= bigbyte[j];
+ if ( pcr[pc2[j+24]] != 0 )
+ kn[n] |= bigbyte[j];
+ }
+ }
+ cookey( kn, KnL );
+ }
+
+ private void cookey( int[] raw, int KnL[] )
+ {
+ int raw0, raw1;
+ int rawi, KnLi;
+ int i;
+
+ for ( i = 0, rawi = 0, KnLi = 0; i < 16; ++i )
+ {
+ raw0 = raw[rawi++];
+ raw1 = raw[rawi++];
+ KnL[KnLi] = (raw0 & 0x00fc0000) << 6;
+ KnL[KnLi] |= (raw0 & 0x00000fc0) << 10;
+ KnL[KnLi] |= (raw1 & 0x00fc0000) >>> 10;
+ KnL[KnLi] |= (raw1 & 0x00000fc0) >>> 6;
+ ++KnLi;
+ KnL[KnLi] = (raw0 & 0x0003f000) << 12;
+ KnL[KnLi] |= (raw0 & 0x0000003f) << 16;
+ KnL[KnLi] |= (raw1 & 0x0003f000) >>> 4;
+ KnL[KnLi] |= (raw1 & 0x0000003f);
+ ++KnLi;
+ }
+ }
+
+
+ // Block encryption routines.
+
+ private int[] tempInts = new int[2];
+
+ /// Encrypt a block of eight bytes.
+ public void encrypt( byte[] clearText, int clearOff, byte[] cipherText, int cipherOff )
+ {
+ squashBytesToInts( clearText, clearOff, tempInts, 0, 2 );
+ des( tempInts, tempInts, encryptKeys );
+ spreadIntsToBytes( tempInts, 0, cipherText, cipherOff, 2 );
+ }
+
+ /// Decrypt a block of eight bytes.
+ public void decrypt( byte[] cipherText, int cipherOff, byte[] clearText, int clearOff )
+ {
+ squashBytesToInts( cipherText, cipherOff, tempInts, 0, 2 );
+ des( tempInts, tempInts, decryptKeys );
+ spreadIntsToBytes( tempInts, 0, clearText, clearOff, 2 );
+ }
+
+ // The DES function.
+ private void des( int[] inInts, int[] outInts, int[] keys )
+ {
+ int fval, work, right, leftt;
+ int round;
+ int keysi = 0;
+
+ leftt = inInts[0];
+ right = inInts[1];
+
+ work = ((leftt >>> 4) ^ right) & 0x0f0f0f0f;
+ right ^= work;
+ leftt ^= (work << 4);
+
+ work = ((leftt >>> 16) ^ right) & 0x0000ffff;
+ right ^= work;
+ leftt ^= (work << 16);
+
+ work = ((right >>> 2) ^ leftt) & 0x33333333;
+ leftt ^= work;
+ right ^= (work << 2);
+
+ work = ((right >>> 8) ^ leftt) & 0x00ff00ff;
+ leftt ^= work;
+ right ^= (work << 8);
+ right = (right << 1) | ((right >>> 31) & 1);
+
+ work = (leftt ^ right) & 0xaaaaaaaa;
+ leftt ^= work;
+ right ^= work;
+ leftt = (leftt << 1) | ((leftt >>> 31) & 1);
+
+ for ( round = 0; round < 8; ++round )
+ {
+ work = (right << 28) | (right >>> 4);
+ work ^= keys[keysi++];
+ fval = SP7[ work & 0x0000003f ];
+ fval |= SP5[(work >>> 8) & 0x0000003f ];
+ fval |= SP3[(work >>> 16) & 0x0000003f ];
+ fval |= SP1[(work >>> 24) & 0x0000003f ];
+ work = right ^ keys[keysi++];
+ fval |= SP8[ work & 0x0000003f ];
+ fval |= SP6[(work >>> 8) & 0x0000003f ];
+ fval |= SP4[(work >>> 16) & 0x0000003f ];
+ fval |= SP2[(work >>> 24) & 0x0000003f ];
+ leftt ^= fval;
+ work = (leftt << 28) | (leftt >>> 4);
+ work ^= keys[keysi++];
+ fval = SP7[ work & 0x0000003f ];
+ fval |= SP5[(work >>> 8) & 0x0000003f ];
+ fval |= SP3[(work >>> 16) & 0x0000003f ];
+ fval |= SP1[(work >>> 24) & 0x0000003f ];
+ work = leftt ^ keys[keysi++];
+ fval |= SP8[ work & 0x0000003f ];
+ fval |= SP6[(work >>> 8) & 0x0000003f ];
+ fval |= SP4[(work >>> 16) & 0x0000003f ];
+ fval |= SP2[(work >>> 24) & 0x0000003f ];
+ right ^= fval;
+ }
+
+ right = (right << 31) | (right >>> 1);
+ work = (leftt ^ right) & 0xaaaaaaaa;
+ leftt ^= work;
+ right ^= work;
+ leftt = (leftt << 31) | (leftt >>> 1);
+ work = ((leftt >>> 8) ^ right) & 0x00ff00ff;
+ right ^= work;
+ leftt ^= (work << 8);
+ work = ((leftt >>> 2) ^ right) & 0x33333333;
+ right ^= work;
+ leftt ^= (work << 2);
+ work = ((right >>> 16) ^ leftt) & 0x0000ffff;
+ leftt ^= work;
+ right ^= (work << 16);
+ work = ((right >>> 4) ^ leftt) & 0x0f0f0f0f;
+ leftt ^= work;
+ right ^= (work << 4);
+ outInts[0] = right;
+ outInts[1] = leftt;
+ }
+
+
+ // Tables, permutations, S-boxes, etc.
+
+ private static byte[] bytebit = {
+ (byte)0x01, (byte)0x02, (byte)0x04, (byte)0x08,
+ (byte)0x10, (byte)0x20, (byte)0x40, (byte)0x80
+ };
+ private static int[] bigbyte = {
+ 0x800000, 0x400000, 0x200000, 0x100000,
+ 0x080000, 0x040000, 0x020000, 0x010000,
+ 0x008000, 0x004000, 0x002000, 0x001000,
+ 0x000800, 0x000400, 0x000200, 0x000100,
+ 0x000080, 0x000040, 0x000020, 0x000010,
+ 0x000008, 0x000004, 0x000002, 0x000001
+ };
+ private static byte[] pc1 = {
+ (byte)56, (byte)48, (byte)40, (byte)32, (byte)24, (byte)16, (byte) 8,
+ (byte) 0, (byte)57, (byte)49, (byte)41, (byte)33, (byte)25, (byte)17,
+ (byte) 9, (byte) 1, (byte)58, (byte)50, (byte)42, (byte)34, (byte)26,
+ (byte)18, (byte)10, (byte) 2, (byte)59, (byte)51, (byte)43, (byte)35,
+ (byte)62, (byte)54, (byte)46, (byte)38, (byte)30, (byte)22, (byte)14,
+ (byte) 6, (byte)61, (byte)53, (byte)45, (byte)37, (byte)29, (byte)21,
+ (byte)13, (byte) 5, (byte)60, (byte)52, (byte)44, (byte)36, (byte)28,
+ (byte)20, (byte)12, (byte) 4, (byte)27, (byte)19, (byte)11, (byte)3
+ };
+ private static int[] totrot = {
+ 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28
+ };
+
+ private static byte[] pc2 = {
+ (byte)13, (byte)16, (byte)10, (byte)23, (byte) 0, (byte) 4,
+ (byte) 2, (byte)27, (byte)14, (byte) 5, (byte)20, (byte) 9,
+ (byte)22, (byte)18, (byte)11, (byte)3 , (byte)25, (byte) 7,
+ (byte)15, (byte) 6, (byte)26, (byte)19, (byte)12, (byte) 1,
+ (byte)40, (byte)51, (byte)30, (byte)36, (byte)46, (byte)54,
+ (byte)29, (byte)39, (byte)50, (byte)44, (byte)32, (byte)47,
+ (byte)43, (byte)48, (byte)38, (byte)55, (byte)33, (byte)52,
+ (byte)45, (byte)41, (byte)49, (byte)35, (byte)28, (byte)31,
+ };
+
+ private static int[] SP1 = {
+ 0x01010400, 0x00000000, 0x00010000, 0x01010404,
+ 0x01010004, 0x00010404, 0x00000004, 0x00010000,
+ 0x00000400, 0x01010400, 0x01010404, 0x00000400,
+ 0x01000404, 0x01010004, 0x01000000, 0x00000004,
+ 0x00000404, 0x01000400, 0x01000400, 0x00010400,
+ 0x00010400, 0x01010000, 0x01010000, 0x01000404,
+ 0x00010004, 0x01000004, 0x01000004, 0x00010004,
+ 0x00000000, 0x00000404, 0x00010404, 0x01000000,
+ 0x00010000, 0x01010404, 0x00000004, 0x01010000,
+ 0x01010400, 0x01000000, 0x01000000, 0x00000400,
+ 0x01010004, 0x00010000, 0x00010400, 0x01000004,
+ 0x00000400, 0x00000004, 0x01000404, 0x00010404,
+ 0x01010404, 0x00010004, 0x01010000, 0x01000404,
+ 0x01000004, 0x00000404, 0x00010404, 0x01010400,
+ 0x00000404, 0x01000400, 0x01000400, 0x00000000,
+ 0x00010004, 0x00010400, 0x00000000, 0x01010004
+ };
+ private static int[] SP2 = {
+ 0x80108020, 0x80008000, 0x00008000, 0x00108020,
+ 0x00100000, 0x00000020, 0x80100020, 0x80008020,
+ 0x80000020, 0x80108020, 0x80108000, 0x80000000,
+ 0x80008000, 0x00100000, 0x00000020, 0x80100020,
+ 0x00108000, 0x00100020, 0x80008020, 0x00000000,
+ 0x80000000, 0x00008000, 0x00108020, 0x80100000,
+ 0x00100020, 0x80000020, 0x00000000, 0x00108000,
+ 0x00008020, 0x80108000, 0x80100000, 0x00008020,
+ 0x00000000, 0x00108020, 0x80100020, 0x00100000,
+ 0x80008020, 0x80100000, 0x80108000, 0x00008000,
+ 0x80100000, 0x80008000, 0x00000020, 0x80108020,
+ 0x00108020, 0x00000020, 0x00008000, 0x80000000,
+ 0x00008020, 0x80108000, 0x00100000, 0x80000020,
+ 0x00100020, 0x80008020, 0x80000020, 0x00100020,
+ 0x00108000, 0x00000000, 0x80008000, 0x00008020,
+ 0x80000000, 0x80100020, 0x80108020, 0x00108000
+ };
+ private static int[] SP3 = {
+ 0x00000208, 0x08020200, 0x00000000, 0x08020008,
+ 0x08000200, 0x00000000, 0x00020208, 0x08000200,
+ 0x00020008, 0x08000008, 0x08000008, 0x00020000,
+ 0x08020208, 0x00020008, 0x08020000, 0x00000208,
+ 0x08000000, 0x00000008, 0x08020200, 0x00000200,
+ 0x00020200, 0x08020000, 0x08020008, 0x00020208,
+ 0x08000208, 0x00020200, 0x00020000, 0x08000208,
+ 0x00000008, 0x08020208, 0x00000200, 0x08000000,
+ 0x08020200, 0x08000000, 0x00020008, 0x00000208,
+ 0x00020000, 0x08020200, 0x08000200, 0x00000000,
+ 0x00000200, 0x00020008, 0x08020208, 0x08000200,
+ 0x08000008, 0x00000200, 0x00000000, 0x08020008,
+ 0x08000208, 0x00020000, 0x08000000, 0x08020208,
+ 0x00000008, 0x00020208, 0x00020200, 0x08000008,
+ 0x08020000, 0x08000208, 0x00000208, 0x08020000,
+ 0x00020208, 0x00000008, 0x08020008, 0x00020200
+ };
+ private static int[] SP4 = {
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+ 0x00802080, 0x00800081, 0x00800001, 0x00002001,
+ 0x00000000, 0x00802000, 0x00802000, 0x00802081,
+ 0x00000081, 0x00000000, 0x00800080, 0x00800001,
+ 0x00000001, 0x00002000, 0x00800000, 0x00802001,
+ 0x00000080, 0x00800000, 0x00002001, 0x00002080,
+ 0x00800081, 0x00000001, 0x00002080, 0x00800080,
+ 0x00002000, 0x00802080, 0x00802081, 0x00000081,
+ 0x00800080, 0x00800001, 0x00802000, 0x00802081,
+ 0x00000081, 0x00000000, 0x00000000, 0x00802000,
+ 0x00002080, 0x00800080, 0x00800081, 0x00000001,
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+ 0x00802081, 0x00000081, 0x00000001, 0x00002000,
+ 0x00800001, 0x00002001, 0x00802080, 0x00800081,
+ 0x00002001, 0x00002080, 0x00800000, 0x00802001,
+ 0x00000080, 0x00800000, 0x00002000, 0x00802080
+ };
+ private static int[] SP5 = {
+ 0x00000100, 0x02080100, 0x02080000, 0x42000100,
+ 0x00080000, 0x00000100, 0x40000000, 0x02080000,
+ 0x40080100, 0x00080000, 0x02000100, 0x40080100,
+ 0x42000100, 0x42080000, 0x00080100, 0x40000000,
+ 0x02000000, 0x40080000, 0x40080000, 0x00000000,
+ 0x40000100, 0x42080100, 0x42080100, 0x02000100,
+ 0x42080000, 0x40000100, 0x00000000, 0x42000000,
+ 0x02080100, 0x02000000, 0x42000000, 0x00080100,
+ 0x00080000, 0x42000100, 0x00000100, 0x02000000,
+ 0x40000000, 0x02080000, 0x42000100, 0x40080100,
+ 0x02000100, 0x40000000, 0x42080000, 0x02080100,
+ 0x40080100, 0x00000100, 0x02000000, 0x42080000,
+ 0x42080100, 0x00080100, 0x42000000, 0x42080100,
+ 0x02080000, 0x00000000, 0x40080000, 0x42000000,
+ 0x00080100, 0x02000100, 0x40000100, 0x00080000,
+ 0x00000000, 0x40080000, 0x02080100, 0x40000100
+ };
+ private static int[] SP6 = {
+ 0x20000010, 0x20400000, 0x00004000, 0x20404010,
+ 0x20400000, 0x00000010, 0x20404010, 0x00400000,
+ 0x20004000, 0x00404010, 0x00400000, 0x20000010,
+ 0x00400010, 0x20004000, 0x20000000, 0x00004010,
+ 0x00000000, 0x00400010, 0x20004010, 0x00004000,
+ 0x00404000, 0x20004010, 0x00000010, 0x20400010,
+ 0x20400010, 0x00000000, 0x00404010, 0x20404000,
+ 0x00004010, 0x00404000, 0x20404000, 0x20000000,
+ 0x20004000, 0x00000010, 0x20400010, 0x00404000,
+ 0x20404010, 0x00400000, 0x00004010, 0x20000010,
+ 0x00400000, 0x20004000, 0x20000000, 0x00004010,
+ 0x20000010, 0x20404010, 0x00404000, 0x20400000,
+ 0x00404010, 0x20404000, 0x00000000, 0x20400010,
+ 0x00000010, 0x00004000, 0x20400000, 0x00404010,
+ 0x00004000, 0x00400010, 0x20004010, 0x00000000,
+ 0x20404000, 0x20000000, 0x00400010, 0x20004010
+ };
+ private static int[] SP7 = {
+ 0x00200000, 0x04200002, 0x04000802, 0x00000000,
+ 0x00000800, 0x04000802, 0x00200802, 0x04200800,
+ 0x04200802, 0x00200000, 0x00000000, 0x04000002,
+ 0x00000002, 0x04000000, 0x04200002, 0x00000802,
+ 0x04000800, 0x00200802, 0x00200002, 0x04000800,
+ 0x04000002, 0x04200000, 0x04200800, 0x00200002,
+ 0x04200000, 0x00000800, 0x00000802, 0x04200802,
+ 0x00200800, 0x00000002, 0x04000000, 0x00200800,
+ 0x04000000, 0x00200800, 0x00200000, 0x04000802,
+ 0x04000802, 0x04200002, 0x04200002, 0x00000002,
+ 0x00200002, 0x04000000, 0x04000800, 0x00200000,
+ 0x04200800, 0x00000802, 0x00200802, 0x04200800,
+ 0x00000802, 0x04000002, 0x04200802, 0x04200000,
+ 0x00200800, 0x00000000, 0x00000002, 0x04200802,
+ 0x00000000, 0x00200802, 0x04200000, 0x00000800,
+ 0x04000002, 0x04000800, 0x00000800, 0x00200002
+ };
+ private static int[] SP8 = {
+ 0x10001040, 0x00001000, 0x00040000, 0x10041040,
+ 0x10000000, 0x10001040, 0x00000040, 0x10000000,
+ 0x00040040, 0x10040000, 0x10041040, 0x00041000,
+ 0x10041000, 0x00041040, 0x00001000, 0x00000040,
+ 0x10040000, 0x10000040, 0x10001000, 0x00001040,
+ 0x00041000, 0x00040040, 0x10040040, 0x10041000,
+ 0x00001040, 0x00000000, 0x00000000, 0x10040040,
+ 0x10000040, 0x10001000, 0x00041040, 0x00040000,
+ 0x00041040, 0x00040000, 0x10041000, 0x00001000,
+ 0x00000040, 0x10040040, 0x00001000, 0x00041040,
+ 0x10001000, 0x00000040, 0x10000040, 0x10040000,
+ 0x10040040, 0x10000000, 0x00040000, 0x10001040,
+ 0x00000000, 0x10041040, 0x00040040, 0x10000040,
+ 0x10040000, 0x10001000, 0x10001040, 0x00000000,
+ 0x10041040, 0x00041000, 0x00041000, 0x00001040,
+ 0x00001040, 0x00040040, 0x10000000, 0x10041000
+ };
+
+ // Routines taken from other parts of the Acme utilities.
+
+ /// Squash bytes down to ints.
+ public static void squashBytesToInts( byte[] inBytes, int inOff, int[] outInts, int outOff, int intLen )
+ {
+ for ( int i = 0; i < intLen; ++i )
+ outInts[outOff + i] =
+ ( ( inBytes[inOff + i * 4 ] & 0xff ) << 24 ) |
+ ( ( inBytes[inOff + i * 4 + 1] & 0xff ) << 16 ) |
+ ( ( inBytes[inOff + i * 4 + 2] & 0xff ) << 8 ) |
+ ( inBytes[inOff + i * 4 + 3] & 0xff );
+ }
+
+ /// Spread ints into bytes.
+ public static void spreadIntsToBytes( int[] inInts, int inOff, byte[] outBytes, int outOff, int intLen )
+ {
+ for ( int i = 0; i < intLen; ++i )
+ {
+ outBytes[outOff + i * 4 ] = (byte) ( inInts[inOff + i] >>> 24 );
+ outBytes[outOff + i * 4 + 1] = (byte) ( inInts[inOff + i] >>> 16 );
+ outBytes[outOff + i * 4 + 2] = (byte) ( inInts[inOff + i] >>> 8 );
+ outBytes[outOff + i * 4 + 3] = (byte) inInts[inOff + i];
+ }
+ }
+ }
hunk ./androidVNC/src/android/androidVNC/HTTPConnectSocket.java 1
+//
+// Copyright (C) 2002 Constantin Kaplinsky, Inc. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// HTTPConnectSocket.java together with HTTPConnectSocketFactory.java
+// implement an alternate way to connect to VNC servers via one or two
+// HTTP proxies supporting the HTTP CONNECT method.
+//
+package android.androidVNC;
+
+import java.net.*;
+import java.io.*;
+
+class HTTPConnectSocket extends Socket {
+
+ public HTTPConnectSocket(String host, int port,
+ String proxyHost, int proxyPort)
+ throws IOException {
+
+ // Connect to the specified HTTP proxy
+ super(proxyHost, proxyPort);
+
+ // Send the CONNECT request
+ getOutputStream().write(("CONNECT " + host + ":" + port +
+ " HTTP/1.0\r\n\r\n").getBytes());
+
+ // Read the first line of the response
+ DataInputStream is = new DataInputStream(getInputStream());
+ BufferedReader in = new BufferedReader(new InputStreamReader(is));
+
+ //- String str = is.readLine();
+ String str = in.readLine();
+
+ // Check the HTTP error code -- it should be "200" on success
+ if (!str.startsWith("HTTP/1.0 200 ")) {
+ if (str.startsWith("HTTP/1.0 "))
+ str = str.substring(9);
+ throw new IOException("Proxy reports \"" + str + "\"");
+ }
+
+ // Success -- skip remaining HTTP headers
+ do {
+ //- str = is.readLine();
+ str = in.readLine();
+ } while (str.length() != 0);
+ }
+}
+
hunk ./androidVNC/src/android/androidVNC/HTTPConnectSocketFactory.java 1
+//
+// Copyright (C) 2002 Constantin Kaplinsky, Inc. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// HTTPConnectSocketFactory.java together with HTTPConnectSocket.java
+// implement an alternate way to connect to VNC servers via one or two
+// HTTP proxies supporting the HTTP CONNECT method.
+//
+package android.androidVNC;
+
+//- import java.applet.*;
+import java.net.*;
+import java.io.*;
+
+class HTTPConnectSocketFactory implements SocketFactory {
+
+ /*-
+ public Socket createSocket(String host, int port, Applet applet)
+ throws IOException {
+
+ return createSocket(host, port,
+ applet.getParameter("PROXYHOST1"),
+ applet.getParameter("PROXYPORT1"));
+ }
+ */
+
+ public Socket createSocket(String host, int port, String[] args)
+ throws IOException {
+
+ return createSocket(host, port,
+ readArg(args, "PROXYHOST1"),
+ readArg(args, "PROXYPORT1"));
+ }
+
+ public Socket createSocket(String host, int port,
+ String proxyHost, String proxyPortStr)
+ throws IOException {
+
+ int proxyPort = 0;
+ if (proxyPortStr != null) {
+ try {
+ proxyPort = Integer.parseInt(proxyPortStr);
+ } catch (NumberFormatException e) { }
+ }
+
+ if (proxyHost == null || proxyPort == 0) {
+ System.out.println("Incomplete parameter list for HTTPConnectSocket");
+ return new Socket(host, port);
+ }
+
+ System.out.println("HTTP CONNECT via proxy " + proxyHost +
+ " port " + proxyPort);
+ HTTPConnectSocket s =
+ new HTTPConnectSocket(host, port, proxyHost, proxyPort);
+
+ return (Socket)s;
+ }
+
+ private String readArg(String[] args, String name) {
+
+ for (int i = 0; i < args.length; i += 2) {
+ if (args[i].equalsIgnoreCase(name)) {
+ try {
+ return args[i+1];
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+}
+
hunk ./androidVNC/src/android/androidVNC/InStream.java 1
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+//
+// rdr::InStream marshalls data from a buffer stored in RDR (RFB Data
+// Representation).
+//
+package android.androidVNC;
+
+abstract public class InStream {
+
+ // check() ensures there is buffer data for at least one item of size
+ // itemSize bytes. Returns the number of items in the buffer (up to a
+ // maximum of nItems).
+
+ public final int check(int itemSize, int nItems) throws Exception {
+ if (ptr + itemSize * nItems > end) {
+ if (ptr + itemSize > end)
+ return overrun(itemSize, nItems);
+
+ nItems = (end - ptr) / itemSize;
+ }
+ return nItems;
+ }
+
+ public final void check(int itemSize) throws Exception {
+ if (ptr + itemSize > end)
+ overrun(itemSize, 1);
+ }
+
+ // readU/SN() methods read unsigned and signed N-bit integers.
+
+ public final int readS8() throws Exception {
+ check(1); return b[ptr++];
+ }
+
+ public final int readS16() throws Exception {
+ check(2); int b0 = b[ptr++];
+ int b1 = b[ptr++] & 0xff; return b0 << 8 | b1;
+ }
+
+ public final int readS32() throws Exception {
+ check(4); int b0 = b[ptr++];
+ int b1 = b[ptr++] & 0xff;
+ int b2 = b[ptr++] & 0xff;
+ int b3 = b[ptr++] & 0xff;
+ return b0 << 24 | b1 << 16 | b2 << 8 | b3;
+ }
+
+ public final int readU8() throws Exception {
+ return readS8() & 0xff;
+ }
+
+ public final int readU16() throws Exception {
+ return readS16() & 0xffff;
+ }
+
+ public final int readU32() throws Exception {
+ return readS32() & 0xffffffff;
+ }
+
+ // readString() reads a string - a U32 length followed by the data.
+
+ public final String readString() throws Exception {
+ int len = readU32();
+ if (len > maxStringLength)
+ throw new Exception("InStream max string length exceeded");
+
+ char[] str = new char[len];
+ int i = 0;
+ while (i < len) {
+ int j = i + check(1, len - i);
+ while (i < j) {
+ str[i++] = (char)b[ptr++];
+ }
+ }
+
+ return new String(str);
+ }
+
+ // maxStringLength protects against allocating a huge buffer. Set it
+ // higher if you need longer strings.
+
+ public static int maxStringLength = 65535;
+
+ public final void skip(int bytes) throws Exception {
+ while (bytes > 0) {
+ int n = check(1, bytes);
+ ptr += n;
+ bytes -= n;
+ }
+ }
+
+ // readBytes() reads an exact number of bytes into an array at an offset.
+
+ public void readBytes(byte[] data, int offset, int length) throws Exception {
+ int offsetEnd = offset + length;
+ while (offset < offsetEnd) {
+ int n = check(1, offsetEnd - offset);
+ System.arraycopy(b, ptr, data, offset, n);
+ ptr += n;
+ offset += n;
+ }
+ }
+
+ // readOpaqueN() reads a quantity "without byte-swapping". Because java has
+ // no byte-ordering, we just use big-endian.
+
+ public final int readOpaque8() throws Exception {
+ return readU8();
+ }
+
+ public final int readOpaque16() throws Exception {
+ return readU16();
+ }
+
+ public final int readOpaque32() throws Exception {
+ return readU32();
+ }
+
+ public final int readOpaque24A() throws Exception {
+ check(3); int b0 = b[ptr++];
+ int b1 = b[ptr++]; int b2 = b[ptr++];
+ return b0 << 24 | b1 << 16 | b2 << 8;
+ }
+
+ public final int readOpaque24B() throws Exception {
+ check(3); int b0 = b[ptr++];
+ int b1 = b[ptr++]; int b2 = b[ptr++];
+ return b0 << 16 | b1 << 8 | b2;
+ }
+
+ // pos() returns the position in the stream.
+
+ abstract public int pos();
+
+ // bytesAvailable() returns true if at least one byte can be read from the
+ // stream without blocking. i.e. if false is returned then readU8() would
+ // block.
+
+ public boolean bytesAvailable() { return end != ptr; }
+
+ // getbuf(), getptr(), getend() and setptr() are "dirty" methods which allow
+ // you to manipulate the buffer directly. This is useful for a stream which
+ // is a wrapper around an underlying stream.
+
+ public final byte[] getbuf() { return b; }
+ public final int getptr() { return ptr; }
+ public final int getend() { return end; }
+ public final void setptr(int p) { ptr = p; }
+
+ // overrun() is implemented by a derived class to cope with buffer overrun.
+ // It ensures there are at least itemSize bytes of buffer data. Returns
+ // the number of items in the buffer (up to a maximum of nItems). itemSize
+ // is supposed to be "small" (a few bytes).
+
+ abstract protected int overrun(int itemSize, int nItems) throws Exception;
+
+ protected InStream() {}
+ protected byte[] b;
+ protected int ptr;
+ protected int end;
+}
hunk ./androidVNC/src/android/androidVNC/MemInStream.java 1
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+package android.androidVNC;
+
+public class MemInStream extends InStream {
+
+ public MemInStream(byte[] data, int offset, int len) {
+ b = data;
+ ptr = offset;
+ end = offset + len;
+ }
+
+ public int pos() { return ptr; }
+
+ protected int overrun(int itemSize, int nItems) throws Exception {
+ throw new Exception("MemInStream overrun: end of stream");
+ }
+}
hunk ./androidVNC/src/android/androidVNC/R.java 1
+/* AUTO-GENERATED FILE. DO NOT MODIFY.
+ *
+ * This class was automatically generated by the
+ * aapt tool from the resource data it found. It
+ * should not be modified by hand.
+ */
+
+package android.androidVNC;
+
+public final class R {
+ public static final class attr {
+ }
+ public static final class drawable {
+ public static final int icon=0x7f020000;
+ }
+ public static final class id {
+ public static final int buttonGO=0x7f050004;
+ public static final int text1=0x7f050000;
+ public static final int text2=0x7f050002;
+ public static final int textIP=0x7f050001;
+ public static final int textPORT=0x7f050003;
+ }
+ public static final class layout {
+ public static final int canvas=0x7f030000;
+ public static final int main=0x7f030001;
+ }
+ public static final class string {
+ public static final int app_name=0x7f040000;
+ }
+}
hunk ./androidVNC/src/android/androidVNC/RfbProto.java 1
+//
+// Copyright (C) 2001-2004 HorizonLive.com, Inc. All Rights Reserved.
+// Copyright (C) 2001-2006 Constantin Kaplinsky. All Rights Reserved.
+// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
+// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+// This is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This software is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this software; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+
+//
+// RfbProto.java
+//
+
+package android.androidVNC;
+
+import java.io.*;
+//- import java.awt.*;
+//- import java.awt.event.*;
+import java.net.Socket;
+//- import java.util.zip.*;
+import android.util.Log;
+
+class RfbProto {
+
+ final static String TAG = "RfbProto";
+
+ final static String
+ versionMsg_3_3 = "RFB 003.003\n",
+ versionMsg_3_7 = "RFB 003.007\n",
+ versionMsg_3_8 = "RFB 003.008\n";
+
+ // Vendor signatures: standard VNC/RealVNC, TridiaVNC, and TightVNC
+ final static String
+ StandardVendor = "STDV",
+ TridiaVncVendor = "TRDV",
+ TightVncVendor = "TGHT";
+
+ // Security types
+ final static int
+ SecTypeInvalid = 0,
+ SecTypeNone = 1,
+ SecTypeVncAuth = 2,
+ SecTypeTight = 16;
+
+ // Supported tunneling types
+ final static int
+ NoTunneling = 0;
+ final static String
+ SigNoTunneling = "NOTUNNEL";
+
+ // Supported authentication types
+ final static int
+ AuthNone = 1,
+ AuthVNC = 2,
+ AuthUnixLogin = 129;
+ final static String
+ SigAuthNone = "NOAUTH__",
+ SigAuthVNC = "VNCAUTH_",
+ SigAuthUnixLogin = "ULGNAUTH";
+
+ // VNC authentication results
+ final static int
+ VncAuthOK = 0,
+ VncAuthFailed = 1,
+ VncAuthTooMany = 2;
+
+ // Server-to-client messages
+ final static int
+ FramebufferUpdate = 0,
+ SetColourMapEntries = 1,
+ Bell = 2,
+ ServerCutText = 3;
+
+ // Client-to-server messages
+ final static int
+ SetPixelFormat = 0,
+ FixColourMapEntries = 1,
+ SetEncodings = 2,
+ FramebufferUpdateRequest = 3,
+ KeyboardEvent = 4,
+ PointerEvent = 5,
+ ClientCutText = 6;
+
+ // Supported encodings and pseudo-encodings
+ final static int
+ EncodingRaw = 0,
+ EncodingCopyRect = 1,
+ EncodingRRE = 2,
+ EncodingCoRRE = 4,
+ EncodingHextile = 5,
+ EncodingZlib = 6,
+ EncodingTight = 7,
+ EncodingZRLE = 16,
+ EncodingCompressLevel0 = 0xFFFFFF00,
+ EncodingQualityLevel0 = 0xFFFFFFE0,
+ EncodingXCursor = 0xFFFFFF10,
+ EncodingRichCursor = 0xFFFFFF11,
+ EncodingPointerPos = 0xFFFFFF18,
+ EncodingLastRect = 0xFFFFFF20,
+ EncodingNewFBSize = 0xFFFFFF21;
+ final static String
+ SigEncodingRaw = "RAW_____",
+ SigEncodingCopyRect = "COPYRECT",
+ SigEncodingRRE = "RRE_____",
+ SigEncodingCoRRE = "CORRE___",
+ SigEncodingHextile = "HEXTILE_",
+ SigEncodingZlib = "ZLIB____",
+ SigEncodingTight = "TIGHT___",
+ SigEncodingZRLE = "ZRLE____",
+ SigEncodingCompressLevel0 = "COMPRLVL",
+ SigEncodingQualityLevel0 = "JPEGQLVL",
+ SigEncodingXCursor = "X11CURSR",
+ SigEncodingRichCursor = "RCHCURSR",
+ SigEncodingPointerPos = "POINTPOS",
+ SigEncodingLastRect = "LASTRECT",
+ SigEncodingNewFBSize = "NEWFBSIZ";
+
+ final static int MaxNormalEncoding = 255;
+
+ // Contstants used in the Hextile decoder
+ final static int
+ HextileRaw = 1,
+ HextileBackgroundSpecified = 2,
+ HextileForegroundSpecified = 4,
+ HextileAnySubrects = 8,
+ HextileSubrectsColoured = 16;
+
+ // Contstants used in the Tight decoder
+ final static int TightMinToCompress = 12;
+ final static int
+ TightExplicitFilter = 0x04,
+ TightFill = 0x08,
+ TightJpeg = 0x09,
+ TightMaxSubencoding = 0x09,
+ TightFilterCopy = 0x00,
+ TightFilterPalette = 0x01,
+ TightFilterGradient = 0x02;
+
+
+ String host;
+ int port;
+ Socket sock;
+ DataInputStream is;
+ OutputStream os;
+ //- SessionRecorder rec;
+ boolean inNormalProtocol = false;
+ //- VncViewer viewer;
+
+ // Java on UNIX does not call keyPressed() on some keys, for example
+ // swedish keys To prevent our workaround to produce duplicate
+ // keypresses on JVMs that actually works, keep track of if
+ // keyPressed() for a "broken" key was called or not.
+ boolean brokenKeyPressed = false;
+
+ // This will be set to true on the first framebuffer update
+ // containing Zlib-, ZRLE- or Tight-encoded data.
+ boolean wereZlibUpdates = false;
+
+ // This will be set to false if the startSession() was called after
+ // we have received at least one Zlib-, ZRLE- or Tight-encoded
+ // framebuffer update.
+ boolean recordFromBeginning = true;
+
+ // This fields are needed to show warnings about inefficiently saved
+ // sessions only once per each saved session file.
+ boolean zlibWarningShown;
+ boolean tightWarningShown;
+
+ // Before starting to record each saved session, we set this field
+ // to 0, and increment on each framebuffer update. We don't flush
+ // the SessionRecorder data into the file before the second update.
+ // This allows us to write initial framebuffer update with zero
+ // timestamp, to let the player show initial desktop before
+ // playback.
+ int numUpdatesInSession;
+
+ // Measuring network throughput.
+ boolean timing;
+ long timeWaitedIn100us;
+ long timedKbits;
+
+ // Protocol version and TightVNC-specific protocol options.
+ int serverMajor, serverMinor;
+ int clientMajor, clientMinor;
+ boolean protocolTightVNC;
+ CapsContainer tunnelCaps, authCaps;
+ CapsContainer serverMsgCaps, clientMsgCaps;
+ CapsContainer encodingCaps;
+
+ // If true, informs that the RFB socket was closed.
+ private boolean closed;
+
+ //
+ // Constructor. Make TCP connection to RFB server.
+ //
+
+
+ //-RfbProto(String h, int p, VncViewer v) throws IOException {
+ RfbProto(String h, int p) throws IOException{
+ //- viewer = v;
+ host = h;
+ port = p;
+
+ /*
+ if (viewer.socketFactory == null) {
+ sock = new Socket(host, port);
+ } else {
+ try {
+ Class factoryClass = Class.forName(viewer.socketFactory);
+ SocketFactory factory = (SocketFactory)factoryClass.newInstance();
+ //- if (viewer.inAnApplet)
+ //- sock = factory.createSocket(host, port, viewer);
+ //- else
+ sock = factory.createSocket(host, port, viewer.mainArgs);
+ }
+ catch(Exception e) {
+ e.printStackTrace();
+ throw new IOException(e.getMessage());
+ }
+ } */
+ //+
+ sock = new Socket(host, port);
+ is = new DataInputStream(new BufferedInputStream(sock.getInputStream(),
+ 16384));
+ os = sock.getOutputStream();
+
+ timing = false;
+ timeWaitedIn100us = 5;
+ timedKbits = 0;
+ }
+
+
+ synchronized void close() {
+ try {
+ sock.close();
+ closed = true;
+ //- System.out.println("RFB socket closed");
+ Log.v(TAG, "RFB socket closed");
+ /*-
+ if (rec != null) {
+ rec.close();
+ rec = null;
+
+ } */
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ synchronized boolean closed() {
+ return closed;
+ }
+
+ //
+ // Read server's protocol version message
+ //
+
+ void readVersionMsg() throws Exception {
+
+ byte[] b = new byte[12];
+
+ readFully(b);
+
+ if ((b[0] != 'R') || (b[1] != 'F') || (b[2] != 'B') || (b[3] != ' ')
+ || (b[4] < '0') || (b[4] > '9') || (b[5] < '0') || (b[5] > '9')
+ || (b[6] < '0') || (b[6] > '9') || (b[7] != '.')
+ || (b[8] < '0') || (b[8] > '9') || (b[9] < '0') || (b[9] > '9')
+ || (b[10] < '0') || (b[10] > '9') || (b[11] != '\n'))
+ {
+ throw new Exception("Host " + host + " port " + port +
+ " is not an RFB server");
+ }
+
+ serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0');
+ serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0');
+
+ if (serverMajor < 3) {
+ throw new Exception("RFB server does not support protocol version 3");
+ }
+ }
+
+
+ //
+ // Write our protocol version message
+ //
+
+ void writeVersionMsg() throws IOException {
+ clientMajor = 3;
+ if (serverMajor > 3 || serverMinor >= 8) {
+ clientMinor = 8;
+ os.write(versionMsg_3_8.getBytes());
+ } else if (serverMinor >= 7) {
+ clientMinor = 7;
+ os.write(versionMsg_3_7.getBytes());
+ } else {
+ clientMinor = 3;
+ os.write(versionMsg_3_3.getBytes());
+ }
+ protocolTightVNC = false;
+ }
+
+
+ //
+ // Negotiate the authentication scheme.
+ //
+
+ int negotiateSecurity() throws Exception {
+ return (clientMinor >= 7) ?
+ selectSecurityType() : readSecurityType();
+ }
+
+ //
+ // Read security type from the server (protocol version 3.3).
+ //
+
+ int readSecurityType() throws Exception {
+ int secType = is.readInt();
+
+ switch (secType) {
+ case SecTypeInvalid:
+ readConnFailedReason();
+ return SecTypeInvalid; // should never be executed
+ case SecTypeNone:
+ case SecTypeVncAuth:
+ return secType;
+ default:
+ throw new Exception("Unknown security type from RFB server: " + secType);
+ }
+ }
+
+ //
+ // Select security type from the server's list (protocol versions 3.7/3.8).
+ //
+
+ int selectSecurityType() throws Exception {
+ int secType = SecTypeInvalid;
+
+ // Read the list of secutiry types.
+ int nSecTypes = is.readUnsignedByte();
+ if (nSecTypes == 0) {
+ readConnFailedReason();
+ return SecTypeInvalid; // should never be executed
+ }
+ byte[] secTypes = new byte[nSecTypes];
+ readFully(secTypes);
+
+ // Find out if the server supports TightVNC protocol extensions
+ for (int i = 0; i < nSecTypes; i++) {
+ if (secTypes[i] == SecTypeTight) {
+ protocolTightVNC = true;
+ os.write(SecTypeTight);
+ return SecTypeTight;
+ }
+ }
+
+ // Find first supported security type.
+ for (int i = 0; i < nSecTypes; i++) {
+ if (secTypes[i] == SecTypeNone || secTypes[i] == SecTypeVncAuth) {
+ secType = secTypes[i];
+ break;
+ }
+ }
+
+ if (secType == SecTypeInvalid) {
+ throw new Exception("Server did not offer supported security type");
+ } else {
+ os.write(secType);
+ }
+
+ return secType;
+ }
+
+ //
+ // Perform "no authentication".
+ //
+
+ void authenticateNone() throws Exception {
+ if (clientMinor >= 8)
+ readSecurityResult("No authentication");
+ }
+
+ //
+ // Perform standard VNC Authentication.
+ //
+
+ void authenticateVNC(String pw) throws Exception {
+ byte[] challenge = new byte[16];
+ readFully(challenge);
+
+ if (pw.length() > 8)
+ pw = pw.substring(0, 8); // Truncate to 8 chars
+
+ // Truncate password on the first zero byte.
+ int firstZero = pw.indexOf(0);
+ if (firstZero != -1)
+ pw = pw.substring(0, firstZero);
+
+ byte[] key = {0, 0, 0, 0, 0, 0, 0, 0};
+ System.arraycopy(pw.getBytes(), 0, key, 0, pw.length());
+
+ DesCipher des = new DesCipher(key);
+
+ des.encrypt(challenge, 0, challenge, 0);
+ des.encrypt(challenge, 8, challenge, 8);
+
+ os.write(challenge);
+
+ readSecurityResult("VNC authentication");
+ }
+
+ //
+ // Read security result.
+ // Throws an exception on authentication failure.
+ //
+
+ void readSecurityResult(String authType) throws Exception {
+ int securityResult = is.readInt();
+
+ switch (securityResult) {
+ case VncAuthOK:
+ System.out.println(authType + ": success");
+ break;
+ case VncAuthFailed:
+ if (clientMinor >= 8)
+ readConnFailedReason();
+ throw new Exception(authType + ": failed");
+ case VncAuthTooMany:
+ throw new Exception(authType + ": failed, too many tries");
+ default:
+ throw new Exception(authType + ": unknown result " + securityResult);
+ }
+ }
+
+ //
+ // Read the string describing the reason for a connection failure,
+ // and throw an exception.
+ //
+
+ void readConnFailedReason() throws Exception {
+ int reasonLen = is.readInt();
+ byte[] reason = new byte[reasonLen];
+ readFully(reason);
+ Log.v(TAG, String.valueOf(reason));
+ throw new Exception(new String(reason));
+ }
+
+ //
+ // Initialize capability lists (TightVNC protocol extensions).
+ //
+
+ void initCapabilities() {
+ tunnelCaps = new CapsContainer();
+ authCaps = new CapsContainer();
+ serverMsgCaps = new CapsContainer();
+ clientMsgCaps = new CapsContainer();
+ encodingCaps = new CapsContainer();
+
+ // Supported authentication methods
+ authCaps.add(AuthNone, StandardVendor, SigAuthNone,
+ "No authentication");
+ authCaps.add(AuthVNC, StandardVendor, SigAuthVNC,
+ "Standard VNC password authentication");
+
+ // Supported encoding types
+ encodingCaps.add(EncodingCopyRect, StandardVendor,
+ SigEncodingCopyRect, "Standard CopyRect encoding");
+ encodingCaps.add(EncodingRRE, StandardVendor,
+ SigEncodingRRE, "Standard RRE encoding");
+ encodingCaps.add(EncodingCoRRE, StandardVendor,
+ SigEncodingCoRRE, "Standard CoRRE encoding");
+ encodingCaps.add(EncodingHextile, StandardVendor,
+ SigEncodingHextile, "Standard Hextile encoding");
+ encodingCaps.add(EncodingZRLE, StandardVendor,
+ SigEncodingZRLE, "Standard ZRLE encoding");
+ encodingCaps.add(EncodingZlib, TridiaVncVendor,
+ SigEncodingZlib, "Zlib encoding");
+ encodingCaps.add(EncodingTight, TightVncVendor,
+ SigEncodingTight, "Tight encoding");
+
+ // Supported pseudo-encoding types
+ encodingCaps.add(EncodingCompressLevel0, TightVncVendor,
+ SigEncodingCompressLevel0, "Compression level");
+ encodingCaps.add(EncodingQualityLevel0, TightVncVendor,
+ SigEncodingQualityLevel0, "JPEG quality level");
+ encodingCaps.add(EncodingXCursor, TightVncVendor,
+ SigEncodingXCursor, "X-style cursor shape update");
+ encodingCaps.add(EncodingRichCursor, TightVncVendor,
+ SigEncodingRichCursor, "Rich-color cursor shape update");
+ encodingCaps.add(EncodingPointerPos, TightVncVendor,
+ SigEncodingPointerPos, "Pointer position update");
+ encodingCaps.add(EncodingLastRect, TightVncVendor,
+ SigEncodingLastRect, "LastRect protocol extension");
+ encodingCaps.add(EncodingNewFBSize, TightVncVendor,
+ SigEncodingNewFBSize, "Framebuffer size change");
+ }
+
+ //
+ // Setup tunneling (TightVNC protocol extensions)
+ //
+
+ void setupTunneling() throws IOException {
+ int nTunnelTypes = is.readInt();
+ if (nTunnelTypes != 0) {
+ readCapabilityList(tunnelCaps, nTunnelTypes);
+
+ // We don't support tunneling yet.
+ writeInt(NoTunneling);
+ }
+ }
+
+ //
+ // Negotiate authentication scheme (TightVNC protocol extensions)
+ //
+
+ int negotiateAuthenticationTight() throws Exception {
+ int nAuthTypes = is.readInt();
+ if (nAuthTypes == 0)
+ return AuthNone;
+
+ readCapabilityList(authCaps, nAuthTypes);
+ for (int i = 0; i < authCaps.numEnabled(); i++) {
+ int authType = authCaps.getByOrder(i);
+ if (authType == AuthNone || authType == AuthVNC) {
+ writeInt(authType);
+ return authType;
+ }
+ }
+ throw new Exception("No suitable authentication scheme found");
+ }
+
+ //
+ // Read a capability list (TightVNC protocol extensions)
+ //
+
+ void readCapabilityList(CapsContainer caps, int count) throws IOException {
+ int code;
+ byte[] vendor = new byte[4];
+ byte[] name = new byte[8];
+ for (int i = 0; i < count; i++) {
+ code = is.readInt();
+ readFully(vendor);
+ readFully(name);
+ caps.enable(new CapabilityInfo(code, vendor, name));
+ }
+ }
+
+ //
+ // Write a 32-bit integer into the output stream.
+ //
+
+ void writeInt(int value) throws IOException {
+ byte[] b = new byte[4];
+ b[0] = (byte) ((value >> 24) & 0xff);
+ b[1] = (byte) ((value >> 16) & 0xff);
+ b[2] = (byte) ((value >> 8) & 0xff);
+ b[3] = (byte) (value & 0xff);
+ os.write(b);
+ }
+
+ //
+ // Write the client initialisation message
+ //
+
+ void writeClientInit() throws IOException {
+ /*- if (viewer.options.shareDesktop) {
+ os.write(1);
+ } else {
+ os.write(0);
+ }
+ viewer.options.disableShareDesktop();
+ */
+ os.write(0);
+ }
+
+
+ //
+ // Read the server initialisation message
+ //
+
+ String desktopName;
+ int framebufferWidth, framebufferHeight;
+ int bitsPerPixel, depth;
+ boolean bigEndian, trueColour;
+ int redMax, greenMax, blueMax, redShift, greenShift, blueShift;
+
+ void readServerInit() throws IOException {
+ framebufferWidth = is.readUnsignedShort();
+ framebufferHeight = is.readUnsignedShort();
+ bitsPerPixel = is.readUnsignedByte();
+ depth = is.readUnsignedByte();
+ bigEndian = (is.readUnsignedByte() != 0);
+ trueColour = (is.readUnsignedByte() != 0);
+ redMax = is.readUnsignedShort();
+ greenMax = is.readUnsignedShort();
+ blueMax = is.readUnsignedShort();
+ redShift = is.readUnsignedByte();
+ greenShift = is.readUnsignedByte();
+ blueShift = is.readUnsignedByte();
+ byte[] pad = new byte[3];
+ readFully(pad);
+ int nameLength = is.readInt();
+ byte[] name = new byte[nameLength];
+ readFully(name);
+ desktopName = new String(name);
+
+ // Read interaction capabilities (TightVNC protocol extensions)
+ if (protocolTightVNC) {
+ int nServerMessageTypes = is.readUnsignedShort();
+ int nClientMessageTypes = is.readUnsignedShort();
+ int nEncodingTypes = is.readUnsignedShort();
+ is.readUnsignedShort();
+ readCapabilityList(serverMsgCaps, nServerMessageTypes);
+ readCapabilityList(clientMsgCaps, nClientMessageTypes);
+ readCapabilityList(encodingCaps, nEncodingTypes);
+ }
+
+ inNormalProtocol = true;
+ }
+
+
+ //
+ // Create session file and write initial protocol messages into it.
+ //
+ /*-
+ void startSession(String fname) throws IOException {
+ rec = new SessionRecorder(fname);
+ rec.writeHeader();
+ rec.write(versionMsg_3_3.getBytes());
+ rec.writeIntBE(SecTypeNone);
+ rec.writeShortBE(framebufferWidth);
+ rec.writeShortBE(framebufferHeight);
+ byte[] fbsServerInitMsg = {
+ 32, 24, 0, 1, 0,
+ (byte)0xFF, 0, (byte)0xFF, 0, (byte)0xFF,
+ 16, 8, 0, 0, 0, 0
+ };
+ rec.write(fbsServerInitMsg);
+ rec.writeIntBE(desktopName.length());
+ rec.write(desktopName.getBytes());
+ numUpdatesInSession = 0;
+
+ // FIXME: If there were e.g. ZRLE updates only, that should not
+ // affect recording of Zlib and Tight updates. So, actually
+ // we should maintain separate flags for Zlib, ZRLE and
+ // Tight, instead of one ``wereZlibUpdates'' variable.
+ //
+ if (wereZlibUpdates)
+ recordFromBeginning = false;
+
+ zlibWarningShown = false;
+ tightWarningShown = false;
+ }
+
+ //
+ // Close session file.
+ //
+
+ void closeSession() throws IOException {
+ if (rec != null) {
+ rec.close();
+ rec = null;
+ }
+ }
+ */
+
+ //
+ // Set new framebuffer size
+ //
+
+ void setFramebufferSize(int width, int height) {
+ framebufferWidth = width;
+ framebufferHeight = height;
+ }
+
+
+ //
+ // Read the server message type
+ //
+
+ int readServerMessageType() throws IOException {
+ int msgType = is.readUnsignedByte();
+
+ // If the session is being recorded:
+ /*-
+ if (rec != null) {
+ if (msgType == Bell) { // Save Bell messages in session files.
+ rec.writeByte(msgType);
+ if (numUpdatesInSession > 0)
+ rec.flush();
+ }
+ }
+ */
+
+ return msgType;
+ }
+
+
+ //
+ // Read a FramebufferUpdate message
+ //
+
+ int updateNRects;
+
+ void readFramebufferUpdate() throws IOException {
+ is.readByte();
+ updateNRects = is.readUnsignedShort();
+
+ // If the session is being recorded:
+ /*-
+ if (rec != null) {
+ rec.writeByte(FramebufferUpdate);
+ rec.writeByte(0);
+ rec.writeShortBE(updateNRects);
+ }
+ */
+
+ numUpdatesInSession++;
+ }
+
+ // Read a FramebufferUpdate rectangle header
+
+ int updateRectX, updateRectY, updateRectW, updateRectH, updateRectEncoding;
+
+ void readFramebufferUpdateRectHdr() throws Exception {
+ updateRectX = is.readUnsignedShort();
+ updateRectY = is.readUnsignedShort();
+ updateRectW = is.readUnsignedShort();
+ updateRectH = is.readUnsignedShort();
+ updateRectEncoding = is.readInt();
+
+ if (updateRectEncoding == EncodingZlib ||
+ updateRectEncoding == EncodingZRLE ||
+ updateRectEncoding == EncodingTight)
+ wereZlibUpdates = true;
+
+ // If the session is being recorded:
+ /*-
+ if (rec != null) {
+ if (numUpdatesInSession > 1)
+ rec.flush(); // Flush the output on each rectangle.
+ rec.writeShortBE(updateRectX);
+ rec.writeShortBE(updateRectY);
+ rec.writeShortBE(updateRectW);
+ rec.writeShortBE(updateRectH);
+ if (updateRectEncoding == EncodingZlib && !recordFromBeginning) {
+ // Here we cannot write Zlib-encoded rectangles because the
+ // decoder won't be able to reproduce zlib stream state.
+ if (!zlibWarningShown) {
+ System.out.println("Warning: Raw encoding will be used " +
+ "instead of Zlib in recorded session.");
+ zlibWarningShown = true;
+ }
+ rec.writeIntBE(EncodingRaw);
+ } else {
+ rec.writeIntBE(updateRectEncoding);
+ if (updateRectEncoding == EncodingTight && !recordFromBeginning &&
+ !tightWarningShown) {
+ System.out.println("Warning: Re-compressing Tight-encoded " +
+ "updates for session recording.");
+ tightWarningShown = true;
+ }
+ }
+ }
+ */
+
+ if (updateRectEncoding < 0 || updateRectEncoding > MaxNormalEncoding)
+ return;
+
+ if (updateRectX + updateRectW > framebufferWidth ||
+ updateRectY + updateRectH > framebufferHeight) {
+ throw new Exception("Framebuffer update rectangle too large: " +
+ updateRectW + "x" + updateRectH + " at (" +
+ updateRectX + "," + updateRectY + ")");
+ }
+ }
+
+ // Read CopyRect source X and Y.
+
+ int copyRectSrcX, copyRectSrcY;
+
+ void readCopyRect() throws IOException {
+ copyRectSrcX = is.readUnsignedShort();
+ copyRectSrcY = is.readUnsignedShort();
+
+ // If the session is being recorded:
+ /*-
+ if (rec != null) {
+ rec.writeShortBE(copyRectSrcX);
+ rec.writeShortBE(copyRectSrcY);
+ }
+ */
+ }
+
+
+ //
+ // Read a ServerCutText message
+ //
+
+ String readServerCutText() throws IOException {
+ byte[] pad = new byte[3];
+ readFully(pad);
+ int len = is.readInt();
+ byte[] text = new byte[len];
+ readFully(text);
+ return new String(text);
+ }
+
+
+ //
+ // Read an integer in compact representation (1..3 bytes).
+ // Such format is used as a part of the Tight encoding.
+ // Also, this method records data if session recording is active and
+ // the viewer's recordFromBeginning variable is set to true.
+ //
+
+ int readCompactLen() throws IOException {
+ int[] portion = new int[3];
+ portion[0] = is.readUnsignedByte();
+ int byteCount = 1;
+ int len = portion[0] & 0x7F;
+ if ((portion[0] & 0x80) != 0) {
+ portion[1] = is.readUnsignedByte();
+ byteCount++;
+ len |= (portion[1] & 0x7F) << 7;
+ if ((portion[1] & 0x80) != 0) {
+ portion[2] = is.readUnsignedByte();
+ byteCount++;
+ len |= (portion[2] & 0xFF) << 14;
+ }
+ }
+ /*-
+ if (rec != null && recordFromBeginning)
+ for (int i = 0; i < byteCount; i++)
+ rec.writeByte(portion[i]);
+ */
+ return len;
+ }
+
+
+ //
+ // Write a FramebufferUpdateRequest message
+ //
+
+ void writeFramebufferUpdateRequest(int x, int y, int w, int h,
+ boolean incremental)
+ throws IOException
+ {
+ byte[] b = new byte[10];
+
+ b[0] = (byte) FramebufferUpdateRequest;
+ b[1] = (byte) (incremental ? 1 : 0);
+ b[2] = (byte) ((x >> 8) & 0xff);
+ b[3] = (byte) (x & 0xff);
+ b[4] = (byte) ((y >> 8) & 0xff);
+ b[5] = (byte) (y & 0xff);
+ b[6] = (byte) ((w >> 8) & 0xff);
+ b[7] = (byte) (w & 0xff);
+ b[8] = (byte) ((h >> 8) & 0xff);
+ b[9] = (byte) (h & 0xff);
+
+ os.write(b);
+ }
+
+
+ //
+ // Write a SetPixelFormat message
+ //
+
+ void writeSetPixelFormat(int bitsPerPixel, int depth, boolean bigEndian,
+ boolean trueColour,
+ int redMax, int greenMax, int blueMax,
+ int redShift, int greenShift, int blueShift)
+ throws IOException
+ {
+ byte[] b = new byte[20];
+
+ b[0] = (byte) SetPixelFormat;
+ b[4] = (byte) bitsPerPixel;
+ b[5] = (byte) depth;
+ b[6] = (byte) (bigEndian ? 1 : 0);
+ b[7] = (byte) (trueColour ? 1 : 0);
+ b[8] = (byte) ((redMax >> 8) & 0xff);
+ b[9] = (byte) (redMax & 0xff);
+ b[10] = (byte) ((greenMax >> 8) & 0xff);
+ b[11] = (byte) (greenMax & 0xff);
+ b[12] = (byte) ((blueMax >> 8) & 0xff);
+ b[13] = (byte) (blueMax & 0xff);
+ b[14] = (byte) redShift;
+ b[15] = (byte) greenShift;
+ b[16] = (byte) blueShift;
+
+ os.write(b);
+ }
+
+
+ //
+ // Write a FixColourMapEntries message. The values in the red, green and
+ // blue arrays are from 0 to 65535.
+ //
+
+ void writeFixColourMapEntries(int firstColour, int nColours,
+ int[] red, int[] green, int[] blue)
+ throws IOException
+ {
+ byte[] b = new byte[6 + nColours * 6];
+
+ b[0] = (byte) FixColourMapEntries;
+ b[2] = (byte) ((firstColour >> 8) & 0xff);
+ b[3] = (byte) (firstColour & 0xff);
+ b[4] = (byte) ((nColours >> 8) & 0xff);
+ b[5] = (byte) (nColours & 0xff);
+
+ for (int i = 0; i < nColours; i++) {
+ b[6 + i * 6] = (byte) ((red[i] >> 8) & 0xff);
+ b[6 + i * 6 + 1] = (byte) (red[i] & 0xff);
+ b[6 + i * 6 + 2] = (byte) ((green[i] >> 8) & 0xff);
+ b[6 + i * 6 + 3] = (byte) (green[i] & 0xff);
+ b[6 + i * 6 + 4] = (byte) ((blue[i] >> 8) & 0xff);
+ b[6 + i * 6 + 5] = (byte) (blue[i] & 0xff);
+ }
+
+ os.write(b);
+ }
+
+
+ //
+ // Write a SetEncodings message
+ //
+
+ void writeSetEncodings(int[] encs, int len) throws IOException {
+ byte[] b = new byte[4 + 4 * len];
+
+ b[0] = (byte) SetEncodings;
+ b[2] = (byte) ((len >> 8) & 0xff);
+ b[3] = (byte) (len & 0xff);
+
+ for (int i = 0; i < len; i++) {
+ b[4 + 4 * i] = (byte) ((encs[i] >> 24) & 0xff);
+ b[5 + 4 * i] = (byte) ((encs[i] >> 16) & 0xff);
+ b[6 + 4 * i] = (byte) ((encs[i] >> 8) & 0xff);
+ b[7 + 4 * i] = (byte) (encs[i] & 0xff);
+ }
+
+ os.write(b);
+ }
+
+
+ //
+ // Write a ClientCutText message
+ //
+
+ void writeClientCutText(String text) throws IOException {
+ byte[] b = new byte[8 + text.length()];
+
+ b[0] = (byte) ClientCutText;
+ b[4] = (byte) ((text.length() >> 24) & 0xff);
+ b[5] = (byte) ((text.length() >> 16) & 0xff);
+ b[6] = (byte) ((text.length() >> 8) & 0xff);
+ b[7] = (byte) (text.length() & 0xff);
+
+ System.arraycopy(text.getBytes(), 0, b, 8, text.length());
+
+ os.write(b);
+ }
+
+
+ //
+ // A buffer for putting pointer and keyboard events before being sent. This
+ // is to ensure that multiple RFB events generated from a single Java Event
+ // will all be sent in a single network packet. The maximum possible
+ // length is 4 modifier down events, a single key event followed by 4
+ // modifier up events i.e. 9 key events or 72 bytes.
+ //
+
+ byte[] eventBuf = new byte[72];
+ int eventBufLen;
+
+
+ // Useful shortcuts for modifier masks.
+
+ //- final static int CTRL_MASK = InputEvent.CTRL_MASK;
+ //- final static int SHIFT_MASK = InputEvent.SHIFT_MASK;
+ //- final static int META_MASK = InputEvent.META_MASK;
+ //- final static int ALT_MASK = InputEvent.ALT_MASK;
+
+
+ //
+ // Write a pointer event message. We may need to send modifier key events
+ // around it to set the correct modifier state.
+ //
+ /*-
+ int pointerMask = 0;
+
+ void writePointerEvent(MouseEvent evt) throws IOException {
+ int modifiers = evt.getModifiers();
+
+ int mask2 = 2;
+ int mask3 = 4;
+ if (viewer.options.reverseMouseButtons2And3) {
+ mask2 = 4;
+ mask3 = 2;
+ }
+
+ // Note: For some reason, AWT does not set BUTTON1_MASK on left
+ // button presses. Here we think that it was the left button if
+ // modifiers do not include BUTTON2_MASK or BUTTON3_MASK.
+
+ if (evt.getID() == MouseEvent.MOUSE_PRESSED) {
+ if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
+ pointerMask = mask2;
+ modifiers &= ~ALT_MASK;
+ } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
+ pointerMask = mask3;
+ modifiers &= ~META_MASK;
+ } else {
+ pointerMask = 1;
+ }
+ } else if (evt.getID() == MouseEvent.MOUSE_RELEASED) {
+ pointerMask = 0;
+ if ((modifiers & InputEvent.BUTTON2_MASK) != 0) {
+ modifiers &= ~ALT_MASK;
+ } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) {
+ modifiers &= ~META_MASK;
+ }
+ }
+
+ eventBufLen = 0;
+ writeModifierKeyEvents(modifiers);
+
+ int x = evt.getX();
+ int y = evt.getY();
+
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+
+ eventBuf[eventBufLen++] = (byte) PointerEvent;
+ eventBuf[eventBufLen++] = (byte) pointerMask;
+ eventBuf[eventBufLen++] = (byte) ((x >> 8) & 0xff);
+ eventBuf[eventBufLen++] = (byte) (x & 0xff);
+ eventBuf[eventBufLen++] = (byte) ((y >> 8) & 0xff);
+ eventBuf[eventBufLen++] = (byte) (y & 0xff);
+
+ //
+ // Always release all modifiers after an "up" event
+ //
+
+ if (pointerMask == 0) {
+ writeModifierKeyEvents(0);
+ }
+
+ os.write(eventBuf, 0, eventBufLen);
+ }
+ */
+
+ //
+ // Write a key event message. We may need to send modifier key events
+ // around it to set the correct modifier state. Also we need to translate
+ // from the Java key values to the X keysym values used by the RFB protocol.
+ //
+ /*-
+ void writeKeyEvent(KeyEvent evt) throws IOException {
+
+ int keyChar = evt.getKeyChar();
+
+ //
+ // Ignore event if only modifiers were pressed.
+ //
+
+ // Some JVMs return 0 instead of CHAR_UNDEFINED in getKeyChar().
+ if (keyChar == 0)
+ keyChar = KeyEvent.CHAR_UNDEFINED;
+
+ if (keyChar == KeyEvent.CHAR_UNDEFINED) {
+ int code = evt.getKeyCode();
+ if (code == KeyEvent.VK_CONTROL || code == KeyEvent.VK_SHIFT ||
+ code == KeyEvent.VK_META || code == KeyEvent.VK_ALT)
+ return;
+ }
+
+ //
+ // Key press or key release?
+ //
+
+ boolean down = (evt.getID() == KeyEvent.KEY_PRESSED);
+
+ int key;
+ if (evt.isActionKey()) {
+
+ //
+ // An action key should be one of the following.
+ // If not then just ignore the event.
+ //
+
+ switch(evt.getKeyCode()) {
+ case KeyEvent.VK_HOME: key = 0xff50; break;
+ case KeyEvent.VK_LEFT: key = 0xff51; break;
+ case KeyEvent.VK_UP: key = 0xff52; break;
+ case KeyEvent.VK_RIGHT: key = 0xff53; break;
+ case KeyEvent.VK_DOWN: key = 0xff54; break;
+ case KeyEvent.VK_PAGE_UP: key = 0xff55; break;
+ case KeyEvent.VK_PAGE_DOWN: key = 0xff56; break;
+ case KeyEvent.VK_END: key = 0xff57; break;
+ case KeyEvent.VK_INSERT: key = 0xff63; break;
+ case KeyEvent.VK_F1: key = 0xffbe; break;
+ case KeyEvent.VK_F2: key = 0xffbf; break;
+ case KeyEvent.VK_F3: key = 0xffc0; break;
+ case KeyEvent.VK_F4: key = 0xffc1; break;
+ case KeyEvent.VK_F5: key = 0xffc2; break;
+ case KeyEvent.VK_F6: key = 0xffc3; break;
+ case KeyEvent.VK_F7: key = 0xffc4; break;
+ case KeyEvent.VK_F8: key = 0xffc5; break;
+ case KeyEvent.VK_F9: key = 0xffc6; break;
+ case KeyEvent.VK_F10: key = 0xffc7; break;
+ case KeyEvent.VK_F11: key = 0xffc8; break;
+ case KeyEvent.VK_F12: key = 0xffc9; break;
+ default:
+ return;
+ }
+
+ } else {
+
+ //
+ // A "normal" key press. Ordinary ASCII characters go straight through.
+ // For CTRL-
+// Fetch the entire Acme package.
+//