summaryrefslogtreecommitdiffstats
path: root/java/com/tigervnc
diff options
context:
space:
mode:
authorDRC <dcommander@users.sourceforge.net>2011-10-07 05:38:00 +0000
committerDRC <dcommander@users.sourceforge.net>2011-10-07 05:38:00 +0000
commitc19ab9ec7f3ac4823802388ac953e9494c613575 (patch)
tree63513ffd7ce0b3ab3de2d9b619cc4e5b892eea31 /java/com/tigervnc
parentbba54b0b14fded1d457f426cdc8843a34d6c9dc5 (diff)
downloadtigervnc-c19ab9ec7f3ac4823802388ac953e9494c613575.tar.gz
tigervnc-c19ab9ec7f3ac4823802388ac953e9494c613575.zip
Move Java source up one level and allow Java viewer to be built as a standalone project (per community request)
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4715 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'java/com/tigervnc')
-rw-r--r--java/com/tigervnc/rdr/EndOfStream.java25
-rw-r--r--java/com/tigervnc/rdr/Exception.java25
-rw-r--r--java/com/tigervnc/rdr/IOException.java27
-rw-r--r--java/com/tigervnc/rdr/InStream.java192
-rw-r--r--java/com/tigervnc/rdr/JavaInStream.java148
-rw-r--r--java/com/tigervnc/rdr/JavaOutStream.java77
-rw-r--r--java/com/tigervnc/rdr/MemInStream.java34
-rw-r--r--java/com/tigervnc/rdr/MemOutStream.java53
-rw-r--r--java/com/tigervnc/rdr/OutStream.java160
-rw-r--r--java/com/tigervnc/rdr/ZlibInStream.java138
-rw-r--r--java/com/tigervnc/rfb/AliasParameter.java35
-rw-r--r--java/com/tigervnc/rfb/AuthFailureException.java23
-rw-r--r--java/com/tigervnc/rfb/BoolParameter.java51
-rw-r--r--java/com/tigervnc/rfb/CConnection.java356
-rw-r--r--java/com/tigervnc/rfb/CMsgHandler.java88
-rw-r--r--java/com/tigervnc/rfb/CMsgReader.java179
-rw-r--r--java/com/tigervnc/rfb/CMsgReaderV3.java155
-rw-r--r--java/com/tigervnc/rfb/CMsgWriter.java171
-rw-r--r--java/com/tigervnc/rfb/CMsgWriterV3.java68
-rw-r--r--java/com/tigervnc/rfb/CSecurity.java46
-rw-r--r--java/com/tigervnc/rfb/CSecurityIdent.java58
-rw-r--r--java/com/tigervnc/rfb/CSecurityManaged.java76
-rw-r--r--java/com/tigervnc/rfb/CSecurityNone.java27
-rw-r--r--java/com/tigervnc/rfb/CSecurityPlain.java57
-rw-r--r--java/com/tigervnc/rfb/CSecurityStack.java69
-rw-r--r--java/com/tigervnc/rfb/CSecurityTLS.java251
-rw-r--r--java/com/tigervnc/rfb/CSecurityVeNCrypt.java199
-rw-r--r--java/com/tigervnc/rfb/CSecurityVncAuth.java66
-rw-r--r--java/com/tigervnc/rfb/Configuration.java91
-rw-r--r--java/com/tigervnc/rfb/ConnFailedException.java23
-rw-r--r--java/com/tigervnc/rfb/ConnParams.java171
-rw-r--r--java/com/tigervnc/rfb/Cursor.java34
-rw-r--r--java/com/tigervnc/rfb/Decoder.java51
-rw-r--r--java/com/tigervnc/rfb/DesCipher.java496
-rw-r--r--java/com/tigervnc/rfb/Encoder.java25
-rw-r--r--java/com/tigervnc/rfb/Encodings.java70
-rw-r--r--java/com/tigervnc/rfb/Exception.java23
-rw-r--r--java/com/tigervnc/rfb/Hextile.java27
-rw-r--r--java/com/tigervnc/rfb/HextileDecoder.java101
-rw-r--r--java/com/tigervnc/rfb/Hostname.java41
-rw-r--r--java/com/tigervnc/rfb/IntParameter.java44
-rw-r--r--java/com/tigervnc/rfb/Keysyms.java88
-rw-r--r--java/com/tigervnc/rfb/LogWriter.java99
-rw-r--r--java/com/tigervnc/rfb/ManagedPixelBuffer.java38
-rw-r--r--java/com/tigervnc/rfb/MsgTypes.java40
-rw-r--r--java/com/tigervnc/rfb/PixelBuffer.java116
-rw-r--r--java/com/tigervnc/rfb/PixelFormat.java163
-rw-r--r--java/com/tigervnc/rfb/Point.java40
-rw-r--r--java/com/tigervnc/rfb/RREDecoder.java46
-rw-r--r--java/com/tigervnc/rfb/RawDecoder.java45
-rw-r--r--java/com/tigervnc/rfb/Rect.java89
-rw-r--r--java/com/tigervnc/rfb/Screen.java48
-rw-r--r--java/com/tigervnc/rfb/ScreenSet.java89
-rw-r--r--java/com/tigervnc/rfb/Security.java195
-rw-r--r--java/com/tigervnc/rfb/SecurityClient.java85
-rw-r--r--java/com/tigervnc/rfb/StringParameter.java46
-rw-r--r--java/com/tigervnc/rfb/TightDecoder.java426
-rw-r--r--java/com/tigervnc/rfb/UnicodeToKeysym.java795
-rw-r--r--java/com/tigervnc/rfb/UserMsgBox.java27
-rw-r--r--java/com/tigervnc/rfb/UserPasswdGetter.java27
-rw-r--r--java/com/tigervnc/rfb/VncAuth.java67
-rw-r--r--java/com/tigervnc/rfb/VoidParameter.java41
-rw-r--r--java/com/tigervnc/rfb/ZRLEDecoder.java166
-rw-r--r--java/com/tigervnc/rfb/screenTypes.java36
-rw-r--r--java/com/tigervnc/vncviewer/CConn.java1309
-rw-r--r--java/com/tigervnc/vncviewer/ClipboardDialog.java107
-rw-r--r--java/com/tigervnc/vncviewer/DesktopWindow.java553
-rw-r--r--java/com/tigervnc/vncviewer/Dialog.java143
-rw-r--r--java/com/tigervnc/vncviewer/F8Menu.java133
-rw-r--r--java/com/tigervnc/vncviewer/LICENCE.TXT340
-rw-r--r--java/com/tigervnc/vncviewer/MANIFEST.MF2
-rw-r--r--java/com/tigervnc/vncviewer/OptionsDialog.java413
-rw-r--r--java/com/tigervnc/vncviewer/OptionsDialogCallback.java24
-rw-r--r--java/com/tigervnc/vncviewer/PasswdDialog.java88
-rw-r--r--java/com/tigervnc/vncviewer/PixelBufferImage.java185
-rw-r--r--java/com/tigervnc/vncviewer/README174
-rw-r--r--java/com/tigervnc/vncviewer/ServerDialog.java179
-rw-r--r--java/com/tigervnc/vncviewer/UserPrefs.java286
-rw-r--r--java/com/tigervnc/vncviewer/VncViewer.java314
-rw-r--r--java/com/tigervnc/vncviewer/index.html20
-rw-r--r--java/com/tigervnc/vncviewer/index.vnc20
-rw-r--r--java/com/tigervnc/vncviewer/tigervnc.icobin0 -> 798 bytes
-rw-r--r--java/com/tigervnc/vncviewer/tigervnc.pngbin0 -> 3041 bytes
-rw-r--r--java/com/tigervnc/vncviewer/timestamp.in6
84 files changed, 11159 insertions, 0 deletions
diff --git a/java/com/tigervnc/rdr/EndOfStream.java b/java/com/tigervnc/rdr/EndOfStream.java
new file mode 100644
index 00000000..bdcf7c27
--- /dev/null
+++ b/java/com/tigervnc/rdr/EndOfStream.java
@@ -0,0 +1,25 @@
+/* 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 com.tigervnc.rdr;
+
+public class EndOfStream extends Exception {
+ public EndOfStream() {
+ super("EndOfStream");
+ }
+}
diff --git a/java/com/tigervnc/rdr/Exception.java b/java/com/tigervnc/rdr/Exception.java
new file mode 100644
index 00000000..a5fe938d
--- /dev/null
+++ b/java/com/tigervnc/rdr/Exception.java
@@ -0,0 +1,25 @@
+/* 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 com.tigervnc.rdr;
+
+public class Exception extends RuntimeException {
+ public Exception(String s) {
+ super(s);
+ }
+}
diff --git a/java/com/tigervnc/rdr/IOException.java b/java/com/tigervnc/rdr/IOException.java
new file mode 100644
index 00000000..6343d7a4
--- /dev/null
+++ b/java/com/tigervnc/rdr/IOException.java
@@ -0,0 +1,27 @@
+/* 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 com.tigervnc.rdr;
+
+class IOException extends Exception {
+ public IOException(java.io.IOException ex_) {
+ super(ex_.toString());
+ ex = ex_;
+ }
+ java.io.IOException ex;
+}
diff --git a/java/com/tigervnc/rdr/InStream.java b/java/com/tigervnc/rdr/InStream.java
new file mode 100644
index 00000000..1e0d226e
--- /dev/null
+++ b/java/com/tigervnc/rdr/InStream.java
@@ -0,0 +1,192 @@
+/* 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 com.tigervnc.rdr;
+
+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 int check(int itemSize, int nItems, boolean wait) {
+ if (ptr + itemSize * nItems > end) {
+ if (ptr + itemSize > end)
+ return overrun(itemSize, nItems, wait);
+
+ nItems = (end - ptr) / itemSize;
+ }
+ return nItems;
+ }
+
+ public int check(int itemSize, int nItems) { return check(itemSize, nItems, true); }
+ public int check(int itemSize) { return check(itemSize, 1); }
+
+ // checkNoWait() tries to make sure that the given number of bytes can
+ // be read without blocking. It returns true if this is the case, false
+ // otherwise. The length must be "small" (less than the buffer size).
+
+ public final boolean checkNoWait(int length) { return check(length, 1, false)!=0; }
+
+ // readU/SN() methods read unsigned and signed N-bit integers.
+
+ public final int readS8() { check(1); return b[ptr++]; }
+ public final int readS16() { check(2); int b0 = b[ptr++];
+ int b1 = b[ptr++] & 0xff; return b0 << 8 | b1; }
+ public final int readS32() { 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() { return readS8() & 0xff; }
+ public final int readU16() { return readS16() & 0xffff; }
+ public final int readU32() { return readS32() & 0xffffffff; }
+
+ // readString() reads a string - a U32 length followed by the data.
+
+ public final String readString() {
+ int len = readU32();
+ if (len > maxStringLength)
+ throw new Exception("InStream max string length exceeded");
+
+ byte[] str = new byte[len];
+ readBytes(str, 0, len);
+ String utf8string = new String();
+ try {
+ utf8string = new String(str,"UTF8");
+ } catch(java.io.UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ return utf8string;
+ }
+
+ // 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) {
+ 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 dataPtr, int length) {
+ int dataEnd = dataPtr + length;
+ while (dataPtr < dataEnd) {
+ int n = check(1, dataEnd - dataPtr);
+ System.arraycopy(b, ptr, data, dataPtr, n);
+ ptr += n;
+ dataPtr += n;
+ }
+ }
+
+ public void readBytes(int[] data, int dataPtr, int length) {
+ int dataEnd = dataPtr + length;
+ while (dataPtr < dataEnd) {
+ int n = check(1, dataEnd - dataPtr);
+ System.arraycopy(b, ptr, data, dataPtr, n);
+ ptr += n;
+ dataPtr += n;
+ }
+ }
+
+ // readOpaqueN() reads a quantity "without byte-swapping". Because java has
+ // no byte-ordering, we just use big-endian.
+
+ public final int readOpaque8() { return readU8(); }
+ public final int readOpaque16() { return readU16(); }
+ public final int readOpaque32() { return readU32(); }
+ public final int readOpaque24A() { 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() { check(3); int b0 = b[ptr++];
+ int b1 = b[ptr++]; int b2 = b[ptr++];
+ return b0 << 16 | b1 << 8 | b2; }
+
+ public final int readPixel(int bytesPerPixel, boolean e) {
+ int[] pix = new int[4];
+ for (int i=0; i < bytesPerPixel; i++)
+ pix[i] = readU8();
+ if (e) {
+ return pix[0] << 16 | pix[1] << 8 | pix[2] | (0xff << 24);
+ } else {
+ return pix[2] << 16 | pix[1] << 8 | pix[0] | (0xff << 24);
+ }
+ }
+
+ public final void readPixels(int[] buf, int length, int bytesPerPixel, boolean e) {
+ for (int i = 0; i < length; i++)
+ buf[i] = readPixel(bytesPerPixel, e);
+ }
+
+ public final int readCompactLength() {
+ int b = readU8();
+ int result = b & 0x7F;
+ if ((b & 0x80) != 0) {
+ b = readU8();
+ result |= (b & 0x7F) << 7;
+ if ((b & 0x80) != 0) {
+ b = readU8();
+ result |= (b & 0xFF) << 14;
+ }
+ }
+ return result;
+ }
+
+ // 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, boolean wait);
+
+ protected InStream() {}
+ protected byte[] b;
+ protected int ptr;
+ protected int end;
+}
diff --git a/java/com/tigervnc/rdr/JavaInStream.java b/java/com/tigervnc/rdr/JavaInStream.java
new file mode 100644
index 00000000..ce8efddc
--- /dev/null
+++ b/java/com/tigervnc/rdr/JavaInStream.java
@@ -0,0 +1,148 @@
+/* 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.
+ */
+
+//
+// A JavaInStream reads from a java.io.InputStream
+//
+
+package com.tigervnc.rdr;
+
+public class JavaInStream extends InStream {
+
+ static final int defaultBufSize = 8192;
+ static final int minBulkSize = 1024;
+
+ public JavaInStream(java.io.InputStream jis_, int bufSize_) {
+ jis = jis_;
+ bufSize = bufSize_;
+ b = new byte[bufSize];
+ ptr = end = offset = 0;
+ timeWaitedIn100us = 5;
+ timedKbits = 0;
+ }
+
+ public JavaInStream(java.io.InputStream jis_) { this(jis_, defaultBufSize); }
+
+ public void readBytes(byte[] data, int dataPtr, int length) {
+ if (length < minBulkSize) {
+ super.readBytes(data, dataPtr, length);
+ return;
+ }
+
+ int n = end - ptr;
+ if (n > length) n = length;
+
+ System.arraycopy(b, ptr, data, dataPtr, n);
+ dataPtr += n;
+ length -= n;
+ ptr += n;
+
+ while (length > 0) {
+ n = read(data, dataPtr, length);
+ dataPtr += n;
+ length -= n;
+ offset += n;
+ }
+ }
+
+ public int pos() { return offset + ptr; }
+
+ public void startTiming() {
+ timing = true;
+
+ // Carry over up to 1s worth of previous rate for smoothing.
+
+ if (timeWaitedIn100us > 10000) {
+ timedKbits = timedKbits * 10000 / timeWaitedIn100us;
+ timeWaitedIn100us = 10000;
+ }
+ }
+
+ public void stopTiming() {
+ timing = false;
+ if (timeWaitedIn100us < timedKbits/2)
+ timeWaitedIn100us = timedKbits/2; // upper limit 20Mbit/s
+ }
+
+ public long kbitsPerSecond() {
+ return timedKbits * 10000 / timeWaitedIn100us;
+ }
+
+ public long timeWaited() { return timeWaitedIn100us; }
+
+ protected int overrun(int itemSize, int nItems, boolean wait) {
+ if (itemSize > bufSize)
+ throw new Exception("JavaInStream overrun: max itemSize exceeded");
+
+ if (end - ptr != 0)
+ System.arraycopy(b, ptr, b, 0, end - ptr);
+
+ offset += ptr;
+ end -= ptr;
+ ptr = 0;
+
+ while (end < itemSize) {
+ int n = read(b, end, bufSize - end, wait);
+ end += n;
+ }
+
+ if (itemSize * nItems > end)
+ nItems = end / itemSize;
+
+ return nItems;
+ }
+
+ private int read(byte[] buf, int bufPtr, int len, boolean wait) {
+ try {
+ long before = 0;
+ if (timing)
+ before = System.currentTimeMillis();
+
+ int n = jis.read(buf, bufPtr, len);
+ if (n < 0) throw new EndOfStream();
+
+ if (timing) {
+ long after = System.currentTimeMillis();
+ long newTimeWaited = (after - before) * 10;
+ int newKbits = n * 8 / 1000;
+
+ // limit rate to between 10kbit/s and 40Mbit/s
+
+ if (newTimeWaited > newKbits*1000) newTimeWaited = newKbits*1000;
+ if (newTimeWaited < newKbits/4) newTimeWaited = newKbits/4;
+
+ timeWaitedIn100us += newTimeWaited;
+ timedKbits += newKbits;
+ }
+
+ return n;
+
+ } catch (java.io.IOException e) {
+ throw new IOException(e);
+ }
+ }
+ private int read(byte[] buf, int bufPtr, int len) { return read(buf, bufPtr, len, true); }
+
+ private java.io.InputStream jis;
+ private int offset;
+ private int bufSize;
+
+ boolean timing;
+ long timeWaitedIn100us;
+ long timedKbits;
+}
diff --git a/java/com/tigervnc/rdr/JavaOutStream.java b/java/com/tigervnc/rdr/JavaOutStream.java
new file mode 100644
index 00000000..015f81f5
--- /dev/null
+++ b/java/com/tigervnc/rdr/JavaOutStream.java
@@ -0,0 +1,77 @@
+/* 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.
+ */
+
+//
+// A JavaOutStream writes to a java.io.OutputStream
+//
+
+package com.tigervnc.rdr;
+
+public class JavaOutStream extends OutStream {
+
+ static final int defaultBufSize = 16384;
+ static final int minBulkSize = 1024;
+
+ public JavaOutStream(java.io.OutputStream jos_, int bufSize_) {
+ jos = jos_;
+ bufSize = bufSize_;
+ b = new byte[bufSize];
+ ptr = offset = start = 0;
+ end = start + bufSize;
+ }
+
+ public JavaOutStream(java.io.OutputStream jos) { this(jos, defaultBufSize); }
+
+ public int length()
+ {
+ return offset + ptr - start;
+ }
+
+ public void flush()
+ {
+ int sentUpTo = start;
+ while (sentUpTo < ptr) {
+ try {
+ jos.write(b, sentUpTo, ptr - sentUpTo);
+ sentUpTo += ptr - sentUpTo;
+ offset += ptr - sentUpTo;
+ } catch (java.io.IOException e) {
+ throw new IOException(e);
+ }
+ }
+ ptr = start;
+ }
+
+ protected int overrun(int itemSize, int nItems)
+ {
+ if (itemSize > bufSize)
+ throw new Exception("JavaOutStream overrun: max itemSize exceeded");
+
+ flush();
+
+ if (itemSize * nItems > end - ptr)
+ nItems = (end - ptr) / itemSize;
+
+ return nItems;
+ }
+
+ private java.io.OutputStream jos;
+ private int start;
+ private int offset;
+ private int bufSize;
+}
diff --git a/java/com/tigervnc/rdr/MemInStream.java b/java/com/tigervnc/rdr/MemInStream.java
new file mode 100644
index 00000000..32911a3a
--- /dev/null
+++ b/java/com/tigervnc/rdr/MemInStream.java
@@ -0,0 +1,34 @@
+/* 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 com.tigervnc.rdr;
+
+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, boolean wait) {
+ throw new EndOfStream();
+ }
+}
diff --git a/java/com/tigervnc/rdr/MemOutStream.java b/java/com/tigervnc/rdr/MemOutStream.java
new file mode 100644
index 00000000..b3040793
--- /dev/null
+++ b/java/com/tigervnc/rdr/MemOutStream.java
@@ -0,0 +1,53 @@
+/* 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.
+ */
+
+//
+// A MemOutStream grows as needed when data is written to it.
+//
+
+package com.tigervnc.rdr;
+
+public class MemOutStream extends OutStream {
+
+ public MemOutStream(int len) {
+ b = new byte[len];
+ ptr = 0;
+ end = len;
+ }
+ public MemOutStream() { this(1024); }
+
+ public int length() { return ptr; }
+ public void clear() { ptr = 0; };
+ public void reposition(int pos) { ptr = pos; }
+
+ // overrun() either doubles the buffer or adds enough space for nItems of
+ // size itemSize bytes.
+
+ protected int overrun(int itemSize, int nItems) {
+ int len = ptr + itemSize * nItems;
+ if (len < end * 2)
+ len = end * 2;
+
+ byte[] newBuf = new byte[len];
+ System.arraycopy(b, 0, newBuf, 0, ptr);
+ b = newBuf;
+ end = len;
+
+ return nItems;
+ }
+}
diff --git a/java/com/tigervnc/rdr/OutStream.java b/java/com/tigervnc/rdr/OutStream.java
new file mode 100644
index 00000000..0919453e
--- /dev/null
+++ b/java/com/tigervnc/rdr/OutStream.java
@@ -0,0 +1,160 @@
+/* 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::OutStream marshalls data into a buffer stored in RDR (RFB Data
+// Representation).
+//
+
+package com.tigervnc.rdr;
+
+abstract public class OutStream {
+
+ // check() ensures there is buffer space for at least one item of size
+ // itemSize bytes. Returns the number of items which fit (up to a maximum
+ // of nItems).
+
+ public final int check(int itemSize, int nItems) {
+ 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) {
+ if (ptr + itemSize > end)
+ overrun(itemSize, 1);
+ }
+
+ // writeU/SN() methods write unsigned and signed N-bit integers.
+
+ public final void writeU8( int u) { check(1); b[ptr++] = (byte)u; }
+ public final void writeU16(int u) { check(2); b[ptr++] = (byte)(u >> 8);
+ b[ptr++] = (byte)u; }
+ public final void writeU32(int u) { check(4); b[ptr++] = (byte)(u >> 24);
+ b[ptr++] = (byte)(u >> 16);
+ b[ptr++] = (byte)(u >> 8);
+ b[ptr++] = (byte)u; }
+
+ public final void writeS8( int s) { writeU8( s); }
+ public final void writeS16(int s) { writeU16(s); }
+ public final void writeS32(int s) { writeU32(s); }
+
+ // writeCompactLength() writes 1..3 bytes representing length of the data
+ // following. This method is used by the Tight encoder.
+
+ public final void writeCompactLength(int len) {
+ byte b = (byte)(len & 0x7F);
+ if (len <= 0x7F) {
+ writeU8(b);
+ } else {
+ writeU8(b | 0x80);
+ b = (byte)(len >> 7 & 0x7F);
+ if (len <= 0x3FFF) {
+ writeU8(b);
+ } else {
+ writeU8(b | 0x80);
+ writeU8(len >> 14 & 0xFF);
+ }
+ }
+ }
+
+ // writeString() writes a string - a U32 length followed by the data.
+
+ public final void writeString(String str) {
+ int len = str.length();
+ writeU32(len);
+ try {
+ byte[] utf8str = str.getBytes("UTF8");
+ writeBytes(utf8str, 0, len);
+ } catch(java.io.UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public final void pad(int bytes) {
+ while (bytes-- > 0) writeU8(0);
+ }
+
+ public final void skip(int bytes) {
+ while (bytes > 0) {
+ int n = check(1, bytes);
+ ptr += n;
+ bytes -= n;
+ }
+ }
+
+ // writeBytes() writes an exact number of bytes from an array at an offset.
+
+ public void writeBytes(byte[] data, int dataPtr, int length) {
+ int dataEnd = dataPtr + length;
+ while (dataPtr < dataEnd) {
+ int n = check(1, dataEnd - dataPtr);
+ System.arraycopy(data, dataPtr, b, ptr, n);
+ ptr += n;
+ dataPtr += n;
+ }
+ }
+
+ // writeOpaqueN() writes a quantity without byte-swapping. Because java has
+ // no byte-ordering, we just use big-endian.
+
+ public final void writeOpaque8( int u) { writeU8( u); }
+ public final void writeOpaque16(int u) { writeU16(u); }
+ public final void writeOpaque32(int u) { writeU32(u); }
+ public final void writeOpaque24A(int u) { check(3);
+ b[ptr++] = (byte)(u >> 24);
+ b[ptr++] = (byte)(u >> 16);
+ b[ptr++] = (byte)(u >> 8); }
+ public final void writeOpaque24B(int u) { check(3);
+ b[ptr++] = (byte)(u >> 16);
+ b[ptr++] = (byte)(u >> 8);
+ b[ptr++] = (byte)u; }
+
+ // length() returns the length of the stream.
+
+ abstract public int length();
+
+ // flush() requests that the stream be flushed.
+
+ public void flush() {}
+
+ // 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 space. Returns
+ // the number of items which fit (up to a maximum of nItems). itemSize is
+ // supposed to be "small" (a few bytes).
+
+ abstract protected int overrun(int itemSize, int nItems);
+
+ protected OutStream() {}
+ protected byte[] b;
+ protected int ptr;
+ protected int end;
+}
diff --git a/java/com/tigervnc/rdr/ZlibInStream.java b/java/com/tigervnc/rdr/ZlibInStream.java
new file mode 100644
index 00000000..62c45bd8
--- /dev/null
+++ b/java/com/tigervnc/rdr/ZlibInStream.java
@@ -0,0 +1,138 @@
+/* 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.
+ */
+
+//
+// A ZlibInStream reads from a zlib.io.InputStream
+//
+
+package com.tigervnc.rdr;
+import com.jcraft.jzlib.*;
+
+public class ZlibInStream extends InStream {
+
+ static final int defaultBufSize = 16384;
+
+ public ZlibInStream(int bufSize_)
+ {
+ bufSize = bufSize_;
+ b = new byte[bufSize];
+ bytesIn = offset = 0;
+ zs = new ZStream();
+ zs.next_in = null;
+ zs.next_in_index = 0;
+ zs.avail_in = 0;
+ if (zs.inflateInit() != JZlib.Z_OK) {
+ zs = null;
+ throw new Exception("ZlinInStream: inflateInit failed");
+ }
+ ptr = end = start = 0;
+ }
+
+ public ZlibInStream() { this(defaultBufSize); }
+
+ protected void finalize() throws Throwable {
+ b = null;
+ zs.inflateEnd();
+ }
+
+ public void setUnderlying(InStream is, int bytesIn_)
+ {
+ underlying = is;
+ bytesIn = bytesIn_;
+ ptr = end = start;
+ }
+
+ public int pos()
+ {
+ return offset + ptr - start;
+ }
+
+ public void reset()
+ {
+ ptr = end = start;
+ if (underlying == null) return;
+
+ while (bytesIn > 0) {
+ decompress(true);
+ end = start; // throw away any data
+ }
+ underlying = null;
+ }
+
+ protected int overrun(int itemSize, int nItems, boolean wait)
+ {
+ if (itemSize > bufSize)
+ throw new Exception("ZlibInStream overrun: max itemSize exceeded");
+ if (underlying == null)
+ throw new Exception("ZlibInStream overrun: no underlying stream");
+
+ if (end - ptr != 0)
+ System.arraycopy(b, ptr, b, start, end - ptr);
+
+ offset += ptr - start;
+ end -= ptr - start;
+ ptr = start;
+
+ while (end - ptr < itemSize) {
+ if (!decompress(wait))
+ return 0;
+ }
+
+ if (itemSize * nItems > end - ptr)
+ nItems = (end - ptr) / itemSize;
+
+ return nItems;
+ }
+
+ // decompress() calls the decompressor once. Note that this won't
+ // necessarily generate any output data - it may just consume some input
+ // data. Returns false if wait is false and we would block on the underlying
+ // stream.
+
+ private boolean decompress(boolean wait)
+ {
+ zs.next_out = b;
+ zs.next_out_index = end;
+ zs.avail_out = start + bufSize - end;
+
+ int n = underlying.check(1, 1, wait);
+ if (n == 0) return false;
+ zs.next_in = underlying.getbuf();
+ zs.next_in_index = underlying.getptr();
+ zs.avail_in = underlying.getend() - underlying.getptr();
+ if (zs.avail_in > bytesIn)
+ zs.avail_in = bytesIn;
+
+ int rc = zs.inflate(JZlib.Z_SYNC_FLUSH);
+ if (rc != JZlib.Z_OK) {
+ throw new Exception("ZlibInStream: inflate failed");
+ }
+
+ bytesIn -= zs.next_in_index - underlying.getptr();
+ end = zs.next_out_index;
+ underlying.setptr(zs.next_in_index);
+ return true;
+ }
+
+ private InStream underlying;
+ private int bufSize;
+ private int offset;
+ private com.jcraft.jzlib.ZStream zs;
+ private int bytesIn;
+ private int start;
+}
diff --git a/java/com/tigervnc/rfb/AliasParameter.java b/java/com/tigervnc/rfb/AliasParameter.java
new file mode 100644
index 00000000..2570b877
--- /dev/null
+++ b/java/com/tigervnc/rfb/AliasParameter.java
@@ -0,0 +1,35 @@
+/* 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 com.tigervnc.rfb;
+
+public class AliasParameter extends VoidParameter {
+ public AliasParameter(String name_, String desc_, VoidParameter v) {
+ super(name_, desc_);
+ param = v;
+ }
+
+ public boolean setParam(String v) { return param.setParam(v); }
+ public boolean setParam() { return param.setParam(); }
+
+ public String getDefaultStr() { return param.getDefaultStr(); }
+ public String getValueStr() { return param.getValueStr(); }
+ public boolean isBool() { return param.isBool(); }
+
+ protected VoidParameter param;
+}
diff --git a/java/com/tigervnc/rfb/AuthFailureException.java b/java/com/tigervnc/rfb/AuthFailureException.java
new file mode 100644
index 00000000..35fabef0
--- /dev/null
+++ b/java/com/tigervnc/rfb/AuthFailureException.java
@@ -0,0 +1,23 @@
+/* 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 com.tigervnc.rfb;
+
+public class AuthFailureException extends Exception {
+ public AuthFailureException(String s) { super(s); }
+}
diff --git a/java/com/tigervnc/rfb/BoolParameter.java b/java/com/tigervnc/rfb/BoolParameter.java
new file mode 100644
index 00000000..06c6ed79
--- /dev/null
+++ b/java/com/tigervnc/rfb/BoolParameter.java
@@ -0,0 +1,51 @@
+/* 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 com.tigervnc.rfb;
+
+public class BoolParameter extends VoidParameter {
+ public BoolParameter(String name_, String desc_, boolean v) {
+ super(name_, desc_);
+ value = v;
+ defValue = v;
+ }
+
+ public boolean setParam(String v) {
+ if (v.equals("1") || v.equalsIgnoreCase("on") ||
+ v.equalsIgnoreCase("true") || v.equalsIgnoreCase("yes"))
+ value = true;
+ else if (v.equals("0") || v.equalsIgnoreCase("off") ||
+ v.equalsIgnoreCase("false") || v.equalsIgnoreCase("no"))
+ value = false;
+ else
+ return false;
+ return true;
+ }
+
+ public boolean setParam() { setParam(true); return true; }
+ public void setParam(boolean b) { value = b; }
+
+ public String getDefaultStr() { return defValue ? "1" : "0"; }
+ public String getValueStr() { return value ? "1" : "0"; }
+ public boolean isBool() { return true; }
+
+ final public boolean getValue() { return value; }
+
+ protected boolean value;
+ protected boolean defValue;
+}
diff --git a/java/com/tigervnc/rfb/CConnection.java b/java/com/tigervnc/rfb/CConnection.java
new file mode 100644
index 00000000..15e19896
--- /dev/null
+++ b/java/com/tigervnc/rfb/CConnection.java
@@ -0,0 +1,356 @@
+/* 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 com.tigervnc.rfb;
+
+import java.util.*;
+
+import com.tigervnc.rdr.*;
+
+abstract public class CConnection extends CMsgHandler {
+
+ public CConnection() {
+ security = new SecurityClient();
+ }
+
+ // setStreams() sets the streams to be used for the connection. These must
+ // be set before initialiseProtocol() and processMsg() are called. The
+ // CSecurity object may call setStreams() again to provide alternative
+ // streams over which the RFB protocol is sent (i.e. encrypting/decrypting
+ // streams). Ownership of the streams remains with the caller
+ // (i.e. SConnection will not delete them).
+ public void setStreams(InStream is_, OutStream os_) {
+ is = is_;
+ os = os_;
+ }
+
+ // initialiseProtocol() should be called once the streams and security
+ // types are set. Subsequently, processMsg() should be called whenever
+ // there is data to read on the InStream.
+ public void initialiseProtocol() {
+ state_ = RFBSTATE_PROTOCOL_VERSION;
+ }
+
+ // processMsg() should be called whenever there is data to read on the
+ // InStream. You must have called initialiseProtocol() first.
+ public void processMsg() {
+ switch (state_) {
+
+ case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
+ case RFBSTATE_SECURITY_TYPES: processSecurityTypesMsg(); break;
+ case RFBSTATE_SECURITY: processSecurityMsg(); break;
+ case RFBSTATE_SECURITY_RESULT: processSecurityResultMsg(); break;
+ case RFBSTATE_INITIALISATION: processInitMsg(); break;
+ case RFBSTATE_NORMAL: reader_.readMsg(); break;
+ case RFBSTATE_UNINITIALISED:
+ throw new Exception("CConnection.processMsg: not initialised yet?");
+ default:
+ throw new Exception("CConnection.processMsg: invalid state");
+ }
+ }
+
+ private void processVersionMsg() {
+ vlog.debug("reading protocol version");
+ Boolean done = new Boolean(true);
+ if (!cp.readVersion(is, done)) {
+ state_ = RFBSTATE_INVALID;
+ throw new Exception("reading version failed: not an RFB server?");
+ }
+ if (!done.booleanValue()) return;
+
+ vlog.info("Server supports RFB protocol version "+cp.majorVersion+"."+
+ cp.minorVersion);
+
+ // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
+ if (cp.beforeVersion(3,3)) {
+ String msg = ("Server gave unsupported RFB protocol version "+
+ cp.majorVersion+"."+cp.minorVersion);
+ vlog.error(msg);
+ state_ = RFBSTATE_INVALID;
+ throw new Exception(msg);
+ } else if (useProtocol3_3 || cp.beforeVersion(3,7)) {
+ cp.setVersion(3,3);
+ } else if (cp.afterVersion(3,8)) {
+ cp.setVersion(3,8);
+ }
+
+ cp.writeVersion(os);
+ state_ = RFBSTATE_SECURITY_TYPES;
+
+ vlog.info("Using RFB protocol version "+
+ cp.majorVersion+"."+cp.minorVersion);
+ }
+
+ private void processSecurityTypesMsg() {
+ vlog.info("processing security types message");
+
+ int secType = Security.secTypeInvalid;
+
+ List<Integer> secTypes = new ArrayList<Integer>();
+ secTypes = security.GetEnabledSecTypes();
+ //for (Iterator i = secTypes.iterator(); i.hasNext(); )
+ // vlog.info(((Integer)i.next()).toString());
+
+ if (cp.isVersion(3,3)) {
+
+ // legacy 3.3 server may only offer "vnc authentication" or "none"
+
+ secType = is.readU32();
+ if (secType == Security.secTypeInvalid) {
+ throwConnFailedException();
+
+ } else if (secType == Security.secTypeNone || secType == Security.secTypeVncAuth) {
+ Iterator i;
+ for (i = secTypes.iterator(); i.hasNext(); ) {
+ int refType = (Integer)i.next();
+ if (refType == secType) {
+ secType = refType;
+ break;
+ }
+ if (!i.hasNext())
+ secType = Security.secTypeInvalid;
+ }
+
+ } else {
+ vlog.error("Unknown 3.3 security type "+secType);
+ throw new Exception("Unknown 3.3 security type");
+ }
+
+ } else {
+
+ // 3.7 server will offer us a list
+
+ int nServerSecTypes = is.readU8();
+ if (nServerSecTypes == 0)
+ throwConnFailedException();
+
+ for (int i = 0; i < nServerSecTypes; i++) {
+ int serverSecType = is.readU8();
+ vlog.info("Server offers security type "+
+ Security.secTypeName(serverSecType)+"("+serverSecType+")");
+
+ /*
+ * Use the first type sent by server which matches client's type.
+ * It means server's order specifies priority.
+ */
+ if (secType == Security.secTypeInvalid) {
+ for (Iterator j = secTypes.iterator(); j.hasNext(); ) {
+ int refType = (Integer)j.next();
+ if (refType == serverSecType) {
+ secType = refType;
+ break;
+ }
+ }
+ }
+ }
+
+ // Inform the server of our decision
+ if (secType != Security.secTypeInvalid) {
+ os.writeU8(secType);
+ os.flush();
+ vlog.info("Choosing security type "+Security.secTypeName(secType)+
+ "("+secType+")");
+ }
+ }
+
+ if (secType == Security.secTypeInvalid) {
+ state_ = RFBSTATE_INVALID;
+ vlog.error("No matching security types");
+ throw new Exception("No matching security types");
+ }
+
+ state_ = RFBSTATE_SECURITY;
+ csecurity = security.GetCSecurity(secType);
+ processSecurityMsg();
+ }
+
+ private void processSecurityMsg() {
+ vlog.debug("processing security message");
+ if (csecurity.processMsg(this)) {
+ state_ = RFBSTATE_SECURITY_RESULT;
+ processSecurityResultMsg();
+ }
+ }
+
+ private void processSecurityResultMsg() {
+ vlog.debug("processing security result message");
+ int result;
+ if (cp.beforeVersion(3,8) && csecurity.getType() == Security.secTypeNone) {
+ result = Security.secResultOK;
+ } else {
+ if (!is.checkNoWait(1)) return;
+ result = is.readU32();
+ }
+ switch (result) {
+ case Security.secResultOK:
+ securityCompleted();
+ return;
+ case Security.secResultFailed:
+ vlog.debug("auth failed");
+ break;
+ case Security.secResultTooMany:
+ vlog.debug("auth failed - too many tries");
+ break;
+ default:
+ throw new Exception("Unknown security result from server");
+ }
+ String reason;
+ if (cp.beforeVersion(3,8))
+ reason = "Authentication failure";
+ else
+ reason = is.readString();
+ state_ = RFBSTATE_INVALID;
+ throw new AuthFailureException(reason);
+ }
+
+ private void processInitMsg() {
+ vlog.debug("reading server initialisation");
+ reader_.readServerInit();
+ }
+
+ private void throwConnFailedException() {
+ state_ = RFBSTATE_INVALID;
+ String reason;
+ reason = is.readString();
+ throw new ConnFailedException(reason);
+ }
+
+ private void securityCompleted() {
+ state_ = RFBSTATE_INITIALISATION;
+ reader_ = new CMsgReaderV3(this, is);
+ writer_ = new CMsgWriterV3(cp, os);
+ vlog.debug("Authentication success!");
+ authSuccess();
+ writer_.writeClientInit(shared);
+ }
+
+ // Methods to initialise the connection
+
+ // setServerName() is used to provide a unique(ish) name for the server to
+ // which we are connected. This might be the result of getPeerEndpoint on
+ // a TcpSocket, for example, or a host specified by DNS name & port.
+ // The serverName is used when verifying the Identity of a host (see RA2).
+ public void setServerName(String name) {
+ serverName = name;
+ }
+
+ public void setServerPort(int port) {
+ serverPort = port;
+ }
+
+ public void initSecTypes() {
+ nSecTypes = 0;
+ }
+
+ // setShared sets the value of the shared flag which will be sent to the
+ // server upon initialisation.
+ public void setShared(boolean s) { shared = s; }
+
+ // setProtocol3_3 configures whether or not the CConnection should
+ // only ever support protocol version 3.3
+ public void setProtocol3_3(boolean s) { useProtocol3_3 = s; }
+
+ // Methods to be overridden in a derived class
+
+ // getCSecurity() gets the CSecurity object for the given type. The type
+ // is guaranteed to be one of the secTypes passed in to addSecType(). The
+ // CSecurity object's destroy() method will be called by the CConnection
+ // from its destructor.
+ //abstract public CSecurity getCSecurity(int secType);
+
+ // getCurrentCSecurity() gets the CSecurity instance used for this
+ // connection.
+ //public CSecurity getCurrentCSecurity() { return security; }
+
+ // setClientSecTypeOrder() determines whether the client should obey the
+ // server's security type preference, by picking the first server security
+ // type that the client supports, or whether it should pick the first type
+ // that the server supports, from the client-supported list of types.
+ public void setClientSecTypeOrder( boolean csto ) {
+ clientSecTypeOrder = csto;
+ }
+
+ // authSuccess() is called when authentication has succeeded.
+ public void authSuccess() {}
+
+ // serverInit() is called when the ServerInit message is received. The
+ // derived class must call on to CConnection::serverInit().
+ public void serverInit() {
+ state_ = RFBSTATE_NORMAL;
+ vlog.debug("initialisation done");
+ }
+
+ // Other methods
+
+ public CMsgReaderV3 reader() { return reader_; }
+ public CMsgWriterV3 writer() { return writer_; }
+
+ public InStream getInStream() { return is; }
+ public OutStream getOutStream() { return os; }
+
+ public String getServerName() { return serverName; }
+ public int getServerPort() { return serverPort; }
+
+ public static final int RFBSTATE_UNINITIALISED = 0;
+ public static final int RFBSTATE_PROTOCOL_VERSION = 1;
+ public static final int RFBSTATE_SECURITY_TYPES = 2;
+ public static final int RFBSTATE_SECURITY = 3;
+ public static final int RFBSTATE_SECURITY_RESULT = 4;
+ public static final int RFBSTATE_INITIALISATION = 5;
+ public static final int RFBSTATE_NORMAL = 6;
+ public static final int RFBSTATE_INVALID = 7;
+
+ public int state() { return state_; }
+
+ protected void setState(int s) { state_ = s; }
+
+ private void throwAuthFailureException() {
+ String reason;
+ vlog.debug("state="+state()+", ver="+cp.majorVersion+"."+cp.minorVersion);
+ if (state() == RFBSTATE_SECURITY_RESULT && !cp.beforeVersion(3,8)) {
+ reason = is.readString();
+ } else {
+ reason = "Authentication failure";
+ }
+ state_ = RFBSTATE_INVALID;
+ vlog.error(reason);
+ throw new AuthFailureException(reason);
+ }
+
+ InStream is = null;
+ OutStream os = null;
+ CMsgReaderV3 reader_ = null;
+ CMsgWriterV3 writer_ = null;
+ boolean shared = false;
+ public CSecurity csecurity;
+ public SecurityClient security;
+ public static final int maxSecTypes = 8;
+ int nSecTypes;
+ int[] secTypes;
+ int state_ = RFBSTATE_UNINITIALISED;
+ String serverName;
+ int serverPort;
+ boolean useProtocol3_3 = false;
+ boolean clientSecTypeOrder;
+ public static java.net.Socket sock;
+
+ public static java.net.Socket getSocket() { return sock; }
+ public static void setSocket(java.net.Socket sock_) { sock = sock_; }
+
+ static LogWriter vlog = new LogWriter("CConnection");
+}
diff --git a/java/com/tigervnc/rfb/CMsgHandler.java b/java/com/tigervnc/rfb/CMsgHandler.java
new file mode 100644
index 00000000..81fd2a1b
--- /dev/null
+++ b/java/com/tigervnc/rfb/CMsgHandler.java
@@ -0,0 +1,88 @@
+/* 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.
+ */
+
+//
+// CMsgHandler
+//
+
+package com.tigervnc.rfb;
+
+public class CMsgHandler {
+
+ public CMsgHandler() {
+ cp = new ConnParams();
+ }
+
+ public void setDesktopSize(int width, int height)
+ {
+ cp.width = width;
+ cp.height = height;
+ }
+
+ public void setExtendedDesktopSize(int reason, int result,
+ int width, int height,
+ ScreenSet layout)
+ {
+ cp.supportsSetDesktopSize = true;
+
+ if ((reason == screenTypes.reasonClient) && (result != screenTypes.resultSuccess))
+ return;
+
+ if (!layout.validate(width, height))
+ vlog.error("Server sent us an invalid screen layout");
+
+ cp.width = width;
+ cp.height = height;
+ cp.screenLayout = layout;
+ }
+
+ public void setPixelFormat(PixelFormat pf)
+ {
+ cp.setPF(pf);
+ }
+
+ public void setName(String name)
+ {
+ cp.setName(name);
+ }
+
+ public void clientRedirect(int port, String host,
+ String x509subject) {}
+
+ public void setCursor(int width, int height, Point hotspot,
+ int[] data, byte[] mask) {}
+ public void serverInit() {}
+
+ public void framebufferUpdateStart() {}
+ public void framebufferUpdateEnd() {}
+ public void beginRect(Rect r, int encoding) {}
+ public void endRect(Rect r, int encoding) {}
+
+ public void setColourMapEntries(int firstColour, int nColours,
+ int[] rgbs) { }
+ public void bell() {}
+ public void serverCutText(String str, int len) {}
+
+ public void fillRect(Rect r, int pix) {}
+ public void imageRect(Rect r, int[] pixels) {}
+ public void copyRect(Rect r, int srcX, int srcY) {}
+
+ public ConnParams cp;
+
+ static LogWriter vlog = new LogWriter("CMsgHandler");
+}
diff --git a/java/com/tigervnc/rfb/CMsgReader.java b/java/com/tigervnc/rfb/CMsgReader.java
new file mode 100644
index 00000000..41230560
--- /dev/null
+++ b/java/com/tigervnc/rfb/CMsgReader.java
@@ -0,0 +1,179 @@
+/* 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.
+ */
+
+//
+// CMsgReader - class for reading RFB messages on the client side
+// (i.e. messages from server to client).
+//
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+abstract public class CMsgReader {
+
+ protected CMsgReader(CMsgHandler handler_, InStream is_)
+ {
+ imageBufIdealSize = 0;
+ handler = handler_;
+ is = is_;
+ imageBuf = null;
+ imageBufSize = 0;
+ decoders = new Decoder[Encodings.encodingMax+1];
+ }
+
+ protected void readSetColourMapEntries()
+ {
+ is.skip(1);
+ int firstColour = is.readU16();
+ int nColours = is.readU16();
+ int[] rgbs = new int[nColours * 3];
+ for (int i = 0; i < nColours * 3; i++)
+ rgbs[i] = is.readU16();
+ handler.setColourMapEntries(firstColour, nColours, rgbs);
+ }
+
+ protected void readBell()
+ {
+ handler.bell();
+ }
+
+ protected void readServerCutText()
+ {
+ is.skip(3);
+ int len = is.readU32();
+ if (len > 256*1024) {
+ is.skip(len);
+ vlog.error("cut text too long ("+len+" bytes) - ignoring");
+ return;
+ }
+ byte[] buf = new byte[len];
+ is.readBytes(buf, 0, len);
+ String str = new String();
+ try {
+ str = new String(buf,"UTF8");
+ } catch(java.io.UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ handler.serverCutText(str, len);
+ }
+
+ protected void readFramebufferUpdateStart()
+ {
+ handler.framebufferUpdateStart();
+ }
+
+ protected void readFramebufferUpdateEnd()
+ {
+ handler.framebufferUpdateEnd();
+ }
+
+ protected void readRect(Rect r, int encoding)
+ {
+ if ((r.br.x > handler.cp.width) || (r.br.y > handler.cp.height)) {
+ vlog.error("Rect too big: "+r.width()+"x"+r.height()+" at "+
+ r.tl.x+","+r.tl.y+" exceeds "+handler.cp.width+"x"+
+ handler.cp.height);
+ throw new Exception("Rect too big");
+ }
+
+ if (r.is_empty())
+ vlog.error("Ignoring zero size rect");
+
+ handler.beginRect(r, encoding);
+
+ if (encoding == Encodings.encodingCopyRect) {
+ readCopyRect(r);
+ } else {
+
+ if (decoders[encoding] == null) {
+ decoders[encoding] = Decoder.createDecoder(encoding, this);
+ if (decoders[encoding] == null) {
+ vlog.error("Unknown rect encoding "+encoding);
+ throw new Exception("Unknown rect encoding");
+ }
+ }
+ decoders[encoding].readRect(r, handler);
+ }
+
+ handler.endRect(r, encoding);
+ }
+
+ protected void readCopyRect(Rect r)
+ {
+ int srcX = is.readU16();
+ int srcY = is.readU16();
+ handler.copyRect(r, srcX, srcY);
+ }
+
+ protected void readSetCursor(int width, int height, Point hotspot)
+ {
+ int data_len = width * height;
+ int mask_len = ((width+7)/8) * height;
+ int[] data = new int[data_len];
+ byte[] mask = new byte[mask_len];
+
+ is.readPixels(data, data_len, (handler.cp.pf().bpp/8), handler.cp.pf().bigEndian);
+ is.readBytes(mask, 0, mask_len);
+
+ handler.setCursor(width, height, hotspot, data, mask);
+ }
+
+ public int[] getImageBuf(int required) { return getImageBuf(required, 0, 0); }
+
+ public int[] getImageBuf(int required, int requested, int nPixels)
+ {
+ int requiredBytes = required * (handler.cp.pf().bpp / 8);
+ int requestedBytes = requested * (handler.cp.pf().bpp / 8);
+ int size = requestedBytes;
+ if (size > imageBufIdealSize) size = imageBufIdealSize;
+
+ if (size < requiredBytes)
+ size = requiredBytes;
+
+ if (imageBufSize < size) {
+ imageBufSize = size;
+ imageBuf = new int[imageBufSize];
+ }
+ if (nPixels != 0)
+ nPixels = imageBufSize / (handler.cp.pf().bpp / 8);
+ return imageBuf;
+ }
+
+ public final int bpp()
+ {
+ return handler.cp.pf().bpp;
+ }
+
+ abstract public void readServerInit();
+
+ // readMsg() reads a message, calling the handler as appropriate.
+ abstract public void readMsg();
+
+ public InStream getInStream() { return is; }
+
+ public int imageBufIdealSize;
+
+ protected CMsgHandler handler;
+ protected InStream is;
+ protected Decoder[] decoders;
+ protected int[] imageBuf;
+ protected int imageBufSize;
+
+ static LogWriter vlog = new LogWriter("CMsgReader");
+}
diff --git a/java/com/tigervnc/rfb/CMsgReaderV3.java b/java/com/tigervnc/rfb/CMsgReaderV3.java
new file mode 100644
index 00000000..6d9e254b
--- /dev/null
+++ b/java/com/tigervnc/rfb/CMsgReaderV3.java
@@ -0,0 +1,155 @@
+/* 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 com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+public class CMsgReaderV3 extends CMsgReader {
+
+ public CMsgReaderV3(CMsgHandler handler_, InStream is_)
+ {
+ super(handler_, is_);
+ nUpdateRectsLeft = 0;
+ }
+
+ public void readServerInit()
+ {
+ int width = is.readU16();
+ int height = is.readU16();
+ handler.setDesktopSize(width, height);
+ PixelFormat pf = new PixelFormat();
+ pf.read(is);
+ handler.setPixelFormat(pf);
+ String name = is.readString();
+ handler.setName(name);
+ handler.serverInit();
+ }
+
+ public void readMsg()
+ {
+ if (nUpdateRectsLeft == 0) {
+
+ int type = is.readU8();
+ switch (type) {
+ case MsgTypes.msgTypeFramebufferUpdate: readFramebufferUpdate(); break;
+ case MsgTypes.msgTypeSetColourMapEntries: readSetColourMapEntries(); break;
+ case MsgTypes.msgTypeBell: readBell(); break;
+ case MsgTypes.msgTypeServerCutText: readServerCutText(); break;
+ default:
+ vlog.error("unknown message type "+type);
+ throw new Exception("unknown message type");
+ }
+
+ } else {
+
+ int x = is.readU16();
+ int y = is.readU16();
+ int w = is.readU16();
+ int h = is.readU16();
+ int encoding = is.readS32();
+
+ switch (encoding) {
+ case Encodings.pseudoEncodingDesktopSize:
+ handler.setDesktopSize(w, h);
+ break;
+ case Encodings.pseudoEncodingExtendedDesktopSize:
+ readExtendedDesktopSize(x, y, w, h);
+ break;
+ case Encodings.pseudoEncodingDesktopName:
+ readSetDesktopName(x, y, w, h);
+ break;
+ case Encodings.pseudoEncodingCursor:
+ readSetCursor(w, h, new Point(x,y));
+ break;
+ case Encodings.pseudoEncodingLastRect:
+ nUpdateRectsLeft = 1; // this rectangle is the last one
+ break;
+ case Encodings.pseudoEncodingClientRedirect:
+ readClientRedirect(x, y, w, h);
+ break;
+ default:
+ readRect(new Rect(x, y, x+w, y+h), encoding);
+ break;
+ }
+
+ nUpdateRectsLeft--;
+ if (nUpdateRectsLeft == 0) handler.framebufferUpdateEnd();
+ }
+ }
+
+ void readFramebufferUpdate()
+ {
+ is.skip(1);
+ nUpdateRectsLeft = is.readU16();
+ handler.framebufferUpdateStart();
+ }
+
+ void readSetDesktopName(int x, int y, int w, int h)
+ {
+ String name = is.readString();
+
+ if (x != 0 || y != 0 || w != 0 || h != 0) {
+ vlog.error("Ignoring DesktopName rect with non-zero position/size");
+ } else {
+ handler.setName(name);
+ }
+
+ }
+
+ void readExtendedDesktopSize(int x, int y, int w, int h)
+ {
+ int screens, i;
+ int id, flags;
+ int sx, sy, sw, sh;
+ ScreenSet layout = new ScreenSet();
+
+ screens = is.readU8();
+ is.skip(3);
+
+ for (i = 0;i < screens;i++) {
+ id = is.readU32();
+ sx = is.readU16();
+ sy = is.readU16();
+ sw = is.readU16();
+ sh = is.readU16();
+ flags = is.readU32();
+
+ layout.add_screen(new Screen(id, sx, sy, sw, sh, flags));
+ }
+
+ handler.setExtendedDesktopSize(x, y, w, h, layout);
+ }
+
+ void readClientRedirect(int x, int y, int w, int h)
+ {
+ int port = is.readU16();
+ String host = is.readString();
+ String x509subject = is.readString();
+
+ if (x != 0 || y != 0 || w != 0 || h != 0) {
+ vlog.error("Ignoring ClientRedirect rect with non-zero position/size");
+ } else {
+ handler.clientRedirect(port, host, x509subject);
+ }
+ }
+
+ int nUpdateRectsLeft;
+
+ static LogWriter vlog = new LogWriter("CMsgReaderV3");
+}
diff --git a/java/com/tigervnc/rfb/CMsgWriter.java b/java/com/tigervnc/rfb/CMsgWriter.java
new file mode 100644
index 00000000..7cafddde
--- /dev/null
+++ b/java/com/tigervnc/rfb/CMsgWriter.java
@@ -0,0 +1,171 @@
+/* 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 com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+abstract public class CMsgWriter {
+
+ abstract public void writeClientInit(boolean shared);
+
+ public void writeSetPixelFormat(PixelFormat pf)
+ {
+ startMsg(MsgTypes.msgTypeSetPixelFormat);
+ os.pad(3);
+ pf.write(os);
+ endMsg();
+ }
+
+ public void writeSetEncodings(int nEncodings, int[] encodings)
+ {
+ startMsg(MsgTypes.msgTypeSetEncodings);
+ os.skip(1);
+ os.writeU16(nEncodings);
+ for (int i = 0; i < nEncodings; i++)
+ os.writeU32(encodings[i]);
+ endMsg();
+ }
+
+ // Ask for encodings based on which decoders are supported. Assumes higher
+ // encoding numbers are more desirable.
+
+ public void writeSetEncodings(int preferredEncoding, boolean useCopyRect)
+ {
+ int nEncodings = 0;
+ int[] encodings = new int[Encodings.encodingMax+3];
+ if (cp.supportsLocalCursor)
+ encodings[nEncodings++] = Encodings.pseudoEncodingCursor;
+ if (cp.supportsDesktopResize)
+ encodings[nEncodings++] = Encodings.pseudoEncodingDesktopSize;
+ if (cp.supportsExtendedDesktopSize)
+ encodings[nEncodings++] = Encodings.pseudoEncodingExtendedDesktopSize;
+ if (cp.supportsDesktopRename)
+ encodings[nEncodings++] = Encodings.pseudoEncodingDesktopName;
+ if (cp.supportsClientRedirect)
+ encodings[nEncodings++] = Encodings.pseudoEncodingClientRedirect;
+ if (Decoder.supported(preferredEncoding)) {
+ encodings[nEncodings++] = preferredEncoding;
+ }
+ if (useCopyRect) {
+ encodings[nEncodings++] = Encodings.encodingCopyRect;
+ }
+
+ /*
+ * Prefer encodings in this order:
+ *
+ * Tight, ZRLE, Hextile, *
+ */
+
+ if ((preferredEncoding != Encodings.encodingTight) &&
+ Decoder.supported(Encodings.encodingTight))
+ encodings[nEncodings++] = Encodings.encodingTight;
+
+ if ((preferredEncoding != Encodings.encodingZRLE) &&
+ Decoder.supported(Encodings.encodingZRLE))
+ encodings[nEncodings++] = Encodings.encodingZRLE;
+
+ if ((preferredEncoding != Encodings.encodingHextile) &&
+ Decoder.supported(Encodings.encodingHextile))
+ encodings[nEncodings++] = Encodings.encodingHextile;
+
+ // Remaining encodings
+ for (int i = Encodings.encodingMax; i >= 0; i--) {
+ switch (i) {
+ case Encodings.encodingTight:
+ case Encodings.encodingZRLE:
+ case Encodings.encodingHextile:
+ break;
+ default:
+ if ((i != preferredEncoding) && Decoder.supported(i))
+ encodings[nEncodings++] = i;
+ }
+ }
+
+ encodings[nEncodings++] = Encodings.pseudoEncodingLastRect;
+ if (cp.customCompressLevel && cp.compressLevel >= 0 && cp.compressLevel <= 9)
+ encodings[nEncodings++] = Encodings.pseudoEncodingCompressLevel0 + cp.compressLevel;
+ if (!cp.noJpeg && cp.qualityLevel >= 0 && cp.qualityLevel <= 9)
+ encodings[nEncodings++] = Encodings.pseudoEncodingQualityLevel0 + cp.qualityLevel;
+
+ writeSetEncodings(nEncodings, encodings);
+ }
+
+ public void writeFramebufferUpdateRequest(Rect r, boolean incremental)
+ {
+ startMsg(MsgTypes.msgTypeFramebufferUpdateRequest);
+ os.writeU8(incremental?1:0);
+ os.writeU16(r.tl.x);
+ os.writeU16(r.tl.y);
+ os.writeU16(r.width());
+ os.writeU16(r.height());
+ endMsg();
+ }
+
+ public void writeKeyEvent(int key, boolean down)
+ {
+ startMsg(MsgTypes.msgTypeKeyEvent);
+ os.writeU8(down?1:0);
+ os.pad(2);
+ os.writeU32(key);
+ endMsg();
+ }
+
+ public void writePointerEvent(Point pos, int buttonMask)
+ {
+ Point p = new Point(pos.x,pos.y);
+ if (p.x < 0) p.x = 0;
+ if (p.y < 0) p.y = 0;
+ if (p.x >= cp.width) p.x = cp.width - 1;
+ if (p.y >= cp.height) p.y = cp.height - 1;
+
+ startMsg(MsgTypes.msgTypePointerEvent);
+ os.writeU8(buttonMask);
+ os.writeU16(p.x);
+ os.writeU16(p.y);
+ endMsg();
+ }
+
+ public void writeClientCutText(String str, int len)
+ {
+ startMsg(MsgTypes.msgTypeClientCutText);
+ os.pad(3);
+ os.writeU32(len);
+ try {
+ byte[] utf8str = str.getBytes("UTF8");
+ os.writeBytes(utf8str, 0, len);
+ } catch(java.io.UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ endMsg();
+ }
+
+ abstract public void startMsg(int type);
+ abstract public void endMsg();
+
+ public void setOutStream(OutStream os_) { os = os_; }
+
+ ConnParams getConnParams() { return cp; }
+ OutStream getOutStream() { return os; }
+
+ protected CMsgWriter(ConnParams cp_, OutStream os_) {cp = cp_; os = os_;}
+
+ ConnParams cp;
+ OutStream os;
+ static LogWriter vlog = new LogWriter("CMsgWriter");
+}
diff --git a/java/com/tigervnc/rfb/CMsgWriterV3.java b/java/com/tigervnc/rfb/CMsgWriterV3.java
new file mode 100644
index 00000000..ec30a826
--- /dev/null
+++ b/java/com/tigervnc/rfb/CMsgWriterV3.java
@@ -0,0 +1,68 @@
+/* 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 com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+import java.util.*;
+
+public class CMsgWriterV3 extends CMsgWriter {
+
+ public CMsgWriterV3(ConnParams cp_, OutStream os_) { super(cp_, os_); }
+
+ public void writeClientInit(boolean shared) {
+ os.writeU8(shared?1:0);
+ endMsg();
+ }
+
+ public void startMsg(int type) {
+ os.writeU8(type);
+ }
+
+ public void endMsg() {
+ os.flush();
+ }
+
+ public void writeSetDesktopSize(int width, int height,
+ ScreenSet layout)
+ {
+ if (!cp.supportsSetDesktopSize)
+ throw new Exception("Server does not support SetDesktopSize");
+
+ startMsg(MsgTypes.msgTypeSetDesktopSize);
+ os.pad(1);
+
+ os.writeU16(width);
+ os.writeU16(height);
+
+ os.writeU8(layout.num_screens());
+ os.pad(1);
+
+ for (Iterator iter = layout.screens.iterator(); iter.hasNext(); ) {
+ Screen refScreen = (Screen)iter.next();
+ os.writeU32(refScreen.id);
+ os.writeU16(refScreen.dimensions.tl.x);
+ os.writeU16(refScreen.dimensions.tl.y);
+ os.writeU16(refScreen.dimensions.width());
+ os.writeU16(refScreen.dimensions.height());
+ os.writeU32(refScreen.flags);
+ }
+
+ endMsg();
+ }
+}
diff --git a/java/com/tigervnc/rfb/CSecurity.java b/java/com/tigervnc/rfb/CSecurity.java
new file mode 100644
index 00000000..e5b300f6
--- /dev/null
+++ b/java/com/tigervnc/rfb/CSecurity.java
@@ -0,0 +1,46 @@
+/* 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.
+ */
+
+//
+// CSecurity - class on the client side for handling security handshaking. A
+// derived class for a particular security type overrides the processMsg()
+// method. processMsg() is called first when the security type has been
+// decided on, and will keep being called whenever there is data to read from
+// the server until either it returns 0, indicating authentication/security
+// failure, or it returns 1, to indicate success. A return value of 2
+// (actually anything other than 0 or 1) indicates that it should be called
+// back when there is more data to read.
+//
+// Note that the first time processMsg() is called, there is no guarantee that
+// there is any data to read from the CConnection's InStream, but subsequent
+// calls guarantee there is at least one byte which can be read without
+// blocking.
+
+package com.tigervnc.rfb;
+
+abstract public class CSecurity {
+ abstract public boolean processMsg(CConnection cc);
+ abstract public int getType();
+ abstract public String description();
+
+ /*
+ * Use variable directly instead of dumb get/set methods.
+ * It MUST be set by viewer.
+ */
+ static UserPasswdGetter upg;
+}
diff --git a/java/com/tigervnc/rfb/CSecurityIdent.java b/java/com/tigervnc/rfb/CSecurityIdent.java
new file mode 100644
index 00000000..6523e411
--- /dev/null
+++ b/java/com/tigervnc/rfb/CSecurityIdent.java
@@ -0,0 +1,58 @@
+/* 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 com.tigervnc.rfb;
+
+import java.io.IOException;
+
+import com.tigervnc.rdr.*;
+import com.tigervnc.vncviewer.*;
+
+public class CSecurityIdent extends CSecurity {
+
+ public CSecurityIdent() { }
+
+ public boolean processMsg(CConnection cc) {
+ InStream is = cc.getInStream();
+ OutStream os = cc.getOutStream();
+
+ StringBuffer username = new StringBuffer();
+
+ CConn.upg.getUserPasswd(username, null);
+
+ // Return the response to the server
+ os.writeU32(username.length());
+ try {
+ byte[] utf8str = username.toString().getBytes("UTF8");
+ os.writeBytes(utf8str, 0, username.length());
+ } catch(java.io.UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ os.flush();
+ return true;
+ }
+
+ public int getType() { return Security.secTypeIdent; }
+
+ java.net.Socket sock;
+ UserPasswdGetter upg;
+
+ static LogWriter vlog = new LogWriter("Ident");
+ public String description() { return "No Encryption"; }
+
+}
diff --git a/java/com/tigervnc/rfb/CSecurityManaged.java b/java/com/tigervnc/rfb/CSecurityManaged.java
new file mode 100644
index 00000000..2461682d
--- /dev/null
+++ b/java/com/tigervnc/rfb/CSecurityManaged.java
@@ -0,0 +1,76 @@
+/* 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 com.tigervnc.rfb;
+
+import java.io.IOException;
+
+import com.tigervnc.rdr.*;
+import com.tigervnc.vncviewer.*;
+
+public class CSecurityManaged extends CSecurity {
+
+ public CSecurityManaged() { }
+
+ public boolean processMsg(CConnection cc) {
+ InStream is = cc.getInStream();
+ OutStream os = cc.getOutStream();
+
+ StringBuffer username = new StringBuffer();
+
+ CConn.upg.getUserPasswd(username, null);
+
+ // Return the response to the server
+ os.writeU8(username.length());
+ try {
+ byte[] utf8str = username.toString().getBytes("UTF8");
+ os.writeBytes(utf8str, 0, username.length());
+ } catch(java.io.UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ os.flush();
+ int serverPort = is.readU16();
+ //if (serverPort==0) { return true; };
+ String serverName = cc.getServerName();
+ vlog.debug("Redirected to "+serverName+" port "+serverPort);
+ try {
+ CConn.getSocket().close();
+ cc.setServerPort(serverPort);
+ sock = new java.net.Socket(serverName, serverPort);
+ sock.setTcpNoDelay(true);
+ sock.setTrafficClass(0x10);
+ CConn.setSocket(sock);
+ vlog.debug("connected to host "+serverName+" port "+serverPort);
+ cc.setStreams(new JavaInStream(sock.getInputStream()),
+ new JavaOutStream(sock.getOutputStream()));
+ cc.initialiseProtocol();
+ } catch (java.io.IOException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ public int getType() { return Security.secTypeManaged; }
+
+ java.net.Socket sock;
+ UserPasswdGetter upg;
+
+ static LogWriter vlog = new LogWriter("Managed");
+ public String description() { return "No Encryption"; }
+
+}
diff --git a/java/com/tigervnc/rfb/CSecurityNone.java b/java/com/tigervnc/rfb/CSecurityNone.java
new file mode 100644
index 00000000..e31056da
--- /dev/null
+++ b/java/com/tigervnc/rfb/CSecurityNone.java
@@ -0,0 +1,27 @@
+/* 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 com.tigervnc.rfb;
+
+public class CSecurityNone extends CSecurity {
+
+ public boolean processMsg(CConnection cc) { return true; }
+ public int getType() { return Security.secTypeNone; }
+ public String description() { return "No Encryption"; }
+ static LogWriter vlog = new LogWriter("CSecurityNone");
+}
diff --git a/java/com/tigervnc/rfb/CSecurityPlain.java b/java/com/tigervnc/rfb/CSecurityPlain.java
new file mode 100644
index 00000000..707915cc
--- /dev/null
+++ b/java/com/tigervnc/rfb/CSecurityPlain.java
@@ -0,0 +1,57 @@
+/* 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 com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+import com.tigervnc.vncviewer.*;
+
+public class CSecurityPlain extends CSecurity {
+
+ public CSecurityPlain() { }
+
+ public boolean processMsg(CConnection cc)
+ {
+ OutStream os = cc.getOutStream();
+
+ StringBuffer username = new StringBuffer();
+ StringBuffer password = new StringBuffer();
+
+ CConn.upg.getUserPasswd(username, password);
+
+ // Return the response to the server
+ os.writeU32(username.length());
+ os.writeU32(password.length());
+ byte[] utf8str;
+ try {
+ utf8str = username.toString().getBytes("UTF8");
+ os.writeBytes(utf8str, 0, username.length());
+ utf8str = password.toString().getBytes("UTF8");
+ os.writeBytes(utf8str, 0, password.length());
+ } catch(java.io.UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ os.flush();
+ return true;
+ }
+
+ public int getType() { return Security.secTypePlain; }
+ public String description() { return "ask for username and password"; }
+
+ static LogWriter vlog = new LogWriter("Plain");
+}
diff --git a/java/com/tigervnc/rfb/CSecurityStack.java b/java/com/tigervnc/rfb/CSecurityStack.java
new file mode 100644
index 00000000..5886268e
--- /dev/null
+++ b/java/com/tigervnc/rfb/CSecurityStack.java
@@ -0,0 +1,69 @@
+/* Copyright (C) 2005 Martin Koegler
+ * Copyright (C) 2010 TigerVNC Team
+ *
+ * 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 com.tigervnc.rfb;
+
+public class CSecurityStack extends CSecurity {
+
+ public CSecurityStack(int Type, String Name, CSecurity s0,
+ CSecurity s1)
+ {
+ name = Name;
+ type = Type;
+ state = 0;
+ state0 = s0;
+ state1 = s1;
+ }
+
+ public boolean processMsg(CConnection cc)
+ {
+ boolean res = true;
+ if (state == 0) {
+ if (state0 != null)
+ res = state0.processMsg(cc);
+
+ if (!res)
+ return res;
+
+ state++;
+ }
+
+ if (state == 1) {
+ if(state1 != null)
+ res = state1.processMsg(cc);
+
+ if(!res)
+ return res;
+
+ state++;
+ }
+
+ return res;
+ }
+
+ public final int getType() { return type; }
+ public final String description() { return name; }
+
+ private int state;
+ private CSecurity state0;
+ private CSecurity state1;
+ private String name;
+ private int type;
+
+}
diff --git a/java/com/tigervnc/rfb/CSecurityTLS.java b/java/com/tigervnc/rfb/CSecurityTLS.java
new file mode 100644
index 00000000..73eb6199
--- /dev/null
+++ b/java/com/tigervnc/rfb/CSecurityTLS.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * 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 com.tigervnc.rfb;
+
+import javax.net.ssl.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.KeyStore;
+import java.io.File;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import javax.swing.JOptionPane;
+
+import com.tigervnc.vncviewer.UserPrefs;
+import com.tigervnc.rdr.*;
+
+public class CSecurityTLS extends CSecurity {
+
+ public static StringParameter x509ca
+ = new StringParameter("x509ca",
+ "X509 CA certificate", "");
+ public static StringParameter x509crl
+ = new StringParameter("x509crl",
+ "X509 CRL file", "");
+
+ private void initGlobal()
+ {
+ try {
+ SSLSocketFactory sslfactory;
+ SSLContext ctx = SSLContext.getInstance("TLS");
+ if (anon) {
+ ctx.init(null, null, null);
+ } else {
+ TrustManager[] myTM = new TrustManager[] {
+ new MyX509TrustManager()
+ };
+ ctx.init (null, myTM, null);
+ }
+ sslfactory = ctx.getSocketFactory();
+ try {
+ ssl = (SSLSocket)sslfactory.createSocket(cc.sock,
+ cc.sock.getInetAddress().getHostName(),
+ cc.sock.getPort(), true);
+ } catch (java.io.IOException e) {
+ throw new Exception(e.toString());
+ }
+
+ if (anon) {
+ String[] supported;
+ ArrayList<String> enabled = new ArrayList<String>();
+
+ supported = ssl.getSupportedCipherSuites();
+
+ for (int i = 0; i < supported.length; i++)
+ if (supported[i].matches("TLS_DH_anon.*"))
+ enabled.add(supported[i]);
+
+ ssl.setEnabledCipherSuites(enabled.toArray(new String[0]));
+ } else {
+ ssl.setEnabledCipherSuites(ssl.getSupportedCipherSuites());
+ }
+
+ ssl.setEnabledProtocols(new String[]{"SSLv3","TLSv1"});
+ ssl.addHandshakeCompletedListener(new MyHandshakeListener());
+ }
+ catch (java.security.GeneralSecurityException e)
+ {
+ vlog.error ("TLS handshake failed " + e.toString ());
+ return;
+ }
+ }
+
+ public CSecurityTLS(boolean _anon)
+ {
+ anon = _anon;
+ setDefaults();
+ cafile = x509ca.getData();
+ crlfile = x509crl.getData();
+ }
+
+ public static void setDefaults()
+ {
+ String homeDir = null;
+
+ if ((homeDir=UserPrefs.getHomeDir()) == null) {
+ vlog.error("Could not obtain VNC home directory path");
+ return;
+ }
+
+ String vnchomedir = homeDir+UserPrefs.getFileSeparator()+".vnc"+
+ UserPrefs.getFileSeparator();
+ String caDefault = new String(vnchomedir+"x509_ca.pem");
+ String crlDefault = new String(vnchomedir+"x509_crl.pem");
+
+ if (new File(caDefault).exists())
+ x509ca.setDefaultStr(caDefault);
+ if (new File(crlDefault).exists())
+ x509crl.setDefaultStr(crlDefault);
+ }
+
+ public boolean processMsg(CConnection cc) {
+ is = cc.getInStream();
+ os = cc.getOutStream();
+
+ initGlobal();
+
+ if (!is.checkNoWait(1))
+ return false;
+
+ if (is.readU8() == 0) {
+ int result = is.readU32();
+ String reason;
+ if (result == Security.secResultFailed ||
+ result == Security.secResultTooMany)
+ reason = is.readString();
+ else
+ reason = new String("Authentication failure (protocol error)");
+ throw new AuthFailureException(reason);
+ }
+
+ // SSLSocket.getSession blocks until the handshake is complete
+ session = ssl.getSession();
+ if (!session.isValid())
+ throw new Exception("TLS Handshake failed!");
+
+ try {
+ cc.setStreams(new JavaInStream(ssl.getInputStream()),
+ new JavaOutStream(ssl.getOutputStream()));
+ } catch (java.io.IOException e) {
+ throw new Exception("Failed to set streams");
+ }
+
+ return true;
+ }
+
+ class MyHandshakeListener implements HandshakeCompletedListener {
+ public void handshakeCompleted(HandshakeCompletedEvent e) {
+ vlog.info("Handshake succesful!");
+ vlog.info("Using cipher suite: " + e.getCipherSuite());
+ }
+ }
+
+ class MyX509TrustManager implements X509TrustManager
+ {
+
+ X509TrustManager tm;
+
+ MyX509TrustManager() throws java.security.GeneralSecurityException
+ {
+ TrustManagerFactory tmf =
+ TrustManagerFactory.getInstance("PKIX");
+ KeyStore ks = KeyStore.getInstance("JKS");
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ try {
+ ks.load(null, null);
+ File cacert = new File(cafile);
+ if (!cacert.exists() || !cacert.canRead())
+ return;
+ InputStream caStream = new FileInputStream(cafile);
+ X509Certificate ca = (X509Certificate)cf.generateCertificate(caStream);
+ ks.setCertificateEntry("CA", ca);
+ PKIXBuilderParameters params = new PKIXBuilderParameters(ks, new X509CertSelector());
+ File crlcert = new File(crlfile);
+ if (!crlcert.exists() || !crlcert.canRead()) {
+ params.setRevocationEnabled(false);
+ } else {
+ InputStream crlStream = new FileInputStream(crlfile);
+ Collection<? extends CRL> crls = cf.generateCRLs(crlStream);
+ CertStoreParameters csp = new CollectionCertStoreParameters(crls);
+ CertStore store = CertStore.getInstance("Collection", csp);
+ params.addCertStore(store);
+ params.setRevocationEnabled(true);
+ }
+ tmf.init(new CertPathTrustManagerParameters(params));
+ } catch (java.io.FileNotFoundException e) {
+ vlog.error(e.toString());
+ } catch (java.io.IOException e) {
+ vlog.error(e.toString());
+ }
+ tm = (X509TrustManager)tmf.getTrustManagers()[0];
+ }
+
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException
+ {
+ tm.checkClientTrusted(chain, authType);
+ }
+
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException
+ {
+ try {
+ tm.checkServerTrusted(chain, authType);
+ } catch (CertificateException e) {
+ Object[] answer = {"Proceed", "Exit"};
+ int ret = JOptionPane.showOptionDialog(null,
+ e.getCause().getLocalizedMessage()+"\n"+
+ "Continue connecting to this host?",
+ "Confirm certificate exception?",
+ JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
+ null, answer, answer[0]);
+ if (ret == JOptionPane.NO_OPTION)
+ System.exit(1);
+ } catch (java.lang.Exception e) {
+ throw new Exception(e.toString());
+ }
+ }
+
+ public X509Certificate[] getAcceptedIssuers ()
+ {
+ return tm.getAcceptedIssuers();
+ }
+ }
+
+ public final int getType() { return anon ? Security.secTypeTLSNone : Security.secTypeX509None; }
+ public final String description()
+ { return anon ? "TLS Encryption without VncAuth" : "X509 Encryption without VncAuth"; }
+
+
+ //protected void setParam();
+ //protected void checkSession();
+ protected CConnection cc;
+
+ private boolean anon;
+ private SSLSession session;
+ private String cafile, crlfile;
+ private InStream is;
+ private OutStream os;
+ private SSLSocket ssl;
+
+ static LogWriter vlog = new LogWriter("CSecurityTLS");
+}
diff --git a/java/com/tigervnc/rfb/CSecurityVeNCrypt.java b/java/com/tigervnc/rfb/CSecurityVeNCrypt.java
new file mode 100644
index 00000000..ae758e7f
--- /dev/null
+++ b/java/com/tigervnc/rfb/CSecurityVeNCrypt.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2003 Sun Microsystems, Inc.
+ *
+ * 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 com.tigervnc.rfb;
+
+import java.util.*;
+
+import com.tigervnc.rdr.*;
+
+public class CSecurityVeNCrypt extends CSecurity {
+
+ public CSecurityVeNCrypt(SecurityClient sec)
+ {
+ haveRecvdMajorVersion = false;
+ haveRecvdMinorVersion = false;
+ haveSentVersion = false;
+ haveAgreedVersion = false;
+ haveListOfTypes = false;
+ haveNumberOfTypes = false;
+ haveChosenType = false;
+ majorVersion = 0;
+ minorVersion = 0;
+ chosenType = Security.secTypeVeNCrypt;
+ nAvailableTypes = 0;
+ availableTypes = null;
+ iAvailableType = 0;
+ security = sec;
+ }
+
+ public boolean processMsg(CConnection cc) {
+ InStream is = cc.getInStream();
+ OutStream os = cc.getOutStream();
+
+ /* get major, minor versions, send what we can support (or 0.0 for can't support it) */
+ if (!haveRecvdMinorVersion) {
+ minorVersion = is.readU8();
+ haveRecvdMinorVersion = true;
+
+ return false;
+ }
+
+ if (!haveRecvdMajorVersion) {
+ majorVersion = is.readU8();
+ haveRecvdMajorVersion = true;
+ }
+
+ /* major version in upper 8 bits and minor version in lower 8 bits */
+ int Version = (majorVersion << 8) | minorVersion;
+
+ if (!haveSentVersion) {
+ /* Currently we don't support former VeNCrypt 0.1 */
+ if (Version >= 0x0002) {
+ majorVersion = 0;
+ minorVersion = 2;
+ os.writeU8(majorVersion);
+ os.writeU8(minorVersion);
+ os.flush();
+ } else {
+ /* Send 0.0 to indicate no support */
+ majorVersion = 0;
+ minorVersion = 0;
+ os.writeU8(majorVersion);
+ os.writeU8(minorVersion);
+ os.flush();
+ throw new Exception("Server reported an unsupported VeNCrypt version");
+ }
+
+ haveSentVersion = true;
+ return false;
+ }
+
+ /* Check that the server is OK */
+ if (!haveAgreedVersion) {
+ if (is.readU8() != 0)
+ throw new Exception("Server reported it could not support the VeNCrypt version");
+
+ haveAgreedVersion = true;
+ return false;
+ }
+
+ /* get a number of types */
+ if (!haveNumberOfTypes) {
+ nAvailableTypes = is.readU8();
+ iAvailableType = 0;
+
+ if (nAvailableTypes <= 0)
+ throw new Exception("The server reported no VeNCrypt sub-types");
+
+ availableTypes = new int[nAvailableTypes];
+ haveNumberOfTypes = true;
+ return false;
+ }
+
+ if (nAvailableTypes > 0) {
+ /* read in the types possible */
+ if (!haveListOfTypes) {
+ if (is.checkNoWait(4)) {
+ availableTypes[iAvailableType++] = is.readU32();
+ haveListOfTypes = (iAvailableType >= nAvailableTypes);
+ vlog.debug("Server offers security type "+
+ Security.secTypeName(availableTypes[iAvailableType - 1])+" ("+
+ availableTypes[iAvailableType - 1]+")");
+
+ if (!haveListOfTypes)
+ return false;
+
+ } else
+ return false;
+ }
+
+ /* make a choice and send it to the server, meanwhile set up the stack */
+ if (!haveChosenType) {
+ chosenType = Security.secTypeInvalid;
+ int i;
+ Iterator j;
+ List<Integer> secTypes = new ArrayList<Integer>();
+
+ secTypes = security.GetEnabledExtSecTypes();
+
+ /* Honor server's security type order */
+ for (i = 0; i < nAvailableTypes; i++) {
+ for (j = secTypes.iterator(); j.hasNext(); ) {
+ int refType = (Integer)j.next();
+ if (refType == availableTypes[i]) {
+ chosenType = refType;
+ break;
+ }
+ }
+
+ if (chosenType != Security.secTypeInvalid)
+ break;
+ }
+
+ vlog.debug("Choosing security type "+Security.secTypeName(chosenType)+
+ " ("+chosenType+")");
+
+ /* Set up the stack according to the chosen type: */
+ if (chosenType == Security.secTypeInvalid || chosenType == Security.secTypeVeNCrypt)
+ throw new AuthFailureException("No valid VeNCrypt sub-type");
+
+ csecurity = security.GetCSecurity(chosenType);
+
+ /* send chosen type to server */
+ os.writeU32(chosenType);
+ os.flush();
+
+ haveChosenType = true;
+ }
+ } else {
+ /*
+ * Server told us that there are 0 types it can support - this should not
+ * happen, since if the server supports 0 sub-types, it doesn't support
+ * this security type
+ */
+ throw new AuthFailureException("The server reported 0 VeNCrypt sub-types");
+ }
+
+ return csecurity.processMsg(cc);
+ }
+
+ public final int getType() { return chosenType; }
+ public final String description() { return Security.secTypeName(chosenType); }
+
+ public static StringParameter secTypesStr;
+
+ private CSecurity csecurity;
+ SecurityClient security;
+ private boolean haveRecvdMajorVersion;
+ private boolean haveRecvdMinorVersion;
+ private boolean haveSentVersion;
+ private boolean haveAgreedVersion;
+ private boolean haveListOfTypes;
+ private boolean haveNumberOfTypes;
+ private boolean haveChosenType;
+ private int majorVersion, minorVersion;
+ private int chosenType;
+ private int nAvailableTypes;
+ private int[] availableTypes;
+ private int iAvailableType;
+ //private final String desc;
+
+ static LogWriter vlog = new LogWriter("CSecurityVeNCrypt");
+}
diff --git a/java/com/tigervnc/rfb/CSecurityVncAuth.java b/java/com/tigervnc/rfb/CSecurityVncAuth.java
new file mode 100644
index 00000000..405e79fa
--- /dev/null
+++ b/java/com/tigervnc/rfb/CSecurityVncAuth.java
@@ -0,0 +1,66 @@
+/* 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 com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+import com.tigervnc.vncviewer.*;
+
+public class CSecurityVncAuth extends CSecurity {
+
+ public CSecurityVncAuth() { }
+
+ private static final int vncAuthChallengeSize = 16;
+
+ public boolean processMsg(CConnection cc)
+ {
+ InStream is = cc.getInStream();
+ OutStream os = cc.getOutStream();
+
+ // Read the challenge & obtain the user's password
+ byte[] challenge = new byte[vncAuthChallengeSize];
+ is.readBytes(challenge, 0, vncAuthChallengeSize);
+ StringBuffer passwd = new StringBuffer();
+ CConn.upg.getUserPasswd(null, passwd);
+
+ // Calculate the correct response
+ byte[] key = new byte[8];
+ int pwdLen = passwd.length();
+ byte[] utf8str = new byte[pwdLen];
+ try {
+ utf8str = passwd.toString().getBytes("UTF8");
+ } catch(java.io.UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ for (int i=0; i<8; i++)
+ key[i] = i<pwdLen ? utf8str[i] : 0;
+ DesCipher des = new DesCipher(key);
+ for (int j = 0; j < vncAuthChallengeSize; j += 8)
+ des.encrypt(challenge,j,challenge,j);
+
+ // Return the response to the server
+ os.writeBytes(challenge, 0, vncAuthChallengeSize);
+ os.flush();
+ return true;
+ }
+
+ public int getType() { return Security.secTypeVncAuth; }
+ public String description() { return "No Encryption"; }
+
+ static LogWriter vlog = new LogWriter("VncAuth");
+}
diff --git a/java/com/tigervnc/rfb/Configuration.java b/java/com/tigervnc/rfb/Configuration.java
new file mode 100644
index 00000000..bc676087
--- /dev/null
+++ b/java/com/tigervnc/rfb/Configuration.java
@@ -0,0 +1,91 @@
+/* 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.
+ */
+
+//
+// Configuration - class for dealing with configuration parameters.
+//
+
+package com.tigervnc.rfb;
+
+public class Configuration {
+
+ // - Set named parameter to value
+ public static boolean setParam(String name, String value) {
+ VoidParameter param = getParam(name);
+ if (param == null) return false;
+ return param.setParam(value);
+ }
+
+ // - Set parameter to value (separated by "=")
+ public static boolean setParam(String config) {
+ boolean hyphen = false;
+ if (config.charAt(0) == '-') {
+ hyphen = true;
+ if (config.charAt(1) == '-')
+ config = config.substring(2); // allow gnu-style --<option>
+ else
+ config = config.substring(1);
+ }
+ int equal = config.indexOf('=');
+ if (equal != -1) {
+ return setParam(config.substring(0, equal), config.substring(equal+1));
+ } else if (hyphen) {
+ VoidParameter param = getParam(config);
+ if (param == null) return false;
+ return param.setParam();
+ }
+ return false;
+ }
+
+ // - Get named parameter
+ public static VoidParameter getParam(String name) {
+ VoidParameter current = head;
+ while (current != null) {
+ if (name.equalsIgnoreCase(current.getName()))
+ return current;
+ current = current.next;
+ }
+ return null;
+ }
+
+ public static String listParams() {
+ StringBuffer s = new StringBuffer();
+
+ VoidParameter current = head;
+ while (current != null) {
+ String def_str = current.getDefaultStr();
+ String desc = current.getDescription();
+ s.append(" "+current.getName()+" - "+desc+" (default="+def_str+")\n");
+ current = current.next;
+ }
+
+ return s.toString();
+ }
+
+ public static void readAppletParams(java.applet.Applet applet) {
+ VoidParameter current = head;
+ while (current != null) {
+ String str = applet.getParameter(current.getName());
+ if (str != null)
+ current.setParam(str);
+ current = current.next;
+ }
+ }
+
+ public static VoidParameter head;
+}
diff --git a/java/com/tigervnc/rfb/ConnFailedException.java b/java/com/tigervnc/rfb/ConnFailedException.java
new file mode 100644
index 00000000..d1ddcb4e
--- /dev/null
+++ b/java/com/tigervnc/rfb/ConnFailedException.java
@@ -0,0 +1,23 @@
+/* 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 com.tigervnc.rfb;
+
+public class ConnFailedException extends Exception {
+ public ConnFailedException(String s) { super(s); }
+}
diff --git a/java/com/tigervnc/rfb/ConnParams.java b/java/com/tigervnc/rfb/ConnParams.java
new file mode 100644
index 00000000..70d6114f
--- /dev/null
+++ b/java/com/tigervnc/rfb/ConnParams.java
@@ -0,0 +1,171 @@
+/* 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 com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+public class ConnParams {
+ static LogWriter vlog = new LogWriter("ConnParams");
+
+ public ConnParams() {
+ majorVersion = 0; minorVersion = 0;
+ width = 0; height = 0; useCopyRect = false;
+ supportsLocalCursor = false; supportsLocalXCursor = false;
+ supportsDesktopResize = false; supportsExtendedDesktopSize = false;
+ supportsDesktopRename = false; supportsLastRect = false;
+ supportsSetDesktopSize = false; supportsClientRedirect = false;
+ customCompressLevel = false; compressLevel = 6;
+ noJpeg = false; qualityLevel = -1;
+ name_ = null; nEncodings_ = 0; encodings_ = null;
+ currentEncoding_ = Encodings.encodingRaw; verStrPos = 0;
+ screenLayout = new ScreenSet();
+
+ setName("");
+ }
+
+ public boolean readVersion(InStream is, Boolean done)
+ {
+ if (verStrPos >= 12) return false;
+ verStr = new StringBuilder(13);
+ while (verStrPos < 12 && is.checkNoWait(1)) {
+ verStr.insert(verStrPos++,(char)is.readU8());
+ }
+
+ if (verStrPos < 12) {
+ done = Boolean.valueOf(false);
+ return true;
+ }
+ done = Boolean.valueOf(true);
+ verStr.insert(12,'0');
+ verStrPos = 0;
+ if (verStr.toString().matches("RFB \\d{3}\\.\\d{3}\\n0")) {
+ majorVersion = Integer.parseInt(verStr.substring(4,7));
+ minorVersion = Integer.parseInt(verStr.substring(8,11));
+ return true;
+ }
+ return false;
+ }
+
+ public void writeVersion(OutStream os) {
+ String str = String.format("RFB %03d.%03d\n", majorVersion, minorVersion);
+ os.writeBytes(str.getBytes(), 0, 12);
+ os.flush();
+ }
+
+ public int majorVersion;
+ public int minorVersion;
+
+ public void setVersion(int major, int minor) {
+ majorVersion = major; minorVersion = minor;
+ }
+ public boolean isVersion(int major, int minor) {
+ return majorVersion == major && minorVersion == minor;
+ }
+ public boolean beforeVersion(int major, int minor) {
+ return (majorVersion < major ||
+ (majorVersion == major && minorVersion < minor));
+ }
+ public boolean afterVersion(int major, int minor) {
+ return !beforeVersion(major,minor+1);
+ }
+
+ public int width;
+ public int height;
+ public ScreenSet screenLayout;
+
+ public PixelFormat pf() { return pf_; }
+ public void setPF(PixelFormat pf) {
+ pf_ = pf;
+ if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32) {
+ throw new Exception("setPF: not 8, 16 or 32 bpp?");
+ }
+ }
+
+ public String name() { return name_; }
+ public void setName(String name)
+ {
+ name_ = name;
+ }
+
+ public int currentEncoding() { return currentEncoding_; }
+ public int nEncodings() { return nEncodings_; }
+ public int[] encodings() { return encodings_; }
+ public void setEncodings(int nEncodings, int[] encodings)
+ {
+ if (nEncodings > nEncodings_) {
+ encodings_ = new int[nEncodings];
+ }
+ nEncodings_ = nEncodings;
+ useCopyRect = false;
+ supportsLocalCursor = false;
+ supportsDesktopResize = false;
+ customCompressLevel = false;
+ compressLevel = -1;
+ noJpeg = true;
+ qualityLevel = -1;
+ currentEncoding_ = Encodings.encodingRaw;
+
+ for (int i = nEncodings-1; i >= 0; i--) {
+ encodings_[i] = encodings[i];
+ if (encodings[i] == Encodings.encodingCopyRect)
+ useCopyRect = true;
+ else if (encodings[i] == Encodings.pseudoEncodingCursor)
+ supportsLocalCursor = true;
+ else if (encodings[i] == Encodings.pseudoEncodingDesktopSize)
+ supportsDesktopResize = true;
+ else if (encodings[i] == Encodings.pseudoEncodingClientRedirect)
+ supportsClientRedirect = true;
+ else if (encodings[i] >= Encodings.pseudoEncodingCompressLevel0 &&
+ encodings[i] <= Encodings.pseudoEncodingCompressLevel9) {
+ customCompressLevel = true;
+ compressLevel = encodings[i] - Encodings.pseudoEncodingCompressLevel0;
+ } else if (encodings[i] >= Encodings.pseudoEncodingQualityLevel0 &&
+ encodings[i] <= Encodings.pseudoEncodingQualityLevel9) {
+ noJpeg = false;
+ qualityLevel = encodings[i] - Encodings.pseudoEncodingQualityLevel0;
+ } else if (encodings[i] <= Encodings.encodingMax &&
+ Encoder.supported(encodings[i]))
+ currentEncoding_ = encodings[i];
+ }
+ }
+ public boolean useCopyRect;
+
+ public boolean supportsLocalCursor;
+ public boolean supportsLocalXCursor;
+ public boolean supportsDesktopResize;
+ public boolean supportsExtendedDesktopSize;
+ public boolean supportsDesktopRename;
+ public boolean supportsClientRedirect;
+ public boolean supportsLastRect;
+
+ public boolean supportsSetDesktopSize;
+
+ public boolean customCompressLevel;
+ public int compressLevel;
+ public boolean noJpeg;
+ public int qualityLevel;
+
+ private PixelFormat pf_;
+ private String name_;
+ private int nEncodings_;
+ private int[] encodings_;
+ private int currentEncoding_;
+ private StringBuilder verStr;
+ private int verStrPos;
+}
diff --git a/java/com/tigervnc/rfb/Cursor.java b/java/com/tigervnc/rfb/Cursor.java
new file mode 100644
index 00000000..420eb82a
--- /dev/null
+++ b/java/com/tigervnc/rfb/Cursor.java
@@ -0,0 +1,34 @@
+/* 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 com.tigervnc.rfb;
+
+import java.awt.*;
+
+public class Cursor extends ManagedPixelBuffer {
+
+ public void setSize(int w, int h) {
+ super.setSize(w, h);
+ if (mask == null || mask.length < maskLen())
+ mask = new byte[maskLen()];
+ }
+ public int maskLen() { return (width() + 7) / 8 * height(); }
+
+ public Point hotspot;
+ public byte[] mask;
+}
diff --git a/java/com/tigervnc/rfb/Decoder.java b/java/com/tigervnc/rfb/Decoder.java
new file mode 100644
index 00000000..8d42ea5e
--- /dev/null
+++ b/java/com/tigervnc/rfb/Decoder.java
@@ -0,0 +1,51 @@
+/* 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 com.tigervnc.rfb;
+
+abstract public class Decoder {
+
+ abstract public void readRect(Rect r, CMsgHandler handler);
+
+ static public boolean supported(int encoding)
+ {
+/*
+ return encoding <= Encodings.encodingMax && createFns[encoding];
+*/
+ return (encoding == Encodings.encodingRaw ||
+ encoding == Encodings.encodingRRE ||
+ encoding == Encodings.encodingHextile ||
+ encoding == Encodings.encodingTight ||
+ encoding == Encodings.encodingZRLE);
+ }
+ static public Decoder createDecoder(int encoding, CMsgReader reader) {
+/*
+ if (encoding <= Encodings.encodingMax && createFns[encoding])
+ return (createFns[encoding])(reader);
+ return 0;
+*/
+ switch(encoding) {
+ case Encodings.encodingRaw: return new RawDecoder(reader);
+ case Encodings.encodingRRE: return new RREDecoder(reader);
+ case Encodings.encodingHextile: return new HextileDecoder(reader);
+ case Encodings.encodingTight: return new TightDecoder(reader);
+ case Encodings.encodingZRLE: return new ZRLEDecoder(reader);
+ }
+ return null;
+ }
+}
diff --git a/java/com/tigervnc/rfb/DesCipher.java b/java/com/tigervnc/rfb/DesCipher.java
new file mode 100644
index 00000000..f7ae9db9
--- /dev/null
+++ b/java/com/tigervnc/rfb/DesCipher.java
@@ -0,0 +1,496 @@
+//
+// This DES class has been extracted from package Acme.Crypto for use in VNC.
+// The bytebit[] array has been reversed so that the most significant bit
+// in each byte of the key is ignored, not the least significant. Also the
+// unnecessary odd parity code has been removed.
+//
+// These changes are:
+// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+// 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.
+//
+
+// DesCipher - the DES encryption method
+//
+// The meat of this code is by Dave Zimmerman <dzimm@widget.com>, and is:
+//
+// Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
+//
+// Permission to use, copy, modify, and distribute this software
+// and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
+// without fee is hereby granted, provided that this copyright notice is kept
+// intact.
+//
+// WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
+// OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+// PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE
+// FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+// DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
+//
+// THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
+// CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
+// PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
+// NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
+// SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
+// SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
+// PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET WORKSHOP
+// SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
+// HIGH RISK ACTIVITIES.
+//
+//
+// The rest is:
+//
+// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. 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.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+//
+// Visit the ACME Labs Java page for up-to-date versions of this and other
+// fine Java utilities: http://www.acme.com/java/
+
+
+/// The DES encryption method.
+// <P>
+// 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.
+// <P>
+// Most of this code is by Dave Zimmerman <dzimm@widget.com>, and is
+// Copyright (c) 1996 Widget Workshop, Inc. See the source file for details.
+// <P>
+// <A HREF="/resources/classes/Acme/Crypto/DesCipher.java">Fetch the software.</A><BR>
+// <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
+// <P>
+// @see Des3Cipher
+// @see EncryptedOutputStream
+// @see EncryptedInputStream
+
+package com.tigervnc.rfb;
+
+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];
+ }
+ }
+ }
diff --git a/java/com/tigervnc/rfb/Encoder.java b/java/com/tigervnc/rfb/Encoder.java
new file mode 100644
index 00000000..0964f88e
--- /dev/null
+++ b/java/com/tigervnc/rfb/Encoder.java
@@ -0,0 +1,25 @@
+/* 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 com.tigervnc.rfb;
+
+public class Encoder {
+ static public boolean supported(int encoding) {
+ return false;
+ }
+}
diff --git a/java/com/tigervnc/rfb/Encodings.java b/java/com/tigervnc/rfb/Encodings.java
new file mode 100644
index 00000000..493d5488
--- /dev/null
+++ b/java/com/tigervnc/rfb/Encodings.java
@@ -0,0 +1,70 @@
+/* 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 com.tigervnc.rfb;
+
+public class Encodings {
+
+ public static final int encodingRaw = 0;
+ public static final int encodingCopyRect = 1;
+ public static final int encodingRRE = 2;
+ public static final int encodingCoRRE = 4;
+ public static final int encodingHextile = 5;
+ public static final int encodingTight = 7;
+ public static final int encodingZRLE = 16;
+
+ public static final int encodingMax = 255;
+
+ public static final int pseudoEncodingXCursor = -240;
+ public static final int pseudoEncodingCursor = -239;
+ public static final int pseudoEncodingDesktopSize = -223;
+ public static final int pseudoEncodingExtendedDesktopSize = -308;
+ public static final int pseudoEncodingDesktopName = -307;
+ public static final int pseudoEncodingClientRedirect = -311;
+
+ // TightVNC-specific
+ public static final int pseudoEncodingLastRect = -224;
+ public static final int pseudoEncodingQualityLevel0 = -32;
+ public static final int pseudoEncodingQualityLevel9 = -23;
+ public static final int pseudoEncodingCompressLevel0 = -256;
+ public static final int pseudoEncodingCompressLevel9 = -247;
+
+ public static int encodingNum(String name) {
+ if (name.equalsIgnoreCase("raw")) return encodingRaw;
+ if (name.equalsIgnoreCase("copyRect")) return encodingCopyRect;
+ if (name.equalsIgnoreCase("RRE")) return encodingRRE;
+ if (name.equalsIgnoreCase("coRRE")) return encodingCoRRE;
+ if (name.equalsIgnoreCase("hextile")) return encodingHextile;
+ if (name.equalsIgnoreCase("Tight")) return encodingTight;
+ if (name.equalsIgnoreCase("ZRLE")) return encodingZRLE;
+ return -1;
+ }
+
+ public static String encodingName(int num) {
+ switch (num) {
+ case encodingRaw: return "raw";
+ case encodingCopyRect: return "copyRect";
+ case encodingRRE: return "RRE";
+ case encodingCoRRE: return "CoRRE";
+ case encodingHextile: return "hextile";
+ case encodingTight: return "Tight";
+ case encodingZRLE: return "ZRLE";
+ default: return "[unknown encoding]";
+ }
+ }
+}
diff --git a/java/com/tigervnc/rfb/Exception.java b/java/com/tigervnc/rfb/Exception.java
new file mode 100644
index 00000000..26ac355b
--- /dev/null
+++ b/java/com/tigervnc/rfb/Exception.java
@@ -0,0 +1,23 @@
+/* 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 com.tigervnc.rfb;
+
+public class Exception extends com.tigervnc.rdr.Exception {
+ public Exception(String s) { super(s); }
+}
diff --git a/java/com/tigervnc/rfb/Hextile.java b/java/com/tigervnc/rfb/Hextile.java
new file mode 100644
index 00000000..9c05b729
--- /dev/null
+++ b/java/com/tigervnc/rfb/Hextile.java
@@ -0,0 +1,27 @@
+/* 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 com.tigervnc.rfb;
+
+public class Hextile {
+ public static final int raw = (1 << 0);
+ public static final int bgSpecified = (1 << 1);
+ public static final int fgSpecified = (1 << 2);
+ public static final int anySubrects = (1 << 3);
+ public static final int subrectsColoured = (1 << 4);
+}
diff --git a/java/com/tigervnc/rfb/HextileDecoder.java b/java/com/tigervnc/rfb/HextileDecoder.java
new file mode 100644
index 00000000..4c32b52c
--- /dev/null
+++ b/java/com/tigervnc/rfb/HextileDecoder.java
@@ -0,0 +1,101 @@
+/* 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 com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+public class HextileDecoder extends Decoder {
+
+ public HextileDecoder(CMsgReader reader_) { reader = reader_; }
+
+ public void readRect(Rect r, CMsgHandler handler) {
+ InStream is = reader.getInStream();
+ int bytesPerPixel = handler.cp.pf().bpp / 8;
+ boolean bigEndian = handler.cp.pf().bigEndian;
+
+ int[] buf = reader.getImageBuf(16 * 16 * 4);
+
+ Rect t = new Rect();
+ int bg = 0;
+ int fg = 0;
+
+ for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
+
+ t.br.y = Math.min(r.br.y, t.tl.y + 16);
+
+ for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) {
+
+ t.br.x = Math.min(r.br.x, t.tl.x + 16);
+
+ int tileType = is.readU8();
+
+ if ((tileType & Hextile.raw) != 0) {
+ is.readPixels(buf, t.area(), bytesPerPixel, bigEndian);
+ handler.imageRect(t, buf);
+ continue;
+ }
+
+ if ((tileType & Hextile.bgSpecified) != 0)
+ bg = is.readPixel(bytesPerPixel, bigEndian);
+
+ int len = t.area();
+ int ptr = 0;
+ while (len-- > 0) buf[ptr++] = bg;
+
+ if ((tileType & Hextile.fgSpecified) != 0)
+ fg = is.readPixel(bytesPerPixel, bigEndian);
+
+ if ((tileType & Hextile.anySubrects) != 0) {
+ int nSubrects = is.readU8();
+
+ for (int i = 0; i < nSubrects; i++) {
+
+ if ((tileType & Hextile.subrectsColoured) != 0)
+ fg = is.readPixel(bytesPerPixel, bigEndian);
+
+ int xy = is.readU8();
+ int wh = is.readU8();
+
+/*
+ Rect s = new Rect();
+ s.tl.x = t.tl.x + ((xy >> 4) & 15);
+ s.tl.y = t.tl.y + (xy & 15);
+ s.br.x = s.tl.x + ((wh >> 4) & 15) + 1;
+ s.br.y = s.tl.y + (wh & 15) + 1;
+*/
+ int x = ((xy >> 4) & 15);
+ int y = (xy & 15);
+ int w = ((wh >> 4) & 15) + 1;
+ int h = (wh & 15) + 1;
+ ptr = y * t.width() + x;
+ int rowAdd = t.width() - w;
+ while (h-- > 0) {
+ len = w;
+ while (len-- > 0) buf[ptr++] = fg;
+ ptr += rowAdd;
+ }
+ }
+ }
+ handler.imageRect(t, buf);
+ }
+ }
+ }
+
+ CMsgReader reader;
+}
diff --git a/java/com/tigervnc/rfb/Hostname.java b/java/com/tigervnc/rfb/Hostname.java
new file mode 100644
index 00000000..42fda537
--- /dev/null
+++ b/java/com/tigervnc/rfb/Hostname.java
@@ -0,0 +1,41 @@
+/* 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 com.tigervnc.rfb;
+
+public class Hostname {
+
+ public static String getHost(String vncServerName) {
+ int colonPos = vncServerName.indexOf(':');
+ if (colonPos == 0)
+ return "localhost";
+ if (colonPos == -1)
+ colonPos = vncServerName.length();
+ return vncServerName.substring(0, colonPos);
+ }
+
+ public static int getPort(String vncServerName) {
+ int colonPos = vncServerName.indexOf(':');
+ if (colonPos == -1 || colonPos == vncServerName.length()-1)
+ return 5900;
+ if (vncServerName.charAt(colonPos+1) == ':') {
+ return Integer.parseInt(vncServerName.substring(colonPos+2));
+ }
+ return Integer.parseInt(vncServerName.substring(colonPos+1)) + 5900;
+ }
+}
diff --git a/java/com/tigervnc/rfb/IntParameter.java b/java/com/tigervnc/rfb/IntParameter.java
new file mode 100644
index 00000000..877063e7
--- /dev/null
+++ b/java/com/tigervnc/rfb/IntParameter.java
@@ -0,0 +1,44 @@
+/* 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 com.tigervnc.rfb;
+
+public class IntParameter extends VoidParameter {
+ public IntParameter(String name_, String desc_, int v) {
+ super(name_, desc_);
+ value = v;
+ defValue = v;
+ }
+
+ public boolean setParam(String v) {
+ try {
+ value = Integer.parseInt(v);
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ return true;
+ }
+
+ public String getDefaultStr() { return Integer.toString(defValue); }
+ public String getValueStr() { return Integer.toString(value); }
+
+ public int getValue() { return value; }
+
+ protected int value;
+ protected int defValue;
+}
diff --git a/java/com/tigervnc/rfb/Keysyms.java b/java/com/tigervnc/rfb/Keysyms.java
new file mode 100644
index 00000000..6bfafeaf
--- /dev/null
+++ b/java/com/tigervnc/rfb/Keysyms.java
@@ -0,0 +1,88 @@
+/* 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.
+ */
+
+//
+// Keysyms - defines X keysyms for non-character keys. All keysyms
+// corresponding to characters should be generated by calling
+// UnicodeToKeysym.translate().
+//
+
+package com.tigervnc.rfb;
+
+public class Keysyms {
+
+ public static final int BackSpace = 0xFF08;
+ public static final int Tab = 0xFF09;
+ public static final int Linefeed = 0xFF0A;
+ public static final int Clear = 0xFF0B;
+ public static final int Return = 0xFF0D;
+ public static final int Pause = 0xFF13;
+ public static final int Scroll_Lock = 0xFF14;
+ public static final int Sys_Req = 0xFF15;
+ public static final int Escape = 0xFF1B;
+ public static final int Delete = 0xFFFF;
+
+ public static final int Home = 0xFF50;
+ public static final int Left = 0xFF51;
+ public static final int Up = 0xFF52;
+ public static final int Right = 0xFF53;
+ public static final int Down = 0xFF54;
+ public static final int Prior = 0xFF55;
+ public static final int Page_Up = 0xFF55;
+ public static final int Next = 0xFF56;
+ public static final int Page_Down = 0xFF56;
+ public static final int End = 0xFF57;
+ public static final int Begin = 0xFF58;
+
+ public static final int Select = 0xFF60;
+ public static final int Print = 0xFF61;
+ public static final int Execute = 0xFF62;
+ public static final int Insert = 0xFF63;
+ public static final int Undo = 0xFF65;
+ public static final int Redo = 0xFF66;
+ public static final int Menu = 0xFF67;
+ public static final int Find = 0xFF68;
+ public static final int Cancel = 0xFF69;
+ public static final int Help = 0xFF6A;
+ public static final int Break = 0xFF6B;
+ public static final int Mode_switch = 0xFF7E;
+ public static final int script_switch = 0xFF7E;
+ public static final int Num_Lock = 0xFF7F;
+
+ public static final int F1 = 0xFFBE;
+ public static final int F2 = 0xFFBF;
+ public static final int F3 = 0xFFC0;
+ public static final int F4 = 0xFFC1;
+ public static final int F5 = 0xFFC2;
+ public static final int F6 = 0xFFC3;
+ public static final int F7 = 0xFFC4;
+ public static final int F8 = 0xFFC5;
+ public static final int F9 = 0xFFC6;
+ public static final int F10 = 0xFFC7;
+ public static final int F11 = 0xFFC8;
+ public static final int F12 = 0xFFC9;
+
+ public static final int Shift_L = 0xFFE1;
+ public static final int Shift_R = 0xFFE2;
+ public static final int Control_L = 0xFFE3;
+ public static final int Control_R = 0xFFE4;
+ public static final int Meta_L = 0xFFE7;
+ public static final int Meta_R = 0xFFE8;
+ public static final int Alt_L = 0xFFE9;
+ public static final int Alt_R = 0xFFEA;
+}
diff --git a/java/com/tigervnc/rfb/LogWriter.java b/java/com/tigervnc/rfb/LogWriter.java
new file mode 100644
index 00000000..c5730531
--- /dev/null
+++ b/java/com/tigervnc/rfb/LogWriter.java
@@ -0,0 +1,99 @@
+/* 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 com.tigervnc.rfb;
+
+public class LogWriter {
+
+ public LogWriter(String name_) {
+ name = name_;
+ level = globalLogLevel;
+ next = log_writers;
+ log_writers = this;
+ }
+
+ public void setLevel(int level_) { level = level_; }
+
+ public void write(int level, String str) {
+ if (level <= this.level) {
+ System.err.println(name+": "+str);
+ }
+ }
+
+ public void error(String str) { write(0, str); }
+ public void status(String str) { write(10, str); }
+ public void info(String str) { write(30, str); }
+ public void debug(String str) { write(100, str); }
+
+ public static boolean setLogParams(String params) {
+ globalLogLevel = Integer.parseInt(params);
+ LogWriter current = log_writers;
+ while (current != null) {
+ current.setLevel(globalLogLevel);
+ current = current.next;
+ }
+ return true;
+// int colon = params.indexOf(':');
+// String logwriter_name = params.substring(0, colon);
+// params = params.substring(colon+1);
+// colon = params.indexOf(':');
+// String logger_name = params.substring(0, colon);
+// params = params.substring(colon+1);
+// int level = Integer.parseInt(params);
+// // XXX ignore logger name for the moment
+
+// System.err.println("setting level to "+level);
+// System.err.println("logwriters is "+log_writers);
+// if (logwriter_name.equals("*")) {
+// LogWriter current = log_writers;
+// while (current != null) {
+// //current.setLog(logger);
+// System.err.println("setting level of "+current.name+" to "+level);
+// current.setLevel(level);
+// current = current.next;
+// }
+// return true;
+// }
+
+// LogWriter logwriter = getLogWriter(logwriter_name);
+// if (logwriter == null) {
+// System.err.println("no logwriter found: "+logwriter_name);
+// return false;
+// }
+
+// //logwriter.setLog(logger);
+// logwriter.setLevel(level);
+// return true;
+ }
+
+
+ static LogWriter getLogWriter(String name) {
+ LogWriter current = log_writers;
+ while (current != null) {
+ if (name.equalsIgnoreCase(current.name)) return current;
+ current = current.next;
+ }
+ return null;
+ }
+
+ String name;
+ int level;
+ LogWriter next;
+ static LogWriter log_writers;
+ static int globalLogLevel = 30;
+}
diff --git a/java/com/tigervnc/rfb/ManagedPixelBuffer.java b/java/com/tigervnc/rfb/ManagedPixelBuffer.java
new file mode 100644
index 00000000..46b5acf7
--- /dev/null
+++ b/java/com/tigervnc/rfb/ManagedPixelBuffer.java
@@ -0,0 +1,38 @@
+/* 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 com.tigervnc.rfb;
+
+public class ManagedPixelBuffer extends PixelBuffer {
+ public void setSize(int w, int h) {
+ width_ = w;
+ height_ = h;
+ checkDataSize();
+ }
+ public void setPF(PixelFormat pf) {
+ super.setPF(pf);
+ checkDataSize();
+ }
+
+ public int dataLen() { return area(); }
+
+ final void checkDataSize() {
+ if (data == null || data.length < dataLen())
+ data = new int[dataLen()];
+ }
+}
diff --git a/java/com/tigervnc/rfb/MsgTypes.java b/java/com/tigervnc/rfb/MsgTypes.java
new file mode 100644
index 00000000..a009b396
--- /dev/null
+++ b/java/com/tigervnc/rfb/MsgTypes.java
@@ -0,0 +1,40 @@
+/* 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 com.tigervnc.rfb;
+
+public class MsgTypes {
+ // server to client
+
+ public static final int msgTypeFramebufferUpdate = 0;
+ public static final int msgTypeSetColourMapEntries = 1;
+ public static final int msgTypeBell = 2;
+ public static final int msgTypeServerCutText = 3;
+
+ // client to server
+
+ public static final int msgTypeSetPixelFormat = 0;
+ public static final int msgTypeFixColourMapEntries = 1;
+ public static final int msgTypeSetEncodings = 2;
+ public static final int msgTypeFramebufferUpdateRequest = 3;
+ public static final int msgTypeKeyEvent = 4;
+ public static final int msgTypePointerEvent = 5;
+ public static final int msgTypeClientCutText = 6;
+
+ public static final int msgTypeSetDesktopSize = 251;
+}
diff --git a/java/com/tigervnc/rfb/PixelBuffer.java b/java/com/tigervnc/rfb/PixelBuffer.java
new file mode 100644
index 00000000..f87fead8
--- /dev/null
+++ b/java/com/tigervnc/rfb/PixelBuffer.java
@@ -0,0 +1,116 @@
+/* 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.
+ */
+
+//
+// PixelBuffer - note that this code is only written for the 8, 16, and 32 bpp cases at the
+// moment.
+//
+
+package com.tigervnc.rfb;
+
+import java.awt.image.*;
+
+public class PixelBuffer {
+
+ public PixelBuffer() {
+ setPF(new PixelFormat());
+ }
+
+ public void setPF(PixelFormat pf) {
+ if (!(pf.bpp == 32) && !(pf.bpp == 16) && !(pf.bpp == 8))
+ throw new Exception("Internal error: bpp must be 8, 16, or 32 in PixelBuffer ("+pf.bpp+")");
+ format = pf;
+ switch (pf.depth) {
+ case 8:
+ //cm = new IndexColorModel(8, 256, new byte[256], new byte[256], new byte[256]);
+ cm = new DirectColorModel(8, 7, (7 << 3), (3 << 6));
+ break;
+ case 16:
+ cm = new DirectColorModel(32, 0xF800, 0x07C0, 0x003E, (0xff << 24));
+ break;
+ case 24:
+ cm = new DirectColorModel(32, (0xff << 16), (0xff << 8), 0xff, (0xff << 24));
+ break;
+ }
+ }
+ public PixelFormat getPF() { return format; }
+
+ public final int width() { return width_; }
+ public final int height() { return height_; }
+ public final int area() { return width_ * height_; }
+
+ public void fillRect(int x, int y, int w, int h, int pix) {
+ for (int ry = y; ry < y + h; ry++)
+ for (int rx = x; rx < x + w; rx++)
+ data[ry * width_ + rx] = pix;
+ }
+
+ public void imageRect(int x, int y, int w, int h, int[] pix) {
+ for (int j = 0; j < h; j++)
+ System.arraycopy(pix, (w * j), data, width_ * (y + j) + x, w);
+ }
+
+ public void copyRect(int x, int y, int w, int h, int srcX, int srcY) {
+ int dest = (width_ * y) + x;
+ int src = (width_ * srcY) + srcX;
+ int inc = width_;
+
+ if (y > srcY) {
+ src += (h-1) * inc;
+ dest += (h-1) * inc;
+ inc = -inc;
+ }
+ int destEnd = dest + h * inc;
+
+ while (dest != destEnd) {
+ System.arraycopy(data, src, data, dest, w);
+ src += inc;
+ dest += inc;
+ }
+ }
+
+ public void maskRect(int x, int y, int w, int h, int[] pix, byte[] mask) {
+ int maskBytesPerRow = (w + 7) / 8;
+
+ for (int j = 0; j < h; j++) {
+ int cy = y + j;
+
+ if (cy < 0 || cy >= height_)
+ continue;
+
+ for (int i = 0; i < w; i++) {
+ int cx = x + i;
+
+ if (cx < 0 || cx >= width_)
+ continue;
+
+ int byte_ = j * maskBytesPerRow + i / 8;
+ int bit = 7 - i % 8;
+
+ if ((mask[byte_] & (1 << bit)) != 0)
+ data[cy * width_ + cx] = pix[j * w + i];
+ }
+ }
+ }
+
+ public int[] data;
+ public ColorModel cm;
+
+ protected PixelFormat format;
+ protected int width_, height_;
+}
diff --git a/java/com/tigervnc/rfb/PixelFormat.java b/java/com/tigervnc/rfb/PixelFormat.java
new file mode 100644
index 00000000..a8ab5f11
--- /dev/null
+++ b/java/com/tigervnc/rfb/PixelFormat.java
@@ -0,0 +1,163 @@
+/* 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.
+ */
+
+//
+// PixelFormat
+//
+
+package com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+public class PixelFormat {
+
+ public PixelFormat(int b, int d, boolean e, boolean t) {
+ bpp = b;
+ depth = d;
+ bigEndian = e;
+ trueColour = t;
+ }
+ public PixelFormat(int b, int d, boolean e, boolean t,
+ int rm, int gm, int bm, int rs, int gs, int bs) {
+ this(b, d, e, t);
+ redMax = rm;
+ greenMax = gm;
+ blueMax = bm;
+ redShift = rs;
+ greenShift = gs;
+ blueShift = bs;
+ }
+ public PixelFormat() { this(8,8,false,true,7,7,3,0,3,6); }
+
+ public boolean equal(PixelFormat x) {
+ return (bpp == x.bpp &&
+ depth == x.depth &&
+ (bigEndian == x.bigEndian || bpp == 8) &&
+ trueColour == x.trueColour &&
+ (!trueColour || (redMax == x.redMax &&
+ greenMax == x.greenMax &&
+ blueMax == x.blueMax &&
+ redShift == x.redShift &&
+ greenShift == x.greenShift &&
+ blueShift == x.blueShift)));
+ }
+
+ public void read(InStream is) {
+ bpp = is.readU8();
+ depth = is.readU8();
+ bigEndian = is.readU8()!=0;
+ trueColour = is.readU8()!=0;
+ redMax = is.readU16();
+ greenMax = is.readU16();
+ blueMax = is.readU16();
+ redShift = is.readU8();
+ greenShift = is.readU8();
+ blueShift = is.readU8();
+ is.skip(3);
+ }
+
+ public void write(OutStream os) {
+ os.writeU8(bpp);
+ os.writeU8(depth);
+ os.writeU8(bigEndian?1:0);
+ os.writeU8(trueColour?1:0);
+ os.writeU16(redMax);
+ os.writeU16(greenMax);
+ os.writeU16(blueMax);
+ os.writeU8(redShift);
+ os.writeU8(greenShift);
+ os.writeU8(blueShift);
+ os.pad(3);
+ }
+
+ public final boolean is888() {
+ if(!trueColour)
+ return false;
+ if(bpp != 32)
+ return false;
+ if(depth != 24)
+ return false;
+ if(redMax != 255)
+ return false;
+ if(greenMax != 255)
+ return false;
+ if(blueMax != 255)
+ return false;
+
+ return true;
+ }
+
+ public void bufferFromRGB(int dst, byte[] src) {
+ if (bigEndian) {
+ dst =
+ (src[0] & 0xFF) << 16 | (src[1] & 0xFF) << 8 | (src[2] & 0xFF) | 0xFF << 24;
+ } else {
+ dst =
+ (src[2] & 0xFF) << 16 | (src[1] & 0xFF) << 8 | (src[0] & 0xFF) | 0xFF << 24;
+ }
+ }
+
+ public String print() {
+ StringBuffer s = new StringBuffer();
+ s.append("depth "+depth+" ("+bpp+"bpp)");
+ if (bpp != 8) {
+ if (bigEndian)
+ s.append(" big-endian");
+ else
+ s.append(" little-endian");
+ }
+
+ if (!trueColour) {
+ s.append(" colour-map");
+ return s.toString();
+ }
+
+ if (blueShift == 0 && greenShift > blueShift && redShift > greenShift &&
+ blueMax == (1 << greenShift) - 1 &&
+ greenMax == (1 << (redShift-greenShift)) - 1 &&
+ redMax == (1 << (depth-redShift)) - 1)
+ {
+ s.append(" rgb"+(depth-redShift)+(redShift-greenShift)+greenShift);
+ return s.toString();
+ }
+
+ if (redShift == 0 && greenShift > redShift && blueShift > greenShift &&
+ redMax == (1 << greenShift) - 1 &&
+ greenMax == (1 << (blueShift-greenShift)) - 1 &&
+ blueMax == (1 << (depth-blueShift)) - 1)
+ {
+ s.append(" bgr"+(depth-blueShift)+(blueShift-greenShift)+greenShift);
+ return s.toString();
+ }
+
+ s.append(" rgb max "+redMax+","+greenMax+","+blueMax+" shift "+redShift+
+ ","+greenShift+","+blueShift);
+ return s.toString();
+ }
+
+ public int bpp;
+ public int depth;
+ public boolean bigEndian;
+ public boolean trueColour;
+ public int redMax;
+ public int greenMax;
+ public int blueMax;
+ public int redShift;
+ public int greenShift;
+ public int blueShift;
+}
diff --git a/java/com/tigervnc/rfb/Point.java b/java/com/tigervnc/rfb/Point.java
new file mode 100644
index 00000000..25de8c20
--- /dev/null
+++ b/java/com/tigervnc/rfb/Point.java
@@ -0,0 +1,40 @@
+/* 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 com.tigervnc.rfb;
+
+public class Point {
+
+ // Point
+ //
+ // Represents a point in 2D space, by X and Y coordinates.
+ // Can also be used to represent a delta, or offset, between
+ // two Points.
+ // Functions are provided to allow Points to be compared for
+ // equality and translated by a supplied offset.
+ // Functions are also provided to negate offset Points.
+
+ public Point() {x=0; y=0;}
+ public Point(int x_, int y_) { x=x_; y=y_;}
+ public final Point negate() {return new Point(-x, -y);}
+ public final boolean equals(Point p) {return (x==p.x && y==p.y);}
+ public final Point translate(Point p) {return new Point(x+p.x, y+p.y);}
+ public final Point subtract(Point p) {return new Point(x-p.x, y-p.y);}
+ public int x, y;
+
+}
diff --git a/java/com/tigervnc/rfb/RREDecoder.java b/java/com/tigervnc/rfb/RREDecoder.java
new file mode 100644
index 00000000..e0ff5cfe
--- /dev/null
+++ b/java/com/tigervnc/rfb/RREDecoder.java
@@ -0,0 +1,46 @@
+/* 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 com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+public class RREDecoder extends Decoder {
+
+ public RREDecoder(CMsgReader reader_) { reader = reader_; }
+
+ public void readRect(Rect r, CMsgHandler handler) {
+ InStream is = reader.getInStream();
+ int bytesPerPixel = handler.cp.pf().bpp / 8;
+ boolean bigEndian = handler.cp.pf().bigEndian;
+ int nSubrects = is.readU32();
+ int bg = is.readPixel(bytesPerPixel, bigEndian);
+ handler.fillRect(r, bg);
+
+ for (int i = 0; i < nSubrects; i++) {
+ int pix = is.readPixel(bytesPerPixel, bigEndian);
+ int x = is.readU16();
+ int y = is.readU16();
+ int w = is.readU16();
+ int h = is.readU16();
+ handler.fillRect(new Rect(r.tl.x+x, r.tl.y+y, r.tl.x+x+w, r.tl.y+y+h), pix);
+ }
+ }
+
+ CMsgReader reader;
+}
diff --git a/java/com/tigervnc/rfb/RawDecoder.java b/java/com/tigervnc/rfb/RawDecoder.java
new file mode 100644
index 00000000..79db8260
--- /dev/null
+++ b/java/com/tigervnc/rfb/RawDecoder.java
@@ -0,0 +1,45 @@
+/* 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 com.tigervnc.rfb;
+
+public class RawDecoder extends Decoder {
+
+ public RawDecoder(CMsgReader reader_) { reader = reader_; }
+
+ public void readRect(Rect r, CMsgHandler handler) {
+ int x = r.tl.x;
+ int y = r.tl.y;
+ int w = r.width();
+ int h = r.height();
+ int[] imageBuf = reader.getImageBuf(w * h);
+ int nPixels = imageBuf.length / (reader.bpp() / 8);
+ int bytesPerRow = w * (reader.bpp() / 8);
+ while (h > 0) {
+ int nRows = nPixels / w;
+ if (nRows > h) nRows = h;
+ reader.is.readPixels(imageBuf, w * h, (reader.bpp() / 8), handler.cp.pf().bigEndian);
+ handler.imageRect(new Rect(x, y, x+w, y+nRows), imageBuf);
+ h -= nRows;
+ y += nRows;
+ }
+ }
+
+ CMsgReader reader;
+ static LogWriter vlog = new LogWriter("RawDecoder");
+}
diff --git a/java/com/tigervnc/rfb/Rect.java b/java/com/tigervnc/rfb/Rect.java
new file mode 100644
index 00000000..fab4f5dd
--- /dev/null
+++ b/java/com/tigervnc/rfb/Rect.java
@@ -0,0 +1,89 @@
+/* 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 com.tigervnc.rfb;
+
+public class Rect {
+
+ // Rect
+ //
+ // Represents a rectangular region defined by its top-left (tl)
+ // and bottom-right (br) Points.
+ // Rects may be compared for equality, checked to determine whether
+ // or not they are empty, cleared (made empty), or intersected with
+ // one another. The bounding rectangle of two existing Rects
+ // may be calculated, as may the area of a Rect.
+ // Rects may also be translated, in the same way as Points, by
+ // an offset specified in a Point structure.
+
+ public Rect() {
+ tl=new Point(0,0);
+ br=new Point(0,0);
+ }
+ public Rect(Point tl_, Point br_) {
+ tl=new Point(tl_.x, tl_.y);
+ br=new Point(br_.x,br_.y);
+ }
+ public Rect(int x1, int y1, int x2, int y2) {
+ tl=new Point(x1, y1);
+ br=new Point(x2, y2);
+ }
+ public final void setXYWH(int x, int y, int w, int h) {
+ tl.x = x; tl.y = y; br.x = x+w; br.y = y+h;
+ }
+ public final Rect intersect(Rect r) {
+ Rect result = new Rect();
+ result.tl.x = Math.max(tl.x, r.tl.x);
+ result.tl.y = Math.max(tl.y, r.tl.y);
+ result.br.x = Math.max(Math.min(br.x, r.br.x), result.tl.x);
+ result.br.y = Math.max(Math.min(br.y, r.br.y), result.tl.y);
+ return result;
+ }
+ public final Rect union_boundary(Rect r) {
+ if (r.is_empty()) return this;
+ if (is_empty()) return r;
+ Rect result = new Rect();
+ result.tl.x = Math.min(tl.x, r.tl.x);
+ result.tl.y = Math.min(tl.y, r.tl.y);
+ result.br.x = Math.max(br.x, r.br.x);
+ result.br.y = Math.max(br.y, r.br.y);
+ return result;
+ }
+ public final Rect translate(Point p) {
+ return new Rect(tl.translate(p), br.translate(p));
+ }
+ public final boolean equals(Rect r) {return r.tl.equals(tl) && r.br.equals(br);}
+ public final boolean is_empty() {return (tl.x >= br.x) || (tl.y >= br.y);}
+ public final void clear() {tl = new Point(); br = new Point();}
+ public final boolean enclosed_by(Rect r) {
+ return (tl.x>=r.tl.x) && (tl.y>=r.tl.y) && (br.x<=r.br.x) && (br.y<=r.br.y);
+ }
+ public final boolean overlaps(Rect r) {
+ return tl.x < r.br.x && tl.y < r.br.y && br.x > r.tl.x && br.y > r.tl.y;
+ }
+ public final int area() {return is_empty() ? 0 : (br.x-tl.x)*(br.y-tl.y);}
+ public final Point dimensions() {return new Point(width(), height());}
+ public final int width() {return br.x-tl.x;}
+ public final int height() {return br.y-tl.y;}
+ public final boolean contains(Point p) {
+ return (tl.x<=p.x) && (tl.y<=p.y) && (br.x>p.x) && (br.y>p.y);
+ }
+ public Point tl;
+ public Point br;
+
+}
diff --git a/java/com/tigervnc/rfb/Screen.java b/java/com/tigervnc/rfb/Screen.java
new file mode 100644
index 00000000..90b22b6d
--- /dev/null
+++ b/java/com/tigervnc/rfb/Screen.java
@@ -0,0 +1,48 @@
+/* Copyright 2009 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+// Represents a single RFB virtual screen, which includes
+// coordinates, an id and flags.
+
+package com.tigervnc.rfb;
+
+public class Screen {
+
+ public Screen() { id=0; flags=0; dimensions = new Rect(); }
+
+ public Screen(int id_, int x_, int y_, int w_, int h_, int flags_) {
+ id = id_;
+ dimensions = new Rect(x_, y_, x_+w_, y_+h_);
+ flags = flags_;
+ }
+
+ public final static boolean operator(Screen r) {
+ if (id != r.id)
+ return false;
+ if (!dimensions.equals(r.dimensions))
+ return false;
+ if (flags != r.flags)
+ return false;
+ return true;
+ }
+
+ public static int id;
+ public static Rect dimensions;
+ public static int flags;
+
+}
diff --git a/java/com/tigervnc/rfb/ScreenSet.java b/java/com/tigervnc/rfb/ScreenSet.java
new file mode 100644
index 00000000..071282ff
--- /dev/null
+++ b/java/com/tigervnc/rfb/ScreenSet.java
@@ -0,0 +1,89 @@
+/* Copyright 2009 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+// Management class for the RFB virtual screens
+
+package com.tigervnc.rfb;
+
+import java.util.*;
+
+public class ScreenSet {
+
+ // Represents a complete screen configuration, excluding framebuffer
+ // dimensions.
+
+ public ScreenSet() {
+ screens = new ArrayList<Screen>();
+ }
+
+ public static final int num_screens() { return screens.size(); }
+
+ public static final void add_screen(Screen screen) { screens.add(screen); }
+ public static final void remove_screen(int id) {
+ for (Iterator iter = screens.iterator(); iter.hasNext(); ) {
+ Screen refScreen = (Screen)iter.next();
+ if (refScreen.id == id)
+ iter.remove();
+ }
+ }
+
+ public static final boolean validate(int fb_width, int fb_height) {
+ List<Integer> seen_ids = new ArrayList<Integer>();
+ Rect fb_rect = new Rect();
+
+ if (screens.isEmpty())
+ return false;
+ if (num_screens() > 255)
+ return false;
+
+ fb_rect.setXYWH(0, 0, fb_width, fb_height);
+
+ for (Iterator iter = screens.iterator(); iter.hasNext(); ) {
+ Screen refScreen = (Screen)iter.next();
+ if (refScreen.dimensions.is_empty())
+ return false;
+ if (!refScreen.dimensions.enclosed_by(fb_rect))
+ return false;
+ //if (seen_ids.lastIndexOf(refScreen.id) != seen_ids.get(-1))
+ // return false;
+ seen_ids.add(refScreen.id);
+ }
+
+ return true;
+ }
+
+ public final void debug_print() {
+ for (Iterator iter = screens.iterator(); iter.hasNext(); ) {
+ Screen refScreen = (Screen)iter.next();
+ vlog.error(" "+refScreen.id+" (0x"+refScreen.id+"): "+
+ refScreen.dimensions.width()+"x"+refScreen.dimensions.height()+
+ "+"+refScreen.dimensions.tl.x+"+"+refScreen.dimensions.tl.y+
+ " (flags 0x"+refScreen.flags+")");
+ }
+ }
+
+ // FIXME: List order shouldn't matter
+ //inline bool operator(const ScreenSet& r) const { return screens == r.screens; }
+ //inline bool operator(const ScreenSet& r) const { return screens != r.screens; }
+
+ public static List<Screen> screens;
+
+ static LogWriter vlog = new LogWriter("ScreenSet");
+
+}
+
diff --git a/java/com/tigervnc/rfb/Security.java b/java/com/tigervnc/rfb/Security.java
new file mode 100644
index 00000000..379851d8
--- /dev/null
+++ b/java/com/tigervnc/rfb/Security.java
@@ -0,0 +1,195 @@
+/* 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.
+ */
+
+//
+// SecTypes.java - constants for the various security types.
+//
+
+package com.tigervnc.rfb;
+import java.util.*;
+
+public class Security {
+
+ public static final int secTypeInvalid = 0;
+ public static final int secTypeNone = 1;
+ public static final int secTypeVncAuth = 2;
+
+ public static final int secTypeRA2 = 5;
+ public static final int secTypeRA2ne = 6;
+
+ public static final int secTypeSSPI = 7;
+ public static final int secTypeSSPIne = 8;
+
+ public static final int secTypeTight = 16;
+ public static final int secTypeUltra = 17;
+ public static final int secTypeTLS = 18;
+ public static final int secTypeVeNCrypt = 19;
+
+ /* VeNCrypt subtypes */
+ public static final int secTypePlain = 256;
+ public static final int secTypeTLSNone = 257;
+ public static final int secTypeTLSVnc = 258;
+ public static final int secTypeTLSPlain = 259;
+ public static final int secTypeX509None = 260;
+ public static final int secTypeX509Vnc = 261;
+ public static final int secTypeX509Plain = 262;
+ public static final int secTypeIdent = 265;
+ public static final int secTypeTLSIdent = 266;
+ public static final int secTypeX509Ident = 267;
+
+ // result types
+
+ public static final int secResultOK = 0;
+ public static final int secResultFailed = 1;
+ public static final int secResultTooMany = 2; // deprecated
+
+ public Security(StringParameter secTypes)
+ {
+ String secTypesStr;
+
+ secTypesStr = secTypes.getData();
+ enabledSecTypes = parseSecTypes(secTypesStr);
+
+ secTypesStr = null;
+ }
+
+ public static List<Integer> enabledSecTypes = new ArrayList<Integer>();
+
+ public static final List<Integer> GetEnabledSecTypes()
+ {
+ List<Integer> result = new ArrayList<Integer>();
+
+ result.add(secTypeVeNCrypt);
+ for (Iterator i = enabledSecTypes.iterator(); i.hasNext(); ) {
+ int refType = (Integer)i.next();
+ if (refType < 0x100)
+ result.add(refType);
+ }
+
+ return (result);
+ }
+
+ public static final List<Integer> GetEnabledExtSecTypes()
+ {
+ List<Integer> result = new ArrayList<Integer>();
+
+ for (Iterator i = enabledSecTypes.iterator(); i.hasNext(); ) {
+ int refType = (Integer)i.next();
+ if (refType != secTypeVeNCrypt) /* Do not include VeNCrypt to avoid loops */
+ result.add(refType);
+ }
+
+ return (result);
+ }
+
+ public static final void EnableSecType(int secType)
+ {
+
+ for (Iterator i = enabledSecTypes.iterator(); i.hasNext(); )
+ if ((Integer)i.next() == secType)
+ return;
+
+ enabledSecTypes.add(secType);
+ }
+
+ public boolean IsSupported(int secType)
+ {
+ Iterator i;
+
+ for (i = enabledSecTypes.iterator(); i.hasNext(); )
+ if ((Integer)i.next() == secType)
+ return true;
+ if (secType == secTypeVeNCrypt)
+ return true;
+
+ return false;
+ }
+
+ public static void DisableSecType(int secType) { enabledSecTypes.remove((Object)secType); }
+
+ public static int secTypeNum(String name) {
+ if (name.equalsIgnoreCase("None")) return secTypeNone;
+ if (name.equalsIgnoreCase("VncAuth")) return secTypeVncAuth;
+ if (name.equalsIgnoreCase("Tight")) return secTypeTight;
+ if (name.equalsIgnoreCase("RA2")) return secTypeRA2;
+ if (name.equalsIgnoreCase("RA2ne")) return secTypeRA2ne;
+ if (name.equalsIgnoreCase("SSPI")) return secTypeSSPI;
+ if (name.equalsIgnoreCase("SSPIne")) return secTypeSSPIne;
+ //if (name.equalsIgnoreCase("ultra")) return secTypeUltra;
+ //if (name.equalsIgnoreCase("TLS")) return secTypeTLS;
+ if (name.equalsIgnoreCase("VeNCrypt")) return secTypeVeNCrypt;
+
+ /* VeNCrypt subtypes */
+ if (name.equalsIgnoreCase("Plain")) return secTypePlain;
+ if (name.equalsIgnoreCase("Ident")) return secTypeIdent;
+ if (name.equalsIgnoreCase("TLSNone")) return secTypeTLSNone;
+ if (name.equalsIgnoreCase("TLSVnc")) return secTypeTLSVnc;
+ if (name.equalsIgnoreCase("TLSPlain")) return secTypeTLSPlain;
+ if (name.equalsIgnoreCase("TLSIdent")) return secTypeTLSIdent;
+ if (name.equalsIgnoreCase("X509None")) return secTypeX509None;
+ if (name.equalsIgnoreCase("X509Vnc")) return secTypeX509Vnc;
+ if (name.equalsIgnoreCase("X509Plain")) return secTypeX509Plain;
+ if (name.equalsIgnoreCase("X509Ident")) return secTypeX509Ident;
+
+ return secTypeInvalid;
+ }
+
+ public static String secTypeName(int num) {
+ switch (num) {
+ case secTypeNone: return "None";
+ case secTypeVncAuth: return "VncAuth";
+ case secTypeTight: return "Tight";
+ case secTypeRA2: return "RA2";
+ case secTypeRA2ne: return "RA2ne";
+ case secTypeSSPI: return "SSPI";
+ case secTypeSSPIne: return "SSPIne";
+ //case secTypeUltra: return "Ultra";
+ //case secTypeTLS: return "TLS";
+ case secTypeVeNCrypt: return "VeNCrypt";
+
+ /* VeNCrypt subtypes */
+ case secTypePlain: return "Plain";
+ case secTypeIdent: return "Ident";
+ case secTypeTLSNone: return "TLSNone";
+ case secTypeTLSVnc: return "TLSVnc";
+ case secTypeTLSPlain: return "TLSPlain";
+ case secTypeTLSIdent: return "TLSIdent";
+ case secTypeX509None: return "X509None";
+ case secTypeX509Vnc: return "X509Vnc";
+ case secTypeX509Plain: return "X509Plain";
+ case secTypeX509Ident: return "X509Ident";
+ default: return "[unknown secType]";
+ }
+ }
+
+ public final static List<Integer> parseSecTypes(String types_)
+ {
+ List<Integer> result = new ArrayList<Integer>();
+ String[] types = types_.split(",");
+ for (int i = 0; i < types.length; i++) {
+ int typeNum = secTypeNum(types[i]);
+ if (typeNum != secTypeInvalid)
+ result.add(typeNum);
+ }
+ return (result);
+ }
+
+ public final void SetSecTypes(List<Integer> secTypes) { enabledSecTypes = secTypes; }
+
+ static LogWriter vlog = new LogWriter("Security");
+}
diff --git a/java/com/tigervnc/rfb/SecurityClient.java b/java/com/tigervnc/rfb/SecurityClient.java
new file mode 100644
index 00000000..a8abd9e1
--- /dev/null
+++ b/java/com/tigervnc/rfb/SecurityClient.java
@@ -0,0 +1,85 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright (C) 2010 TigerVNC Team
+ *
+ * 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 com.tigervnc.rfb;
+
+import com.tigervnc.vncviewer.CConn;
+
+public class SecurityClient extends Security {
+
+ public SecurityClient() { super(secTypes); }
+
+ public CSecurity GetCSecurity(int secType)
+ {
+ assert (CConn.upg != null); /* (upg == null) means bug in the viewer */
+ assert (msg != null);
+
+ if (!IsSupported(secType))
+ throw new Exception("Security type not supported");
+
+ switch (secType) {
+ case Security.secTypeNone: return (new CSecurityNone());
+ case Security.secTypeVncAuth: return (new CSecurityVncAuth());
+ case Security.secTypeVeNCrypt: return (new CSecurityVeNCrypt(this));
+ case Security.secTypePlain: return (new CSecurityPlain());
+ case Security.secTypeIdent: return (new CSecurityIdent());
+ case Security.secTypeTLSNone:
+ return (new CSecurityStack(secTypeTLSNone, "TLS with no password",
+ new CSecurityTLS(true), null));
+ case Security.secTypeTLSVnc:
+ return (new CSecurityStack(secTypeTLSVnc, "TLS with VNCAuth",
+ new CSecurityTLS(true), new CSecurityVncAuth()));
+ case Security.secTypeTLSPlain:
+ return (new CSecurityStack(secTypeTLSPlain, "TLS with Username/Password",
+ new CSecurityTLS(true), new CSecurityPlain()));
+ case Security.secTypeTLSIdent:
+ return (new CSecurityStack(secTypeTLSIdent, "TLS with username only",
+ new CSecurityTLS(true), new CSecurityIdent()));
+ case Security.secTypeX509None:
+ return (new CSecurityStack(secTypeX509None, "X509 with no password",
+ new CSecurityTLS(false), null));
+ case Security.secTypeX509Vnc:
+ return (new CSecurityStack(secTypeX509Vnc, "X509 with VNCAuth",
+ new CSecurityTLS(false), new CSecurityVncAuth()));
+ case Security.secTypeX509Plain:
+ return (new CSecurityStack(secTypeX509Plain, "X509 with Username/Password",
+ new CSecurityTLS(false), new CSecurityPlain()));
+ case Security.secTypeX509Ident:
+ return (new CSecurityStack(secTypeX509Ident, "X509 with username only",
+ new CSecurityTLS(false), new CSecurityIdent()));
+ default:
+ throw new Exception("Security type not supported");
+ }
+
+ }
+
+ public static void setDefaults()
+ {
+ CSecurityTLS.setDefaults();
+ }
+
+ //UserPasswdGetter upg = null;
+ String msg = null;
+
+ static StringParameter secTypes
+ = new StringParameter("SecurityTypes",
+ "Specify which security scheme to use (None, VncAuth)",
+ "Ident,TLSIdent,X509Ident,X509Plain,TLSPlain,X509Vnc,TLSVnc,X509None,TLSNone,VncAuth,None");
+
+}
diff --git a/java/com/tigervnc/rfb/StringParameter.java b/java/com/tigervnc/rfb/StringParameter.java
new file mode 100644
index 00000000..d7fd1a51
--- /dev/null
+++ b/java/com/tigervnc/rfb/StringParameter.java
@@ -0,0 +1,46 @@
+/* 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 com.tigervnc.rfb;
+
+public class StringParameter extends VoidParameter {
+ public StringParameter(String name_, String desc_, String v) {
+ super(name_, desc_);
+ value = v;
+ defValue = v;
+ }
+
+ public boolean setParam(String v) {
+ value = v;
+ return value != null;
+ }
+
+ public boolean setDefaultStr(String v) {
+ value = defValue = v;
+ return defValue != null;
+ }
+
+ public String getDefaultStr() { return defValue; }
+ public String getValueStr() { return value; }
+
+ public String getValue() { return value; }
+ public String getData() { return value; }
+
+ protected String value;
+ protected String defValue;
+}
diff --git a/java/com/tigervnc/rfb/TightDecoder.java b/java/com/tigervnc/rfb/TightDecoder.java
new file mode 100644
index 00000000..5cce3a93
--- /dev/null
+++ b/java/com/tigervnc/rfb/TightDecoder.java
@@ -0,0 +1,426 @@
+/* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
+ * Copyright 2004-2005 Cendio AB.
+ *
+ * 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 com.tigervnc.rfb;
+
+import com.tigervnc.rdr.InStream;
+import com.tigervnc.rdr.ZlibInStream;
+import java.awt.image.PixelGrabber;
+import java.awt.Image;
+import java.util.ArrayList;
+
+public class TightDecoder extends Decoder {
+
+ final static int TIGHT_MAX_WIDTH = 2048;
+
+ // Compression control
+ final static int rfbTightExplicitFilter = 0x04;
+ final static int rfbTightFill = 0x08;
+ final static int rfbTightJpeg = 0x09;
+ final static int rfbTightMaxSubencoding = 0x09;
+
+ // Filters to improve compression efficiency
+ final static int rfbTightFilterCopy = 0x00;
+ final static int rfbTightFilterPalette = 0x01;
+ final static int rfbTightFilterGradient = 0x02;
+ final static int rfbTightMinToCompress = 12;
+
+ public TightDecoder(CMsgReader reader_) {
+ reader = reader_;
+ zis = new ZlibInStream[4];
+ for (int i = 0; i < 4; i++)
+ zis[i] = new ZlibInStream();
+ }
+
+ public void readRect(Rect r, CMsgHandler handler)
+ {
+ InStream is = reader.getInStream();
+ int[] buf = reader.getImageBuf(r.width() * r.height());
+ boolean cutZeros = false;
+ PixelFormat myFormat = handler.cp.pf();
+ int bpp = handler.cp.pf().bpp;
+ if (bpp == 32) {
+ if (myFormat.is888()) {
+ cutZeros = true;
+ }
+ }
+
+ int comp_ctl = is.readU8();
+
+ int bytesPerPixel = handler.cp.pf().bpp / 8;
+ boolean bigEndian = handler.cp.pf().bigEndian;
+
+ // Flush zlib streams if we are told by the server to do so.
+ for (int i = 0; i < 4; i++) {
+ if ((comp_ctl & 1) != 0) {
+ zis[i].reset();
+ }
+ comp_ctl >>= 1;
+ }
+
+ // "Fill" compression type.
+ if (comp_ctl == rfbTightFill) {
+ int pix;
+ if (cutZeros) {
+ byte[] elem = new byte[3];
+ is.readBytes(elem, 0, 3);
+ if (bigEndian) {
+ pix =
+ (elem[2] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[0] & 0xFF) | 0xFF << 24;
+ } else {
+ pix =
+ (elem[0] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[2] & 0xFF) | 0xFF << 24;
+ }
+ } else {
+ pix = (bpp == 8) ? is.readOpaque8() : is.readOpaque24B();
+ }
+ handler.fillRect(r, pix);
+ return;
+ }
+
+ // "JPEG" compression type.
+ if (comp_ctl == rfbTightJpeg) {
+ // Read length
+ int compressedLen = is.readCompactLength();
+ if (compressedLen <= 0)
+ vlog.info("Incorrect data received from the server.");
+
+ // Allocate netbuf and read in data
+ byte[] netbuf = new byte[compressedLen];
+ is.readBytes(netbuf, 0, compressedLen);
+
+ // Create an Image object from the JPEG data.
+ Image jpeg = java.awt.Toolkit.getDefaultToolkit().createImage(netbuf);
+ PixelGrabber pg = new PixelGrabber(jpeg, 0, 0, r.width(), r.height(), true);
+ try {
+ boolean ret = pg.grabPixels();
+ if (!ret)
+ vlog.info("failed to grab pixels");
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ Object pixels = pg.getPixels();
+ buf = (pixels instanceof byte[]) ?
+ convertByteArrayToIntArray((byte[])pixels) : (int[])pixels;
+ handler.imageRect(r, buf);
+ return;
+ }
+
+ // Quit on unsupported compression type.
+ if (comp_ctl > rfbTightMaxSubencoding) {
+ throw new Exception("TightDecoder: bad subencoding value received");
+ }
+
+ // "Basic" compression type.
+ int palSize = 0;
+ int[] palette = new int[256];
+ boolean useGradient = false;
+
+ if ((comp_ctl & rfbTightExplicitFilter) != 0) {
+ int filterId = is.readU8();
+
+ switch (filterId) {
+ case rfbTightFilterPalette:
+ palSize = is.readU8() + 1;
+ if (cutZeros) {
+ byte[] elem = new byte[3];
+ for (int i = 0; i < palSize; i++) {
+ is.readBytes(elem, 0, 3);
+ if (bigEndian) {
+ palette[i] =
+ (elem[2] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[0] & 0xFF) | 0xFF << 24;
+ } else {
+ palette[i] =
+ (elem[0] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[2] & 0xFF) | 0xFF << 24;
+ }
+ }
+ } else {
+ for (int i = 0; i < palSize; i++) {
+ palette[i] = (bpp == 8) ? is.readOpaque8() : is.readOpaque24B();
+ }
+ }
+ break;
+ case rfbTightFilterGradient:
+ useGradient = true;
+ break;
+ case rfbTightFilterCopy:
+ break;
+ default:
+ throw new Exception("TightDecoder: unknown filter code recieved");
+ }
+ }
+
+ int bppp = bpp;
+ if (palSize != 0) {
+ bppp = (palSize <= 2) ? 1 : 8;
+ } else if (cutZeros) {
+ bppp = 24;
+ }
+
+ // Determine if the data should be decompressed or just copied.
+ int rowSize = (r.width() * bppp + 7) / 8;
+ int dataSize = r.height() * rowSize;
+ int streamId = -1;
+ InStream input;
+ if (dataSize < rfbTightMinToCompress) {
+ input = is;
+ } else {
+ int length = is.readCompactLength();
+ streamId = comp_ctl & 0x03;
+ zis[streamId].setUnderlying(is, length);
+ input = (ZlibInStream)zis[streamId];
+ }
+
+ if (palSize == 0) {
+ // Truecolor data.
+ if (useGradient) {
+ vlog.info("useGradient");
+ if (bpp == 32 && cutZeros) {
+ vlog.info("FilterGradient24");
+ FilterGradient24(r, input, dataSize, buf, handler);
+ } else {
+ vlog.info("FilterGradient");
+ FilterGradient(r, input, dataSize, buf, handler);
+ }
+ } else {
+ if (cutZeros) {
+ byte[] elem = new byte[3];
+ for (int i = 0; i < r.area(); i++) {
+ input.readBytes(elem, 0, 3);
+ if (bigEndian) {
+ buf[i] =
+ (elem[2] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[0] & 0xFF) | 0xFF << 24;
+ } else {
+ buf[i] =
+ (elem[0] & 0xFF) << 16 | (elem[1] & 0xFF) << 8 | (elem[2] & 0xFF) | 0xFF << 24;
+ }
+ }
+ } else {
+ for (int ptr=0; ptr < dataSize; ptr++)
+ buf[ptr] = input.readU8();
+ }
+ }
+ } else {
+ int x, y, b;
+ int ptr = 0;
+ int bits;
+ if (palSize <= 2) {
+ // 2-color palette
+ for (y = 0; y < r.height(); y++) {
+ for (x = 0; x < r.width() / 8; x++) {
+ bits = input.readU8();
+ for(b = 7; b >= 0; b--) {
+ buf[ptr++] = palette[bits >> b & 1];
+ }
+ }
+ if (r.width() % 8 != 0) {
+ bits = input.readU8();
+ for (b = 7; b >= 8 - r.width() % 8; b--) {
+ buf[ptr++] = palette[bits >> b & 1];
+ }
+ }
+ }
+ } else {
+ // 256-color palette
+ for (y = 0; y < r.height(); y++) {
+ for (x = 0; x < r.width(); x++) {
+ buf[ptr++] = palette[input.readU8()];
+ }
+ }
+ }
+ }
+
+ handler.imageRect(r, buf);
+
+ if (streamId != -1) {
+ zis[streamId].reset();
+ }
+ }
+
+ private CMsgReader reader;
+ private ZlibInStream[] zis;
+ static LogWriter vlog = new LogWriter("TightDecoder");
+
+ private static int convertByteArrayToInt(byte[] bytes) {
+ return (bytes[0] << 32) | (bytes[1] << 24) | (bytes[2] << 16) | (bytes[3] << 8) | bytes[4];
+ }
+
+ private static byte[] convertIntToByteArray(int integer) {
+ byte[] bytes = new byte[4];
+ bytes[0] =(byte)( integer >> 24 );
+ bytes[1] =(byte)( (integer << 8) >> 24 );
+ bytes[2] =(byte)( (integer << 16) >> 24 );
+ bytes[3] =(byte)( (integer << 24) >> 24 );
+ return bytes;
+ }
+ private static int[] convertByteArrayToIntArray(byte[] bytes) {
+ vlog.info("convertByteArrayToIntArray");
+ ArrayList<Integer> integers = new ArrayList<Integer>();
+ for (int index = 0; index < bytes.length; index += 4) {
+ byte[] fourBytes = new byte[4];
+ fourBytes[0] = bytes[index];
+ fourBytes[1] = bytes[index+1];
+ fourBytes[2] = bytes[index+2];
+ fourBytes[3] = bytes[index+3];
+ int integer = convertByteArrayToInt(fourBytes);
+ integers.add(new Integer(integer));
+ }
+ int[] ints = new int[bytes.length/4];
+ for (int index = 0; index < integers.size() ; index++) {
+ ints[index] = (integers.get(index)).intValue();
+ }
+ return ints;
+ }
+
+ private static byte[] convertIntArrayToByteArray(int[] integers) {
+ byte[] bytes = new byte[integers.length*4];
+ for (int index = 0; index < integers.length; index++) {
+ byte[] integerBytes = convertIntToByteArray(integers[index]);
+ bytes[index*4] = integerBytes[0];
+ bytes[1 + (index*4)] = integerBytes[1];
+ bytes[2 + (index*4)] = integerBytes[2];
+ bytes[3 + (index*4)] = integerBytes[3];
+ }
+ return bytes;
+ }
+
+ //
+ // Decode data processed with the "Gradient" filter.
+ //
+
+ final private void FilterGradient24(Rect r, InStream is, int dataSize, int[] buf, CMsgHandler handler) {
+
+ int x, y, c;
+ int[] prevRow = new int[TIGHT_MAX_WIDTH * 3];
+ int[] thisRow = new int[TIGHT_MAX_WIDTH * 3];
+ int[] pix = new int[3];
+ int[] est = new int[3];
+
+ // Allocate netbuf and read in data
+ int[] netbuf = new int[dataSize];
+ for (int i = 0; i < dataSize; i++)
+ netbuf[i] = is.readU8();
+ //is.readBytes(netbuf, 0, dataSize);
+
+ PixelFormat myFormat = handler.cp.pf();
+ int rectHeight = r.height();
+ int rectWidth = r.width();
+
+ for (y = 0; y < rectHeight; y++) {
+ /* First pixel in a row */
+ for (c = 0; c < 3; c++) {
+ pix[c] = netbuf[y*rectWidth*3+c] + prevRow[c];
+ thisRow[c] = pix[c];
+ }
+ if (myFormat.bigEndian) {
+ buf[y*rectWidth] =
+ (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF) | 0xFF << 24;
+ } else {
+ buf[y*rectWidth] =
+ (pix[2] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[0] & 0xFF) | 0xFF << 24;
+ }
+
+ /* Remaining pixels of a row */
+ for (x = 1; x < rectWidth; x++) {
+ for (c = 0; c < 3; c++) {
+ est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
+ if (est[c] > 0xFF) {
+ est[c] = 0xFF;
+ } else if (est[c] < 0) {
+ est[c] = 0;
+ }
+ pix[c] = netbuf[(y*rectWidth+x)*3+c] + est[c];
+ thisRow[x*3+c] = pix[c];
+ }
+ if (myFormat.bigEndian) {
+ buf[y*rectWidth] =
+ (pix[2] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[0] & 0xFF) | 0xFF << 24;
+ } else {
+ buf[y*rectWidth] =
+ (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF) | 0xFF << 24;
+ }
+ }
+
+ System.arraycopy(thisRow, 0, prevRow, 0, prevRow.length);
+ }
+ }
+
+ final private void FilterGradient(Rect r, InStream is, int dataSize, int[] buf, CMsgHandler handler) {
+
+ int x, y, c;
+ int[] prevRow = new int[TIGHT_MAX_WIDTH];
+ int[] thisRow = new int[TIGHT_MAX_WIDTH];
+ int[] pix = new int[3];
+ int[] est = new int[3];
+
+ // Allocate netbuf and read in data
+ int[] netbuf = new int[dataSize];
+ for (int i = 0; i < dataSize; i++)
+ netbuf[i] = is.readU8();
+ //is.readBytes(netbuf, 0, dataSize);
+
+ PixelFormat myFormat = handler.cp.pf();
+ int rectHeight = r.height();
+ int rectWidth = r.width();
+
+ for (y = 0; y < rectHeight; y++) {
+ /* First pixel in a row */
+ if (myFormat.bigEndian) {
+ buf[y*rectWidth] =
+ (pix[2] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[0] & 0xFF) | 0xFF << 24;
+ } else {
+ buf[y*rectWidth] =
+ (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF) | 0xFF << 24;
+ }
+ for (c = 0; c < 3; c++)
+ pix[c] += prevRow[c];
+
+ /* Remaining pixels of a row */
+ for (x = 1; x < rectWidth; x++) {
+ for (c = 0; c < 3; c++) {
+ est[c] = prevRow[x*3+c] + pix[c] - prevRow[(x-1)*3+c];
+ if (est[c] > 255) {
+ est[c] = 255;
+ } else if (est[c] < 0) {
+ est[c] = 0;
+ }
+ }
+
+ // FIXME?
+ System.arraycopy(pix, 0, netbuf, 0, netbuf.length);
+ for (c = 0; c < 3; c++)
+ pix[c] += est[c];
+
+ System.arraycopy(thisRow, x*3, pix, 0, pix.length);
+
+ if (myFormat.bigEndian) {
+ buf[y*rectWidth+x] =
+ (pix[2] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[0] & 0xFF) | 0xFF << 24;
+ } else {
+ buf[y*rectWidth+x] =
+ (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF) | 0xFF << 24;
+ }
+
+ }
+
+ System.arraycopy(thisRow, 0, prevRow, 0, prevRow.length);
+ }
+ }
+
+}
diff --git a/java/com/tigervnc/rfb/UnicodeToKeysym.java b/java/com/tigervnc/rfb/UnicodeToKeysym.java
new file mode 100644
index 00000000..44f61ba6
--- /dev/null
+++ b/java/com/tigervnc/rfb/UnicodeToKeysym.java
@@ -0,0 +1,795 @@
+/* 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.
+ */
+//
+// UnicodeToKeysym - provides a translate() method to convert from unicode
+// characters to the equivalent X keysym.
+//
+
+package com.tigervnc.rfb;
+
+public class UnicodeToKeysym {
+
+ public static short[][] table = {
+ { 0x03c0, 0x0100 },
+ { 0x03e0, 0x0101 },
+ { 0x01c3, 0x0102 },
+ { 0x01e3, 0x0103 },
+ { 0x01a1, 0x0104 },
+ { 0x01b1, 0x0105 },
+ { 0x01c6, 0x0106 },
+ { 0x01e6, 0x0107 },
+ { 0x02c6, 0x0108 },
+ { 0x02e6, 0x0109 },
+ { 0x02c5, 0x010a },
+ { 0x02e5, 0x010b },
+ { 0x01c8, 0x010c },
+ { 0x01e8, 0x010d },
+ { 0x01cf, 0x010e },
+ { 0x01ef, 0x010f },
+ { 0x01d0, 0x0110 },
+ { 0x01f0, 0x0111 },
+ { 0x03aa, 0x0112 },
+ { 0x03ba, 0x0113 },
+ { 0x03cc, 0x0116 },
+ { 0x03ec, 0x0117 },
+ { 0x01ca, 0x0118 },
+ { 0x01ea, 0x0119 },
+ { 0x01cc, 0x011a },
+ { 0x01ec, 0x011b },
+ { 0x02d8, 0x011c },
+ { 0x02f8, 0x011d },
+ { 0x02ab, 0x011e },
+ { 0x02bb, 0x011f },
+ { 0x02d5, 0x0120 },
+ { 0x02f5, 0x0121 },
+ { 0x03ab, 0x0122 },
+ { 0x03bb, 0x0123 },
+ { 0x02a6, 0x0124 },
+ { 0x02b6, 0x0125 },
+ { 0x02a1, 0x0126 },
+ { 0x02b1, 0x0127 },
+ { 0x03a5, 0x0128 },
+ { 0x03b5, 0x0129 },
+ { 0x03cf, 0x012a },
+ { 0x03ef, 0x012b },
+ { 0x03c7, 0x012e },
+ { 0x03e7, 0x012f },
+ { 0x02a9, 0x0130 },
+ { 0x02b9, 0x0131 },
+ { 0x02ac, 0x0134 },
+ { 0x02bc, 0x0135 },
+ { 0x03d3, 0x0136 },
+ { 0x03f3, 0x0137 },
+ { 0x03a2, 0x0138 },
+ { 0x01c5, 0x0139 },
+ { 0x01e5, 0x013a },
+ { 0x03a6, 0x013b },
+ { 0x03b6, 0x013c },
+ { 0x01a5, 0x013d },
+ { 0x01b5, 0x013e },
+ { 0x01a3, 0x0141 },
+ { 0x01b3, 0x0142 },
+ { 0x01d1, 0x0143 },
+ { 0x01f1, 0x0144 },
+ { 0x03d1, 0x0145 },
+ { 0x03f1, 0x0146 },
+ { 0x01d2, 0x0147 },
+ { 0x01f2, 0x0148 },
+ { 0x03bd, 0x014a },
+ { 0x03bf, 0x014b },
+ { 0x03d2, 0x014c },
+ { 0x03f2, 0x014d },
+ { 0x01d5, 0x0150 },
+ { 0x01f5, 0x0151 },
+ { 0x13bc, 0x0152 },
+ { 0x13bd, 0x0153 },
+ { 0x01c0, 0x0154 },
+ { 0x01e0, 0x0155 },
+ { 0x03a3, 0x0156 },
+ { 0x03b3, 0x0157 },
+ { 0x01d8, 0x0158 },
+ { 0x01f8, 0x0159 },
+ { 0x01a6, 0x015a },
+ { 0x01b6, 0x015b },
+ { 0x02de, 0x015c },
+ { 0x02fe, 0x015d },
+ { 0x01aa, 0x015e },
+ { 0x01ba, 0x015f },
+ { 0x01a9, 0x0160 },
+ { 0x01b9, 0x0161 },
+ { 0x01de, 0x0162 },
+ { 0x01fe, 0x0163 },
+ { 0x01ab, 0x0164 },
+ { 0x01bb, 0x0165 },
+ { 0x03ac, 0x0166 },
+ { 0x03bc, 0x0167 },
+ { 0x03dd, 0x0168 },
+ { 0x03fd, 0x0169 },
+ { 0x03de, 0x016a },
+ { 0x03fe, 0x016b },
+ { 0x02dd, 0x016c },
+ { 0x02fd, 0x016d },
+ { 0x01d9, 0x016e },
+ { 0x01f9, 0x016f },
+ { 0x01db, 0x0170 },
+ { 0x01fb, 0x0171 },
+ { 0x03d9, 0x0172 },
+ { 0x03f9, 0x0173 },
+ { 0x13be, 0x0178 },
+ { 0x01ac, 0x0179 },
+ { 0x01bc, 0x017a },
+ { 0x01af, 0x017b },
+ { 0x01bf, 0x017c },
+ { 0x01ae, 0x017d },
+ { 0x01be, 0x017e },
+ { 0x08f6, 0x0192 },
+ { 0x01b7, 0x02c7 },
+ { 0x01a2, 0x02d8 },
+ { 0x01ff, 0x02d9 },
+ { 0x01b2, 0x02db },
+ { 0x01bd, 0x02dd },
+ { 0x07ae, 0x0385 },
+ { 0x07a1, 0x0386 },
+ { 0x07a2, 0x0388 },
+ { 0x07a3, 0x0389 },
+ { 0x07a4, 0x038a },
+ { 0x07a7, 0x038c },
+ { 0x07a8, 0x038e },
+ { 0x07ab, 0x038f },
+ { 0x07b6, 0x0390 },
+ { 0x07c1, 0x0391 },
+ { 0x07c2, 0x0392 },
+ { 0x07c3, 0x0393 },
+ { 0x07c4, 0x0394 },
+ { 0x07c5, 0x0395 },
+ { 0x07c6, 0x0396 },
+ { 0x07c7, 0x0397 },
+ { 0x07c8, 0x0398 },
+ { 0x07c9, 0x0399 },
+ { 0x07ca, 0x039a },
+ { 0x07cb, 0x039b },
+ { 0x07cc, 0x039c },
+ { 0x07cd, 0x039d },
+ { 0x07ce, 0x039e },
+ { 0x07cf, 0x039f },
+ { 0x07d0, 0x03a0 },
+ { 0x07d1, 0x03a1 },
+ { 0x07d2, 0x03a3 },
+ { 0x07d4, 0x03a4 },
+ { 0x07d5, 0x03a5 },
+ { 0x07d6, 0x03a6 },
+ { 0x07d7, 0x03a7 },
+ { 0x07d8, 0x03a8 },
+ { 0x07d9, 0x03a9 },
+ { 0x07a5, 0x03aa },
+ { 0x07a9, 0x03ab },
+ { 0x07b1, 0x03ac },
+ { 0x07b2, 0x03ad },
+ { 0x07b3, 0x03ae },
+ { 0x07b4, 0x03af },
+ { 0x07ba, 0x03b0 },
+ { 0x07e1, 0x03b1 },
+ { 0x07e2, 0x03b2 },
+ { 0x07e3, 0x03b3 },
+ { 0x07e4, 0x03b4 },
+ { 0x07e5, 0x03b5 },
+ { 0x07e6, 0x03b6 },
+ { 0x07e7, 0x03b7 },
+ { 0x07e8, 0x03b8 },
+ { 0x07e9, 0x03b9 },
+ { 0x07ea, 0x03ba },
+ { 0x07eb, 0x03bb },
+ { 0x07ec, 0x03bc },
+ { 0x07ed, 0x03bd },
+ { 0x07ee, 0x03be },
+ { 0x07ef, 0x03bf },
+ { 0x07f0, 0x03c0 },
+ { 0x07f1, 0x03c1 },
+ { 0x07f3, 0x03c2 },
+ { 0x07f2, 0x03c3 },
+ { 0x07f4, 0x03c4 },
+ { 0x07f5, 0x03c5 },
+ { 0x07f6, 0x03c6 },
+ { 0x07f7, 0x03c7 },
+ { 0x07f8, 0x03c8 },
+ { 0x07f9, 0x03c9 },
+ { 0x07b5, 0x03ca },
+ { 0x07b9, 0x03cb },
+ { 0x07b7, 0x03cc },
+ { 0x07b8, 0x03cd },
+ { 0x07bb, 0x03ce },
+ { 0x06b3, 0x0401 },
+ { 0x06b1, 0x0402 },
+ { 0x06b2, 0x0403 },
+ { 0x06b4, 0x0404 },
+ { 0x06b5, 0x0405 },
+ { 0x06b6, 0x0406 },
+ { 0x06b7, 0x0407 },
+ { 0x06b8, 0x0408 },
+ { 0x06b9, 0x0409 },
+ { 0x06ba, 0x040a },
+ { 0x06bb, 0x040b },
+ { 0x06bc, 0x040c },
+ { 0x06be, 0x040e },
+ { 0x06bf, 0x040f },
+ { 0x06e1, 0x0410 },
+ { 0x06e2, 0x0411 },
+ { 0x06f7, 0x0412 },
+ { 0x06e7, 0x0413 },
+ { 0x06e4, 0x0414 },
+ { 0x06e5, 0x0415 },
+ { 0x06f6, 0x0416 },
+ { 0x06fa, 0x0417 },
+ { 0x06e9, 0x0418 },
+ { 0x06ea, 0x0419 },
+ { 0x06eb, 0x041a },
+ { 0x06ec, 0x041b },
+ { 0x06ed, 0x041c },
+ { 0x06ee, 0x041d },
+ { 0x06ef, 0x041e },
+ { 0x06f0, 0x041f },
+ { 0x06f2, 0x0420 },
+ { 0x06f3, 0x0421 },
+ { 0x06f4, 0x0422 },
+ { 0x06f5, 0x0423 },
+ { 0x06e6, 0x0424 },
+ { 0x06e8, 0x0425 },
+ { 0x06e3, 0x0426 },
+ { 0x06fe, 0x0427 },
+ { 0x06fb, 0x0428 },
+ { 0x06fd, 0x0429 },
+ { 0x06ff, 0x042a },
+ { 0x06f9, 0x042b },
+ { 0x06f8, 0x042c },
+ { 0x06fc, 0x042d },
+ { 0x06e0, 0x042e },
+ { 0x06f1, 0x042f },
+ { 0x06c1, 0x0430 },
+ { 0x06c2, 0x0431 },
+ { 0x06d7, 0x0432 },
+ { 0x06c7, 0x0433 },
+ { 0x06c4, 0x0434 },
+ { 0x06c5, 0x0435 },
+ { 0x06d6, 0x0436 },
+ { 0x06da, 0x0437 },
+ { 0x06c9, 0x0438 },
+ { 0x06ca, 0x0439 },
+ { 0x06cb, 0x043a },
+ { 0x06cc, 0x043b },
+ { 0x06cd, 0x043c },
+ { 0x06ce, 0x043d },
+ { 0x06cf, 0x043e },
+ { 0x06d0, 0x043f },
+ { 0x06d2, 0x0440 },
+ { 0x06d3, 0x0441 },
+ { 0x06d4, 0x0442 },
+ { 0x06d5, 0x0443 },
+ { 0x06c6, 0x0444 },
+ { 0x06c8, 0x0445 },
+ { 0x06c3, 0x0446 },
+ { 0x06de, 0x0447 },
+ { 0x06db, 0x0448 },
+ { 0x06dd, 0x0449 },
+ { 0x06df, 0x044a },
+ { 0x06d9, 0x044b },
+ { 0x06d8, 0x044c },
+ { 0x06dc, 0x044d },
+ { 0x06c0, 0x044e },
+ { 0x06d1, 0x044f },
+ { 0x06a3, 0x0451 },
+ { 0x06a1, 0x0452 },
+ { 0x06a2, 0x0453 },
+ { 0x06a4, 0x0454 },
+ { 0x06a5, 0x0455 },
+ { 0x06a6, 0x0456 },
+ { 0x06a7, 0x0457 },
+ { 0x06a8, 0x0458 },
+ { 0x06a9, 0x0459 },
+ { 0x06aa, 0x045a },
+ { 0x06ab, 0x045b },
+ { 0x06ac, 0x045c },
+ { 0x06ae, 0x045e },
+ { 0x06af, 0x045f },
+ { 0x0ce0, 0x05d0 },
+ { 0x0ce1, 0x05d1 },
+ { 0x0ce2, 0x05d2 },
+ { 0x0ce3, 0x05d3 },
+ { 0x0ce4, 0x05d4 },
+ { 0x0ce5, 0x05d5 },
+ { 0x0ce6, 0x05d6 },
+ { 0x0ce7, 0x05d7 },
+ { 0x0ce8, 0x05d8 },
+ { 0x0ce9, 0x05d9 },
+ { 0x0cea, 0x05da },
+ { 0x0ceb, 0x05db },
+ { 0x0cec, 0x05dc },
+ { 0x0ced, 0x05dd },
+ { 0x0cee, 0x05de },
+ { 0x0cef, 0x05df },
+ { 0x0cf0, 0x05e0 },
+ { 0x0cf1, 0x05e1 },
+ { 0x0cf2, 0x05e2 },
+ { 0x0cf3, 0x05e3 },
+ { 0x0cf4, 0x05e4 },
+ { 0x0cf5, 0x05e5 },
+ { 0x0cf6, 0x05e6 },
+ { 0x0cf7, 0x05e7 },
+ { 0x0cf8, 0x05e8 },
+ { 0x0cf9, 0x05e9 },
+ { 0x0cfa, 0x05ea },
+ { 0x05ac, 0x060c },
+ { 0x05bb, 0x061b },
+ { 0x05bf, 0x061f },
+ { 0x05c1, 0x0621 },
+ { 0x05c2, 0x0622 },
+ { 0x05c3, 0x0623 },
+ { 0x05c4, 0x0624 },
+ { 0x05c5, 0x0625 },
+ { 0x05c6, 0x0626 },
+ { 0x05c7, 0x0627 },
+ { 0x05c8, 0x0628 },
+ { 0x05c9, 0x0629 },
+ { 0x05ca, 0x062a },
+ { 0x05cb, 0x062b },
+ { 0x05cc, 0x062c },
+ { 0x05cd, 0x062d },
+ { 0x05ce, 0x062e },
+ { 0x05cf, 0x062f },
+ { 0x05d0, 0x0630 },
+ { 0x05d1, 0x0631 },
+ { 0x05d2, 0x0632 },
+ { 0x05d3, 0x0633 },
+ { 0x05d4, 0x0634 },
+ { 0x05d5, 0x0635 },
+ { 0x05d6, 0x0636 },
+ { 0x05d7, 0x0637 },
+ { 0x05d8, 0x0638 },
+ { 0x05d9, 0x0639 },
+ { 0x05da, 0x063a },
+ { 0x05e0, 0x0640 },
+ { 0x05e1, 0x0641 },
+ { 0x05e2, 0x0642 },
+ { 0x05e3, 0x0643 },
+ { 0x05e4, 0x0644 },
+ { 0x05e5, 0x0645 },
+ { 0x05e6, 0x0646 },
+ { 0x05e7, 0x0647 },
+ { 0x05e8, 0x0648 },
+ { 0x05e9, 0x0649 },
+ { 0x05ea, 0x064a },
+ { 0x05eb, 0x064b },
+ { 0x05ec, 0x064c },
+ { 0x05ed, 0x064d },
+ { 0x05ee, 0x064e },
+ { 0x05ef, 0x064f },
+ { 0x05f0, 0x0650 },
+ { 0x05f1, 0x0651 },
+ { 0x05f2, 0x0652 },
+ { 0x0da1, 0x0e01 },
+ { 0x0da2, 0x0e02 },
+ { 0x0da3, 0x0e03 },
+ { 0x0da4, 0x0e04 },
+ { 0x0da5, 0x0e05 },
+ { 0x0da6, 0x0e06 },
+ { 0x0da7, 0x0e07 },
+ { 0x0da8, 0x0e08 },
+ { 0x0da9, 0x0e09 },
+ { 0x0daa, 0x0e0a },
+ { 0x0dab, 0x0e0b },
+ { 0x0dac, 0x0e0c },
+ { 0x0dad, 0x0e0d },
+ { 0x0dae, 0x0e0e },
+ { 0x0daf, 0x0e0f },
+ { 0x0db0, 0x0e10 },
+ { 0x0db1, 0x0e11 },
+ { 0x0db2, 0x0e12 },
+ { 0x0db3, 0x0e13 },
+ { 0x0db4, 0x0e14 },
+ { 0x0db5, 0x0e15 },
+ { 0x0db6, 0x0e16 },
+ { 0x0db7, 0x0e17 },
+ { 0x0db8, 0x0e18 },
+ { 0x0db9, 0x0e19 },
+ { 0x0dba, 0x0e1a },
+ { 0x0dbb, 0x0e1b },
+ { 0x0dbc, 0x0e1c },
+ { 0x0dbd, 0x0e1d },
+ { 0x0dbe, 0x0e1e },
+ { 0x0dbf, 0x0e1f },
+ { 0x0dc0, 0x0e20 },
+ { 0x0dc1, 0x0e21 },
+ { 0x0dc2, 0x0e22 },
+ { 0x0dc3, 0x0e23 },
+ { 0x0dc4, 0x0e24 },
+ { 0x0dc5, 0x0e25 },
+ { 0x0dc6, 0x0e26 },
+ { 0x0dc7, 0x0e27 },
+ { 0x0dc8, 0x0e28 },
+ { 0x0dc9, 0x0e29 },
+ { 0x0dca, 0x0e2a },
+ { 0x0dcb, 0x0e2b },
+ { 0x0dcc, 0x0e2c },
+ { 0x0dcd, 0x0e2d },
+ { 0x0dce, 0x0e2e },
+ { 0x0dcf, 0x0e2f },
+ { 0x0dd0, 0x0e30 },
+ { 0x0dd1, 0x0e31 },
+ { 0x0dd2, 0x0e32 },
+ { 0x0dd3, 0x0e33 },
+ { 0x0dd4, 0x0e34 },
+ { 0x0dd5, 0x0e35 },
+ { 0x0dd6, 0x0e36 },
+ { 0x0dd7, 0x0e37 },
+ { 0x0dd8, 0x0e38 },
+ { 0x0dd9, 0x0e39 },
+ { 0x0dda, 0x0e3a },
+ { 0x0ddf, 0x0e3f },
+ { 0x0de0, 0x0e40 },
+ { 0x0de1, 0x0e41 },
+ { 0x0de2, 0x0e42 },
+ { 0x0de3, 0x0e43 },
+ { 0x0de4, 0x0e44 },
+ { 0x0de5, 0x0e45 },
+ { 0x0de6, 0x0e46 },
+ { 0x0de7, 0x0e47 },
+ { 0x0de8, 0x0e48 },
+ { 0x0de9, 0x0e49 },
+ { 0x0dea, 0x0e4a },
+ { 0x0deb, 0x0e4b },
+ { 0x0dec, 0x0e4c },
+ { 0x0ded, 0x0e4d },
+ { 0x0df0, 0x0e50 },
+ { 0x0df1, 0x0e51 },
+ { 0x0df2, 0x0e52 },
+ { 0x0df3, 0x0e53 },
+ { 0x0df4, 0x0e54 },
+ { 0x0df5, 0x0e55 },
+ { 0x0df6, 0x0e56 },
+ { 0x0df7, 0x0e57 },
+ { 0x0df8, 0x0e58 },
+ { 0x0df9, 0x0e59 },
+ { 0x0ed4, 0x11a8 },
+ { 0x0ed5, 0x11a9 },
+ { 0x0ed6, 0x11aa },
+ { 0x0ed7, 0x11ab },
+ { 0x0ed8, 0x11ac },
+ { 0x0ed9, 0x11ad },
+ { 0x0eda, 0x11ae },
+ { 0x0edb, 0x11af },
+ { 0x0edc, 0x11b0 },
+ { 0x0edd, 0x11b1 },
+ { 0x0ede, 0x11b2 },
+ { 0x0edf, 0x11b3 },
+ { 0x0ee0, 0x11b4 },
+ { 0x0ee1, 0x11b5 },
+ { 0x0ee2, 0x11b6 },
+ { 0x0ee3, 0x11b7 },
+ { 0x0ee4, 0x11b8 },
+ { 0x0ee5, 0x11b9 },
+ { 0x0ee6, 0x11ba },
+ { 0x0ee7, 0x11bb },
+ { 0x0ee8, 0x11bc },
+ { 0x0ee9, 0x11bd },
+ { 0x0eea, 0x11be },
+ { 0x0eeb, 0x11bf },
+ { 0x0eec, 0x11c0 },
+ { 0x0eed, 0x11c1 },
+ { 0x0eee, 0x11c2 },
+ { 0x0ef8, 0x11eb },
+ { 0x0ef9, 0x11f0 },
+ { 0x0efa, 0x11f9 },
+ { 0x0aa2, 0x2002 },
+ { 0x0aa1, 0x2003 },
+ { 0x0aa3, 0x2004 },
+ { 0x0aa4, 0x2005 },
+ { 0x0aa5, 0x2007 },
+ { 0x0aa6, 0x2008 },
+ { 0x0aa7, 0x2009 },
+ { 0x0aa8, 0x200a },
+ { 0x0abb, 0x2012 },
+ { 0x0aaa, 0x2013 },
+ { 0x0aa9, 0x2014 },
+ { 0x07af, 0x2015 },
+ { 0x0cdf, 0x2017 },
+ { 0x0ad0, 0x2018 },
+ { 0x0ad1, 0x2019 },
+ { 0x0afd, 0x201a },
+ { 0x0ad2, 0x201c },
+ { 0x0ad3, 0x201d },
+ { 0x0afe, 0x201e },
+ { 0x0af1, 0x2020 },
+ { 0x0af2, 0x2021 },
+ { 0x0ae6, 0x2022 },
+ { 0x0aaf, 0x2025 },
+ { 0x0aae, 0x2026 },
+ { 0x0ad6, 0x2032 },
+ { 0x0ad7, 0x2033 },
+ { 0x0afc, 0x2038 },
+ { 0x047e, 0x203e },
+ { 0x0eff, 0x20a9 },
+ { 0x20ac, 0x20ac },
+ { 0x0ab8, 0x2105 },
+ { 0x06b0, 0x2116 },
+ { 0x0afb, 0x2117 },
+ { 0x0ad4, 0x211e },
+ { 0x0ac9, 0x2122 },
+ { 0x0ab0, 0x2153 },
+ { 0x0ab1, 0x2154 },
+ { 0x0ab2, 0x2155 },
+ { 0x0ab3, 0x2156 },
+ { 0x0ab4, 0x2157 },
+ { 0x0ab5, 0x2158 },
+ { 0x0ab6, 0x2159 },
+ { 0x0ab7, 0x215a },
+ { 0x0ac3, 0x215b },
+ { 0x0ac4, 0x215c },
+ { 0x0ac5, 0x215d },
+ { 0x0ac6, 0x215e },
+ { 0x08fb, 0x2190 },
+ { 0x08fc, 0x2191 },
+ { 0x08fd, 0x2192 },
+ { 0x08fe, 0x2193 },
+ { 0x08ce, 0x21d2 },
+ { 0x08cd, 0x21d4 },
+ { 0x08ef, 0x2202 },
+ { 0x08c5, 0x2207 },
+ { 0x0bca, 0x2218 },
+ { 0x08d6, 0x221a },
+ { 0x08c1, 0x221d },
+ { 0x08c2, 0x221e },
+ { 0x08de, 0x2227 },
+ { 0x08df, 0x2228 },
+ { 0x08dc, 0x2229 },
+ { 0x08dd, 0x222a },
+ { 0x08bf, 0x222b },
+ { 0x08c0, 0x2234 },
+ { 0x08c8, 0x223c },
+ { 0x08c9, 0x2243 },
+ { 0x08bd, 0x2260 },
+ { 0x08cf, 0x2261 },
+ { 0x08bc, 0x2264 },
+ { 0x08be, 0x2265 },
+ { 0x08da, 0x2282 },
+ { 0x08db, 0x2283 },
+ { 0x0bfc, 0x22a2 },
+ { 0x0bdc, 0x22a3 },
+ { 0x0bce, 0x22a4 },
+ { 0x0bc2, 0x22a5 },
+ { 0x0bd3, 0x2308 },
+ { 0x0bc4, 0x230a },
+ { 0x0afa, 0x2315 },
+ { 0x08a4, 0x2320 },
+ { 0x08a5, 0x2321 },
+ { 0x0abc, 0x2329 },
+ { 0x0abe, 0x232a },
+ { 0x0bcc, 0x2395 },
+ { 0x08ab, 0x239b },
+ { 0x08ac, 0x239d },
+ { 0x08ad, 0x239e },
+ { 0x08ae, 0x23a0 },
+ { 0x08a7, 0x23a1 },
+ { 0x08a8, 0x23a3 },
+ { 0x08a9, 0x23a4 },
+ { 0x08aa, 0x23a6 },
+ { 0x08af, 0x23a8 },
+ { 0x08b0, 0x23ac },
+ { 0x08a1, 0x23b7 },
+ { 0x09ef, 0x23ba },
+ { 0x09f0, 0x23bb },
+ { 0x09f2, 0x23bc },
+ { 0x09f3, 0x23bd },
+ { 0x09e2, 0x2409 },
+ { 0x09e5, 0x240a },
+ { 0x09e9, 0x240b },
+ { 0x09e3, 0x240c },
+ { 0x09e4, 0x240d },
+ { 0x09e8, 0x2424 },
+ { 0x09f1, 0x2500 },
+ { 0x09f8, 0x2502 },
+ { 0x09ec, 0x250c },
+ { 0x09eb, 0x2510 },
+ { 0x09ed, 0x2514 },
+ { 0x09ea, 0x2518 },
+ { 0x09f4, 0x251c },
+ { 0x09f5, 0x2524 },
+ { 0x09f7, 0x252c },
+ { 0x09f6, 0x2534 },
+ { 0x09ee, 0x253c },
+ { 0x09e1, 0x2592 },
+ { 0x0ae7, 0x25aa },
+ { 0x0ae1, 0x25ab },
+ { 0x0adb, 0x25ac },
+ { 0x0ae2, 0x25ad },
+ { 0x0adf, 0x25ae },
+ { 0x0acf, 0x25af },
+ { 0x0ae8, 0x25b2 },
+ { 0x0ae3, 0x25b3 },
+ { 0x0add, 0x25b6 },
+ { 0x0acd, 0x25b7 },
+ { 0x0ae9, 0x25bc },
+ { 0x0ae4, 0x25bd },
+ { 0x0adc, 0x25c0 },
+ { 0x0acc, 0x25c1 },
+ { 0x09e0, 0x25c6 },
+ { 0x0ace, 0x25cb },
+ { 0x0ade, 0x25cf },
+ { 0x0ae0, 0x25e6 },
+ { 0x0ae5, 0x2606 },
+ { 0x0af9, 0x260e },
+ { 0x0aca, 0x2613 },
+ { 0x0aea, 0x261c },
+ { 0x0aeb, 0x261e },
+ { 0x0af8, 0x2640 },
+ { 0x0af7, 0x2642 },
+ { 0x0aec, 0x2663 },
+ { 0x0aee, 0x2665 },
+ { 0x0aed, 0x2666 },
+ { 0x0af6, 0x266d },
+ { 0x0af5, 0x266f },
+ { 0x0af3, 0x2713 },
+ { 0x0af4, 0x2717 },
+ { 0x0ad9, 0x271d },
+ { 0x0af0, 0x2720 },
+ { 0x04a4, 0x3001 },
+ { 0x04a1, 0x3002 },
+ { 0x04a2, 0x300c },
+ { 0x04a3, 0x300d },
+ { 0x04de, 0x309b },
+ { 0x04df, 0x309c },
+ { 0x04a7, 0x30a1 },
+ { 0x04b1, 0x30a2 },
+ { 0x04a8, 0x30a3 },
+ { 0x04b2, 0x30a4 },
+ { 0x04a9, 0x30a5 },
+ { 0x04b3, 0x30a6 },
+ { 0x04aa, 0x30a7 },
+ { 0x04b4, 0x30a8 },
+ { 0x04ab, 0x30a9 },
+ { 0x04b5, 0x30aa },
+ { 0x04b6, 0x30ab },
+ { 0x04b7, 0x30ad },
+ { 0x04b8, 0x30af },
+ { 0x04b9, 0x30b1 },
+ { 0x04ba, 0x30b3 },
+ { 0x04bb, 0x30b5 },
+ { 0x04bc, 0x30b7 },
+ { 0x04bd, 0x30b9 },
+ { 0x04be, 0x30bb },
+ { 0x04bf, 0x30bd },
+ { 0x04c0, 0x30bf },
+ { 0x04c1, 0x30c1 },
+ { 0x04af, 0x30c3 },
+ { 0x04c2, 0x30c4 },
+ { 0x04c3, 0x30c6 },
+ { 0x04c4, 0x30c8 },
+ { 0x04c5, 0x30ca },
+ { 0x04c6, 0x30cb },
+ { 0x04c7, 0x30cc },
+ { 0x04c8, 0x30cd },
+ { 0x04c9, 0x30ce },
+ { 0x04ca, 0x30cf },
+ { 0x04cb, 0x30d2 },
+ { 0x04cc, 0x30d5 },
+ { 0x04cd, 0x30d8 },
+ { 0x04ce, 0x30db },
+ { 0x04cf, 0x30de },
+ { 0x04d0, 0x30df },
+ { 0x04d1, 0x30e0 },
+ { 0x04d2, 0x30e1 },
+ { 0x04d3, 0x30e2 },
+ { 0x04ac, 0x30e3 },
+ { 0x04d4, 0x30e4 },
+ { 0x04ad, 0x30e5 },
+ { 0x04d5, 0x30e6 },
+ { 0x04ae, 0x30e7 },
+ { 0x04d6, 0x30e8 },
+ { 0x04d7, 0x30e9 },
+ { 0x04d8, 0x30ea },
+ { 0x04d9, 0x30eb },
+ { 0x04da, 0x30ec },
+ { 0x04db, 0x30ed },
+ { 0x04dc, 0x30ef },
+ { 0x04a6, 0x30f2 },
+ { 0x04dd, 0x30f3 },
+ { 0x04a5, 0x30fb },
+ { 0x04b0, 0x30fc },
+ { 0x0ea1, 0x3131 },
+ { 0x0ea2, 0x3132 },
+ { 0x0ea3, 0x3133 },
+ { 0x0ea4, 0x3134 },
+ { 0x0ea5, 0x3135 },
+ { 0x0ea6, 0x3136 },
+ { 0x0ea7, 0x3137 },
+ { 0x0ea8, 0x3138 },
+ { 0x0ea9, 0x3139 },
+ { 0x0eaa, 0x313a },
+ { 0x0eab, 0x313b },
+ { 0x0eac, 0x313c },
+ { 0x0ead, 0x313d },
+ { 0x0eae, 0x313e },
+ { 0x0eaf, 0x313f },
+ { 0x0eb0, 0x3140 },
+ { 0x0eb1, 0x3141 },
+ { 0x0eb2, 0x3142 },
+ { 0x0eb3, 0x3143 },
+ { 0x0eb4, 0x3144 },
+ { 0x0eb5, 0x3145 },
+ { 0x0eb6, 0x3146 },
+ { 0x0eb7, 0x3147 },
+ { 0x0eb8, 0x3148 },
+ { 0x0eb9, 0x3149 },
+ { 0x0eba, 0x314a },
+ { 0x0ebb, 0x314b },
+ { 0x0ebc, 0x314c },
+ { 0x0ebd, 0x314d },
+ { 0x0ebe, 0x314e },
+ { 0x0ebf, 0x314f },
+ { 0x0ec0, 0x3150 },
+ { 0x0ec1, 0x3151 },
+ { 0x0ec2, 0x3152 },
+ { 0x0ec3, 0x3153 },
+ { 0x0ec4, 0x3154 },
+ { 0x0ec5, 0x3155 },
+ { 0x0ec6, 0x3156 },
+ { 0x0ec7, 0x3157 },
+ { 0x0ec8, 0x3158 },
+ { 0x0ec9, 0x3159 },
+ { 0x0eca, 0x315a },
+ { 0x0ecb, 0x315b },
+ { 0x0ecc, 0x315c },
+ { 0x0ecd, 0x315d },
+ { 0x0ece, 0x315e },
+ { 0x0ecf, 0x315f },
+ { 0x0ed0, 0x3160 },
+ { 0x0ed1, 0x3161 },
+ { 0x0ed2, 0x3162 },
+ { 0x0ed3, 0x3163 },
+ { 0x0eef, 0x316d },
+ { 0x0ef0, 0x3171 },
+ { 0x0ef1, 0x3178 },
+ { 0x0ef2, 0x317f },
+ { 0x0ef3, 0x3181 },
+ { 0x0ef4, 0x3184 },
+ { 0x0ef5, 0x3186 },
+ { 0x0ef6, 0x318d },
+ { 0x0ef7, 0x318e }
+ };
+
+ public static int translate(int unicode) {
+ if ((unicode >= 0x20 && unicode <= 0x7e) ||
+ (unicode >= 0xa0 && unicode <= 0xff))
+ return unicode;
+
+ int min = 0;
+ int max = table.length - 1;
+ int mid;
+
+ while (max >= min) {
+ mid = (min + max) / 2;
+ if (table[mid][1] < unicode)
+ min = mid + 1;
+ else if (table[mid][1] > unicode)
+ max = mid - 1;
+ else
+ return table[mid][0];
+ }
+
+ /* no matching Unicode value found */
+ return -1;
+ }
+}
diff --git a/java/com/tigervnc/rfb/UserMsgBox.java b/java/com/tigervnc/rfb/UserMsgBox.java
new file mode 100644
index 00000000..e83d9956
--- /dev/null
+++ b/java/com/tigervnc/rfb/UserMsgBox.java
@@ -0,0 +1,27 @@
+/* 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.
+ */
+
+// getUserPasswd() gets the username and password. This might involve a
+// dialog, getpass(), etc. The user buffer pointer can be null, in which case
+// no user name will be retrieved.
+
+package com.tigervnc.rfb;
+
+public interface UserMsgBox {
+ public boolean showMsgBox(int flags,String title, String text);
+}
diff --git a/java/com/tigervnc/rfb/UserPasswdGetter.java b/java/com/tigervnc/rfb/UserPasswdGetter.java
new file mode 100644
index 00000000..9796b66f
--- /dev/null
+++ b/java/com/tigervnc/rfb/UserPasswdGetter.java
@@ -0,0 +1,27 @@
+/* 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.
+ */
+
+// getUserPasswd() gets the username and password. This might involve a
+// dialog, getpass(), etc. The user buffer pointer can be null, in which case
+// no user name will be retrieved.
+
+package com.tigervnc.rfb;
+
+public interface UserPasswdGetter {
+ public boolean getUserPasswd(StringBuffer user, StringBuffer password);
+}
diff --git a/java/com/tigervnc/rfb/VncAuth.java b/java/com/tigervnc/rfb/VncAuth.java
new file mode 100644
index 00000000..cce8d81c
--- /dev/null
+++ b/java/com/tigervnc/rfb/VncAuth.java
@@ -0,0 +1,67 @@
+/* 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 com.tigervnc.rfb;
+
+public class VncAuth {
+
+ public static final int ok = 0;
+ public static final int failed = 1;
+ public static final int tooMany = 2; // deprecated
+
+ public static final int challengeSize = 16;
+
+ public static void encryptChallenge(byte[] challenge, String passwd) {
+ byte[] key = new byte[8];
+ for (int i = 0; i < 8 && i < passwd.length(); i++) {
+ key[i] = (byte)passwd.charAt(i);
+ }
+
+ DesCipher des = new DesCipher(key);
+
+ for (int j = 0; j < challengeSize; j += 8)
+ des.encrypt(challenge,j,challenge,j);
+ }
+
+ void obfuscatePasswd(String passwd, byte[] obfuscated) {
+ for (int i = 0; i < 8; i++) {
+ if (i < passwd.length())
+ obfuscated[i] = (byte)passwd.charAt(i);
+ else
+ obfuscated[i] = 0;
+ }
+ DesCipher des = new DesCipher(obfuscationKey);
+ des.encrypt(obfuscated,0,obfuscated,0);
+ }
+
+ String unobfuscatePasswd(byte[] obfuscated) {
+ DesCipher des = new DesCipher(obfuscationKey);
+ des.decrypt(obfuscated,0,obfuscated,0);
+ int len;
+ for (len = 0; len < 8; len++) {
+ if (obfuscated[len] == 0) break;
+ }
+ char[] plain = new char[len];
+ for (int i = 0; i < len; i++) {
+ plain[i] = (char)obfuscated[i];
+ }
+ return new String(plain);
+ }
+
+ static byte[] obfuscationKey = {23,82,107,6,35,78,88,7};
+}
diff --git a/java/com/tigervnc/rfb/VoidParameter.java b/java/com/tigervnc/rfb/VoidParameter.java
new file mode 100644
index 00000000..f41f4c84
--- /dev/null
+++ b/java/com/tigervnc/rfb/VoidParameter.java
@@ -0,0 +1,41 @@
+/* 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 com.tigervnc.rfb;
+
+abstract public class VoidParameter {
+ public VoidParameter(String name_, String desc_) {
+ name = name_;
+ description = desc_;
+ next = Configuration.head;
+ Configuration.head = this;
+ }
+
+ final public String getName() { return name; }
+ final public String getDescription() { return description; }
+
+ abstract public boolean setParam(String value);
+ public boolean setParam() { return false; }
+ abstract public String getDefaultStr();
+ abstract public String getValueStr();
+ public boolean isBool() { return false; }
+
+ VoidParameter next;
+ protected String name;
+ protected String description;
+}
diff --git a/java/com/tigervnc/rfb/ZRLEDecoder.java b/java/com/tigervnc/rfb/ZRLEDecoder.java
new file mode 100644
index 00000000..4f740f9d
--- /dev/null
+++ b/java/com/tigervnc/rfb/ZRLEDecoder.java
@@ -0,0 +1,166 @@
+/* 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 com.tigervnc.rfb;
+
+import com.tigervnc.rdr.*;
+
+public class ZRLEDecoder extends Decoder {
+
+ public ZRLEDecoder(CMsgReader reader_) {
+ reader = reader_;
+ zis = new ZlibInStream();
+ }
+
+ public void readRect(Rect r, CMsgHandler handler) {
+ InStream is = reader.getInStream();
+ int[] buf = reader.getImageBuf(64 * 64 * 4);
+ int bytesPerPixel = handler.cp.pf().bpp / 8;
+ boolean bigEndian = handler.cp.pf().bigEndian;
+
+ int length = is.readU32();
+ zis.setUnderlying(is, length);
+ Rect t = new Rect();
+
+ for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
+
+ t.br.y = Math.min(r.br.y, t.tl.y + 64);
+
+ for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
+
+ t.br.x = Math.min(r.br.x, t.tl.x + 64);
+
+ int mode = zis.readU8();
+ boolean rle = (mode & 128) != 0;
+ int palSize = mode & 127;
+ int[] palette = new int[128];
+
+ if (bytesPerPixel > 1) {
+ zis.readPixels(palette, palSize, 3, bigEndian);
+ } else {
+ for (int i = 0; i < palSize; i++) {
+ palette[i] = zis.readPixel(bytesPerPixel, bigEndian);
+ }
+ }
+
+ if (palSize == 1) {
+ int pix = palette[0];
+ handler.fillRect(t, pix);
+ continue;
+ }
+
+ if (!rle) {
+ if (palSize == 0) {
+
+ // raw
+
+ if (bytesPerPixel > 1) {
+ zis.readPixels(buf, t.area(), 3, bigEndian);
+ } else {
+ zis.readPixels(buf, t.area(), bytesPerPixel, bigEndian);
+ }
+
+ } else {
+
+ // packed pixels
+ int bppp = ((palSize > 16) ? 8 :
+ ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
+
+ int ptr = 0;
+
+ for (int i = 0; i < t.height(); i++) {
+ int eol = ptr + t.width();
+ int b = 0;
+ int nbits = 0;
+
+ while (ptr < eol) {
+ if (nbits == 0) {
+ b = zis.readU8();
+ nbits = 8;
+ }
+ nbits -= bppp;
+ int index = (b >> nbits) & ((1 << bppp) - 1) & 127;
+ buf[ptr++] = palette[index];
+ }
+ }
+ }
+
+ } else {
+
+ if (palSize == 0) {
+
+ // plain RLE
+
+ int ptr = 0;
+ int end = ptr + t.area();
+ while (ptr < end) {
+ int pix = (bytesPerPixel > 1 ? zis.readPixel(3, bigEndian) :
+ zis.readPixel(bytesPerPixel, bigEndian));
+ int len = 1;
+ int b;
+ do {
+ b = zis.readU8();
+ len += b;
+ } while (b == 255);
+
+ if (!(len <= end - ptr))
+ throw new Exception("ZRLEDecoder: assertion (len <= end - ptr)"
+ +" failed");
+
+ while (len-- > 0) buf[ptr++] = pix;
+ }
+ } else {
+
+ // palette RLE
+
+ int ptr = 0;
+ int end = ptr + t.area();
+ while (ptr < end) {
+ int index = zis.readU8();
+ int len = 1;
+ if ((index & 128) != 0) {
+ int b;
+ do {
+ b = zis.readU8();
+ len += b;
+ } while (b == 255);
+
+ if (!(len <= end - ptr))
+ throw new Exception("ZRLEDecoder: assertion "
+ +"(len <= end - ptr) failed");
+ }
+
+ index &= 127;
+
+ int pix = palette[index];
+
+ while (len-- > 0) buf[ptr++] = pix;
+ }
+ }
+ }
+
+ handler.imageRect(t, buf);
+ }
+ }
+
+ zis.reset();
+ }
+
+ CMsgReader reader;
+ ZlibInStream zis;
+}
diff --git a/java/com/tigervnc/rfb/screenTypes.java b/java/com/tigervnc/rfb/screenTypes.java
new file mode 100644
index 00000000..d46741c6
--- /dev/null
+++ b/java/com/tigervnc/rfb/screenTypes.java
@@ -0,0 +1,36 @@
+/* Copyright 2009 Pierre Ossman for Cendio AB
+ *
+ * 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 com.tigervnc.rfb;
+
+public class screenTypes {
+
+ // Reasons
+ public static final int reasonServer = 0;
+ public static final int reasonClient = 1;
+ public static final int reasonOtherClient = 2;
+
+ // Result codes
+ public static final int resultSuccess = 0;
+ public static final int resultProhibited = 1;
+ public static final int resultNoResources = 2;
+ public static final int resultInvalid = 3;
+
+ public static final int resultUnsolicited = 0xffff; // internal code used for server changes
+
+}
diff --git a/java/com/tigervnc/vncviewer/CConn.java b/java/com/tigervnc/vncviewer/CConn.java
new file mode 100644
index 00000000..7d76beed
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/CConn.java
@@ -0,0 +1,1309 @@
+/* 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.
+ */
+
+//
+// CConn
+//
+// Methods on CConn are called from both the GUI thread and the thread which
+// processes incoming RFB messages ("the RFB thread"). This means we need to
+// be careful with synchronization here.
+//
+// Any access to writer() must not only be synchronized, but we must also make
+// sure that the connection is in RFBSTATE_NORMAL. We are guaranteed this for
+// any code called after serverInit() has been called. Since the DesktopWindow
+// isn't created until then, any methods called only from DesktopWindow can
+// assume that we are in RFBSTATE_NORMAL.
+
+package com.tigervnc.vncviewer;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.event.*;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Event;
+import java.awt.Frame;
+import java.awt.ScrollPane;
+
+import java.io.*;
+import javax.net.ssl.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.File;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import javax.swing.*;
+import javax.swing.filechooser.*;
+import javax.swing.ImageIcon;
+import java.net.URL;
+import java.net.ServerSocket;
+import javax.swing.border.*;
+import java.util.*;
+
+import com.tigervnc.rdr.*;
+import com.tigervnc.rfb.*;
+import com.tigervnc.rfb.Exception;
+import com.tigervnc.rfb.Point;
+import com.tigervnc.rfb.Rect;
+
+class ViewportFrame extends JFrame
+{
+ public ViewportFrame(String name, CConn cc_) {
+ cc = cc_;
+ setTitle("TigerVNC: "+name);
+ setFocusable(false);
+ setFocusTraversalKeysEnabled(false);
+ addWindowFocusListener(new WindowAdapter() {
+ public void windowGainedFocus(WindowEvent e) {
+ sp.getViewport().getView().requestFocusInWindow();
+ }
+ });
+ addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ cc.close();
+ }
+ });
+ addComponentListener(new ComponentAdapter() {
+ public void componentResized(ComponentEvent e) {
+ if (cc.options.autoScale || cc.options.fixedRatioScale) {
+ if (sp.getSize().width != cc.desktop.scaledWidth ||
+ sp.getSize().height != cc.desktop.scaledHeight) {
+ cc.desktop.setScaledSize();
+ sp.setSize(new Dimension(cc.desktop.scaledWidth,
+ cc.desktop.scaledHeight));
+ sp.validate();
+ pack();
+ update(g);
+ if (cc.desktop.cursor != null) {
+ Cursor cursor = cc.desktop.cursor;
+ cc.setCursor(cursor.width(),cursor.height(),cursor.hotspot,
+ cursor.data, cursor.mask);
+ }
+ }
+ }
+ }
+ });
+ }
+
+ public void addChild(DesktopWindow child) {
+ sp = new JScrollPane(child);
+ child.setBackground(Color.BLACK);
+ child.setOpaque(true);
+ sp.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
+ getContentPane().add(sp);
+ }
+
+ public void setChild(DesktopWindow child) {
+ getContentPane().removeAll();
+ addChild(child);
+ }
+
+ public void setGeometry(int x, int y, int w, int h, boolean pack) {
+ if (pack) {
+ pack();
+ } else {
+ setSize(w, h);
+ }
+ if (!cc.options.autoScale && !cc.options.fixedRatioScale)
+ setLocation(x, y);
+ setBackground(Color.BLACK);
+ }
+
+
+ CConn cc;
+ Graphics g;
+ JScrollPane sp;
+ static LogWriter vlog = new LogWriter("ViewportFrame");
+}
+
+public class CConn extends CConnection
+ implements UserPasswdGetter, UserMsgBox, OptionsDialogCallback
+{
+ ////////////////////////////////////////////////////////////////////
+ // The following methods are all called from the RFB thread
+
+ public CConn(VncViewer viewer_, java.net.Socket sock_,
+ String vncServerName, boolean reverse)
+ {
+ serverHost = null; serverPort = 0; sock = sock_; viewer = viewer_;
+ currentEncoding = Encodings.encodingTight; lastServerEncoding = -1;
+ fullColour = viewer.fullColour.getValue();
+ lowColourLevel = 2;
+ autoSelect = viewer.autoSelect.getValue();
+ shared = viewer.shared.getValue(); formatChange = false;
+ encodingChange = false; sameMachine = false;
+ fullScreen = viewer.fullScreen.getValue();
+ menuKey = Keysyms.F8;
+ options = new OptionsDialog(this);
+ options.initDialog();
+ clipboardDialog = new ClipboardDialog(this);
+ firstUpdate = true; pendingUpdate = false;
+
+ setShared(shared);
+ upg = this;
+ msg = this;
+
+ String encStr = viewer.preferredEncoding.getValue();
+ int encNum = Encodings.encodingNum(encStr);
+ if (encNum != -1) {
+ currentEncoding = encNum;
+ }
+ cp.supportsDesktopResize = true;
+ cp.supportsExtendedDesktopSize = true;
+ cp.supportsClientRedirect = true;
+ cp.supportsDesktopRename = true;
+ cp.supportsLocalCursor = viewer.useLocalCursor.getValue();
+ cp.customCompressLevel = viewer.customCompressLevel.getValue();
+ cp.compressLevel = viewer.compressLevel.getValue();
+ cp.noJpeg = viewer.noJpeg.getValue();
+ cp.qualityLevel = viewer.qualityLevel.getValue();
+ initMenu();
+
+ if (sock != null) {
+ String name = sock.getRemoteSocketAddress()+"::"+sock.getPort();
+ vlog.info("Accepted connection from "+name);
+ } else {
+ if (vncServerName != null) {
+ serverHost = Hostname.getHost(vncServerName);
+ serverPort = Hostname.getPort(vncServerName);
+ } else {
+ ServerDialog dlg = new ServerDialog(options, vncServerName, this);
+ if (!dlg.showDialog() || dlg.server.getSelectedItem().equals("")) {
+ System.exit(1);
+ }
+ vncServerName = (String)dlg.server.getSelectedItem();
+ serverHost = Hostname.getHost(vncServerName);
+ serverPort = Hostname.getPort(vncServerName);
+ }
+
+ try {
+ sock = new java.net.Socket(serverHost, serverPort);
+ } catch (java.io.IOException e) {
+ throw new Exception(e.toString());
+ }
+ vlog.info("connected to host "+serverHost+" port "+serverPort);
+ }
+
+ sameMachine = (sock.getLocalSocketAddress() == sock.getRemoteSocketAddress());
+ try {
+ sock.setTcpNoDelay(true);
+ sock.setTrafficClass(0x10);
+ setServerName(serverHost);
+ jis = new JavaInStream(sock.getInputStream());
+ jos = new JavaOutStream(sock.getOutputStream());
+ } catch (java.net.SocketException e) {
+ throw new Exception(e.toString());
+ } catch (java.io.IOException e) {
+ throw new Exception(e.toString());
+ }
+ setStreams(jis, jos);
+ initialiseProtocol();
+ }
+
+ public boolean showMsgBox(int flags, String title, String text)
+ {
+ StringBuffer titleText = new StringBuffer("VNC Viewer: "+title);
+
+ return true;
+ }
+
+ // deleteWindow() is called when the user closes the desktop or menu windows.
+
+ void deleteWindow() {
+ if (viewport != null)
+ viewport.dispose();
+ viewport = null;
+ }
+
+ // getUserPasswd() is called by the CSecurity object when it needs us to read
+ // a password from the user.
+
+ public final boolean getUserPasswd(StringBuffer user, StringBuffer passwd) {
+ String title = ("VNC Authentication ["
+ +csecurity.description() + "]");
+ PasswdDialog dlg;
+ if (user == null) {
+ dlg = new PasswdDialog(title, (user == null), (passwd == null));
+ } else {
+ if ((passwd == null) && viewer.sendLocalUsername.getValue()) {
+ user.append((String)System.getProperties().get("user.name"));
+ return true;
+ }
+ dlg = new PasswdDialog(title, viewer.sendLocalUsername.getValue(),
+ (passwd == null));
+ }
+ if (!dlg.showDialog()) return false;
+ if (user != null) {
+ if (viewer.sendLocalUsername.getValue()) {
+ user.append((String)System.getProperties().get("user.name"));
+ } else {
+ user.append(dlg.userEntry.getText());
+ }
+ }
+ if (passwd != null)
+ passwd.append(dlg.passwdEntry.getText());
+ return true;
+ }
+
+ // CConnection callback methods
+
+ // serverInit() is called when the serverInit message has been received. At
+ // this point we create the desktop window and display it. We also tell the
+ // server the pixel format and encodings to use and request the first update.
+ public void serverInit() {
+ super.serverInit();
+
+ // If using AutoSelect with old servers, start in FullColor
+ // mode. See comment in autoSelectFormatAndEncoding.
+ if (cp.beforeVersion(3, 8) && autoSelect) {
+ fullColour = true;
+ }
+
+ serverPF = cp.pf();
+ desktop = new DesktopWindow(cp.width, cp.height, serverPF, this);
+ //desktopEventHandler = desktop.setEventHandler(this);
+ //desktop.addEventMask(KeyPressMask | KeyReleaseMask);
+ fullColourPF = desktop.getPF();
+ if (!serverPF.trueColour)
+ fullColour = true;
+ recreateViewport();
+ formatChange = true; encodingChange = true;
+ requestNewUpdate();
+ }
+
+ // setDesktopSize() is called when the desktop size changes (including when
+ // it is set initially).
+ public void setDesktopSize(int w, int h) {
+ super.setDesktopSize(w,h);
+ resizeFramebuffer();
+ }
+
+ // setExtendedDesktopSize() is a more advanced version of setDesktopSize()
+ public void setExtendedDesktopSize(int reason, int result, int w, int h,
+ ScreenSet layout) {
+ super.setExtendedDesktopSize(reason, result, w, h, layout);
+
+ if ((reason == screenTypes.reasonClient) &&
+ (result != screenTypes.resultSuccess)) {
+ vlog.error("SetDesktopSize failed: "+result);
+ return;
+ }
+
+ resizeFramebuffer();
+ }
+
+ // clientRedirect() migrates the client to another host/port
+ public void clientRedirect(int port, String host,
+ String x509subject) {
+ try {
+ getSocket().close();
+ setServerPort(port);
+ sock = new java.net.Socket(host, port);
+ sock.setTcpNoDelay(true);
+ sock.setTrafficClass(0x10);
+ setSocket(sock);
+ vlog.info("Redirected to "+host+":"+port);
+ setStreams(new JavaInStream(sock.getInputStream()),
+ new JavaOutStream(sock.getOutputStream()));
+ initialiseProtocol();
+ } catch (java.io.IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // setName() is called when the desktop name changes
+ public void setName(String name) {
+ super.setName(name);
+
+ if (viewport != null) {
+ viewport.setTitle("TigerVNC: "+name);
+ }
+ }
+
+ // framebufferUpdateStart() is called at the beginning of an update.
+ // Here we try to send out a new framebuffer update request so that the
+ // next update can be sent out in parallel with us decoding the current
+ // one. We cannot do this if we're in the middle of a format change
+ // though.
+ public void framebufferUpdateStart() {
+ if (!formatChange) {
+ pendingUpdate = true;
+ requestNewUpdate();
+ } else
+ pendingUpdate = false;
+ }
+
+ // framebufferUpdateEnd() is called at the end of an update.
+ // For each rectangle, the FdInStream will have timed the speed
+ // of the connection, allowing us to select format and encoding
+ // appropriately, and then request another incremental update.
+ public void framebufferUpdateEnd() {
+ desktop.framebufferUpdateEnd();
+
+ if (firstUpdate) {
+ int width, height;
+
+ if (cp.supportsSetDesktopSize &&
+ viewer.desktopSize.getValue() != null &&
+ viewer.desktopSize.getValue().split("x").length == 2) {
+ width = Integer.parseInt(viewer.desktopSize.getValue().split("x")[0]);
+ height = Integer.parseInt(viewer.desktopSize.getValue().split("x")[1]);
+ ScreenSet layout;
+
+ layout = cp.screenLayout;
+
+ if (layout.num_screens() == 0)
+ layout.add_screen(new Screen());
+ else if (layout.num_screens() != 1) {
+
+ while (true) {
+ Iterator iter = layout.screens.iterator();
+ Screen screen = (Screen)iter.next();
+
+ if (!iter.hasNext())
+ break;
+
+ layout.remove_screen(screen.id);
+ }
+ }
+
+ Screen screen0 = (Screen)layout.screens.iterator().next();
+ screen0.dimensions.tl.x = 0;
+ screen0.dimensions.tl.y = 0;
+ screen0.dimensions.br.x = width;
+ screen0.dimensions.br.y = height;
+
+ writer().writeSetDesktopSize(width, height, layout);
+ }
+
+ firstUpdate = false;
+ }
+
+ // A format change prevented us from sending this before the update,
+ // so make sure to send it now.
+ if (formatChange && !pendingUpdate)
+ requestNewUpdate();
+
+ // Compute new settings based on updated bandwidth values
+ if (autoSelect)
+ autoSelectFormatAndEncoding();
+ }
+
+ // The rest of the callbacks are fairly self-explanatory...
+
+ public void setColourMapEntries(int firstColour, int nColours, int[] rgbs) {
+ desktop.setColourMapEntries(firstColour, nColours, rgbs);
+ }
+
+ public void bell() {
+ if (viewer.acceptBell.getValue())
+ desktop.getToolkit().beep();
+ }
+
+ public void serverCutText(String str, int len) {
+ if (viewer.acceptClipboard.getValue())
+ clipboardDialog.serverCutText(str, len);
+ }
+
+ // We start timing on beginRect and stop timing on endRect, to
+ // avoid skewing the bandwidth estimation as a result of the server
+ // being slow or the network having high latency
+ public void beginRect(Rect r, int encoding) {
+ ((JavaInStream)getInStream()).startTiming();
+ if (encoding != Encodings.encodingCopyRect) {
+ lastServerEncoding = encoding;
+ }
+ }
+
+ public void endRect(Rect r, int encoding) {
+ ((JavaInStream)getInStream()).stopTiming();
+ }
+
+ public void fillRect(Rect r, int p) {
+ desktop.fillRect(r.tl.x, r.tl.y, r.width(), r.height(), p);
+ }
+ public void imageRect(Rect r, int[] p) {
+ desktop.imageRect(r.tl.x, r.tl.y, r.width(), r.height(), p);
+ }
+ public void copyRect(Rect r, int sx, int sy) {
+ desktop.copyRect(r.tl.x, r.tl.y, r.width(), r.height(), sx, sy);
+ }
+
+ public void setCursor(int width, int height, Point hotspot,
+ int[] data, byte[] mask) {
+ desktop.setCursor(width, height, hotspot, data, mask);
+ }
+
+ private void resizeFramebuffer()
+ {
+ if ((cp.width == 0) && (cp.height == 0))
+ return;
+ if (desktop == null)
+ return;
+ if ((desktop.width() == cp.width) && (desktop.height() == cp.height))
+ return;
+
+ desktop.resize();
+ recreateViewport();
+ }
+
+ // recreateViewport() recreates our top-level window. This seems to be
+ // better than attempting to resize the existing window, at least with
+ // various X window managers.
+
+ private void recreateViewport()
+ {
+ if (viewport != null) viewport.dispose();
+ viewport = new ViewportFrame(cp.name(), this);
+ viewport.setUndecorated(fullScreen);
+ desktop.setViewport(viewport);
+ ClassLoader loader = this.getClass().getClassLoader();
+ URL url = loader.getResource("com/tigervnc/vncviewer/tigervnc.ico");
+ ImageIcon icon = null;
+ if (url != null) {
+ icon = new ImageIcon(url);
+ viewport.setIconImage(icon.getImage());
+ }
+ viewport.addChild(desktop);
+ reconfigureViewport();
+ if ((cp.width > 0) && (cp.height > 0))
+ viewport.setVisible(true);
+ desktop.initGraphics();
+ desktop.requestFocusInWindow();
+ }
+
+ private void reconfigureViewport()
+ {
+ //viewport.setMaxSize(cp.width, cp.height);
+ boolean pack = true;
+ Dimension dpySize = viewport.getToolkit().getScreenSize();
+ desktop.setScaledSize();
+ int w = desktop.scaledWidth;
+ int h = desktop.scaledHeight;
+ if (fullScreen) {
+ viewport.setExtendedState(JFrame.MAXIMIZED_BOTH);
+ viewport.setGeometry(0, 0, dpySize.width, dpySize.height, false);
+ } else {
+ int wmDecorationWidth = viewport.getInsets().left + viewport.getInsets().right;
+ int wmDecorationHeight = viewport.getInsets().top + viewport.getInsets().bottom;
+ if (w + wmDecorationWidth >= dpySize.width) {
+ w = dpySize.width - wmDecorationWidth;
+ pack = false;
+ }
+ if (h + wmDecorationHeight >= dpySize.height) {
+ h = dpySize.height - wmDecorationHeight;
+ pack = false;
+ }
+
+ if (!pack)
+ viewport.setPreferredSize(new Dimension(w,h));
+
+ int x = (dpySize.width - w - wmDecorationWidth) / 2;
+ int y = (dpySize.height - h - wmDecorationHeight)/2;
+
+ viewport.setExtendedState(JFrame.NORMAL);
+ viewport.setGeometry(x, y, w, h, pack);
+ }
+ viewport.update(viewport.g);
+ }
+
+ // autoSelectFormatAndEncoding() chooses the format and encoding appropriate
+ // to the connection speed:
+ //
+ // First we wait for at least one second of bandwidth measurement.
+ //
+ // Above 16Mbps (i.e. LAN), we choose the second highest JPEG quality,
+ // which should be perceptually lossless.
+ //
+ // If the bandwidth is below that, we choose a more lossy JPEG quality.
+ //
+ // If the bandwidth drops below 256 Kbps, we switch to palette mode.
+ //
+ // Note: The system here is fairly arbitrary and should be replaced
+ // with something more intelligent at the server end.
+ //
+ private void autoSelectFormatAndEncoding() {
+ long kbitsPerSecond = ((JavaInStream)getInStream()).kbitsPerSecond();
+ long timeWaited = ((JavaInStream)getInStream()).timeWaited();
+ boolean newFullColour = fullColour;
+ int newQualityLevel = cp.qualityLevel;
+
+ // Always use Tight
+ if (currentEncoding != Encodings.encodingTight) {
+ currentEncoding = Encodings.encodingTight;
+ encodingChange = true;
+ }
+
+ // Check that we have a decent bandwidth measurement
+ if ((kbitsPerSecond == 0) || (timeWaited < 10000))
+ return;
+
+ // Select appropriate quality level
+ if (!cp.noJpeg) {
+ if (kbitsPerSecond > 16000)
+ newQualityLevel = 8;
+ else
+ newQualityLevel = 6;
+
+ if (newQualityLevel != cp.qualityLevel) {
+ vlog.info("Throughput "+kbitsPerSecond+
+ " kbit/s - changing to quality "+newQualityLevel);
+ cp.qualityLevel = newQualityLevel;
+ viewer.qualityLevel.setParam(Integer.toString(newQualityLevel));
+ encodingChange = true;
+ }
+ }
+
+ if (cp.beforeVersion(3, 8)) {
+ // Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with
+ // cursors "asynchronously". If this happens in the middle of a
+ // pixel format change, the server will encode the cursor with
+ // the old format, but the client will try to decode it
+ // according to the new format. This will lead to a
+ // crash. Therefore, we do not allow automatic format change for
+ // old servers.
+ return;
+ }
+
+ // Select best color level
+ newFullColour = (kbitsPerSecond > 256);
+ if (newFullColour != fullColour) {
+ vlog.info("Throughput "+kbitsPerSecond+
+ " kbit/s - full color is now "+
+ (newFullColour ? "enabled" : "disabled"));
+ fullColour = newFullColour;
+ formatChange = true;
+ }
+ }
+
+ // requestNewUpdate() requests an update from the server, having set the
+ // format and encoding appropriately.
+ private void requestNewUpdate()
+ {
+ if (formatChange) {
+
+ /* Catch incorrect requestNewUpdate calls */
+ assert(pendingUpdate == false);
+
+ if (fullColour) {
+ desktop.setPF(fullColourPF);
+ } else {
+ if (lowColourLevel == 0) {
+ desktop.setPF(new PixelFormat(8,3,false,true,1,1,1,2,1,0));
+ } else if (lowColourLevel == 1) {
+ desktop.setPF(new PixelFormat(8,6,false,true,3,3,3,4,2,0));
+ } else {
+ desktop.setPF(new PixelFormat(8,8,false,true,7,7,3,0,3,6));
+ }
+ }
+ String str = desktop.getPF().print();
+ vlog.info("Using pixel format "+str);
+ cp.setPF(desktop.getPF());
+ synchronized (this) {
+ writer().writeSetPixelFormat(cp.pf());
+ }
+ }
+ checkEncodings();
+ synchronized (this) {
+ writer().writeFramebufferUpdateRequest(new Rect(0,0,cp.width,cp.height),
+ !formatChange);
+ }
+ formatChange = false;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////
+ // The following methods are all called from the GUI thread
+
+ // close() closes the socket, thus waking up the RFB thread.
+ public void close() {
+ try {
+ shuttingDown = true;
+ sock.close();
+ } catch (java.io.IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ // Menu callbacks. These are guaranteed only to be called after serverInit()
+ // has been called, since the menu is only accessible from the DesktopWindow
+
+ private void initMenu() {
+ menu = new F8Menu(this);
+ }
+
+ void showMenu(int x, int y) {
+ String os = System.getProperty("os.name");
+ if (os.startsWith("Windows"))
+ com.sun.java.swing.plaf.windows.WindowsLookAndFeel.setMnemonicHidden(false);
+ menu.show(desktop, x, y);
+ }
+
+ void showAbout() {
+ InputStream stream = cl.getResourceAsStream("com/tigervnc/vncviewer/timestamp");
+ String pkgDate = "";
+ String pkgTime = "";
+ try {
+ Manifest manifest = new Manifest(stream);
+ Attributes attributes = manifest.getMainAttributes();
+ pkgDate = attributes.getValue("Package-Date");
+ pkgTime = attributes.getValue("Package-Time");
+ } catch (IOException e) { }
+ JOptionPane.showMessageDialog((viewport != null ? viewport : null),
+ VncViewer.about1+" v"+VncViewer.version+" ("+VncViewer.build+")\n"
+ +"Built on "+pkgDate+" at "+pkgTime+"\n"
+ +VncViewer.about2+"\n"
+ +VncViewer.about3,
+ "About TigerVNC Viewer for Java",
+ JOptionPane.INFORMATION_MESSAGE,
+ logo);
+ }
+
+ void showInfo() {
+ JOptionPane.showMessageDialog(viewport,
+ "Desktop name: "+cp.name()+"\n"
+ +"Host: "+serverHost+":"+sock.getPort()+"\n"
+ +"Size: "+cp.width+"x"+cp.height+"\n"
+ +"Pixel format: "+desktop.getPF().print()+"\n"
+ +"(server default "+serverPF.print()+")\n"
+ +"Requested encoding: "+Encodings.encodingName(currentEncoding)+"\n"
+ +"Last used encoding: "+Encodings.encodingName(lastServerEncoding)+"\n"
+ +"Line speed estimate: "+((JavaInStream)getInStream()).kbitsPerSecond()+" kbit/s"+"\n"
+ +"Protocol version: "+cp.majorVersion+"."+cp.minorVersion+"\n"
+ +"Security method: "+Security.secTypeName(csecurity.getType())
+ +" ["+csecurity.description()+"]",
+ "VNC connection info",
+ JOptionPane.PLAIN_MESSAGE);
+ }
+
+ synchronized public void refresh() {
+ writer().writeFramebufferUpdateRequest(new Rect(0,0,cp.width,cp.height), false);
+ pendingUpdate = true;
+ }
+
+
+ // OptionsDialogCallback. setOptions() sets the options dialog's checkboxes
+ // etc to reflect our flags. getOptions() sets our flags according to the
+ // options dialog's checkboxes. They are both called from the GUI thread.
+ // Some of the flags are also accessed by the RFB thread. I believe that
+ // reading and writing boolean and int values in java is atomic, so there is
+ // no need for synchronization.
+
+ public void setOptions() {
+ int digit;
+ options.autoSelect.setSelected(autoSelect);
+ options.fullColour.setSelected(fullColour);
+ options.veryLowColour.setSelected(!fullColour && lowColourLevel == 0);
+ options.lowColour.setSelected(!fullColour && lowColourLevel == 1);
+ options.mediumColour.setSelected(!fullColour && lowColourLevel == 2);
+ options.tight.setSelected(currentEncoding == Encodings.encodingTight);
+ options.zrle.setSelected(currentEncoding == Encodings.encodingZRLE);
+ options.hextile.setSelected(currentEncoding == Encodings.encodingHextile);
+ options.raw.setSelected(currentEncoding == Encodings.encodingRaw);
+
+ options.customCompressLevel.setSelected(viewer.customCompressLevel.getValue());
+ digit = 0 + viewer.compressLevel.getValue();
+ if (digit >= 0 && digit <= 9) {
+ options.compressLevel.setSelectedItem(digit);
+ } else {
+ options.compressLevel.setSelectedItem(Integer.parseInt(viewer.compressLevel.getDefaultStr()));
+ }
+ options.noJpeg.setSelected(!viewer.noJpeg.getValue());
+ digit = 0 + viewer.qualityLevel.getValue();
+ if (digit >= 0 && digit <= 9) {
+ options.qualityLevel.setSelectedItem(digit);
+ } else {
+ options.qualityLevel.setSelectedItem(Integer.parseInt(viewer.qualityLevel.getDefaultStr()));
+ }
+
+ options.viewOnly.setSelected(viewer.viewOnly.getValue());
+ options.acceptClipboard.setSelected(viewer.acceptClipboard.getValue());
+ options.sendClipboard.setSelected(viewer.sendClipboard.getValue());
+ options.menuKey.setSelectedIndex(menuKey-0xFFBE);
+
+ if (state() == RFBSTATE_NORMAL) {
+ options.shared.setEnabled(false);
+ options.secVeNCrypt.setEnabled(false);
+ options.encNone.setEnabled(false);
+ options.encTLS.setEnabled(false);
+ options.encX509.setEnabled(false);
+ options.ca.setEnabled(false);
+ options.crl.setEnabled(false);
+ options.secIdent.setEnabled(false);
+ options.secNone.setEnabled(false);
+ options.secVnc.setEnabled(false);
+ options.secPlain.setEnabled(false);
+ options.sendLocalUsername.setEnabled(false);
+ } else {
+ options.shared.setSelected(shared);
+
+ /* Process non-VeNCrypt sectypes */
+ java.util.List<Integer> secTypes = new ArrayList<Integer>();
+ secTypes = security.GetEnabledSecTypes();
+ for (Iterator i = secTypes.iterator(); i.hasNext();) {
+ switch ((Integer)i.next()) {
+ case Security.secTypeVeNCrypt:
+ options.secVeNCrypt.setSelected(true);
+ break;
+ case Security.secTypeNone:
+ options.encNone.setSelected(true);
+ options.secNone.setSelected(true);
+ break;
+ case Security.secTypeVncAuth:
+ options.encNone.setSelected(true);
+ options.secVnc.setSelected(true);
+ break;
+ }
+ }
+
+ /* Process VeNCrypt subtypes */
+ if (options.secVeNCrypt.isSelected()) {
+ java.util.List<Integer> secTypesExt = new ArrayList<Integer>();
+ secTypesExt = security.GetEnabledExtSecTypes();
+ for (Iterator iext = secTypesExt.iterator(); iext.hasNext();) {
+ switch ((Integer)iext.next()) {
+ case Security.secTypePlain:
+ options.secPlain.setSelected(true);
+ options.sendLocalUsername.setSelected(true);
+ break;
+ case Security.secTypeIdent:
+ options.secIdent.setSelected(true);
+ options.sendLocalUsername.setSelected(true);
+ break;
+ case Security.secTypeTLSNone:
+ options.encTLS.setSelected(true);
+ options.secNone.setSelected(true);
+ break;
+ case Security.secTypeTLSVnc:
+ options.encTLS.setSelected(true);
+ options.secVnc.setSelected(true);
+ break;
+ case Security.secTypeTLSPlain:
+ options.encTLS.setSelected(true);
+ options.secPlain.setSelected(true);
+ options.sendLocalUsername.setSelected(true);
+ break;
+ case Security.secTypeTLSIdent:
+ options.encTLS.setSelected(true);
+ options.secIdent.setSelected(true);
+ options.sendLocalUsername.setSelected(true);
+ break;
+ case Security.secTypeX509None:
+ options.encX509.setSelected(true);
+ options.secNone.setSelected(true);
+ break;
+ case Security.secTypeX509Vnc:
+ options.encX509.setSelected(true);
+ options.secVnc.setSelected(true);
+ break;
+ case Security.secTypeX509Plain:
+ options.encX509.setSelected(true);
+ options.secPlain.setSelected(true);
+ options.sendLocalUsername.setSelected(true);
+ break;
+ case Security.secTypeX509Ident:
+ options.encX509.setSelected(true);
+ options.secIdent.setSelected(true);
+ options.sendLocalUsername.setSelected(true);
+ break;
+ }
+ }
+ }
+ options.sendLocalUsername.setEnabled(options.secPlain.isSelected()||
+ options.secIdent.isSelected());
+ }
+
+ options.fullScreen.setSelected(fullScreen);
+ options.useLocalCursor.setSelected(viewer.useLocalCursor.getValue());
+ options.fastCopyRect.setSelected(viewer.fastCopyRect.getValue());
+ options.acceptBell.setSelected(viewer.acceptBell.getValue());
+ options.autoScale = false;
+ options.fixedRatioScale = false;
+ String scaleString = viewer.scalingFactor.getValue();
+ if (scaleString.equals("Auto")) {
+ options.autoScale = true;
+ options.scalingFactor.setSelectedItem("Auto");
+ // FIXME: set scaleFactor?
+ } else if(scaleString.equals("FixedRatio")) {
+ options.fixedRatioScale = true;
+ options.scalingFactor.setSelectedItem("Fixed Aspect Ratio");
+ // FIXME: set scaleFactor?
+ } else {
+ digit = Integer.parseInt(scaleString);
+ if (digit >= 1 && digit <= 1000) {
+ options.scalingFactor.setSelectedItem(digit+"%");
+ } else {
+ options.scalingFactor.setSelectedItem(Integer.parseInt(viewer.scalingFactor.getDefaultStr())+"%");
+ }
+ scaleFactor =
+ Integer.parseInt(scaleString.substring(0, scaleString.length()));
+ if (desktop != null)
+ desktop.setScaledSize();
+ }
+ }
+
+ public void getOptions() {
+ autoSelect = options.autoSelect.isSelected();
+ if (fullColour != options.fullColour.isSelected())
+ formatChange = true;
+ fullColour = options.fullColour.isSelected();
+ if (!fullColour) {
+ int newLowColourLevel = (options.veryLowColour.isSelected() ? 0 :
+ options.lowColour.isSelected() ? 1 : 2);
+ if (newLowColourLevel != lowColourLevel) {
+ lowColourLevel = newLowColourLevel;
+ formatChange = true;
+ }
+ }
+ int newEncoding = (options.zrle.isSelected() ? Encodings.encodingZRLE :
+ options.hextile.isSelected() ? Encodings.encodingHextile :
+ options.tight.isSelected() ? Encodings.encodingTight :
+ Encodings.encodingRaw);
+ if (newEncoding != currentEncoding) {
+ currentEncoding = newEncoding;
+ encodingChange = true;
+ }
+
+ viewer.customCompressLevel.setParam(options.customCompressLevel.isSelected());
+ if (cp.customCompressLevel != viewer.customCompressLevel.getValue()) {
+ cp.customCompressLevel = viewer.customCompressLevel.getValue();
+ encodingChange = true;
+ }
+ if (Integer.parseInt(options.compressLevel.getSelectedItem().toString()) >= 0 &&
+ Integer.parseInt(options.compressLevel.getSelectedItem().toString()) <= 9) {
+ viewer.compressLevel.setParam(options.compressLevel.getSelectedItem().toString());
+ } else {
+ viewer.compressLevel.setParam(viewer.compressLevel.getDefaultStr());
+ }
+ if (cp.compressLevel != viewer.compressLevel.getValue()) {
+ cp.compressLevel = viewer.compressLevel.getValue();
+ encodingChange = true;
+ }
+ viewer.noJpeg.setParam(!options.noJpeg.isSelected());
+ if (cp.noJpeg != viewer.noJpeg.getValue()) {
+ cp.noJpeg = viewer.noJpeg.getValue();
+ encodingChange = true;
+ }
+ viewer.qualityLevel.setParam(options.qualityLevel.getSelectedItem().toString());
+ if (cp.qualityLevel != viewer.qualityLevel.getValue()) {
+ cp.qualityLevel = viewer.qualityLevel.getValue();
+ encodingChange = true;
+ }
+ viewer.sendLocalUsername.setParam(options.sendLocalUsername.isSelected());
+
+ viewer.viewOnly.setParam(options.viewOnly.isSelected());
+ viewer.acceptClipboard.setParam(options.acceptClipboard.isSelected());
+ viewer.sendClipboard.setParam(options.sendClipboard.isSelected());
+ viewer.fastCopyRect.setParam(options.fastCopyRect.isSelected());
+ viewer.acceptBell.setParam(options.acceptBell.isSelected());
+ if (options.autoScale) {
+ viewer.scalingFactor.setParam("Auto");
+ scaleFactor = -1;
+ if (desktop != null) {
+ reconfigureViewport();
+ viewport.update(viewport.g);
+ }
+ } else if(options.fixedRatioScale) {
+ viewer.scalingFactor.setParam("FixedRatio");
+ scaleFactor = -1;
+ if (desktop != null) {
+ reconfigureViewport();
+ viewport.update(viewport.g);
+ }
+ } else {
+ String scaleString =
+ options.scalingFactor.getSelectedItem().toString();
+ viewer.scalingFactor.setParam(scaleString.substring(0, scaleString.length()-1));
+ int oldScaleFactor = scaleFactor;
+ scaleFactor =
+ Integer.parseInt(scaleString.substring(0, scaleString.length()-1));
+ if (oldScaleFactor != scaleFactor && desktop != null) {
+ reconfigureViewport();
+ viewport.update(viewport.g);
+ }
+ }
+
+ clipboardDialog.setSendingEnabled(viewer.sendClipboard.getValue());
+ menuKey = (options.menuKey.getSelectedIndex()+0xFFBE);
+ F8Menu.f8.setText("Send F"+(menuKey-Keysyms.F1+1));
+
+ shared = options.shared.isSelected();
+ setShared(shared);
+ viewer.useLocalCursor.setParam(options.useLocalCursor.isSelected());
+ if (cp.supportsLocalCursor != viewer.useLocalCursor.getValue()) {
+ cp.supportsLocalCursor = viewer.useLocalCursor.getValue();
+ encodingChange = true;
+ if (desktop != null)
+ desktop.resetLocalCursor();
+ }
+
+ checkEncodings();
+
+ if (state() != RFBSTATE_NORMAL) {
+ /* Process security types which don't use encryption */
+ if (options.encNone.isSelected()) {
+ if (options.secNone.isSelected())
+ Security.EnableSecType(Security.secTypeNone);
+ if (options.secVnc.isSelected())
+ Security.EnableSecType(Security.secTypeVncAuth);
+ if (options.secPlain.isSelected())
+ Security.EnableSecType(Security.secTypePlain);
+ if (options.secIdent.isSelected())
+ Security.EnableSecType(Security.secTypeIdent);
+ } else {
+ Security.DisableSecType(Security.secTypeNone);
+ Security.DisableSecType(Security.secTypeVncAuth);
+ Security.DisableSecType(Security.secTypePlain);
+ Security.DisableSecType(Security.secTypeIdent);
+ }
+
+ /* Process security types which use TLS encryption */
+ if (options.encTLS.isSelected()) {
+ if (options.secNone.isSelected())
+ Security.EnableSecType(Security.secTypeTLSNone);
+ if (options.secVnc.isSelected())
+ Security.EnableSecType(Security.secTypeTLSVnc);
+ if (options.secPlain.isSelected())
+ Security.EnableSecType(Security.secTypeTLSPlain);
+ if (options.secIdent.isSelected())
+ Security.EnableSecType(Security.secTypeTLSIdent);
+ } else {
+ Security.DisableSecType(Security.secTypeTLSNone);
+ Security.DisableSecType(Security.secTypeTLSVnc);
+ Security.DisableSecType(Security.secTypeTLSPlain);
+ Security.DisableSecType(Security.secTypeTLSIdent);
+ }
+
+ /* Process security types which use X509 encryption */
+ if (options.encX509.isSelected()) {
+ if (options.secNone.isSelected())
+ Security.EnableSecType(Security.secTypeX509None);
+ if (options.secVnc.isSelected())
+ Security.EnableSecType(Security.secTypeX509Vnc);
+ if (options.secPlain.isSelected())
+ Security.EnableSecType(Security.secTypeX509Plain);
+ if (options.secIdent.isSelected())
+ Security.EnableSecType(Security.secTypeX509Ident);
+ } else {
+ Security.DisableSecType(Security.secTypeX509None);
+ Security.DisableSecType(Security.secTypeX509Vnc);
+ Security.DisableSecType(Security.secTypeX509Plain);
+ Security.DisableSecType(Security.secTypeX509Ident);
+ }
+
+ /* Process *None security types */
+ if (options.secNone.isSelected()) {
+ if (options.encNone.isSelected())
+ Security.EnableSecType(Security.secTypeNone);
+ if (options.encTLS.isSelected())
+ Security.EnableSecType(Security.secTypeTLSNone);
+ if (options.encX509.isSelected())
+ Security.EnableSecType(Security.secTypeX509None);
+ } else {
+ Security.DisableSecType(Security.secTypeNone);
+ Security.DisableSecType(Security.secTypeTLSNone);
+ Security.DisableSecType(Security.secTypeX509None);
+ }
+
+ /* Process *Vnc security types */
+ if (options.secVnc.isSelected()) {
+ if (options.encNone.isSelected())
+ Security.EnableSecType(Security.secTypeVncAuth);
+ if (options.encTLS.isSelected())
+ Security.EnableSecType(Security.secTypeTLSVnc);
+ if (options.encX509.isSelected())
+ Security.EnableSecType(Security.secTypeX509Vnc);
+ } else {
+ Security.DisableSecType(Security.secTypeVncAuth);
+ Security.DisableSecType(Security.secTypeTLSVnc);
+ Security.DisableSecType(Security.secTypeX509Vnc);
+ }
+
+ /* Process *Plain security types */
+ if (options.secPlain.isSelected()) {
+ if (options.encNone.isSelected())
+ Security.EnableSecType(Security.secTypePlain);
+ if (options.encTLS.isSelected())
+ Security.EnableSecType(Security.secTypeTLSPlain);
+ if (options.encX509.isSelected())
+ Security.EnableSecType(Security.secTypeX509Plain);
+ } else {
+ Security.DisableSecType(Security.secTypePlain);
+ Security.DisableSecType(Security.secTypeTLSPlain);
+ Security.DisableSecType(Security.secTypeX509Plain);
+ }
+
+ /* Process *Ident security types */
+ if (options.secIdent.isSelected()) {
+ if (options.encNone.isSelected())
+ Security.EnableSecType(Security.secTypeIdent);
+ if (options.encTLS.isSelected())
+ Security.EnableSecType(Security.secTypeTLSIdent);
+ if (options.encX509.isSelected())
+ Security.EnableSecType(Security.secTypeX509Ident);
+ } else {
+ Security.DisableSecType(Security.secTypeIdent);
+ Security.DisableSecType(Security.secTypeTLSIdent);
+ Security.DisableSecType(Security.secTypeX509Ident);
+ }
+
+ CSecurityTLS.x509ca.setParam(options.ca.getText());
+ CSecurityTLS.x509crl.setParam(options.crl.getText());
+ }
+ }
+
+ public void toggleFullScreen() {
+ fullScreen = !fullScreen;
+ if (!fullScreen) menu.fullScreen.setSelected(false);
+ recreateViewport();
+ }
+
+ // writeClientCutText() is called from the clipboard dialog
+ synchronized public void writeClientCutText(String str, int len) {
+ if (state() != RFBSTATE_NORMAL) return;
+ writer().writeClientCutText(str,len);
+ }
+
+ synchronized public void writeKeyEvent(int keysym, boolean down) {
+ if (state() != RFBSTATE_NORMAL) return;
+ writer().writeKeyEvent(keysym, down);
+ }
+
+ synchronized public void writeKeyEvent(KeyEvent ev) {
+ if (ev.getID() != KeyEvent.KEY_PRESSED && !ev.isActionKey())
+ return;
+
+ int keysym;
+
+ if (!ev.isActionKey()) {
+ vlog.debug("key press "+ev.getKeyChar());
+ if (ev.getKeyChar() < 32) {
+ // if the ctrl modifier key is down, send the equivalent ASCII since we
+ // will send the ctrl modifier anyway
+
+ if ((ev.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
+ if ((ev.getModifiers() & KeyEvent.SHIFT_MASK) != 0) {
+ keysym = ev.getKeyChar() + 64;
+ if (keysym == -1)
+ return;
+ } else {
+ keysym = ev.getKeyChar() + 96;
+ if (keysym == 127) keysym = 95;
+ }
+ } else {
+ switch (ev.getKeyCode()) {
+ case KeyEvent.VK_BACK_SPACE: keysym = Keysyms.BackSpace; break;
+ case KeyEvent.VK_TAB: keysym = Keysyms.Tab; break;
+ case KeyEvent.VK_ENTER: keysym = Keysyms.Return; break;
+ case KeyEvent.VK_ESCAPE: keysym = Keysyms.Escape; break;
+ default: return;
+ }
+ }
+
+ } else if (ev.getKeyChar() == 127) {
+ keysym = Keysyms.Delete;
+
+ } else {
+ keysym = UnicodeToKeysym.translate(ev.getKeyChar());
+ if (keysym == -1)
+ return;
+ }
+
+ } else {
+ // KEY_ACTION
+ vlog.debug("key action "+ev.getKeyCode());
+ switch (ev.getKeyCode()) {
+ case KeyEvent.VK_HOME: keysym = Keysyms.Home; break;
+ case KeyEvent.VK_END: keysym = Keysyms.End; break;
+ case KeyEvent.VK_PAGE_UP: keysym = Keysyms.Page_Up; break;
+ case KeyEvent.VK_PAGE_DOWN: keysym = Keysyms.Page_Down; break;
+ case KeyEvent.VK_UP: keysym = Keysyms.Up; break;
+ case KeyEvent.VK_DOWN: keysym = Keysyms.Down; break;
+ case KeyEvent.VK_LEFT: keysym = Keysyms.Left; break;
+ case KeyEvent.VK_RIGHT: keysym = Keysyms.Right; break;
+ case KeyEvent.VK_F1: keysym = Keysyms.F1; break;
+ case KeyEvent.VK_F2: keysym = Keysyms.F2; break;
+ case KeyEvent.VK_F3: keysym = Keysyms.F3; break;
+ case KeyEvent.VK_F4: keysym = Keysyms.F4; break;
+ case KeyEvent.VK_F5: keysym = Keysyms.F5; break;
+ case KeyEvent.VK_F6: keysym = Keysyms.F6; break;
+ case KeyEvent.VK_F7: keysym = Keysyms.F7; break;
+ case KeyEvent.VK_F8: keysym = Keysyms.F8; break;
+ case KeyEvent.VK_F9: keysym = Keysyms.F9; break;
+ case KeyEvent.VK_F10: keysym = Keysyms.F10; break;
+ case KeyEvent.VK_F11: keysym = Keysyms.F11; break;
+ case KeyEvent.VK_F12: keysym = Keysyms.F12; break;
+ case KeyEvent.VK_PRINTSCREEN: keysym = Keysyms.Print; break;
+ case KeyEvent.VK_PAUSE: keysym = Keysyms.Pause; break;
+ case KeyEvent.VK_INSERT: keysym = Keysyms.Insert; break;
+ default: return;
+ }
+ }
+
+ writeModifiers(ev.getModifiers());
+ writeKeyEvent(keysym, true);
+ writeKeyEvent(keysym, false);
+ writeModifiers(0);
+ }
+
+
+ synchronized public void writePointerEvent(MouseEvent ev) {
+ if (state() != RFBSTATE_NORMAL) return;
+ int x, y;
+
+ switch (ev.getID()) {
+ case MouseEvent.MOUSE_PRESSED:
+ buttonMask = 1;
+ if ((ev.getModifiers() & KeyEvent.ALT_MASK) != 0) buttonMask = 2;
+ if ((ev.getModifiers() & KeyEvent.META_MASK) != 0) buttonMask = 4;
+ break;
+ case MouseEvent.MOUSE_RELEASED:
+ buttonMask = 0;
+ break;
+ }
+
+ writeModifiers(ev.getModifiers() & ~KeyEvent.ALT_MASK & ~KeyEvent.META_MASK);
+
+ if (cp.width != desktop.scaledWidth ||
+ cp.height != desktop.scaledHeight) {
+ int sx = (desktop.scaleWidthRatio == 1.00)
+ ? ev.getX() : (int)Math.floor(ev.getX()/desktop.scaleWidthRatio);
+ int sy = (desktop.scaleHeightRatio == 1.00)
+ ? ev.getY() : (int)Math.floor(ev.getY()/desktop.scaleHeightRatio);
+ ev.translatePoint(sx - ev.getX(), sy - ev.getY());
+ writer().writePointerEvent(new Point(ev.getX(),ev.getY()), buttonMask);
+ } else {
+ writer().writePointerEvent(new Point(ev.getX(),ev.getY()), buttonMask);
+ }
+
+ if (buttonMask == 0) writeModifiers(0);
+ }
+
+
+ synchronized public void writeWheelEvent(MouseWheelEvent ev) {
+ if (state() != RFBSTATE_NORMAL) return;
+ int x, y;
+ int clicks = ev.getWheelRotation();
+ if (clicks < 0) {
+ buttonMask = 8;
+ } else {
+ buttonMask = 16;
+ }
+ writeModifiers(ev.getModifiers() & ~KeyEvent.ALT_MASK & ~KeyEvent.META_MASK);
+ for (int i=0;i<Math.abs(clicks);i++) {
+ x = ev.getX();
+ y = ev.getY();
+ writer().writePointerEvent(new Point(x, y), buttonMask);
+ buttonMask = 0;
+ writer().writePointerEvent(new Point(x, y), buttonMask);
+ }
+ writeModifiers(0);
+
+ }
+
+
+ void writeModifiers(int m) {
+ if ((m & Event.SHIFT_MASK) != (pressedModifiers & Event.SHIFT_MASK))
+ writeKeyEvent(Keysyms.Shift_L, (m & Event.SHIFT_MASK) != 0);
+ if ((m & Event.CTRL_MASK) != (pressedModifiers & Event.CTRL_MASK))
+ writeKeyEvent(Keysyms.Control_L, (m & Event.CTRL_MASK) != 0);
+ if ((m & Event.ALT_MASK) != (pressedModifiers & Event.ALT_MASK))
+ writeKeyEvent(Keysyms.Alt_L, (m & Event.ALT_MASK) != 0);
+ if ((m & Event.META_MASK) != (pressedModifiers & Event.META_MASK))
+ writeKeyEvent(Keysyms.Meta_L, (m & Event.META_MASK) != 0);
+ pressedModifiers = m;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////
+ // The following methods are called from both RFB and GUI threads
+
+ // checkEncodings() sends a setEncodings message if one is needed.
+ synchronized private void checkEncodings() {
+ if (encodingChange && state() == RFBSTATE_NORMAL) {
+ vlog.info("Using "+Encodings.encodingName(currentEncoding)+" encoding");
+ writer().writeSetEncodings(currentEncoding, true);
+ encodingChange = false;
+ }
+ }
+
+ // the following never change so need no synchronization:
+ JavaInStream jis;
+ JavaOutStream jos;
+
+
+ // viewer object is only ever accessed by the GUI thread so needs no
+ // synchronization (except for one test in DesktopWindow - see comment
+ // there).
+ VncViewer viewer;
+
+ // access to desktop by different threads is specified in DesktopWindow
+
+ // the following need no synchronization:
+
+ ClassLoader cl = this.getClass().getClassLoader();
+ ImageIcon logo = new ImageIcon(cl.getResource("com/tigervnc/vncviewer/tigervnc.png"));
+ public static UserPasswdGetter upg;
+ public UserMsgBox msg;
+
+ // shuttingDown is set by the GUI thread and only ever tested by the RFB
+ // thread after the window has been destroyed.
+ boolean shuttingDown;
+
+ // reading and writing int and boolean is atomic in java, so no
+ // synchronization of the following flags is needed:
+ int currentEncoding, lastServerEncoding;
+
+ int lowColourLevel;
+
+
+ // All menu, options, about and info stuff is done in the GUI thread (apart
+ // from when constructed).
+ F8Menu menu;
+ OptionsDialog options;
+
+ // clipboard sync issues?
+ ClipboardDialog clipboardDialog;
+
+ // the following are only ever accessed by the GUI thread:
+ int buttonMask;
+ int pressedModifiers;
+
+ public String serverHost;
+ public int serverPort;
+ public int menuKey;
+ PixelFormat serverPF;
+ ViewportFrame viewport;
+ DesktopWindow desktop;
+ PixelFormat fullColourPF;
+ boolean fullColour;
+ boolean autoSelect;
+ boolean shared;
+ boolean formatChange;
+ boolean encodingChange;
+ boolean sameMachine;
+ boolean fullScreen;
+ boolean reverseConnection;
+ boolean firstUpdate;
+ boolean pendingUpdate;
+
+ int scaleFactor = 100;
+
+ static LogWriter vlog = new LogWriter("CConn");
+}
diff --git a/java/com/tigervnc/vncviewer/ClipboardDialog.java b/java/com/tigervnc/vncviewer/ClipboardDialog.java
new file mode 100644
index 00000000..dca85f25
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/ClipboardDialog.java
@@ -0,0 +1,107 @@
+/* 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 com.tigervnc.vncviewer;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
+import javax.swing.*;
+import com.tigervnc.rfb.LogWriter;
+
+class ClipboardDialog extends Dialog implements ActionListener {
+
+ public ClipboardDialog(CConn cc_) {
+ super(false);
+ cc = cc_;
+ setTitle("VNC clipboard");
+ textArea = new JTextArea(5,50);
+ getContentPane().add("Center", textArea);
+
+ JPanel pb = new JPanel();
+ clearButton = new JButton("Clear");
+ pb.add(clearButton);
+ clearButton.addActionListener(this);
+ sendButton = new JButton("Send to VNC server");
+ pb.add(sendButton);
+ sendButton.addActionListener(this);
+ cancelButton = new JButton("Cancel");
+ pb.add(cancelButton);
+ cancelButton.addActionListener(this);
+ getContentPane().add("South", pb);
+
+ pack();
+ }
+
+ public void initDialog() {
+ textArea.setText(current);
+ textArea.selectAll();
+ }
+
+ public void setContents(String str) {
+ current = str;
+ textArea.setText(str);
+ textArea.selectAll();
+ }
+
+ public void serverCutText(String str, int len) {
+ setContents(str);
+ SecurityManager sm = System.getSecurityManager();
+ try {
+ if (sm != null) sm.checkSystemClipboardAccess();
+ Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
+ if (cb != null) {
+ StringSelection ss = new StringSelection(str);
+ try {
+ cb.setContents(ss, ss);
+ } catch(Exception e) {
+ vlog.debug(e.toString());
+ }
+ }
+ } catch(SecurityException e) {
+ System.err.println("Cannot access the system clipboard");
+ }
+ }
+
+ public void setSendingEnabled(boolean b) {
+ sendButton.setEnabled(b);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ Object s = e.getSource();
+ if (s instanceof JButton && (JButton)s == clearButton) {
+ current = "";
+ textArea.setText(current);
+ } else if (s instanceof JButton && (JButton)s == sendButton) {
+ ok = true;
+ current = textArea.getText();
+ cc.writeClientCutText(current, current.length());
+ endDialog();
+ } else if (s instanceof JButton && (JButton)s == cancelButton) {
+ ok = false;
+ endDialog();
+ }
+ }
+
+ CConn cc;
+ String current;
+ JTextArea textArea;
+ JButton clearButton, sendButton, cancelButton;
+ static LogWriter vlog = new LogWriter("ClipboardDialog");
+}
diff --git a/java/com/tigervnc/vncviewer/DesktopWindow.java b/java/com/tigervnc/vncviewer/DesktopWindow.java
new file mode 100644
index 00000000..f5acfff1
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/DesktopWindow.java
@@ -0,0 +1,553 @@
+/* Copyright (C) 2010 D. R. Commander. All Rights Reserved.
+ * Copyright (C) 2009 Paul Donohue. All Rights Reserved.
+ * Copyright (C) 2006 Constantin Kaplinsky. All Rights Reserved.
+ * 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.
+ */
+
+//
+// DesktopWindow is an AWT Canvas representing a VNC desktop.
+//
+// Methods on DesktopWindow are called from both the GUI thread and the thread
+// which processes incoming RFB messages ("the RFB thread"). This means we
+// need to be careful with synchronization here.
+//
+
+package com.tigervnc.vncviewer;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.Clipboard;
+import javax.swing.*;
+
+import com.tigervnc.rfb.*;
+import com.tigervnc.rfb.Cursor;
+import com.tigervnc.rfb.Exception;
+import com.tigervnc.rfb.Point;
+
+class DesktopWindow extends JPanel implements
+ Runnable,
+ MouseListener,
+ MouseMotionListener,
+ MouseWheelListener,
+ KeyListener
+{
+
+ ////////////////////////////////////////////////////////////////////
+ // The following methods are all called from the RFB thread
+
+ public DesktopWindow(int width, int height, PixelFormat serverPF, CConn cc_) {
+ cc = cc_;
+ setSize(width, height);
+ im = new PixelBufferImage(width, height, cc, this);
+
+ cursor = new Cursor();
+ cursorBacking = new ManagedPixelBuffer();
+ addMouseListener(this);
+ addMouseWheelListener(this);
+ addMouseMotionListener(this);
+ addKeyListener(this);
+ addFocusListener(new FocusAdapter() {
+ public void focusGained(FocusEvent e) {
+ checkClipboard();
+ }
+ });
+ setFocusTraversalKeysEnabled(false);
+ setFocusable(true);
+ setDoubleBuffered(true);
+ }
+
+ public int width() {
+ return getWidth();
+ }
+
+ public int height() {
+ return getHeight();
+ }
+
+ // initGraphics() is needed because for some reason you can't call
+ // getGraphics() on a newly-created awt Component. It is called when the
+ // DesktopWindow has actually been made visible so that getGraphics() ought
+ // to work.
+
+ public void initGraphics() {
+ cc.viewport.g = cc.viewport.getGraphics();
+ graphics = getComponentGraphics(cc.viewport.g);
+ prepareImage(im.image, scaledWidth, scaledHeight, this);
+ }
+
+ final public PixelFormat getPF() { return im.getPF(); }
+
+ synchronized public void setPF(PixelFormat pf) {
+ im.setPF(pf);
+ }
+
+ public void setViewport(ViewportFrame viewport)
+ {
+ viewport.setChild(this);
+ }
+
+ // Methods called from the RFB thread - these need to be synchronized
+ // wherever they access data shared with the GUI thread.
+
+ public void setCursor(int w, int h, Point hotspot,
+ int[] data, byte[] mask) {
+ // strictly we should use a mutex around this test since useLocalCursor
+ // might be being altered by the GUI thread. However it's only a single
+ // boolean and it doesn't matter if we get the wrong value anyway.
+
+ synchronized(this) {
+ if (!cc.viewer.useLocalCursor.getValue()) return;
+
+ hideLocalCursor();
+
+ cursor.hotspot = hotspot;
+
+ Dimension bsc = tk.getBestCursorSize(w, h);
+
+ cursor.setSize(((int)bsc.getWidth() > w ? (int)bsc.getWidth() : w),
+ ((int)bsc.getHeight() > h ? (int)bsc.getHeight() : h));
+ cursor.setPF(getPF());
+
+ cursorBacking.setSize(cursor.width(), cursor.height());
+ cursorBacking.setPF(getPF());
+
+ cursor.data = new int[cursor.width() * cursor.height()];
+ cursor.mask = new byte[cursor.maskLen()];
+
+ // set the masked pixels of the cursor transparent by using an extra bit in
+ // the colormap. We'll OR this into the data based on the values in the mask.
+ if (cursor.getPF().bpp == 8) {
+ cursor.cm = new DirectColorModel(9, 7, (7 << 3), (3 << 6), (1 << 8));
+ }
+
+ int maskBytesPerRow = (w + 7) / 8;
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ int byte_ = y * maskBytesPerRow + x / 8;
+ int bit = 7 - x % 8;
+ if ((mask[byte_] & (1 << bit)) > 0) {
+ cursor.data[y * cursor.width() + x] = (cursor.getPF().bpp == 8) ?
+ data[y * w + x] | (1 << 8) : data[y * w + x];
+ }
+ }
+ System.arraycopy(mask, y * maskBytesPerRow, cursor.mask,
+ y * ((cursor.width() + 7) / 8), maskBytesPerRow);
+ }
+
+ MemoryImageSource bitmap =
+ new MemoryImageSource(cursor.width(), cursor.height(), cursor.cm,
+ cursor.data, 0, cursor.width());
+ int cw = (int)Math.floor((float)cursor.width() * scaleWidthRatio);
+ int ch = (int)Math.floor((float)cursor.height() * scaleHeightRatio);
+ int hint = java.awt.Image.SCALE_DEFAULT;
+ hotspot = new Point((int)Math.floor((float)hotspot.x * scaleWidthRatio),
+ (int)Math.floor((float)hotspot.y * scaleHeightRatio));
+ Image cursorImage = (cw <= 0 || ch <= 0) ? tk.createImage(bitmap) :
+ tk.createImage(bitmap).getScaledInstance(cw,ch,hint);
+ softCursor = tk.createCustomCursor(cursorImage,
+ new java.awt.Point(hotspot.x,hotspot.y), "Cursor");
+ }
+
+ if (softCursor != null) {
+ setCursor(softCursor);
+ cursorAvailable = true;
+ return;
+ }
+
+ if (!cursorAvailable) {
+ cursorAvailable = true;
+ }
+
+ showLocalCursor();
+ return;
+ }
+
+ // setColourMapEntries() changes some of the entries in the colourmap.
+ // Unfortunately these messages are often sent one at a time, so we delay the
+ // settings taking effect unless the whole colourmap has changed. This is
+ // because getting java to recalculate its internal translation table and
+ // redraw the screen is expensive.
+
+ synchronized public void setColourMapEntries(int firstColour, int nColours,
+ int[] rgbs) {
+ im.setColourMapEntries(firstColour, nColours, rgbs);
+ if (nColours <= 256) {
+ im.updateColourMap();
+ im.put(0, 0, im.width(), im.height(), graphics);
+ } else {
+ if (setColourMapEntriesTimerThread == null) {
+ setColourMapEntriesTimerThread = new Thread(this);
+ setColourMapEntriesTimerThread.start();
+ }
+ }
+ }
+
+// Update the actual window with the changed parts of the framebuffer.
+
+ public void framebufferUpdateEnd()
+ {
+ drawInvalidRect();
+ }
+
+ // resize() is called when the desktop has changed size
+ synchronized public void resize() {
+ int w = cc.cp.width;
+ int h = cc.cp.height;
+ hideLocalCursor();
+ setSize(w, h);
+ im.resize(w, h);
+ }
+
+ final void drawInvalidRect() {
+ if (!invalidRect) return;
+ int x = invalidLeft;
+ int w = invalidRight - x;
+ int y = invalidTop;
+ int h = invalidBottom - y;
+ invalidRect = false;
+
+ synchronized (this) {
+ im.put(x, y, w, h, graphics);
+ }
+ }
+
+ final void invalidate(int x, int y, int w, int h) {
+ if (invalidRect) {
+ if (x < invalidLeft) invalidLeft = x;
+ if (x + w > invalidRight) invalidRight = x + w;
+ if (y < invalidTop) invalidTop = y;
+ if (y + h > invalidBottom) invalidBottom = y + h;
+ } else {
+ invalidLeft = x;
+ invalidRight = x + w;
+ invalidTop = y;
+ invalidBottom = y + h;
+ invalidRect = true;
+ }
+
+ if ((invalidRight - invalidLeft) * (invalidBottom - invalidTop) > 100000)
+ drawInvalidRect();
+ }
+
+ public void beginRect(int x, int y, int w, int h, int encoding) {
+ invalidRect = false;
+ }
+
+ public void endRect(int x, int y, int w, int h, int encoding) {
+ drawInvalidRect();
+ }
+
+ synchronized final public void fillRect(int x, int y, int w, int h, int pix)
+ {
+ if (overlapsCursor(x, y, w, h)) hideLocalCursor();
+ im.fillRect(x, y, w, h, pix);
+ invalidate(x, y, w, h);
+ if (softCursor == null)
+ showLocalCursor();
+ }
+
+ synchronized final public void imageRect(int x, int y, int w, int h,
+ int[] pix) {
+ if (overlapsCursor(x, y, w, h)) hideLocalCursor();
+ im.imageRect(x, y, w, h, pix);
+ invalidate(x, y, w, h);
+ if (softCursor == null)
+ showLocalCursor();
+ }
+
+ synchronized final public void copyRect(int x, int y, int w, int h,
+ int srcX, int srcY) {
+ if (overlapsCursor(x, y, w, h) || overlapsCursor(srcX, srcY, w, h))
+ hideLocalCursor();
+ im.copyRect(x, y, w, h, srcX, srcY);
+ if (!cc.viewer.fastCopyRect.getValue()) {
+ invalidate(x, y, w, h);
+ }
+ }
+
+
+ // mutex MUST be held when overlapsCursor() is called
+ final boolean overlapsCursor(int x, int y, int w, int h) {
+ return (x < cursorBackingX + cursorBacking.width() &&
+ y < cursorBackingY + cursorBacking.height() &&
+ x+w > cursorBackingX && y+h > cursorBackingY);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////
+ // The following methods are all called from the GUI thread
+
+ synchronized void resetLocalCursor() {
+ hideLocalCursor();
+ cursorAvailable = false;
+ }
+
+ //
+ // Callback methods to determine geometry of our Component.
+ //
+
+ public Dimension getPreferredSize() {
+ return new Dimension(scaledWidth, scaledHeight);
+ }
+
+ public Dimension getMinimumSize() {
+ return new Dimension(scaledWidth, scaledHeight);
+ }
+
+ public Dimension getMaximumSize() {
+ return new Dimension(scaledWidth, scaledHeight);
+ }
+
+ public void setScaledSize() {
+ if (!cc.options.autoScale && !cc.options.fixedRatioScale) {
+ scaledWidth = (int)Math.floor((float)cc.cp.width * (float)cc.scaleFactor/100.0);
+ scaledHeight = (int)Math.floor((float)cc.cp.height * (float)cc.scaleFactor/100.0);
+ } else {
+ if (cc.viewport == null) {
+ scaledWidth = cc.cp.width;
+ scaledHeight = cc.cp.height;
+ } else {
+ Dimension vpSize = cc.viewport.getSize();
+ Insets vpInsets = cc.viewport.getInsets();
+ Dimension availableSize =
+ new Dimension(vpSize.width - vpInsets.left - vpInsets.right,
+ vpSize.height - vpInsets.top - vpInsets.bottom);
+ if (availableSize.width == 0 || availableSize.height == 0)
+ availableSize = new Dimension(cc.cp.width, cc.cp.height);
+ if (cc.options.fixedRatioScale) {
+ float widthRatio = (float)availableSize.width / (float)cc.cp.width;
+ float heightRatio = (float)availableSize.height / (float)cc.cp.height;
+ float ratio = Math.min(widthRatio, heightRatio);
+ scaledWidth = (int)Math.floor(cc.cp.width * ratio);
+ scaledHeight = (int)Math.floor(cc.cp.height * ratio);
+ } else {
+ scaledWidth = availableSize.width;
+ scaledHeight = availableSize.height;
+ }
+ }
+ }
+ scaleWidthRatio = (float)scaledWidth / (float)cc.cp.width;
+ scaleHeightRatio = (float)scaledHeight / (float)cc.cp.height;
+ }
+
+ synchronized public void paintComponent(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g;
+ g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ g2.setRenderingHint(RenderingHints.KEY_RENDERING,
+ RenderingHints.VALUE_RENDER_QUALITY);
+ if (cc.cp.width == scaledWidth && cc.cp.height == scaledHeight) {
+ g2.drawImage(im.image, 0, 0, null);
+ } else {
+ g2.drawImage(im.image, 0, 0, scaledWidth, scaledHeight, null);
+ }
+ }
+
+ String oldContents = "";
+
+ synchronized public void checkClipboard() {
+ SecurityManager sm = System.getSecurityManager();
+ try {
+ if (sm != null) sm.checkSystemClipboardAccess();
+ Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
+ if (cb != null && cc.viewer.sendClipboard.getValue()) {
+ Transferable t = cb.getContents(null);
+ if ((t != null) && t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
+ try {
+ String newContents = (String)t.getTransferData(DataFlavor.stringFlavor);
+ if (newContents != null && !newContents.equals(oldContents)) {
+ cc.writeClientCutText(newContents, newContents.length());
+ oldContents = newContents;
+ cc.clipboardDialog.setContents(newContents);
+ }
+ } catch (java.lang.Exception e) {
+ System.out.println("Exception getting clipboard data: " + e.getMessage());
+ }
+ }
+ }
+ } catch(SecurityException e) {
+ System.err.println("Cannot access the system clipboard");
+ }
+ }
+
+ /** Mouse-Motion callback function */
+ private void mouseMotionCB(MouseEvent e) {
+ if (!cc.viewer.viewOnly.getValue())
+ cc.writePointerEvent(e);
+ // - If local cursor rendering is enabled then use it
+ synchronized(this) {
+ if (cursorAvailable) {
+ // - Render the cursor!
+ if (e.getX() != cursorPosX || e.getY() != cursorPosY) {
+ hideLocalCursor();
+ if (e.getX() >= 0 && e.getX() < im.width() &&
+ e.getY() >= 0 && e.getY() < im.height()) {
+ cursorPosX = e.getX();
+ cursorPosY = e.getY();
+ if (softCursor == null)
+ showLocalCursor();
+ }
+ }
+ }
+ }
+ lastX = e.getX();
+ lastY = e.getY();
+ }
+ public void mouseDragged(MouseEvent e) { mouseMotionCB(e);}
+ public void mouseMoved(MouseEvent e) { mouseMotionCB(e);}
+
+ /** Mouse callback function */
+ private void mouseCB(MouseEvent e) {
+ if (!cc.viewer.viewOnly.getValue())
+ cc.writePointerEvent(e);
+ lastX = e.getX();
+ lastY = e.getY();
+ }
+ public void mouseReleased(MouseEvent e){ mouseCB(e);}
+ public void mousePressed(MouseEvent e) { mouseCB(e);}
+ public void mouseClicked(MouseEvent e){}
+ public void mouseEntered(MouseEvent e){}
+ public void mouseExited(MouseEvent e){}
+
+ /** MouseWheel callback function */
+ private void mouseWheelCB(MouseWheelEvent e) {
+ if (!cc.viewer.viewOnly.getValue())
+ cc.writeWheelEvent(e);
+ }
+ public void mouseWheelMoved(MouseWheelEvent e){
+ mouseWheelCB(e);
+ }
+
+ /** Handle the key-typed event. */
+ public void keyTyped(KeyEvent e) {}
+ /** Handle the key-released event. */
+ public void keyReleased(KeyEvent e) {}
+ /** Handle the key-pressed event. */
+ public void keyPressed(KeyEvent e) {
+ if (e.getKeyCode() ==
+ (KeyEvent.VK_F1+cc.menuKey-Keysyms.F1)) {
+ int sx = (scaleWidthRatio == 1.00)
+ ? lastX : (int)Math.floor(lastX*scaleWidthRatio);
+ int sy = (scaleHeightRatio == 1.00)
+ ? lastY : (int)Math.floor(lastY*scaleHeightRatio);
+ java.awt.Point ev = new java.awt.Point(lastX, lastY);
+ ev.translate(sx - lastX, sy - lastY);
+ cc.showMenu((int)ev.getX(), (int)ev.getY());
+ return;
+ }
+ if (!cc.viewer.viewOnly.getValue())
+ cc.writeKeyEvent(e);
+ }
+
+ ////////////////////////////////////////////////////////////////////
+ // The following methods are called from both RFB and GUI threads
+
+ // Note that mutex MUST be held when hideLocalCursor() and showLocalCursor()
+ // are called.
+
+ private void hideLocalCursor() {
+ // - Blit the cursor backing store over the cursor
+ if (cursorVisible) {
+ cursorVisible = false;
+ im.imageRect(cursorBackingX, cursorBackingY, cursorBacking.width(),
+ cursorBacking.height(), cursorBacking.data);
+ im.put(cursorBackingX, cursorBackingY, cursorBacking.width(),
+ cursorBacking.height(), graphics);
+ }
+ }
+
+ private void showLocalCursor() {
+ if (cursorAvailable && !cursorVisible) {
+ if (!im.getPF().equal(cursor.getPF()) ||
+ cursor.width() == 0 || cursor.height() == 0) {
+ vlog.debug("attempting to render invalid local cursor");
+ cursorAvailable = false;
+ return;
+ }
+ cursorVisible = true;
+ if (softCursor != null) return;
+
+ int cursorLeft = cursor.hotspot.x;
+ int cursorTop = cursor.hotspot.y;
+ int cursorRight = cursorLeft + cursor.width();
+ int cursorBottom = cursorTop + cursor.height();
+
+ int x = (cursorLeft >= 0 ? cursorLeft : 0);
+ int y = (cursorTop >= 0 ? cursorTop : 0);
+ int w = ((cursorRight < im.width() ? cursorRight : im.width()) - x);
+ int h = ((cursorBottom < im.height() ? cursorBottom : im.height()) - y);
+
+ cursorBackingX = x;
+ cursorBackingY = y;
+ cursorBacking.setSize(w, h);
+
+ for (int j = 0; j < h; j++)
+ System.arraycopy(im.data, (y+j) * im.width() + x,
+ cursorBacking.data, j*w, w);
+
+ im.maskRect(cursorLeft, cursorTop, cursor.width(), cursor.height(),
+ cursor.data, cursor.mask);
+ im.put(x, y, w, h, graphics);
+ }
+ }
+
+
+ // run() is executed by the setColourMapEntriesTimerThread - it sleeps for
+ // 100ms before actually updating the colourmap.
+ public void run() {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {}
+ synchronized (this) {
+ im.updateColourMap();
+ im.put(0, 0, im.width(), im.height(), graphics);
+ setColourMapEntriesTimerThread = null;
+ }
+ }
+
+ // access to cc by different threads is specified in CConn
+ CConn cc;
+
+ // access to the following must be synchronized:
+ PixelBufferImage im;
+ Graphics graphics;
+ Thread setColourMapEntriesTimerThread;
+
+ Cursor cursor;
+ boolean cursorVisible; // Is cursor currently rendered?
+ boolean cursorAvailable; // Is cursor available for rendering?
+ int cursorPosX, cursorPosY;
+ ManagedPixelBuffer cursorBacking;
+ int cursorBackingX, cursorBackingY;
+ java.awt.Cursor softCursor;
+ static Toolkit tk = Toolkit.getDefaultToolkit();
+
+ public int scaledWidth = 0, scaledHeight = 0;
+ float scaleWidthRatio, scaleHeightRatio;
+
+ // the following are only ever accessed by the RFB thread:
+ boolean invalidRect;
+ int invalidLeft, invalidRight, invalidTop, invalidBottom;
+
+ // the following are only ever accessed by the GUI thread:
+ int lastX, lastY;
+
+ static LogWriter vlog = new LogWriter("DesktopWindow");
+}
diff --git a/java/com/tigervnc/vncviewer/Dialog.java b/java/com/tigervnc/vncviewer/Dialog.java
new file mode 100644
index 00000000..6a11fb3a
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/Dialog.java
@@ -0,0 +1,143 @@
+/* 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.
+ */
+
+//
+// This Dialog class implements a pop-up dialog. This is needed because
+// apparently you can't use the standard AWT Dialog from within an applet. The
+// dialog can be made visible by calling its showDialog() method. Dialogs can
+// be modal or non-modal. For a modal dialog box, the showDialog() method must
+// be called from a thread other than the GUI thread, and it only returns when
+// the dialog box has been dismissed. For a non-modal dialog box, the
+// showDialog() method returns immediately.
+
+package com.tigervnc.vncviewer;
+
+import java.io.*;
+import java.net.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import javax.swing.*;
+import javax.swing.filechooser.*;
+
+//class Dialog extends JFrame implements WindowListener {
+class Dialog extends JFrame {
+
+ protected boolean ok, done;
+ boolean modal;
+
+ public Dialog(boolean modal_) {
+ modal = modal_;
+ //addWindowListener(this);
+ }
+
+ public boolean showDialog() {
+ ok = false;
+ done = false;
+ initDialog();
+ Dimension dpySize = getToolkit().getScreenSize();
+ Dimension mySize = getSize();
+ int x = (dpySize.width - mySize.width) / 2;
+ int y = (dpySize.height - mySize.height) / 2;
+ setLocation(x, y);
+ ClassLoader cl = this.getClass().getClassLoader();
+ ImageIcon icon = new ImageIcon(cl.getResource("com/tigervnc/vncviewer/tigervnc.ico"));
+ setIconImage(icon.getImage());
+ //setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+ //setFont(new Font("SansSerif", Font.PLAIN, 11));
+
+ setVisible(true);
+ setFocusable(true);
+ if (!modal) return true;
+ synchronized(this) {
+ try {
+ while (!done)
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ return ok;
+ }
+
+ public void endDialog() {
+ done = true;
+ setVisible(false);
+ setFocusable(false);
+ if (modal) {
+ synchronized (this) {
+ notify();
+ }
+ }
+ }
+
+ // initDialog() can be overridden in a derived class. Typically it is used
+ // to make sure that checkboxes have the right state, etc.
+ public void initDialog() {
+ }
+
+ //------------------------------------------------------------------
+ // implemented blank methods
+ //public void windowClosed(WindowEvent event){}
+ //public void windowDeiconified(WindowEvent event){}
+ //public void windowIconified(WindowEvent event){}
+ //public void windowActivated(WindowEvent event){}
+ //public void windowDeactivated(WindowEvent event){}
+ //public void windowOpened(WindowEvent event){}
+
+ //------------------------------------------------------------------
+
+ // method to check which window was closing
+ //public void windowClosing(WindowEvent event) {
+ // ok = false;
+ // endDialog();
+ //}
+
+ public void addGBComponent(JComponent c, JComponent cp,
+ int gx, int gy,
+ int gw, int gh,
+ int gipx, int gipy,
+ double gwx, double gwy,
+ int fill, int anchor,
+ Insets insets)
+ {
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.anchor = anchor;
+ gbc.fill = fill;
+ gbc.gridx = gx;
+ gbc.gridy = gy;
+ gbc.gridwidth = gw;
+ gbc.gridheight = gh;
+ gbc.insets = insets;
+ gbc.ipadx = gipx;
+ gbc.ipady = gipy;
+ gbc.weightx = gwx;
+ gbc.weighty = gwy;
+ cp.add(c, gbc);
+ }
+
+ final public String getFileSeperator() {
+ String seperator = System.getProperties().get("file.separator").toString();
+ return seperator;
+ }
+
+ final public String getUserName() {
+ String userName = (String)System.getProperties().get("user.name");
+ return userName;
+ }
+
+}
diff --git a/java/com/tigervnc/vncviewer/F8Menu.java b/java/com/tigervnc/vncviewer/F8Menu.java
new file mode 100644
index 00000000..9b617857
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/F8Menu.java
@@ -0,0 +1,133 @@
+/* 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 com.tigervnc.vncviewer;
+
+import java.awt.Cursor;
+import java.awt.event.*;
+import javax.swing.JFrame;
+import javax.swing.JPopupMenu;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JCheckBoxMenuItem;
+
+import com.tigervnc.rfb.*;
+
+public class F8Menu extends JPopupMenu implements ActionListener {
+ public F8Menu(CConn cc_) {
+ super("VNC Menu");
+ setLightWeightPopupEnabled(false);
+ cc = cc_;
+ restore = addMenuItem("Restore",KeyEvent.VK_R);
+ move = addMenuItem("Move");
+ move.setEnabled(false);
+ size = addMenuItem("Size");
+ size.setEnabled(false);
+ minimize = addMenuItem("Minimize", KeyEvent.VK_N);
+ maximize = addMenuItem("Maximize", KeyEvent.VK_X);
+ addSeparator();
+ exit = addMenuItem("Close Viewer", KeyEvent.VK_C);
+ addSeparator();
+ fullScreen = new JCheckBoxMenuItem("Full Screen");
+ fullScreen.setMnemonic(KeyEvent.VK_F);
+ fullScreen.addActionListener(this);
+ add(fullScreen);
+ addSeparator();
+ clipboard = addMenuItem("Clipboard...");
+ addSeparator();
+ f8 = addMenuItem("Send F"+(cc.menuKey-Keysyms.F1+1));
+ ctrlAltDel = addMenuItem("Send Ctrl-Alt-Del");
+ addSeparator();
+ refresh = addMenuItem("Refresh Screen", KeyEvent.VK_H);
+ addSeparator();
+ newConn = addMenuItem("New connection...", KeyEvent.VK_W);
+ options = addMenuItem("Options...", KeyEvent.VK_O);
+ info = addMenuItem("Connection info...", KeyEvent.VK_I);
+ about = addMenuItem("About VncViewer...", KeyEvent.VK_A);
+ addSeparator();
+ dismiss = addMenuItem("Dismiss menu");
+ setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ }
+
+ JMenuItem addMenuItem(String str, int mnemonic) {
+ JMenuItem item = new JMenuItem(str, mnemonic);
+ item.addActionListener(this);
+ add(item);
+ return item;
+ }
+
+ JMenuItem addMenuItem(String str) {
+ JMenuItem item = new JMenuItem(str);
+ item.addActionListener(this);
+ add(item);
+ return item;
+ }
+
+ boolean actionMatch(ActionEvent ev, JMenuItem item) {
+ return ev.getActionCommand().equals(item.getActionCommand());
+ }
+
+ public void actionPerformed(ActionEvent ev) {
+ if (actionMatch(ev, exit)) {
+ cc.close();
+ } else if (actionMatch(ev, fullScreen)) {
+ cc.toggleFullScreen();
+ } else if (actionMatch(ev, restore)) {
+ if (cc.fullScreen) cc.toggleFullScreen();
+ cc.viewport.setExtendedState(JFrame.NORMAL);
+ } else if (actionMatch(ev, minimize)) {
+ if (cc.fullScreen) cc.toggleFullScreen();
+ cc.viewport.setExtendedState(JFrame.ICONIFIED);
+ } else if (actionMatch(ev, maximize)) {
+ if (cc.fullScreen) cc.toggleFullScreen();
+ cc.viewport.setExtendedState(JFrame.MAXIMIZED_BOTH);
+ } else if (actionMatch(ev, clipboard)) {
+ cc.clipboardDialog.showDialog();
+ } else if (actionMatch(ev, f8)) {
+ cc.writeKeyEvent(cc.menuKey, true);
+ cc.writeKeyEvent(cc.menuKey, false);
+ } else if (actionMatch(ev, ctrlAltDel)) {
+ cc.writeKeyEvent(Keysyms.Control_L, true);
+ cc.writeKeyEvent(Keysyms.Alt_L, true);
+ cc.writeKeyEvent(Keysyms.Delete, true);
+ cc.writeKeyEvent(Keysyms.Delete, false);
+ cc.writeKeyEvent(Keysyms.Alt_L, false);
+ cc.writeKeyEvent(Keysyms.Control_L, false);
+ } else if (actionMatch(ev, refresh)) {
+ cc.refresh();
+ } else if (actionMatch(ev, newConn)) {
+ VncViewer.newViewer(cc.viewer);
+ } else if (actionMatch(ev, options)) {
+ cc.options.showDialog();
+ } else if (actionMatch(ev, info)) {
+ cc.showInfo();
+ } else if (actionMatch(ev, about)) {
+ cc.showAbout();
+ } else if (actionMatch(ev, dismiss)) {
+ firePopupMenuCanceled();
+ }
+ }
+
+ CConn cc;
+ JMenuItem restore, move, size, minimize, maximize;
+ JMenuItem exit, clipboard, ctrlAltDel, refresh;
+ JMenuItem newConn, options, info, about, dismiss;
+ static JMenuItem f8;
+ JCheckBoxMenuItem fullScreen;
+ static LogWriter vlog = new LogWriter("F8Menu");
+}
diff --git a/java/com/tigervnc/vncviewer/LICENCE.TXT b/java/com/tigervnc/vncviewer/LICENCE.TXT
new file mode 100644
index 00000000..ae3b5319
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/LICENCE.TXT
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program 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 program 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 program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/java/com/tigervnc/vncviewer/MANIFEST.MF b/java/com/tigervnc/vncviewer/MANIFEST.MF
new file mode 100644
index 00000000..b3574fe2
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/MANIFEST.MF
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Main-Class: com.tigervnc.vncviewer.VncViewer
diff --git a/java/com/tigervnc/vncviewer/OptionsDialog.java b/java/com/tigervnc/vncviewer/OptionsDialog.java
new file mode 100644
index 00000000..9664dc99
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/OptionsDialog.java
@@ -0,0 +1,413 @@
+/* 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 com.tigervnc.vncviewer;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.filechooser.*;
+import javax.swing.ImageIcon;
+import java.net.URL;
+import java.io.IOException;
+
+import com.tigervnc.rfb.*;
+import com.tigervnc.rfb.Exception;
+
+class OptionsDialog extends Dialog implements
+ ActionListener,
+ ItemListener
+{
+
+ // Constants
+ // Static variables
+ static LogWriter vlog = new LogWriter("OptionsDialog");
+
+ OptionsDialogCallback cb;
+ JPanel FormatPanel, InputsPanel, MiscPanel, DefaultsPanel, SecPanel;
+ JCheckBox autoSelect, customCompressLevel, noJpeg;
+ JComboBox menuKey, compressLevel, qualityLevel, scalingFactor;
+ ButtonGroup encodingGroup, colourGroup;
+ JRadioButton zrle, hextile, tight, raw;
+ JRadioButton fullColour, mediumColour, lowColour, veryLowColour;
+ JCheckBox viewOnly, acceptClipboard, sendClipboard, acceptBell;
+ JCheckBox fullScreen, shared, useLocalCursor, fastCopyRect;
+ JCheckBox secVeNCrypt, encNone, encTLS, encX509;
+ JCheckBox secNone, secVnc, secPlain, secIdent, sendLocalUsername;
+ JButton okButton, cancelButton;
+ JButton ca, crl;
+ JButton defSaveButton;
+ UserPrefs defaults;
+
+ boolean autoScale = false;
+ boolean fixedRatioScale = false;
+
+ public OptionsDialog(OptionsDialogCallback cb_) {
+ super(false);
+ cb = cb_;
+ setResizable(false);
+ setTitle("VNC Viewer Options");
+ defaults = new UserPrefs("vncviewer");
+
+ getContentPane().setLayout(
+ new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
+
+ JTabbedPane tabPane = new JTabbedPane();
+
+ ButtonGroup encodingGroup = new ButtonGroup();
+ ButtonGroup colourGroup = new ButtonGroup();
+
+ // Colour & Encoding tab
+ FormatPanel=new JPanel(new GridBagLayout());
+
+ autoSelect = new JCheckBox("Auto Select");
+ autoSelect.addItemListener(this);
+
+ JPanel encodingPanel = new JPanel(new GridBagLayout());
+ encodingPanel.setBorder(BorderFactory.createTitledBorder("Preferred encoding"));
+ zrle = addRadioCheckbox("ZRLE", encodingGroup, encodingPanel);
+ hextile = addRadioCheckbox("Hextile", encodingGroup, encodingPanel);
+ tight = addRadioCheckbox("Tight", encodingGroup, encodingPanel);
+ raw = addRadioCheckbox("Raw", encodingGroup, encodingPanel);
+
+ JPanel tightPanel = new JPanel(new GridBagLayout());
+ customCompressLevel = new JCheckBox("Custom Compression Level");
+ customCompressLevel.addItemListener(this);
+ Object[] compressionLevels = { 1, 2, 3, 4, 5, 6 };
+ compressLevel = new JComboBox(compressionLevels);
+ compressLevel.setEditable(true);
+ JLabel compressionLabel = new JLabel("Level (1=fast, 6=best [4-6 are rarely useful])");
+ noJpeg = new JCheckBox("Allow JPEG Compression");
+ noJpeg.addItemListener(this);
+ Object[] qualityLevels = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ qualityLevel = new JComboBox(qualityLevels);
+ JLabel qualityLabel = new JLabel("Level (0=poor, 9=best)");
+ compressLevel.setPreferredSize(qualityLevel.getPreferredSize());
+ // Hack to set the left inset on editable JComboBox
+ if (UIManager.getLookAndFeel().getID() == "Windows") {
+ compressLevel.setBorder(BorderFactory.createCompoundBorder(compressLevel.getBorder(),
+ BorderFactory.createEmptyBorder(0,1,0,0)));
+ } else {
+ ComboBoxEditor editor = compressLevel.getEditor();
+ JTextField jtf = (JTextField)editor.getEditorComponent();
+ jtf.setBorder(new CompoundBorder(jtf.getBorder(), new EmptyBorder(0,1,0,0)));
+ }
+ addGBComponent(customCompressLevel, tightPanel, 0, 0, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));
+ addGBComponent(compressLevel, tightPanel, 0, 1, 1, 1, 2, 2, 0, 0, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(0,20,0,0));
+ addGBComponent(compressionLabel, tightPanel, 1, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,5,0,0));
+ addGBComponent(noJpeg, tightPanel, 0, 2, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));
+ addGBComponent(qualityLevel, tightPanel, 0, 3, 1, 1, 2, 2, 0, 0, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(0,20,0,0));
+ addGBComponent(qualityLabel, tightPanel, 1, 3, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,5,0,0));
+
+
+ JPanel colourPanel = new JPanel(new GridBagLayout());
+ colourPanel.setBorder(BorderFactory.createTitledBorder("Colour level"));
+ fullColour = addRadioCheckbox("Full (all available colours)", colourGroup, colourPanel);
+ mediumColour = addRadioCheckbox("Medium (256 colours)", colourGroup, colourPanel);
+ lowColour = addRadioCheckbox("Low (64 colours)", colourGroup, colourPanel);
+ veryLowColour = addRadioCheckbox("Very low(8 colours)", colourGroup, colourPanel);
+
+ addGBComponent(autoSelect,FormatPanel, 0, 0, 2, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));
+ addGBComponent(encodingPanel,FormatPanel, 0, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,2,0,0));
+ addGBComponent(colourPanel,FormatPanel, 1, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_END, new Insets(0,2,0,0));
+ addGBComponent(tightPanel,FormatPanel, 0, 2, 2, GridBagConstraints.REMAINDER, 2, 2, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,0));
+
+ // Inputs tab
+ InputsPanel=new JPanel(new GridBagLayout());
+
+ viewOnly = new JCheckBox("View Only (ignore mouse & keyboard)");
+ viewOnly.addItemListener(this);
+ acceptClipboard = new JCheckBox("Accept clipboard from server");
+ acceptClipboard.addItemListener(this);
+ sendClipboard = new JCheckBox("Send clipboard to server");
+ sendClipboard.addItemListener(this);
+ JLabel menuKeyLabel = new JLabel("Menu Key");
+ String[] menuKeys =
+ { "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12" };
+ menuKey = new JComboBox(menuKeys);
+ menuKey.addItemListener(this);
+ addGBComponent(viewOnly,InputsPanel, 0, 0, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+ addGBComponent(acceptClipboard,InputsPanel, 0, 1, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+ addGBComponent(sendClipboard,InputsPanel, 0, 2, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+ addGBComponent(menuKeyLabel,InputsPanel, 0, 3, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(8,8,0,4));
+ addGBComponent(menuKey,InputsPanel, 1, 3, 1, GridBagConstraints.REMAINDER, 0, 0, 25, 1, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(4,4,0,4));
+
+ // Misc tab
+ MiscPanel=new JPanel(new GridBagLayout());
+
+ fullScreen = new JCheckBox("Full-screen mode");
+ fullScreen.addItemListener(this);
+ shared = new JCheckBox("Shared connection (do not disconnect other viewers)");
+ shared.addItemListener(this);
+ useLocalCursor = new JCheckBox("Render cursor locally");
+ useLocalCursor.addItemListener(this);
+ fastCopyRect = new JCheckBox("Fast CopyRect");
+ fastCopyRect.addItemListener(this);
+ acceptBell = new JCheckBox("Beep when requested by the server");
+ acceptBell.addItemListener(this);
+ JLabel scalingFactorLabel = new JLabel("Scaling Factor");
+ Object[] scalingFactors = {
+ "Auto", "Fixed Aspect Ratio", "50%", "75%", "95%", "100%", "105%",
+ "125%", "150%", "175%", "200%", "250%", "300%", "350%", "400%" };
+ scalingFactor = new JComboBox(scalingFactors);
+ scalingFactor.setEditable(true);
+ scalingFactor.addItemListener(this);
+ addGBComponent(fullScreen,MiscPanel, 0, 0, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+ addGBComponent(shared,MiscPanel, 0, 1, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+ addGBComponent(useLocalCursor,MiscPanel, 0, 2, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+ addGBComponent(fastCopyRect,MiscPanel, 0, 3, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(4,4,0,4));
+ addGBComponent(acceptBell,MiscPanel, 0, 4, 2, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(4,4,0,4));
+ addGBComponent(scalingFactorLabel,MiscPanel, 0, 5, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(8,8,0,4));
+ addGBComponent(scalingFactor,MiscPanel, 1, 5, 1, GridBagConstraints.REMAINDER, 0, 0, 25, 1, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(4,4,0,4));
+
+ // load/save tab
+ DefaultsPanel=new JPanel(new GridBagLayout());
+
+ JPanel configPanel = new JPanel(new GridBagLayout());
+ configPanel.setBorder(BorderFactory.createTitledBorder("Configuration File"));
+ JButton cfReloadButton = new JButton("Reload");
+ cfReloadButton.addActionListener(this);
+ addGBComponent(cfReloadButton,configPanel, 0, 0, 1, 1, 0, 0, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+ JButton cfSaveButton = new JButton("Save");
+ cfSaveButton.addActionListener(this);
+ addGBComponent(cfSaveButton,configPanel, 0, 1, 1, 1, 0, 0, 0, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+ JButton cfSaveAsButton = new JButton("Save As...");
+ cfSaveAsButton.addActionListener(this);
+ addGBComponent(cfSaveAsButton,configPanel, 0, 2, 1, 1, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+ cfReloadButton.setEnabled(false);
+ cfSaveButton.setEnabled(false);
+ //cfSaveAsButton.setEnabled(!applet);
+
+ JPanel defaultsPanel = new JPanel(new GridBagLayout());
+ defaultsPanel.setBorder(BorderFactory.createTitledBorder("Defaults"));
+ JButton defReloadButton = new JButton("Reload");
+ defReloadButton.addActionListener(this);
+ addGBComponent(defReloadButton,defaultsPanel, 0, 0, 1, 1, 0, 0, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+ defSaveButton = new JButton("Save");
+ defSaveButton.addActionListener(this);
+ addGBComponent(defSaveButton,defaultsPanel, 0, 1, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(4,8,4,8));
+
+ addGBComponent(configPanel,DefaultsPanel, 0, 0, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.PAGE_START, new Insets(4,4,4,4));
+ addGBComponent(defaultsPanel,DefaultsPanel, 1, 0, 1, GridBagConstraints.REMAINDER, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.PAGE_START, new Insets(4,4,4,4));
+ //defReloadButton.setEnabled(!applet);
+ //defSaveButton.setEnabled(!applet);
+
+ // security tab
+ SecPanel=new JPanel(new GridBagLayout());
+
+ JPanel encryptionPanel = new JPanel(new GridBagLayout());
+ encryptionPanel.setBorder(BorderFactory.createTitledBorder("Session Encryption"));
+ encNone = addCheckbox("None", null, encryptionPanel);
+ encTLS = addCheckbox("Anonymous TLS", null, encryptionPanel);
+ encX509 = addJCheckBox("TLS with X.509 certificates", null, encryptionPanel, new GridBagConstraints(0,2,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.REMAINDER,new Insets(0,0,0,60),0,0));
+
+ JPanel x509Panel = new JPanel(new GridBagLayout());
+ x509Panel.setBorder(BorderFactory.createTitledBorder("X.509 certificates"));
+ ca = new JButton("Load CA certificate");
+ ca.setPreferredSize(new Dimension(145,25));
+ ca.addActionListener(this);
+ crl = new JButton("Load CRL certificate");
+ crl.setPreferredSize(new Dimension(145,25));
+ crl.addActionListener(this);
+ addGBComponent(ca, x509Panel, 0, 0, 1, 1, 2, 2, 0, 1, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(2,2,2,2));
+ addGBComponent(crl, x509Panel, 1, 0, 1, 1, 2, 2, 1, 1, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(2,2,2,2));
+
+ JPanel authPanel = new JPanel(new GridBagLayout());
+ authPanel.setBorder(BorderFactory.createTitledBorder("Authentication"));
+ secNone = addCheckbox("None", null, authPanel);
+ secVnc = addCheckbox("Standard VNC", null, authPanel);
+ secPlain = addJCheckBox("Plaintext", null, authPanel, new GridBagConstraints(0,2,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.NONE,new Insets(0,0,0,5),0,0));
+ secIdent = addJCheckBox("Ident", null, authPanel, new GridBagConstraints(0,3,1,1,1,1,GridBagConstraints.LINE_START,GridBagConstraints.NONE,new Insets(0,0,0,5),0,0));
+ sendLocalUsername = new JCheckBox("Send Local Username");
+ sendLocalUsername.addItemListener(this);
+ addGBComponent(sendLocalUsername, authPanel, 1, 2, 1, 2, 0, 0, 2, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(0,20,0,0));
+
+ secVeNCrypt = new JCheckBox("Extended encryption and authentication methods (VeNCrypt)");
+ secVeNCrypt.addItemListener(this);
+ addGBComponent(secVeNCrypt,SecPanel, 0, 0, 1, 1, 2, 2, 1, 0, GridBagConstraints.HORIZONTAL, GridBagConstraints.FIRST_LINE_START, new Insets(0,2,0,20));
+ addGBComponent(encryptionPanel,SecPanel, 0, 1, 1, 1, 2, 2, 1, 0, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(0,4,2,4));
+ addGBComponent(x509Panel,SecPanel, 0, 2, 1, 1, 2, 2, 1, 0, GridBagConstraints.NONE, GridBagConstraints.LINE_START, new Insets(2,4,2,4));
+ addGBComponent(authPanel,SecPanel, 0, 3, 1, 1, 2, 2, 1, 1, GridBagConstraints.NONE, GridBagConstraints.FIRST_LINE_START, new Insets(2,4,2,4));
+
+ tabPane.add(FormatPanel);
+ tabPane.add(InputsPanel);
+ tabPane.add(MiscPanel);
+ tabPane.add(DefaultsPanel);
+ tabPane.add(SecPanel);
+ tabPane.addTab("Colour & Encoding", FormatPanel);
+ tabPane.addTab("Inputs", InputsPanel);
+ tabPane.addTab("Misc", MiscPanel);
+ tabPane.addTab("Load / Save", DefaultsPanel);
+ tabPane.addTab("Security", SecPanel);
+ tabPane.setBorder(BorderFactory.createEmptyBorder(4,4,0,4));
+
+ okButton = new JButton("OK");
+ okButton.setPreferredSize(new Dimension(90,30));
+ okButton.addActionListener(this);
+ cancelButton = new JButton("Cancel");
+ cancelButton.setPreferredSize(new Dimension(90,30));
+ cancelButton.addActionListener(this);
+
+ JPanel buttonPane = new JPanel();
+ buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
+ buttonPane.setBorder(BorderFactory.createEmptyBorder(4,0,0,0));
+ buttonPane.add(Box.createHorizontalGlue());
+ buttonPane.add(okButton);
+ buttonPane.add(Box.createRigidArea(new Dimension(4,0)));
+ buttonPane.add(cancelButton);
+ buttonPane.add(Box.createRigidArea(new Dimension(4,0)));
+
+ this.getContentPane().add(tabPane);
+ this.getContentPane().add(buttonPane);
+
+ pack();
+
+ }
+
+ public void initDialog() {
+ if (cb != null) cb.setOptions();
+ zrle.setEnabled(!autoSelect.isSelected());
+ hextile.setEnabled(!autoSelect.isSelected());
+ tight.setEnabled(!autoSelect.isSelected());
+ raw.setEnabled(!autoSelect.isSelected());
+ fullColour.setEnabled(!autoSelect.isSelected());
+ mediumColour.setEnabled(!autoSelect.isSelected());
+ lowColour.setEnabled(!autoSelect.isSelected());
+ veryLowColour.setEnabled(!autoSelect.isSelected());
+ compressLevel.setEnabled(customCompressLevel.isSelected());
+ qualityLevel.setEnabled(noJpeg.isSelected());
+ autoScale = (scalingFactor.getSelectedItem().equals("Auto"));
+ fixedRatioScale =
+ (scalingFactor.getSelectedItem().equals("Fixed Aspect Ratio"));
+ sendLocalUsername.setEnabled(secVeNCrypt.isEnabled()&&
+ (secPlain.isSelected()||secIdent.isSelected()));
+ }
+
+ JRadioButton addRadioCheckbox(String str, ButtonGroup group, JPanel panel) {
+ JRadioButton c = new JRadioButton(str);
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.anchor = GridBagConstraints.LINE_START;
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.weightx = 1;
+ gbc.weighty = 1;
+ panel.add(c,gbc);
+ group.add(c);
+ c.addItemListener(this);
+ return c;
+ }
+
+ JCheckBox addCheckbox(String str, ButtonGroup group, JPanel panel) {
+ JCheckBox c = new JCheckBox(str);
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.anchor = GridBagConstraints.LINE_START;
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.weightx = 1;
+ gbc.weighty = 1;
+ panel.add(c,gbc);
+ if (group != null)
+ group.add(c);
+ c.addItemListener(this);
+ return c;
+ }
+
+ JCheckBox addJCheckBox(String str, ButtonGroup group, JPanel panel,
+ GridBagConstraints gbc) {
+ JCheckBox c = new JCheckBox(str);
+ panel.add(c,gbc);
+ if (group != null)
+ group.add(c);
+ c.addItemListener(this);
+
+ return c;
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ Object s = e.getSource();
+ if (s instanceof JButton && (JButton)s == okButton) {
+ autoScale = (scalingFactor.getSelectedItem().equals("Auto"));
+ fixedRatioScale =
+ (scalingFactor.getSelectedItem().equals("Fixed Aspect Ratio"));
+ ok = true;
+ if (cb != null) cb.getOptions();
+ endDialog();
+ } else if (s instanceof JButton && (JButton)s == cancelButton) {
+ ok = false;
+ endDialog();
+ } else if (s instanceof JButton && (JButton)s == defSaveButton) {
+ try {
+ defaults.Save();
+ } catch (java.lang.Exception x) { }
+ } else if (s instanceof JButton && (JButton)s == ca) {
+ JFileChooser fc = new JFileChooser();
+ fc.setDialogTitle("Path to X509 CA certificate");
+ int ret = fc.showOpenDialog(this);
+ if (ret == JFileChooser.APPROVE_OPTION)
+ CSecurityTLS.x509ca.setParam(fc.getSelectedFile().toString());
+ } else if (s instanceof JButton && (JButton)s == crl) {
+ JFileChooser fc = new JFileChooser();
+ fc.setDialogTitle("Path to X509 CRL file");
+ int ret = fc.showOpenDialog(this);
+ if (ret == JFileChooser.APPROVE_OPTION)
+ CSecurityTLS.x509crl.setParam(fc.getSelectedFile().toString());
+ }
+ }
+
+ public void itemStateChanged(ItemEvent e) {
+ Object s = e.getSource();
+ if (s instanceof JCheckBox && (JCheckBox)s == autoSelect) {
+ zrle.setEnabled(!autoSelect.isSelected());
+ hextile.setEnabled(!autoSelect.isSelected());
+ tight.setEnabled(!autoSelect.isSelected());
+ raw.setEnabled(!autoSelect.isSelected());
+ fullColour.setEnabled(!autoSelect.isSelected());
+ mediumColour.setEnabled(!autoSelect.isSelected());
+ lowColour.setEnabled(!autoSelect.isSelected());
+ veryLowColour.setEnabled(!autoSelect.isSelected());
+ defaults.setPref("autoSelect",(autoSelect.isSelected()) ? "on" : "off");
+ }
+ if (s instanceof JCheckBox && (JCheckBox)s == customCompressLevel) {
+ compressLevel.setEnabled(customCompressLevel.isSelected());
+ defaults.setPref("customCompressLevel",(customCompressLevel.isSelected()) ? "on" : "off");
+ }
+ if (s instanceof JCheckBox && (JCheckBox)s == noJpeg) {
+ qualityLevel.setEnabled(noJpeg.isSelected());
+ defaults.setPref("noJpeg",(noJpeg.isSelected()) ? "on" : "off");
+ }
+ if (s instanceof JCheckBox && (JCheckBox)s == sendLocalUsername) {
+ defaults.setPref("sendLocalUsername",(sendLocalUsername.isSelected()) ? "on" : "off");
+ }
+ if (s instanceof JCheckBox && (JCheckBox)s == secVeNCrypt) {
+ encNone.setEnabled(secVeNCrypt.isSelected());
+ encTLS.setEnabled(secVeNCrypt.isSelected());
+ encX509.setEnabled(secVeNCrypt.isSelected());
+ ca.setEnabled(secVeNCrypt.isSelected());
+ crl.setEnabled(secVeNCrypt.isSelected());
+ secIdent.setEnabled(secVeNCrypt.isSelected());
+ secNone.setEnabled(secVeNCrypt.isSelected());
+ secVnc.setEnabled(secVeNCrypt.isSelected());
+ secPlain.setEnabled(secVeNCrypt.isSelected());
+ sendLocalUsername.setEnabled(secVeNCrypt.isSelected());
+ }
+ if (s instanceof JCheckBox && (JCheckBox)s == secIdent ||
+ s instanceof JCheckBox && (JCheckBox)s == secPlain) {
+ sendLocalUsername.setEnabled(secIdent.isSelected()||secPlain.isSelected());
+ }
+ }
+
+}
diff --git a/java/com/tigervnc/vncviewer/OptionsDialogCallback.java b/java/com/tigervnc/vncviewer/OptionsDialogCallback.java
new file mode 100644
index 00000000..f6897e24
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/OptionsDialogCallback.java
@@ -0,0 +1,24 @@
+/* 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 com.tigervnc.vncviewer;
+
+public interface OptionsDialogCallback {
+ public void setOptions();
+ public void getOptions();
+}
diff --git a/java/com/tigervnc/vncviewer/PasswdDialog.java b/java/com/tigervnc/vncviewer/PasswdDialog.java
new file mode 100644
index 00000000..eaace698
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/PasswdDialog.java
@@ -0,0 +1,88 @@
+/* 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 com.tigervnc.vncviewer;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.net.URL;
+
+class PasswdDialog extends Dialog implements KeyListener{
+
+ public PasswdDialog(String title, boolean userDisabled, boolean passwdDisabled) {
+ super(true);
+ setResizable(false);
+ setTitle(title);
+ setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+
+ JPanel p1 = new JPanel();
+ userLabel = new JLabel("Username:");
+ p1.add(userLabel);
+ userEntry = new JTextField(30);
+ userEntry.setEnabled(!userDisabled);
+ userLabel.setEnabled(!userDisabled);
+ p1.add(userEntry);
+ userEntry.addKeyListener(this);
+
+ JPanel p2 = new JPanel();
+ passwdLabel = new JLabel("Password:");
+ passwdLabel.setPreferredSize(userLabel.getPreferredSize());
+ p2.add(passwdLabel);
+ passwdEntry = new JPasswordField(30);
+ passwdEntry.setEnabled(!passwdDisabled);
+ passwdLabel.setEnabled(!passwdDisabled);
+ p2.add(passwdEntry);
+ passwdEntry.addKeyListener(this);
+
+ getContentPane().setLayout(new BoxLayout(getContentPane(),BoxLayout.Y_AXIS));
+ getContentPane().add(p1);
+ getContentPane().add(p2);
+ pack();
+ if (userEntry.isEnabled()) {
+ userEntry.requestFocus();
+ } else {
+ passwdEntry.requestFocus();
+ }
+ }
+
+ /** Handle the key-typed event. */
+ public void keyTyped(KeyEvent event) { }
+ /** Handle the key-released event. */
+ public void keyReleased(KeyEvent event) { }
+ /** Handle the key-pressed event. */
+ public void keyPressed(KeyEvent event) {
+ Object s = event.getSource();
+ if (s instanceof JTextField && (JTextField)s == userEntry) {
+ if (event.getKeyCode() == KeyEvent.VK_ENTER) {
+ ok = true;
+ endDialog();
+ }
+ } else if (s instanceof JPasswordField && (JPasswordField)s == passwdEntry) {
+ if (event.getKeyCode() == KeyEvent.VK_ENTER) {
+ ok = true;
+ endDialog();
+ }
+ }
+ }
+
+ JLabel userLabel;
+ JTextField userEntry;
+ JLabel passwdLabel;
+ JTextField passwdEntry;
+}
diff --git a/java/com/tigervnc/vncviewer/PixelBufferImage.java b/java/com/tigervnc/vncviewer/PixelBufferImage.java
new file mode 100644
index 00000000..7e5e7174
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/PixelBufferImage.java
@@ -0,0 +1,185 @@
+/* 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.
+ */
+
+//
+// PixelBufferImage is an PixelBuffer which also acts as an ImageProducer.
+// Currently it only supports 8-bit colourmapped pixel format.
+//
+
+package com.tigervnc.vncviewer;
+
+import java.awt.*;
+import java.awt.image.*;
+import java.nio.ByteOrder;
+import javax.swing.JScrollPane;
+
+import com.tigervnc.rfb.*;
+
+public class PixelBufferImage extends PixelBuffer implements ImageProducer
+{
+ public PixelBufferImage(int w, int h, CConn cc_, DesktopWindow desktop_) {
+ cc = cc_;
+ desktop = desktop_;
+ PixelFormat nativePF = getNativePF();
+ switch ((nativePF.depth > cc.serverPF.depth) ? cc.serverPF.depth : nativePF.depth) {
+ case 8:
+ setPF(new PixelFormat(8,8,false,true,7,7,3,0,3,6));
+ break;
+ case 16:
+ setPF(new PixelFormat(16,16,false,true,0xF800,0x07C0,0x003E,0,0,0));
+ break;
+ case 24:
+ setPF(new PixelFormat(32,24,false,true,0xff,0xff,0xff,16,8,0));
+ break;
+ default:
+ setPF(new PixelFormat(8,8,false,true,7,7,3,0,3,6));
+ vlog.debug("Unsupported native PF, defaulting to depth 8");
+ }
+ resize(w, h);
+ }
+
+ // resize() resizes the image, preserving the image data where possible.
+ public void resize(int w, int h) {
+ if (w == width() && h == height()) return;
+
+ int rowsToCopy = h < height() ? h : height();
+ int copyWidth = w < width() ? w : width();
+ int oldWidth = width();
+ int[] oldData = data;
+
+ width_ = w;
+ height_ = h;
+ image = desktop.createImage(this);
+ //image.setAccelerationPriority(1);
+
+ data = new int[width() * height()];
+
+ for (int i = 0; i < rowsToCopy; i++)
+ System.arraycopy(oldData, copyWidth * i,
+ data, width() * i, copyWidth);
+ }
+
+ private PixelFormat getNativePF() {
+ PixelFormat pf;
+ cm = java.awt.Toolkit.getDefaultToolkit().getColorModel();
+ if (cm.getColorSpace().getType() == java.awt.color.ColorSpace.TYPE_RGB) {
+ int depth = cm.getPixelSize();
+ int bpp = (depth > 16 ? 32 : (depth > 8 ? 16 : 8));
+ ByteOrder byteOrder = ByteOrder.nativeOrder();
+ boolean bigEndian = (byteOrder == ByteOrder.BIG_ENDIAN ? true : false);
+ boolean trueColour = (depth > 8 ? true : false);
+ int redShift = cm.getComponentSize()[0] + cm.getComponentSize()[1];
+ int greenShift = cm.getComponentSize()[0];
+ int blueShift = 0;
+ pf = new PixelFormat(bpp, depth, bigEndian, trueColour,
+ (depth > 8 ? 0xff : 0),
+ (depth > 8 ? 0xff : 0),
+ (depth > 8 ? 0xff : 0),
+ (depth > 8 ? redShift : 0),
+ (depth > 8 ? greenShift : 0),
+ (depth > 8 ? blueShift : 0));
+ } else {
+ pf = new PixelFormat(8, 8, false, false, 7, 7, 3, 0, 3, 6);
+ }
+ vlog.debug("Native pixel format is "+pf.print());
+ return pf;
+ }
+
+ // put() causes the given rectangle to be drawn using the given graphics
+ // context.
+ public void put(int x, int y, int w, int h, Graphics g) {
+ if (ic != null) {
+ ic.setPixels(x, y, w, h, cm, data, width() * y + x, width());
+ ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+ }
+ }
+
+ // fillRect(), imageRect(), maskRect() are inherited from PixelBuffer. For
+ // copyRect() we also need to tell the ImageConsumer that the pixels have
+ // changed (this is done in the put() call for the others).
+
+ public void copyRect(int x, int y, int w, int h, int srcX, int srcY) {
+ super.copyRect(x, y, w, h, srcX, srcY);
+ if (ic == null) return;
+ ic.setPixels(x, y, w, h, cm, data, width() * y + x, width());
+ ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+ }
+
+ // setColourMapEntries() changes some of the entries in the colourmap.
+ // However these settings won't take effect until updateColourMap() is
+ // called. This is because getting java to recalculate its internal
+ // translation table and redraw the screen is expensive.
+
+ public void setColourMapEntries(int firstColour, int nColours_,
+ int[] rgbs) {
+ nColours = nColours_;
+ reds = new byte[nColours];
+ blues = new byte[nColours];
+ greens = new byte[nColours];
+ for (int i = 0; i < nColours; i++) {
+ reds[firstColour+i] = (byte)(rgbs[i*3] >> 8);
+ greens[firstColour+i] = (byte)(rgbs[i*3+1] >> 8);
+ blues[firstColour+i] = (byte)(rgbs[i*3+2] >> 8);
+ }
+ }
+
+ // ImageProducer methods
+
+ public void updateColourMap() {
+ cm = new IndexColorModel(8, nColours, reds, greens, blues);
+ }
+
+ public void addConsumer(ImageConsumer c) {
+ if (ic == c) return;
+
+ vlog.debug("adding consumer "+c);
+
+ if (ic != null)
+ vlog.error("Only one ImageConsumer allowed - discarding old one");
+
+ ic = c;
+ ic.setDimensions(width(), height());
+ ic.setHints(ImageConsumer.RANDOMPIXELORDER);
+ // Calling ic.setColorModel(cm) seemed to help in some earlier versions of
+ // the JDK, but it shouldn't be necessary because we pass the ColorModel
+ // with each setPixels() call.
+ ic.setPixels(0, 0, width(), height(), cm, data, 0, width());
+ ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
+ }
+
+ public void removeConsumer(ImageConsumer c) {
+ System.err.println("removeConsumer "+c);
+ if (ic == c) ic = null;
+ }
+
+ public boolean isConsumer(ImageConsumer c) { return ic == c; }
+ public void requestTopDownLeftRightResend(ImageConsumer c) {}
+ public void startProduction(ImageConsumer c) { addConsumer(c); }
+
+ Image image;
+ ImageConsumer ic;
+
+ int nColours;
+ byte[] reds;
+ byte[] greens;
+ byte[] blues;
+
+ CConn cc;
+ DesktopWindow desktop;
+ static LogWriter vlog = new LogWriter("PixelBufferImage");
+}
diff --git a/java/com/tigervnc/vncviewer/README b/java/com/tigervnc/vncviewer/README
new file mode 100644
index 00000000..9d825684
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/README
@@ -0,0 +1,174 @@
+
+TigerVNC Java Viewer
+====================
+
+This distribution is based on the standard VNC source and includes new
+TigerVNC-specific features and fixes, such as additional low-bandwidth
+optimizations, major GUI improvements, and more.
+
+ Copyright (C) 2000-2003 Constantin Kaplinsky
+ Copyright (C) 2003 Sun Microsystems, Inc.
+ Copyright (C) 2002-2005 RealVNC Ltd.
+ Copyright (C) 2004-2005 Cendio AB
+ Copyright (C) 2005 Martin Koegler
+ Copyright (C) 2009 Pierre Ossman for Cendio AB
+ Copyright (C) 2009-2011 TigerVNC Team
+ All rights reserved.
+
+This software is distributed under the GNU General Public Licence as
+published by the Free Software Foundation. See the file LICENCE.TXT for the
+conditions under which this software is made available. TigerVNC also
+contains code from other sources. See the Acknowledgements section below, and
+the individual files for details of the conditions under which they are made
+available.
+
+
+Installation
+============
+
+There are three basic ways to use the TigerVNC Java Viewer:
+
+ 1. Running the applet as part of a TigerVNC Server installation.
+
+ Both the Unix and Windows versions of the TigerVNC Server include a small
+ built-in HTTP server that can serve the TigerVNC Java Viewer to web
+ clients. This enables easy access to the shared desktop without the need
+ to install any software on the client machine.
+
+ The Unix TigerVNC Server (Xvnc) is able to serve up any set of files that
+ are present in a particular directory, which is specified in the -httpd
+ argument to Xvnc. The default version of the vncserver script will look
+ for a directory called vnc/classes, one level up from the directory
+ containing the vncserver script, then it will look for a directory called
+ /usr/share/vnc/classes, then /usr/local/vnc/classes. It will set the
+ -httpd argument to Xvnc to the first one of these VNC classes directories
+ it finds. Thus, one can easily deploy a modified version of the TigerVNC
+ Java Viewer by simply copying a new version of VncViewer.jar and/or
+ index.vnc into the VNC classes directory.
+
+ In the case of the Windows TigerVNC Server, VncViewer.jar and index.vnc
+ are embedded as resources in the WinVNC executable, so deploying a
+ modified version of the TigerVNC Java Viewer on a Windows server requires
+ rebuilding WinVNC.
+
+ 2. Running the applet from a standalone web server.
+
+ Another possibility for using the TigerVNC Java Viewer is to install it
+ under a fully-functional HTTP server, such as Apache or IIS. Due to Java
+ security restrictions, the applet must be signed in order for it to
+ connect to a VNC server running on a different machine from the HTTP
+ server.
+
+ One can install the TigerVNC Java Viewer by simply copying the .class and
+ .jar files into a directory that is under the control of the HTTP server.
+ Also, an HTML page should be created to act as a the base document for the
+ TigerVNC Java Viewer applet (an example named index.html is provided in
+ this directory. Modify this file to suit your specific needs.)
+
+ 3. Running the viewer as a standalone application.
+
+ Finally, the TigerVNC Java Viewer can be executed locally on the client
+ machine, but this method requires installation of either a JRE (Java
+ Runtime Environment) or a JDK (Java Development Kit). If VncViewer.jar is
+ in the current directory, then the TigerVNC Java Viewer can be launched
+ with the following command line:
+
+ java -jar VncViewer.jar [parameters]
+
+ Add an argument of -? to the above command line to print a list of
+ optional parameters supported by VncViewer.
+
+
+Parameters
+==========
+
+The TigerVNC Java Viewer accepts a number of optional parameters, allowing you
+to customize its behavior.
+
+Parameters can be specified in one of the two ways, depending on how the
+TigerVNC Java Viewer is used:
+
+ 1. When the TigerVNC Java Viewer is run as an applet (embedded within an HTML
+ document), parameters should be specified using the <PARAM> HTML tags
+ within the appropriate <APPLET> section. Example:
+
+ <APPLET CODE=com.tigervnc.vncviewer.VncViewer ARCHIVE=VncViewer.jar
+ WIDTH=400 HEIGHT=300>
+ <PARAM NAME="PORT" VALUE=5901>
+ <PARAM NAME="ScalingFactor" VALUE=50>
+ </APPLET>
+
+ 2. When run as a standalone application, the TigerVNC Java Viewer reads
+ parameters from the command line. Example:
+
+ java -jar VncViewer.jar Port=5901 ScalingFactor=50
+
+Both parameter names and their values are case-insensitive.
+
+For a complete list of parameters and their descriptions, run:
+
+ java -jar VncViewer.jar -?
+
+
+HINTS
+=====
+
+--> To refresh the remote desktop in the view-only mode, press "r" or "R"
+ on the keyboard.
+
+
+ACKNOWLEDGEMENTS
+================
+
+This distribution contains Java DES software by Dave Zimmerman
+<dzimm@widget.com> and Jef Poskanzer <jef@acme.com>. This is:
+
+ Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee
+ is hereby granted, provided that this copyright notice is kept intact.
+
+ WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
+ SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE
+ LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
+ MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
+
+ THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
+ CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
+ PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
+ NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
+ SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
+ SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
+ PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET
+ WORKSHOP SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF
+ FITNESS FOR HIGH RISK ACTIVITIES.
+
+ Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. 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.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Visit the ACME Labs Java page for up-to-date versions of this and other
+ fine Java utilities: http://www.acme.com/java/
diff --git a/java/com/tigervnc/vncviewer/ServerDialog.java b/java/com/tigervnc/vncviewer/ServerDialog.java
new file mode 100644
index 00000000..00a7e183
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/ServerDialog.java
@@ -0,0 +1,179 @@
+/* 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 com.tigervnc.vncviewer;
+
+import java.awt.*;
+import java.awt.image.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import java.net.URL;
+import java.io.File;
+import java.util.*;
+
+import com.tigervnc.rfb.*;
+import com.tigervnc.rfb.Exception;
+
+class ServerDialog extends Dialog implements
+ ActionListener,
+ ItemListener
+{
+
+ public ServerDialog(OptionsDialog options_,
+ String defaultServerName, CConn cc_) {
+
+ super(true);
+ cc = cc_;
+ setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+ setResizable(false);
+ setSize(new Dimension(340, 135));
+ setTitle("VNC Viewer : Connection Details");
+
+ options = options_;
+ getContentPane().setLayout(new GridBagLayout());
+
+ JLabel serverLabel = new JLabel("Server:", JLabel.RIGHT);
+ if (options.defaults.getString("server") != null) {
+ server = new JComboBox(options.defaults.getString("server").split(","));
+ } else {
+ server = new JComboBox();
+ }
+
+ // Hack to set the left inset on editable JComboBox
+ if (UIManager.getLookAndFeel().getID() == "Windows") {
+ server.setBorder(BorderFactory.createCompoundBorder(server.getBorder(),
+ BorderFactory.createEmptyBorder(0,2,0,0)));
+ } else {
+ ComboBoxEditor editor = server.getEditor();
+ JTextField jtf = (JTextField)editor.getEditorComponent();
+ jtf.setBorder(new CompoundBorder(jtf.getBorder(), new EmptyBorder(0,2,0,0)));
+ }
+
+ server.setEditable(true);
+ editor = server.getEditor();
+ JLabel encryptionLabel = new JLabel("Encryption:");
+ encryption = new JComboBox();
+ serverLabel.setPreferredSize(encryptionLabel.getPreferredSize());
+
+ JPanel topPanel = new JPanel(new GridBagLayout());
+
+ addGBComponent(new JLabel(cc.logo),topPanel, 0, 0, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_START, new Insets(5,5,5,15));
+ addGBComponent(serverLabel,topPanel, 1, 0, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.LINE_END, new Insets(10,0,5,5));
+ addGBComponent(server,topPanel, 2, 0, 1, 1, 0, 0, 1, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(10,0,5,40));
+
+ optionsButton = new JButton("Options...");
+ aboutButton = new JButton("About...");
+ okButton = new JButton("OK");
+ cancelButton = new JButton("Cancel");
+ JPanel buttonPanel = new JPanel(new GridBagLayout());
+ buttonPanel.setPreferredSize(new Dimension(340, 40));
+ addGBComponent(aboutButton,buttonPanel, 0, 3, 1, 1, 0, 0, 0.2, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));
+ addGBComponent(optionsButton,buttonPanel, 1, 3, 1, 1, 0, 0, 0, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));
+ addGBComponent(okButton,buttonPanel, 2, 3, 1, 1, 0, 0, 0.8, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));
+ addGBComponent(cancelButton,buttonPanel, 3, 3, 1, 1, 0, 0, 0.5, 1, GridBagConstraints.HORIZONTAL, GridBagConstraints.CENTER, new Insets(0,5,0,5));
+
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.anchor = GridBagConstraints.LINE_START;
+ gbc.fill = GridBagConstraints.BOTH;
+ gbc.gridwidth = GridBagConstraints.REMAINDER;
+ gbc.gridheight = 1;
+ gbc.insets = new Insets(0,0,0,0);
+ gbc.ipadx = 0;
+ gbc.ipady = 0;
+ gbc.weightx = 1;
+ gbc.weighty = 1;
+ getContentPane().add(topPanel,gbc);
+ getContentPane().add(buttonPanel);
+
+ server.addActionListener(this);
+ optionsButton.addActionListener(this);
+ aboutButton.addActionListener(this);
+ okButton.addActionListener(this);
+ cancelButton.addActionListener(this);
+
+ pack();
+ }
+
+ public void itemStateChanged(ItemEvent e) {
+ Object s = e.getSource();
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ Object s = e.getSource();
+ if (s instanceof JButton && (JButton)s == okButton) {
+ ok = true;
+ endDialog();
+ } else if (s instanceof JButton && (JButton)s == cancelButton) {
+ ok = false;
+ endDialog();
+ } else if (s instanceof JButton && (JButton)s == optionsButton) {
+ options.showDialog();
+ } else if (s instanceof JButton && (JButton)s == aboutButton) {
+ cc.showAbout();
+ } else if (s instanceof JComboBox && (JComboBox)s == server) {
+ if (e.getActionCommand().equals("comboBoxEdited")) {
+ server.insertItemAt(editor.getItem(), 0);
+ server.setSelectedIndex(0);
+ ok = true;
+ endDialog();
+ }
+ }
+ }
+
+ public void endDialog() {
+ if (ok) {
+ try {
+ options.defaults.setPref("encryption",(encryption.getSelectedIndex()==1) ? "off" : "on");
+ if (!server.getSelectedItem().toString().equals("")) {
+ String t = (options.defaults.getString("server")==null) ? "" : options.defaults.getString("server");
+ StringTokenizer st = new StringTokenizer(t, ",");
+ StringBuffer sb = new StringBuffer().append((String)server.getSelectedItem());
+ while (st.hasMoreTokens()) {
+ String s = st.nextToken();
+ if (!s.equals((String)server.getSelectedItem()) && !s.equals("")) {
+ sb.append(',');
+ sb.append(s);
+ }
+ }
+ options.defaults.setPref("server", sb.toString());
+ }
+ options.defaults.Save();
+ } catch (java.io.IOException e) {
+ System.out.println(e.toString());
+ } catch(java.security.AccessControlException e) {
+ System.out.println(e.toString());
+ }
+ }
+ done = true;
+ if (modal) {
+ synchronized (this) {
+ notify();
+ }
+ }
+ this.dispose();
+ }
+
+ CConn cc;
+ JComboBox encryption, server;
+ ComboBoxEditor editor;
+ JButton aboutButton, optionsButton, okButton, cancelButton;
+ OptionsDialog options;
+ static LogWriter vlog = new LogWriter("ServerDialog");
+
+}
diff --git a/java/com/tigervnc/vncviewer/UserPrefs.java b/java/com/tigervnc/vncviewer/UserPrefs.java
new file mode 100644
index 00000000..bc2cf0f1
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/UserPrefs.java
@@ -0,0 +1,286 @@
+/* Copyright (C) 2011 TigerVNC Team. 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 com.tigervnc.vncviewer;
+
+import java.util.Properties;
+import java.io.FileOutputStream;
+import javax.swing.filechooser.*;
+
+/**
+ * Simple, generic class to load up or save properties for an application.
+ * (eg user preferences)
+ *
+ * While reading in values, it will automatically convert from string format,
+ * to your choice of int or boolean, if desired.
+ *
+ * We assume that you want properties stored in a file named
+ * $HOME/.yourappname, where $HOME represents the users "home directory"
+ *
+ * Feel free to email comments or suggestions to the author
+ *
+ * @version 1.0, 09/16/1997
+ * @author Philip Brown phil@bolthole.com
+ */
+
+public class UserPrefs extends Properties {
+ String userhome=null; //This will have fileseparator on end if it
+ String prefFile;
+ String appName;
+
+ Properties systemprops;
+
+
+ /**
+ * We try to read in a preferences file, from the user's "HOME"
+ * directory. We base the name of the file, on the name of the
+ * application we are in.
+ * Use the getHomeDir() call if you want to know what directory
+ * this is in.
+ *
+ * @param appName_ name of application calling this class
+ */
+ public UserPrefs(String appName_) {
+ appName = appName_;
+
+ try {
+ systemprops=System.getProperties();
+ } catch(java.security.AccessControlException e) {
+ System.out.println("Cannot access system properties");
+ }
+ // This is guaranteed as always being some valid directory,
+ // according to spec.
+ prefFile= getHomeDir()+getFileSeparator()+
+ "."+appName;
+ try {
+ load(new java.io.FileInputStream(prefFile));
+ } catch(java.security.AccessControlException e) {
+ System.out.println("Cannot access system properties");
+ } catch (Exception err) {
+ if(err instanceof java.io.FileNotFoundException) {
+ try {
+ store(new FileOutputStream(prefFile), appName+" preferences");
+ } catch (Exception e) { /* FIXME */ }
+ } else {
+ // FIXME - should be a dialog
+ System.out.println("Error opening prefs file:"+err.getMessage());
+ }
+ }
+
+ }
+
+ // Strip off any comments
+ String trimValue(String prop) {
+ if(prop==null)
+ return null;
+
+ int lastpos;
+ lastpos=prop.indexOf('#');
+ if(lastpos==-1)
+ lastpos=prop.length()-1;
+ while((prop.charAt(lastpos)==' ') ||
+ (prop.charAt(lastpos)=='\t')) {
+ lastpos--;
+ if(lastpos==0)
+ break;
+ }
+
+ return prop.substring(0, lastpos+1);
+ }
+
+ /**
+ * The java spec guarantees that a "home" directory be
+ * specified. We look it up for our own uses at initialization
+ * If you want to do other things in the user's home dir,
+ * this routine is an easy way to find out where it is.
+ *
+ * This returns string that will have trailing fileseparator, eg "/")
+ * so you can slap together a filename directly after it, and
+ * not worry about that sort of junk.
+ */
+ final public static String getHomeDir() {
+ String homeDir = null;
+ try {
+ String os = System.getProperty("os.name");
+ try {
+ if (os.startsWith("Windows")) {
+ // JRE prior to 1.5 cannot reliably determine USERPROFILE
+ // return user.home and hope it's right...
+ if (Integer.parseInt(System.getProperty("java.version").split("\\.")[1]) < 5) {
+ try {
+ homeDir = System.getProperty("user.home");
+ } catch(java.security.AccessControlException e) {
+ System.out.println("Cannot access user.home system property");
+ }
+ } else {
+ homeDir = System.getenv("USERPROFILE");
+ }
+ } else {
+ try {
+ homeDir = FileSystemView.getFileSystemView().
+ getDefaultDirectory().getCanonicalPath();
+ } catch(java.security.AccessControlException e) {
+ System.out.println("Cannot access system property");
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } catch(java.security.AccessControlException e) {
+ System.out.println("Cannot access os.name system property");
+ }
+ return homeDir;
+ }
+
+ final private String getUserName() {
+ String userName = null;
+ try {
+ userName = (String) System.getProperties().get("user.name");
+ } catch(java.security.AccessControlException e) {
+ System.out.println("Cannot access user.name system property");
+ }
+ return userName;
+ }
+
+ final public static String getFileSeparator() {
+ String separator = null;
+ try {
+ separator = Character.toString(java.io.File.separatorChar);
+ } catch(java.security.AccessControlException e) {
+ System.out.println("Cannot access file.separator system property");
+ }
+ return separator;
+ }
+
+ /**
+ * way to directly set a preference. You'll have to
+ * do your own type conversion.
+ * @param prefname name of property
+ * @param value string value of property
+ */
+ public void setPref(String prefname, String value) {
+ setProperty(prefname, value);
+ }
+
+ public void setPref(String prefname, int value) {
+ systemprops.put(prefname, java.lang.Integer.toString(value));
+ }
+
+ public void setPref(String prefname, boolean value) {
+ put(prefname, (value ? "true" : "false"));
+ }
+
+ /**
+ * Gets named resource, as a string value.
+ * returns null if no such resource defined.
+ * @param name name of property
+ */
+ public String getString(String name) {
+ return trimValue(getProperty(name));
+ }
+ /**
+ * Gets named resource, as a string value.
+ *
+ * @param name name of property
+ * @param defval default value to remember and return , if
+ * no existing property name found.
+ */
+ public String getString(String name, String defstr) {
+ String val = trimValue(getProperty(name));
+ if(val==null) {
+ setPref(name, defstr);
+ return defstr;
+ }
+ return val;
+ }
+
+ /**
+ * look up property that is an int value
+ * @param name name of property
+ */
+ public int getInt(String name) {
+ String strint = trimValue(getProperty(name));
+ int val=0;
+ try {
+ val = Integer.parseInt(strint);
+ } catch (NumberFormatException err) {
+ //we dont care
+ }
+ return val;
+ }
+
+ /**
+ * look up property that is an int value
+ * @param name name of property
+ * @param defval default value to remember and return , if
+ * no existing property name found.
+ */
+ public int getInt(String name, int defval) {
+ String strint = trimValue(getProperty(name));
+ if(strint==null) {
+ setPref(name, String.valueOf(defval));
+ return defval;
+ }
+ int val=0;
+ try {
+ val = Integer.parseInt(strint);
+ } catch (NumberFormatException err) {
+ //we dont care
+ }
+ return val;
+ }
+
+ /**
+ * look up property that is a boolean value
+ * @param name name of property
+ * @param defval default value to remember and return , if
+ * no existing property name found.
+ */
+ public boolean getBool(String name) {
+ String strval = trimValue(getProperty(name));
+ if(strval.equals("true"))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * @param name name of property
+ * @param defval default value to remember and return , if
+ * no existing property name found.
+ */
+ public boolean getBool(String name, boolean defval) {
+ String strval = trimValue(getProperty(name));
+ if(strval==null) {
+ setPref(name, String.valueOf(defval));
+ return defval;
+ }
+
+ if(strval.equals("true"))
+ return true;
+
+ return false;
+ }
+
+ /**
+ * save user preferences to default file. Duh.
+ */
+ public void Save() throws java.io.IOException {
+ store(new FileOutputStream(prefFile), appName+" preferences");
+ }
+}
diff --git a/java/com/tigervnc/vncviewer/VncViewer.java b/java/com/tigervnc/vncviewer/VncViewer.java
new file mode 100644
index 00000000..bea486b0
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/VncViewer.java
@@ -0,0 +1,314 @@
+/* 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.
+ */
+
+//
+// VncViewer - the VNC viewer applet. It can also be run from the
+// command-line, when it behaves as much as possibly like the windows and unix
+// viewers.
+//
+// Unfortunately, because of the way Java classes are loaded on demand, only
+// configuration parameters defined in this file can be set from the command
+// line or in applet parameters.
+
+package com.tigervnc.vncviewer;
+
+import java.awt.*;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.image.*;
+import java.awt.Label;
+import java.io.InputStream;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import javax.swing.*;
+import java.net.URL;
+
+import com.tigervnc.rdr.*;
+import com.tigervnc.rfb.*;
+import com.tigervnc.rfb.Exception;
+
+public class VncViewer extends java.applet.Applet implements Runnable
+{
+ public static final String about1 = "TigerVNC Viewer for Java";
+ public static final String about2 = "Copyright (C) 1998-2011 "+
+ "TigerVNC Team and many others (see README)";
+ public static final String about3 = "Visit http://www.tigervnc.org "+
+ "for information on TigerVNC.";
+ public static String version = null;
+ public static String build = null;
+
+ public static void main(String[] argv) {
+ try {
+ String os = System.getProperty("os.name");
+ if (os.startsWith("Windows")) {
+ String laf = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
+ UIManager.setLookAndFeel(laf);
+ } else {
+ UIManager.put("swing.boldMetal", Boolean.FALSE);
+ javax.swing.plaf.FontUIResource f = new
+ javax.swing.plaf.FontUIResource("SansSerif", Font.PLAIN, 11);
+ java.util.Enumeration keys = UIManager.getDefaults().keys();
+ while (keys.hasMoreElements()) {
+ Object key = keys.nextElement();
+ Object value = UIManager.get (key);
+ if (value instanceof javax.swing.plaf.FontUIResource)
+ UIManager.put(key, f);
+ }
+ }
+ UIManager.put("TitledBorder.titleColor",Color.blue);
+ } catch (java.lang.Exception exc) { }
+ VncViewer viewer = new VncViewer(argv);
+ viewer.start();
+ }
+
+
+ public VncViewer(String[] argv) {
+ applet = false;
+
+ // Override defaults with command-line options
+ for (int i = 0; i < argv.length; i++) {
+ if (argv[i].equalsIgnoreCase("-log")) {
+ if (++i >= argv.length) usage();
+ System.err.println("Log setting: "+argv[i]);
+ LogWriter.setLogParams(argv[i]);
+ continue;
+ }
+
+ if (Configuration.setParam(argv[i]))
+ continue;
+
+ if (argv[i].charAt(0) == '-') {
+ if (i+1 < argv.length) {
+ if (Configuration.setParam(argv[i].substring(1), argv[i+1])) {
+ i++;
+ continue;
+ }
+ }
+ usage();
+ }
+
+ if (vncServerName.getValue() != null)
+ usage();
+ vncServerName.setParam(argv[i]);
+ }
+ }
+
+ public static void usage() {
+ String usage = ("\nusage: vncviewer [options/parameters] "+
+ "[host:displayNum] [options/parameters]\n"+
+ //" vncviewer [options/parameters] -listen [port] "+
+ //"[options/parameters]\n"+
+ "\n"+
+ "Options:\n"+
+ " -log <level> configure logging level\n"+
+ "\n"+
+ "Parameters can be turned on with -<param> or off with "+
+ "-<param>=0\n"+
+ "Parameters which take a value can be specified as "+
+ "-<param> <value>\n"+
+ "Other valid forms are <param>=<value> -<param>=<value> "+
+ "--<param>=<value>\n"+
+ "Parameter names are case-insensitive. The parameters "+
+ "are:\n\n"+
+ Configuration.listParams());
+ System.err.print(usage);
+ System.exit(1);
+ }
+
+ public VncViewer() {
+ applet = true;
+ firstApplet = true;
+ }
+
+ public static void newViewer(VncViewer oldViewer) {
+ VncViewer viewer = new VncViewer();
+ viewer.applet = oldViewer.applet;
+ viewer.firstApplet = false;
+ viewer.start();
+ }
+
+
+ public void init() {
+ vlog.debug("init called");
+ setBackground(Color.white);
+ ClassLoader cl = this.getClass().getClassLoader();
+ ImageIcon icon = new ImageIcon(cl.getResource("com/tigervnc/vncviewer/tigervnc.png"));
+ logo = icon.getImage();
+ }
+
+ public void start() {
+ vlog.debug("start called");
+ if (version == null || build == null) {
+ ClassLoader cl = this.getClass().getClassLoader();
+ InputStream stream = cl.getResourceAsStream("com/tigervnc/vncviewer/timestamp");
+ try {
+ Manifest manifest = new Manifest(stream);
+ Attributes attributes = manifest.getMainAttributes();
+ version = attributes.getValue("Version");
+ build = attributes.getValue("Build");
+ } catch (java.io.IOException e) { }
+ }
+ nViewers++;
+ if (firstApplet) {
+ alwaysShowServerDialog.setParam(true);
+ Configuration.readAppletParams(this);
+ String host = getCodeBase().getHost();
+ if (vncServerName.getValue() == null && vncServerPort.getValue() != 0) {
+ int port = vncServerPort.getValue();
+ vncServerName.setParam(host + ((port >= 5900 && port <= 5999)
+ ? (":"+(port-5900))
+ : ("::"+port)));
+ }
+ }
+ thread = new Thread(this);
+ thread.start();
+ }
+
+ public void paint(Graphics g) {
+ g.drawImage(logo, 0, 0, this);
+ int h = logo.getHeight(this)+20;
+ g.drawString(about1+" v"+version+" ("+build+")", 0, h);
+ h += g.getFontMetrics().getHeight();
+ g.drawString(about2, 0, h);
+ h += g.getFontMetrics().getHeight();
+ g.drawString(about3, 0, h);
+ }
+
+ public void run() {
+ CConn cc = null;
+ try {
+ cc = new CConn(this, null, vncServerName.getValue(), false);
+ while (true)
+ cc.processMsg();
+ } catch (EndOfStream e) {
+ vlog.info(e.toString());
+ } catch (java.lang.Exception e) {
+ if (cc != null) cc.deleteWindow();
+ if (cc == null || !cc.shuttingDown) {
+ e.printStackTrace();
+ JOptionPane.showMessageDialog(null,
+ e.toString(),
+ "VNC Viewer : Error",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ if (cc != null) cc.deleteWindow();
+ nViewers--;
+ if (!applet && nViewers == 0) {
+ System.exit(0);
+ }
+ }
+
+ BoolParameter fastCopyRect
+ = new BoolParameter("FastCopyRect",
+ "Use fast CopyRect - turn this off if you get "+
+ "screen corruption when copying from off-screen",
+ true);
+ BoolParameter useLocalCursor
+ = new BoolParameter("UseLocalCursor",
+ "Render the mouse cursor locally", true);
+ BoolParameter sendLocalUsername
+ = new BoolParameter("SendLocalUsername",
+ "Send the local username for SecurityTypes "+
+ "such as Plain rather than prompting", true);
+ BoolParameter autoSelect
+ = new BoolParameter("AutoSelect",
+ "Auto select pixel format and encoding", true);
+ BoolParameter fullColour
+ = new BoolParameter("FullColour",
+ "Use full colour - otherwise 6-bit colour is used "+
+ "until AutoSelect decides the link is fast enough",
+ true);
+ AliasParameter fullColor
+ = new AliasParameter("FullColor", "Alias for FullColour", fullColour);
+ StringParameter preferredEncoding
+ = new StringParameter("PreferredEncoding",
+ "Preferred encoding to use (Tight, ZRLE, hextile or"+
+ " raw) - implies AutoSelect=0", "Tight");
+ BoolParameter viewOnly
+ = new BoolParameter("ViewOnly", "Don't send any mouse or keyboard "+
+ "events to the server", false);
+ BoolParameter shared
+ = new BoolParameter("Shared", "Don't disconnect other viewers upon "+
+ "connection - share the desktop instead", false);
+ BoolParameter fullScreen
+ = new BoolParameter("FullScreen", "Full Screen Mode", false);
+ BoolParameter acceptClipboard
+ = new BoolParameter("AcceptClipboard",
+ "Accept clipboard changes from the server", true);
+ BoolParameter sendClipboard
+ = new BoolParameter("SendClipboard",
+ "Send clipboard changes to the server", true);
+ StringParameter desktopSize
+ = new StringParameter("DesktopSize",
+ "Reconfigure desktop size on the server on "+
+ "connect (if possible)", "");
+ StringParameter scalingFactor
+ = new StringParameter("ScalingFactor",
+ "Reduce or enlarge the remote desktop image. "+
+ "The value is interpreted as a scaling factor "+
+ "in percent. If the parameter is set to "+
+ "\"Auto\", then automatic scaling is "+
+ "performed. Auto-scaling tries to choose a "+
+ "scaling factor in such a way that the whole "+
+ "remote desktop will fit on the local screen. "+
+ "If the parameter is set to \"FixedRatio\", "+
+ "then automatic scaling is performed, but the "+
+ "original aspect ratio is preserved.", "100");
+ BoolParameter alwaysShowServerDialog
+ = new BoolParameter("AlwaysShowServerDialog",
+ "Always show the server dialog even if a server "+
+ "has been specified in an applet parameter or on "+
+ "the command line", false);
+ StringParameter vncServerName
+ = new StringParameter("Server",
+ "The VNC server <host>[:<dpyNum>] or "+
+ "<host>::<port>", null);
+ IntParameter vncServerPort
+ = new IntParameter("Port",
+ "The VNC server's port number, assuming it is on "+
+ "the host from which the applet was downloaded", 0);
+ BoolParameter acceptBell
+ = new BoolParameter("AcceptBell",
+ "Produce a system beep when requested to by the server.",
+ true);
+ BoolParameter customCompressLevel
+ = new BoolParameter("CustomCompressLevel",
+ "Use custom compression level. "+
+ "Default if CompressLevel is specified.", false);
+ IntParameter compressLevel
+ = new IntParameter("CompressLevel",
+ "Use specified compression level "+
+ "0 = Low, 6 = High",
+ 1);
+ BoolParameter noJpeg
+ = new BoolParameter("NoJPEG",
+ "Disable lossy JPEG compression in Tight encoding.", false);
+ IntParameter qualityLevel
+ = new IntParameter("QualityLevel",
+ "JPEG quality level. "+
+ "0 = Low, 9 = High",
+ 8);
+
+ Thread thread;
+ boolean applet, firstApplet;
+ Image logo;
+ static int nViewers;
+ static LogWriter vlog = new LogWriter("main");
+}
diff --git a/java/com/tigervnc/vncviewer/index.html b/java/com/tigervnc/vncviewer/index.html
new file mode 100644
index 00000000..ba00e26b
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/index.html
@@ -0,0 +1,20 @@
+<!--
+ index.html - an example HTML page for the TigerVNC Java Viewer applet, to
+ be used with a standalone web server. Before using this example, please
+ MAKE SURE to check the following:
+
+ * the CODE and ARCHIVE attributes of the <APPLET> tag should point to
+ the correct directory (this example assumes that this page is in the
+ same directory as VncViewer.jar);
+-->
+
+<HTML>
+<TITLE>
+TigerVNC desktop
+</TITLE>
+<APPLET CODE="com.tigervnc.vncviewer.VncViewer" ARCHIVE="VncViewer.jar"
+ WIDTH=500>
+</APPLET>
+<BR>
+<A href="http://www.tigervnc.org/">TigerVNC site</A>
+</HTML>
diff --git a/java/com/tigervnc/vncviewer/index.vnc b/java/com/tigervnc/vncviewer/index.vnc
new file mode 100644
index 00000000..e8899875
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/index.vnc
@@ -0,0 +1,20 @@
+<!--
+ index.vnc - default HTML page for TigerVNC Java viewer applet, to be
+ used with Xvnc. On any file ending in .vnc, the HTTP server embedded in
+ Xvnc will substitute the following variables when preceded by a dollar:
+ USER, DESKTOP, DISPLAY, APPLETWIDTH, APPLETHEIGHT, WIDTH, HEIGHT, PORT,
+ Use two dollar signs ($$) to get a dollar sign in the generated
+ HTML page.
+-->
+
+<HTML>
+<TITLE>
+$USER's $DESKTOP desktop ($DISPLAY)
+</TITLE>
+<APPLET CODE=com.tigervnc.vncviewer.VncViewer ARCHIVE=VncViewer.jar
+ WIDTH=$APPLETWIDTH HEIGHT=$APPLETHEIGHT>
+<param name=PORT value=$PORT>
+</APPLET>
+<BR>
+<A href="http://www.tigervnc.org/">TigerVNC site</A>
+</HTML>
diff --git a/java/com/tigervnc/vncviewer/tigervnc.ico b/java/com/tigervnc/vncviewer/tigervnc.ico
new file mode 100644
index 00000000..50b90f00
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/tigervnc.ico
Binary files differ
diff --git a/java/com/tigervnc/vncviewer/tigervnc.png b/java/com/tigervnc/vncviewer/tigervnc.png
new file mode 100644
index 00000000..8ac883ef
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/tigervnc.png
Binary files differ
diff --git a/java/com/tigervnc/vncviewer/timestamp.in b/java/com/tigervnc/vncviewer/timestamp.in
new file mode 100644
index 00000000..b666e7c0
--- /dev/null
+++ b/java/com/tigervnc/vncviewer/timestamp.in
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+Main-Class: com.tigervnc.vncviewer.VncViewer
+Package-Date: @JAVA_DATE@
+Package-Time: @JAVA_TIME@
+Version: @VERSION@
+Build: @BUILD@