From 6a62329fa573cd519cc36b6d491a7cdcc3261e01 Mon Sep 17 00:00:00 2001 From: Quentin Smith Date: Wed, 8 Aug 2007 23:58:16 -0400 Subject: [PATCH] Initial checkin of modified Java VNC viewer for use as remote console svn path=/trunk/vnc/vnc_javasrc/; revision=66 --- AuthPanel.java | 116 +++ ButtonPanel.java | 154 ++++ CapabilityInfo.java | 87 ++ CapsContainer.java | 103 +++ ChangeLog | 1708 +++++++++++++++++++++++++++++++++++ ClipboardFrame.java | 133 +++ DesCipher.java | 496 ++++++++++ HTTPConnectSocket.java | 59 ++ HTTPConnectSocketFactory.java | 86 ++ InStream.java | 177 ++++ LICENCE.TXT | 340 +++++++ MANIFEST.MF | 2 + Makefile | 49 + MemInStream.java | 32 + OptionsFrame.java | 411 +++++++++ README | 493 ++++++++++ RecordingFrame.java | 311 +++++++ ReloginPanel.java | 65 ++ RfbProto.java | 1312 +++++++++++++++++++++++++++ SessionRecorder.java | 193 ++++ SocketFactory.java | 36 + VNCProxyConnectSocket.java | 61 ++ VNCProxyConnectSocketFactory.java | 80 ++ VncCanvas.java | 1803 +++++++++++++++++++++++++++++++++++++ VncCanvas2.java | 63 ++ VncViewer.java | 972 ++++++++++++++++++++ WhatsNew | 930 +++++++++++++++++++ ZlibInStream.java | 111 +++ index.html | 29 + index.vnc | 25 + 30 files changed, 10437 insertions(+) create mode 100644 AuthPanel.java create mode 100644 ButtonPanel.java create mode 100644 CapabilityInfo.java create mode 100644 CapsContainer.java create mode 100644 ChangeLog create mode 100644 ClipboardFrame.java create mode 100644 DesCipher.java create mode 100644 HTTPConnectSocket.java create mode 100644 HTTPConnectSocketFactory.java create mode 100644 InStream.java create mode 100644 LICENCE.TXT create mode 100644 MANIFEST.MF create mode 100644 Makefile create mode 100644 MemInStream.java create mode 100644 OptionsFrame.java create mode 100644 README create mode 100644 RecordingFrame.java create mode 100644 ReloginPanel.java create mode 100644 RfbProto.java create mode 100644 SessionRecorder.java create mode 100644 SocketFactory.java create mode 100644 VNCProxyConnectSocket.java create mode 100644 VNCProxyConnectSocketFactory.java create mode 100644 VncCanvas.java create mode 100644 VncCanvas2.java create mode 100644 VncViewer.java create mode 100644 WhatsNew create mode 100644 ZlibInStream.java create mode 100644 index.html create mode 100644 index.vnc diff --git a/AuthPanel.java b/AuthPanel.java new file mode 100644 index 0000000..0043090 --- /dev/null +++ b/AuthPanel.java @@ -0,0 +1,116 @@ +// +// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. +// Copyright (C) 2002-2006 Constantin Kaplinsky. 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. +// + +import java.awt.*; +import java.awt.event.*; + +// +// The panel which implements the user authentication scheme +// + +class AuthPanel extends Panel implements ActionListener { + + TextField passwordField; + Button okButton; + + // + // Constructor. + // + + public AuthPanel(VncViewer viewer) + { + Label titleLabel = new Label("VNC Authentication", Label.CENTER); + titleLabel.setFont(new Font("Helvetica", Font.BOLD, 18)); + + Label promptLabel = new Label("Password:", Label.CENTER); + + passwordField = new TextField(10); + passwordField.setForeground(Color.black); + passwordField.setBackground(Color.white); + passwordField.setEchoChar('*'); + + okButton = new Button("OK"); + + GridBagLayout gridbag = new GridBagLayout(); + GridBagConstraints gbc = new GridBagConstraints(); + + setLayout(gridbag); + + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.insets = new Insets(0,0,20,0); + gridbag.setConstraints(titleLabel,gbc); + add(titleLabel); + + gbc.fill = GridBagConstraints.NONE; + gbc.gridwidth = 1; + gbc.insets = new Insets(0,0,0,0); + gridbag.setConstraints(promptLabel,gbc); + add(promptLabel); + + gridbag.setConstraints(passwordField,gbc); + add(passwordField); + passwordField.addActionListener(this); + + // gbc.ipady = 10; + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.fill = GridBagConstraints.BOTH; + gbc.insets = new Insets(0,20,0,0); + gbc.ipadx = 30; + gridbag.setConstraints(okButton,gbc); + add(okButton); + okButton.addActionListener(this); + } + + // + // Move keyboard focus to the default object, that is, the password + // text field. + // + + public void moveFocusToDefaultField() + { + passwordField.requestFocus(); + } + + // + // This method is called when a button is pressed or return is + // pressed in the password text field. + // + + public synchronized void actionPerformed(ActionEvent evt) + { + if (evt.getSource() == passwordField || evt.getSource() == okButton) { + passwordField.setEnabled(false); + notify(); + } + } + + // + // Wait for user entering a password, and return it as String. + // + + public synchronized String getPassword() throws Exception + { + try { + wait(); + } catch (InterruptedException e) { } + return passwordField.getText(); + } + +} diff --git a/ButtonPanel.java b/ButtonPanel.java new file mode 100644 index 0000000..5cae865 --- /dev/null +++ b/ButtonPanel.java @@ -0,0 +1,154 @@ +// +// Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved. +// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. +// +// This is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this software; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. +// + +// +// ButtonPanel class implements panel with four buttons in the +// VNCViewer desktop window. +// + +import java.awt.*; +import java.awt.event.*; +import java.io.*; + +class ButtonPanel extends Panel implements ActionListener { + + VncViewer viewer; + Button disconnectButton; + Button optionsButton; + Button recordButton; + Button clipboardButton; + Button ctrlAltDelButton; + Button refreshButton; + + ButtonPanel(VncViewer v) { + viewer = v; + + setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); + disconnectButton = new Button("Disconnect"); + disconnectButton.setEnabled(false); + add(disconnectButton); + disconnectButton.addActionListener(this); + optionsButton = new Button("Options"); + add(optionsButton); + optionsButton.addActionListener(this); + clipboardButton = new Button("Clipboard"); + clipboardButton.setEnabled(false); + add(clipboardButton); + clipboardButton.addActionListener(this); + if (viewer.rec != null) { + recordButton = new Button("Record"); + add(recordButton); + recordButton.addActionListener(this); + } + ctrlAltDelButton = new Button("Send Ctrl-Alt-Del"); + ctrlAltDelButton.setEnabled(false); + add(ctrlAltDelButton); + ctrlAltDelButton.addActionListener(this); + refreshButton = new Button("Refresh"); + refreshButton.setEnabled(false); + add(refreshButton); + refreshButton.addActionListener(this); + } + + // + // Enable buttons on successful connection. + // + + public void enableButtons() { + disconnectButton.setEnabled(true); + clipboardButton.setEnabled(true); + refreshButton.setEnabled(true); + } + + // + // Disable all buttons on disconnect. + // + + public void disableButtonsOnDisconnect() { + remove(disconnectButton); + disconnectButton = new Button("Hide desktop"); + disconnectButton.setEnabled(true); + add(disconnectButton, 0); + disconnectButton.addActionListener(this); + + optionsButton.setEnabled(false); + clipboardButton.setEnabled(false); + ctrlAltDelButton.setEnabled(false); + refreshButton.setEnabled(false); + + validate(); + } + + // + // Enable/disable controls that should not be available in view-only + // mode. + // + + public void enableRemoteAccessControls(boolean enable) { + ctrlAltDelButton.setEnabled(enable); + } + + // + // Event processing. + // + + public void actionPerformed(ActionEvent evt) { + + viewer.moveFocusToDesktop(); + + if (evt.getSource() == disconnectButton) { + viewer.disconnect(); + + } else if (evt.getSource() == optionsButton) { + viewer.options.setVisible(!viewer.options.isVisible()); + + } else if (evt.getSource() == recordButton) { + viewer.rec.setVisible(!viewer.rec.isVisible()); + + } else if (evt.getSource() == clipboardButton) { + viewer.clipboard.setVisible(!viewer.clipboard.isVisible()); + + } else if (evt.getSource() == ctrlAltDelButton) { + try { + final int modifiers = InputEvent.CTRL_MASK | InputEvent.ALT_MASK; + + KeyEvent ctrlAltDelEvent = + new KeyEvent(this, KeyEvent.KEY_PRESSED, 0, modifiers, 127); + viewer.rfb.writeKeyEvent(ctrlAltDelEvent); + + ctrlAltDelEvent = + new KeyEvent(this, KeyEvent.KEY_RELEASED, 0, modifiers, 127); + viewer.rfb.writeKeyEvent(ctrlAltDelEvent); + + } catch (IOException e) { + e.printStackTrace(); + } + } else if (evt.getSource() == refreshButton) { + try { + RfbProto rfb = viewer.rfb; + rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth, + rfb.framebufferHeight, false); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} + diff --git a/CapabilityInfo.java b/CapabilityInfo.java new file mode 100644 index 0000000..fcf27db --- /dev/null +++ b/CapabilityInfo.java @@ -0,0 +1,87 @@ +// +// Copyright (C) 2003 Constantin Kaplinsky. 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. +// + +// +// CapabilityInfo.java - A class to hold information about a +// particular capability as used in the RFB protocol 3.130. +// + +class CapabilityInfo { + + // Public methods + + public CapabilityInfo(int code, + String vendorSignature, + String nameSignature, + String description) { + this.code = code; + this.vendorSignature = vendorSignature; + this.nameSignature = nameSignature; + this.description = description; + enabled = false; + } + + public CapabilityInfo(int code, + byte[] vendorSignature, + byte[] nameSignature) { + this.code = code; + this.vendorSignature = new String(vendorSignature); + this.nameSignature = new String(nameSignature); + this.description = null; + enabled = false; + } + + public int getCode() { + return code; + } + + public String getDescription() { + return description; + } + + public boolean isEnabled() { + return enabled; + } + + public void enable() { + enabled = true; + } + + public boolean equals(CapabilityInfo other) { + return (other != null && this.code == other.code && + this.vendorSignature.equals(other.vendorSignature) && + this.nameSignature.equals(other.nameSignature)); + } + + public boolean enableIfEquals(CapabilityInfo other) { + if (this.equals(other)) + enable(); + + return isEnabled(); + } + + // Protected data + + protected int code; + protected String vendorSignature; + protected String nameSignature; + + protected String description; + protected boolean enabled; +} diff --git a/CapsContainer.java b/CapsContainer.java new file mode 100644 index 0000000..e88cc38 --- /dev/null +++ b/CapsContainer.java @@ -0,0 +1,103 @@ +// +// Copyright (C) 2003 Constantin Kaplinsky. 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. +// + +// +// CapsContainer.java - A container of capabilities as used in the RFB +// protocol 3.130 +// + +import java.util.Vector; +import java.util.Hashtable; + +class CapsContainer { + + // Public methods + + public CapsContainer() { + infoMap = new Hashtable(64, (float)0.25); + orderedList = new Vector(32, 8); + } + + public void add(CapabilityInfo capinfo) { + Integer key = new Integer(capinfo.getCode()); + infoMap.put(key, capinfo); + } + + public void add(int code, String vendor, String name, String desc) { + Integer key = new Integer(code); + infoMap.put(key, new CapabilityInfo(code, vendor, name, desc)); + } + + public boolean isKnown(int code) { + return infoMap.containsKey(new Integer(code)); + } + + public CapabilityInfo getInfo(int code) { + return (CapabilityInfo)infoMap.get(new Integer(code)); + } + + public String getDescription(int code) { + CapabilityInfo capinfo = (CapabilityInfo)infoMap.get(new Integer(code)); + if (capinfo == null) + return null; + + return capinfo.getDescription(); + } + + public boolean enable(CapabilityInfo other) { + Integer key = new Integer(other.getCode()); + CapabilityInfo capinfo = (CapabilityInfo)infoMap.get(key); + if (capinfo == null) + return false; + + boolean enabled = capinfo.enableIfEquals(other); + if (enabled) + orderedList.addElement(key); + + return enabled; + } + + public boolean isEnabled(int code) { + CapabilityInfo capinfo = (CapabilityInfo)infoMap.get(new Integer(code)); + if (capinfo == null) + return false; + + return capinfo.isEnabled(); + } + + public int numEnabled() { + return orderedList.size(); + } + + public int getByOrder(int idx) { + int code; + try { + code = ((Integer)orderedList.elementAt(idx)).intValue(); + } catch (ArrayIndexOutOfBoundsException e) { + code = 0; + } + return code; + } + + // Protected data + + protected Hashtable infoMap; + protected Vector orderedList; +} + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..05ce4d2 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,1708 @@ +------------------------------------------------------------------------ +r2273 | const_k | 2007-04-27 09:36:00 +0700 (Fri, 27 Apr 2007) | 5 lines +Changed paths: + M /orig/tags/VERSION_1_3_9/vnc_javasrc/RfbProto.java + M /orig/tags/VERSION_1_3_9/vnc_javasrc/VncCanvas.java + M /orig/tags/VERSION_1_3_9/vnc_javasrc/VncViewer.java + +Reverted changes from orig/trunk/vnc_javasrc, revisions 2252:2244, as they really should not go the the 1.3.9 release. These changes were as follows: +- rev.2245: Printing update statistics on disconnect: number of FramebufferUpdate messages, counters of real and pseudo rectangles in framebuffer updates. +- rev.2246: Printing more statistics on disconnect: average update rate, and rectangle counters per each encoder (Tight, ZRLE, Hextile, Raw, CopyRect, others). +- rev.2252: Initial support for continuous updates. + +------------------------------------------------------------------------ +r2271 | const_k | 2007-04-26 18:28:24 +0700 (Thu, 26 Apr 2007) | 2 lines +Changed paths: + A /orig/tags/VERSION_1_3_9/vnc_javasrc (from /orig/trunk/vnc_javasrc:2270) + +Tagging Java Viewer version 1.3.9. NOTE: Actually this is not version 1.3.9 yet -- some of the recent commits should be reverted to achieve version 1.3.9, see more commits in this directory. + +------------------------------------------------------------------------ +r2262 | const_k | 2007-04-25 16:12:53 +0700 (Wed, 25 Apr 2007) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Version string changed, version 1.3.9. + +------------------------------------------------------------------------ +r2261 | const_k | 2007-04-25 16:02:32 +0700 (Wed, 25 Apr 2007) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Documented auto-scaling. + +------------------------------------------------------------------------ +r2252 | const_k | 2007-04-05 15:45:40 +0700 (Thu, 05 Apr 2007) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Initial support for continuous updates. + +------------------------------------------------------------------------ +r2246 | const_k | 2007-03-29 13:00:23 +0700 (Thu, 29 Mar 2007) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Printing more statistics on disconnect: average update rate, and rectangle counters per each encoder (Tight, ZRLE, Hextile, Raw, CopyRect, others). + +------------------------------------------------------------------------ +r2245 | const_k | 2007-03-29 11:39:46 +0700 (Thu, 29 Mar 2007) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Printing update statistics on disconnect: number of FramebufferUpdate messages, counters of real and pseudo rectangles in framebuffer updates. + +------------------------------------------------------------------------ +r2244 | const_k | 2007-03-29 10:57:07 +0700 (Thu, 29 Mar 2007) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Fixed wrong pixel format interpretation in decoding RichCursor pseudo-encoding. + +------------------------------------------------------------------------ +r2243 | const_k | 2007-03-29 10:02:23 +0700 (Thu, 29 Mar 2007) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncViewer.java + +Requesting encoding types in more suitable order. Now when Tight is preferred, we request Tight,ZRLE,Hextile,others instead of Tight,Hextile,ZRLE,others. + +------------------------------------------------------------------------ +r2230 | const_k | 2007-02-17 01:40:31 +0600 (Sat, 17 Feb 2007) | 7 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncCanvas2.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Implemented support for auto-scaling. To enable it, the "Scaling factor" +parameter should be set to "auto". Auto-scaling tries to choose scaling +factor such way that the whole remote framebuffer will fit on the local +screen. Currently, auto-scaling is supported only when the remote desktop +is shown in a separate frame (always true in application mode, and in +applet mode with "Open new window" parameter set to "yes"). + +------------------------------------------------------------------------ +r2229 | const_k | 2007-02-16 21:46:17 +0600 (Fri, 16 Feb 2007) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncViewer.java + +Minor code refactoring - a chunk of code moved to a new method VncViewer.createCanvas(). + +------------------------------------------------------------------------ +r2228 | const_k | 2007-02-08 18:23:43 +0600 (Thu, 08 Feb 2007) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Optimized ZRLE decoder for better performance. + +------------------------------------------------------------------------ +r2227 | const_k | 2007-02-08 16:58:31 +0600 (Thu, 08 Feb 2007) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + +Minor fix -- a constant was not updated on introducing ZRLE encoding. + +------------------------------------------------------------------------ +r2226 | const_k | 2007-02-08 16:54:03 +0600 (Thu, 08 Feb 2007) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Cleaned up and documented issues with session recording and ZRLE. + +------------------------------------------------------------------------ +r2225 | const_k | 2007-02-06 10:08:39 +0600 (Tue, 06 Feb 2007) | 2 lines +Changed paths: + A /orig/trunk/vnc_javasrc/InStream.java + M /orig/trunk/vnc_javasrc/Makefile + A /orig/trunk/vnc_javasrc/MemInStream.java + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/README + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + A /orig/trunk/vnc_javasrc/ZlibInStream.java + +Initial version of ZRLE decoder. It's fully functional except for session recording which is broken for ZRLE at the moment. + +------------------------------------------------------------------------ +r2224 | const_k | 2007-01-30 12:02:24 +0600 (Tue, 30 Jan 2007) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Added documentation on using parameters. + +------------------------------------------------------------------------ +r2223 | const_k | 2007-01-30 10:46:54 +0600 (Tue, 30 Jan 2007) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Documented the "Scaling factor" parameter. + +------------------------------------------------------------------------ +r2191 | const_k | 2006-12-08 10:55:49 +0600 (Fri, 08 Dec 2006) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Always send the "security result" message in the protocol version 3.8, even after an empty list of authentication capabilities. This almost reverts changes in rev.2180. + +------------------------------------------------------------------------ +r2180 | const_k | 2006-12-05 11:17:15 +0600 (Tue, 05 Dec 2006) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Fixed a problem in handing TightVNC protocol extensions - empty authentication capability list assumes not just skipping authentication itself but also not waiting for the "security result" message. + +------------------------------------------------------------------------ +r2179 | const_k | 2006-12-05 10:50:40 +0600 (Tue, 05 Dec 2006) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc + +Ignoring TAGS file. + +------------------------------------------------------------------------ +r2132 | const_k | 2006-11-26 13:33:32 +0600 (Sun, 26 Nov 2006) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/AuthPanel.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Code refactoring. The primary change is that all authentication code has been moved out of AuthPanel which now provides GUI part only. + +------------------------------------------------------------------------ +r2131 | const_k | 2006-11-24 13:39:49 +0600 (Fri, 24 Nov 2006) | 5 lines +Changed paths: + M /orig/trunk/vnc_javasrc/AuthPanel.java + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Improved support for protocol 3.8. Now authentication failures should be +reported with explanations received from the server. Actual authentication +code has been moved to RfbProto. AuthPanel does not offer repetitive +authentication tries, the "Login again" button should be used instead. + +------------------------------------------------------------------------ +r2130 | const_k | 2006-11-24 10:53:15 +0600 (Fri, 24 Nov 2006) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/AuthPanel.java + +Removed an outdated FIXME comment. + +------------------------------------------------------------------------ +r2128 | const_k | 2006-11-23 18:00:59 +0600 (Thu, 23 Nov 2006) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas2.java + +Disabling focus traversal keys under JVMs 1.4 and higher. This fixes the +problem with not sending Tab key events to the VNC server. + +------------------------------------------------------------------------ +r2127 | const_k | 2006-11-23 16:53:32 +0600 (Thu, 23 Nov 2006) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Fixed rounding problems on calculating the coordinates of changed area. + +------------------------------------------------------------------------ +r2126 | const_k | 2006-11-23 16:39:53 +0600 (Thu, 23 Nov 2006) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/Makefile + M /orig/trunk/vnc_javasrc/VncCanvas.java + A /orig/trunk/vnc_javasrc/VncCanvas2.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Implemented enhanced scaling if Java 2D API is available. This works in +Java 1.2 or higher, but the viewer remains compatible with Java 1.1 where +it would simply use scaling with decreased image quality. + +------------------------------------------------------------------------ +r2124 | const_k | 2006-11-23 10:56:05 +0600 (Thu, 23 Nov 2006) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Small correction in documentation. + +------------------------------------------------------------------------ +r2122 | const_k | 2006-11-22 16:06:29 +0600 (Wed, 22 Nov 2006) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + +Fixed a compilation problem - a variable was removed but is was initialized +elsewhere. + +------------------------------------------------------------------------ +r2115 | const_k | 2006-11-20 17:50:37 +0600 (Mon, 20 Nov 2006) | 7 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Simple implementation of client-side scaling, controlled by new "Scaling +Factor" parameter. This implementation provides low-quality scaling but +is compatible with Java 1.1. Things to do next: (1) GUI for "Scaling +Factor" parameter; (2) documentation for "Scaling Factor" parameter; +(3) new scaling implementation based on Java 2D which would require +Java 2 platform but hopefully would show much higher scaling quality. + +------------------------------------------------------------------------ +r2097 | const_k | 2006-09-14 15:50:08 +0700 (Thu, 14 Sep 2006) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/AuthPanel.java + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Initial support for RFB protocol version 3.8. + +------------------------------------------------------------------------ +r2095 | const_k | 2006-09-14 08:48:00 +0700 (Thu, 14 Sep 2006) | 2 lines +Changed paths: + D /orig/trunk/vnc_javasrc/AuthUnixLoginPanel.java + M /orig/trunk/vnc_javasrc/Makefile + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Removed support for UnixLogin authentication method -- it was not officially supported or documented. + +------------------------------------------------------------------------ +r2094 | const_k | 2006-09-14 08:12:25 +0700 (Thu, 14 Sep 2006) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc + +Ignoring files created on compilation. + +------------------------------------------------------------------------ +r2079 | const_k | 2006-08-10 17:26:41 +0700 (Thu, 10 Aug 2006) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Version string and copyright info changed, version 1.3.8. + +------------------------------------------------------------------------ +r2064 | const_k | 2006-06-15 20:43:19 +0700 (Thu, 15 Jun 2006) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Version string changed for version 1.3dev8. + +------------------------------------------------------------------------ +r2063 | const_k | 2006-06-15 20:38:28 +0700 (Thu, 15 Jun 2006) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Updated description of the "Encoding" parameter that now can be set +and defaults to "Auto". + +------------------------------------------------------------------------ +r2039 | const_k | 2005-10-03 22:51:28 +0700 (Mon, 03 Oct 2005) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Improved the VncViewer.setEncodings() method. Now it does not build +the complete encoding list when auto-selecting encodings. + +------------------------------------------------------------------------ +r2038 | const_k | 2005-10-03 22:26:11 +0700 (Mon, 03 Oct 2005) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Implemented encoding auto selection based on measuring current network +throughput. + +------------------------------------------------------------------------ +r2037 | const_k | 2005-10-03 20:25:49 +0700 (Mon, 03 Oct 2005) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Improved encoding selection code. Also, now we request compression and +quality levels regardless of current preferred encoding and color +format. + +------------------------------------------------------------------------ +r2036 | const_k | 2005-10-03 09:52:26 +0700 (Mon, 03 Oct 2005) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Now the encoding array is prepared in the VncViewer.setEncodings() +method, instead of OptionsFrame.setEncodings(). This will allow to +implement auto encoding selection in VncViewer.setEncodings(). + +------------------------------------------------------------------------ +r2035 | const_k | 2005-10-03 08:32:47 +0700 (Mon, 03 Oct 2005) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/Makefile + +Added JCFLAGS variable for javac command-line flags. + +------------------------------------------------------------------------ +r2033 | const_k | 2005-09-30 19:42:25 +0700 (Fri, 30 Sep 2005) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/Makefile + +Reverted accidental change included in the previous commit. + +------------------------------------------------------------------------ +r2032 | const_k | 2005-09-30 19:27:17 +0700 (Fri, 30 Sep 2005) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/AuthPanel.java + M /orig/trunk/vnc_javasrc/Makefile + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Measuring network throughput. This will allow auto encoding selection +work properly. + +------------------------------------------------------------------------ +r2031 | const_k | 2005-09-30 10:38:26 +0700 (Fri, 30 Sep 2005) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + +Starting implementation of automatic encoding selection. Right now, +the "Auto" choice in the encoding list is equivalent to "Tight", but +without an option to set the compression level. + +------------------------------------------------------------------------ +r2019 | const_k | 2005-07-03 16:03:05 +0700 (Sun, 03 Jul 2005) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Version string changed for version 1.3dev7. + +------------------------------------------------------------------------ +r2018 | const_k | 2005-07-03 15:57:50 +0700 (Sun, 03 Jul 2005) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + M /orig/trunk/vnc_javasrc/index.html + +More information about editing the index.html example. + +------------------------------------------------------------------------ +r1906 | const_k | 2004-10-10 18:05:45 +0700 (Sun, 10 Oct 2004) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Added documentation for the "Scale remote cursor" option. + +------------------------------------------------------------------------ +r1905 | const_k | 2004-10-10 13:15:54 +0700 (Sun, 10 Oct 2004) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + +New "scale remote cursor" option allowing to reduce or enlarge soft +cursor image in the full-control mode. This change is based on a patch +from Horizon Wimba. + +------------------------------------------------------------------------ +r1903 | const_k | 2004-10-09 19:47:22 +0700 (Sat, 09 Oct 2004) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Version string changed, version 1.3dev6. + +------------------------------------------------------------------------ +r1902 | const_k | 2004-10-09 18:08:29 +0700 (Sat, 09 Oct 2004) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Applied a patch from Horizon Wimba, to remove synchronization from the +paint method and deal with cursor repaints properly. + +------------------------------------------------------------------------ +r1838 | const_k | 2004-08-22 13:42:50 +0700 (Sun, 22 Aug 2004) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +A typo fixed. + +------------------------------------------------------------------------ +r1836 | const_k | 2004-08-22 12:14:48 +0700 (Sun, 22 Aug 2004) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Made the VncCanvas.paint() method synchronized, to protect cursorX and +cursorY members from concurrent access. + +------------------------------------------------------------------------ +r1742 | const_k | 2004-05-30 21:50:42 +0700 (Sun, 30 May 2004) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Version string changed, version 1.3dev5. + +------------------------------------------------------------------------ +r1642 | const_k | 2004-03-04 20:02:16 +0600 (Thu, 04 Mar 2004) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Version string changed, version 1.3dev4. + +------------------------------------------------------------------------ +r1641 | const_k | 2004-03-04 19:34:25 +0600 (Thu, 04 Mar 2004) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/AuthPanel.java + A /orig/trunk/vnc_javasrc/AuthUnixLoginPanel.java + M /orig/trunk/vnc_javasrc/Makefile + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Added support for Unix login-style authentication. + +------------------------------------------------------------------------ +r1639 | const_k | 2004-03-04 00:57:24 +0600 (Thu, 04 Mar 2004) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/CapabilityInfo.java + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Added support for TightVNC protocol extensions in RFB 3.7 protocol. + +------------------------------------------------------------------------ +r1635 | const_k | 2004-03-02 22:55:58 +0600 (Tue, 02 Mar 2004) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Added support for RFB protocol version 3.7, without TightVNC protocol +extensions yet. + +------------------------------------------------------------------------ +r1527 | const_k | 2003-07-24 22:29:13 +0700 (Thu, 24 Jul 2003) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncViewer.java + +Minor fix to move the keyboard focus to VncCanvas on opening the +desktop. + +------------------------------------------------------------------------ +r1526 | const_k | 2003-07-24 21:42:30 +0700 (Thu, 24 Jul 2003) | 6 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Applied a set of changes by HorizonLive.com, Inc. In the VncCanvas +class, fixed a problem of createImage() returning null. In the +VncViewer, problems with some JVMs hanging on destroying the applet +were solved. Also, implemented a possibility to enable/disable input +via inter-applet communication. + +------------------------------------------------------------------------ +r1496 | const_k | 2003-07-02 19:05:18 +0700 (Wed, 02 Jul 2003) | 3 lines +Changed paths: + A /orig/trunk/vnc_javasrc/CapabilityInfo.java + A /orig/trunk/vnc_javasrc/CapsContainer.java + M /orig/trunk/vnc_javasrc/Makefile + +Implemented a Java version of the CapsContainer class that will be +used in the protocol 3.130 handling code. + +------------------------------------------------------------------------ +r1465 | const_k | 2003-05-18 20:45:11 +0700 (Sun, 18 May 2003) | 6 lines +Changed paths: + M /orig/trunk/vnc_javasrc/AuthPanel.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Code refactored to enable integration of pluggable authentication +schemes. Now the Java viewer first connects to the server, then shows +the authentication panel only if the server requires authentication. +All the authentication code has been moved to the AuthPanel class. +Also, now the viewer shows status messages on connecting to the server. + +------------------------------------------------------------------------ +r1377 | const_k | 2003-03-02 16:54:57 +0600 (Sun, 02 Mar 2003) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + +Passing through X keysyms for foreign currencies, a modified patch +from Bernd Krueger-Knauber. + +------------------------------------------------------------------------ +r1315 | const_k | 2003-01-22 20:35:58 +0600 (Wed, 22 Jan 2003) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Version string changed, version 1.2.8. + +------------------------------------------------------------------------ +r1236 | const_k | 2002-11-13 23:50:33 +0600 (Wed, 13 Nov 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Version string changed, version 1.2.7. + +------------------------------------------------------------------------ +r1233 | const_k | 2002-11-12 15:21:28 +0600 (Tue, 12 Nov 2002) | 3 lines +Changed paths: + A /orig/trunk/vnc_javasrc/MANIFEST.MF + M /orig/trunk/vnc_javasrc/Makefile + +Added a MANIFEST file with a Main-Class statement to allow easy +execution of the JAR file, using java -jar command-line option. + +------------------------------------------------------------------------ +r1232 | const_k | 2002-11-12 15:18:48 +0600 (Tue, 12 Nov 2002) | 2 lines +Changed paths: + D /orig/trunk/vnc_javasrc/dir.mk + +Removed dir.mk file. + +------------------------------------------------------------------------ +r1231 | const_k | 2002-11-12 15:15:04 +0600 (Tue, 12 Nov 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/index.html + +Applet height increased by 32 pixels. + +------------------------------------------------------------------------ +r1230 | const_k | 2002-11-12 13:34:58 +0600 (Tue, 12 Nov 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/Makefile + +Extra .vnc files have been removed, having just index.vnc should be +enough. + +------------------------------------------------------------------------ +r1229 | const_k | 2002-11-12 13:33:04 +0600 (Tue, 12 Nov 2002) | 4 lines +Changed paths: + D /orig/trunk/vnc_javasrc/hextile.vnc + A /orig/trunk/vnc_javasrc/index.html + M /orig/trunk/vnc_javasrc/index.vnc + D /orig/trunk/vnc_javasrc/noshared.vnc + D /orig/trunk/vnc_javasrc/shared.vnc + D /orig/trunk/vnc_javasrc/tight.vnc + D /orig/trunk/vnc_javasrc/zlib.vnc + +Extra .vnc files have been removed, having just index.vnc should be +enough. Also, an example HTML page has been prepared, to simplify +installation under a standalone Web server. + +------------------------------------------------------------------------ +r1228 | const_k | 2002-11-12 13:13:16 +0600 (Tue, 12 Nov 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Documented three ways to use the Java viewer, in the Installation +section. + +------------------------------------------------------------------------ +r1227 | const_k | 2002-11-07 19:12:46 +0600 (Thu, 07 Nov 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Minor change to preserve keyboard focus in VncCanvas after resizing +the frame, when running in a separate window. + +------------------------------------------------------------------------ +r1226 | const_k | 2002-11-06 22:49:20 +0600 (Wed, 06 Nov 2002) | 5 lines +Changed paths: + M /orig/trunk/vnc_javasrc/Makefile + M /orig/trunk/vnc_javasrc/README + A /orig/trunk/vnc_javasrc/ReloginPanel.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Implemented new buttons "Login again" and "Close window" near the +disconnect or error messages in the applet mode, and introduced new +"Offer Relogin" parameter to control this improvement. Thanks to Peter +Astrand for the initial version of the "Login again" patch. + +------------------------------------------------------------------------ +r1214 | const_k | 2002-10-30 00:26:34 +0600 (Wed, 30 Oct 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Don't defer update requests if there is some data to receive, or if +the last update included a PointerPos message. + +------------------------------------------------------------------------ +r1213 | const_k | 2002-10-29 23:06:06 +0600 (Tue, 29 Oct 2002) | 4 lines +Changed paths: + A /orig/trunk/vnc_javasrc/HTTPConnectSocket.java + A /orig/trunk/vnc_javasrc/HTTPConnectSocketFactory.java + M /orig/trunk/vnc_javasrc/Makefile + +Support for connections via HTTP proxies using HTTP CONNECT method. +Most likely, this will not work in applet mode, due to security +restrictions in JVMs. + +------------------------------------------------------------------------ +r1212 | const_k | 2002-10-29 23:03:21 +0600 (Tue, 29 Oct 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Added support for new CursorPos pseudo-encoding which allows to +transmit pointer position from server to clients. + +------------------------------------------------------------------------ +r1192 | const_k | 2002-09-25 04:29:05 +0700 (Wed, 25 Sep 2002) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RecordingFrame.java + +A patch from Harmen van der Wal -- "a workaround for AFAIK a rare +(Blackdown 1.1.7) SecurityManager.checkPropertyAccess() bug, that +would otherwise be fatal for an unprivileged applet". + +------------------------------------------------------------------------ +r1191 | const_k | 2002-09-25 04:23:48 +0700 (Wed, 25 Sep 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Enhancements to the exception handling mechanisms, a patch from Harmen +van der Wal. + +------------------------------------------------------------------------ +r1190 | const_k | 2002-09-25 04:01:49 +0700 (Wed, 25 Sep 2002) | 5 lines +Changed paths: + M /orig/trunk/vnc_javasrc/Makefile + M /orig/trunk/vnc_javasrc/README + M /orig/trunk/vnc_javasrc/RfbProto.java + A /orig/trunk/vnc_javasrc/SocketFactory.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +A patch from Harmen van der Wal, which makes it easy to plug-in +alternative transport methods to the viewer. It can be useful for for +things like HTTP tunneling, SSL support, or perhaps for integration +with "zebedee", ssh or other tunneling mechanisms. + +------------------------------------------------------------------------ +r1189 | const_k | 2002-09-24 08:52:32 +0700 (Tue, 24 Sep 2002) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Reducing max frame size by 30 pixels in each direction, to leave some +place on the screen, e.g. for the menu bar on Macintosh or the task +bar on Windows; a patch from Steve Kann. + +------------------------------------------------------------------------ +r1171 | const_k | 2002-08-27 19:23:50 +0700 (Tue, 27 Aug 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Version string changed, version 1.2.6. + +------------------------------------------------------------------------ +r1141 | const | 2002-08-04 23:39:35 +0700 (Sun, 04 Aug 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Version string changed, version 1.2.5. Copyrights updated. + +------------------------------------------------------------------------ +r1130 | const | 2002-07-05 15:37:32 +0700 (Fri, 05 Jul 2002) | 5 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +More robust and correct methods to determine if Zlib- or Tight-encoded +data should be saved Raw-encoded or re-compressed in recorded +sessions. Also, always emit warnings in the Java console if such +recoding was necessary. + +------------------------------------------------------------------------ +r1129 | const | 2002-07-05 15:26:16 +0700 (Fri, 05 Jul 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Minor documentation addition. + +------------------------------------------------------------------------ +r1127 | const | 2002-07-05 13:17:23 +0700 (Fri, 05 Jul 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + +JPEG quality setting should be enabled in the Options frame only in +the 24-bit color mode. + +------------------------------------------------------------------------ +r1126 | const | 2002-07-05 13:02:37 +0700 (Fri, 05 Jul 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + +Unused temporary hack was removed. + +------------------------------------------------------------------------ +r1125 | const | 2002-07-04 03:25:47 +0700 (Thu, 04 Jul 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Some documentation on RFB session recording. + +------------------------------------------------------------------------ +r1124 | const | 2002-07-04 02:43:43 +0700 (Thu, 04 Jul 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + +Forgot to remove debugging output. + +------------------------------------------------------------------------ +r1123 | const | 2002-07-04 02:38:15 +0700 (Thu, 04 Jul 2002) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Re-compressing Tight-encoded rectangles when recorded session starts +after the connection was established, to make it possible to +decompress the data without knowing prior pixel data. + +------------------------------------------------------------------------ +r1122 | const | 2002-07-03 21:11:42 +0700 (Wed, 03 Jul 2002) | 6 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Special handling of Zlib-encoded rectangles -- they are written either +Zlib-encoded if it's a beginning of RFB session, or Raw encoded +otherwise. This is needed to make sure it will be possible to decode +saved data without knowing the state of zlib compression stream used +by the encoder. + +------------------------------------------------------------------------ +r1121 | const | 2002-07-03 17:49:59 +0700 (Wed, 03 Jul 2002) | 5 lines +Changed paths: + M /orig/trunk/vnc_javasrc/ButtonPanel.java + M /orig/trunk/vnc_javasrc/RecordingFrame.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +The "Record" button now appears only if current SecurityManager allows +access to the local filesystem. +Exceptions after an intentional disconnect are not shown in the applet +panel or window any more. + +------------------------------------------------------------------------ +r1120 | const | 2002-07-03 16:40:52 +0700 (Wed, 03 Jul 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RecordingFrame.java + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Implement dynamic toggling of session recording. + +------------------------------------------------------------------------ +r1119 | const | 2002-07-03 13:34:35 +0700 (Wed, 03 Jul 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncViewer.java + +Preparing to implement dynamic toggling of session recording. +The "Save Session" parameter was removed. + +------------------------------------------------------------------------ +r1118 | const | 2002-07-01 12:44:17 +0700 (Mon, 01 Jul 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RecordingFrame.java + +Fixed copyright string. + +------------------------------------------------------------------------ +r1114 | const | 2002-06-13 01:45:21 +0700 (Thu, 13 Jun 2002) | 5 lines +Changed paths: + M /orig/trunk/vnc_javasrc/ButtonPanel.java + M /orig/trunk/vnc_javasrc/RecordingFrame.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +A simple hack to make the RecordingFrame work, at least when the +recording is being turned on before making the connection. The +RecordingFrame is still not very useful but at least does allow to +record a whole session in one file. + +------------------------------------------------------------------------ +r1113 | const | 2002-06-12 19:03:20 +0700 (Wed, 12 Jun 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/ButtonPanel.java + M /orig/trunk/vnc_javasrc/Makefile + A /orig/trunk/vnc_javasrc/RecordingFrame.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Added new "Record" button and a GUI to control recording of sessions +in FBS files. + +------------------------------------------------------------------------ +r1112 | const | 2002-06-05 01:01:58 +0700 (Wed, 05 Jun 2002) | 7 lines +Changed paths: + M /orig/trunk/vnc_javasrc/Makefile + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/RfbProto.java + A /orig/trunk/vnc_javasrc/SessionRecorder.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Implemented experimental feature to save RFB sessions in FBS files +compatible with rfbproxy, and the new "Save Session" parameter where a +user can set a file name. Color format requested from the server was +changed to little-endian to make saved sessions similar to ones +written by the VNC Reflector, and to make colors compatible with RFB +Session Player. + +------------------------------------------------------------------------ +r1111 | const | 2002-06-04 12:55:45 +0700 (Tue, 04 Jun 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Cleanups in "throws" statements. + +------------------------------------------------------------------------ +r1110 | const | 2002-06-04 12:50:35 +0700 (Tue, 04 Jun 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Minor cleanup in comment. + +------------------------------------------------------------------------ +r1109 | const | 2002-06-04 12:37:20 +0700 (Tue, 04 Jun 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Major Code cleanup: each decoder was moved from the +processNormalProtocol() method to a separate function. + +------------------------------------------------------------------------ +r1108 | const | 2002-06-04 12:19:13 +0700 (Tue, 04 Jun 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Minor cleanup. + +------------------------------------------------------------------------ +r1107 | const | 2002-05-23 23:58:40 +0700 (Thu, 23 May 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + M /orig/trunk/vnc_javasrc/VncViewer.java + +New "ENCPASSWORD" parameter, modified patch from Peter Astrand. + +------------------------------------------------------------------------ +r1103 | const | 2002-05-19 15:03:47 +0700 (Sun, 19 May 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Throwing Exception instead of IOException if that was not an I/O +error. + +------------------------------------------------------------------------ +r1102 | const | 2002-05-19 13:38:02 +0700 (Sun, 19 May 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + +Applied patch from Peter Astrand to fix problems with Swedish keys and +broken JVMs. + +------------------------------------------------------------------------ +r1091 | const | 2002-04-25 18:51:58 +0700 (Thu, 25 Apr 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Updated version strings for version 1.2.4. + +------------------------------------------------------------------------ +r1090 | const | 2002-04-25 18:49:40 +0700 (Thu, 25 Apr 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Documented new feature to refresh remote desktop in the view-only mode +using "R"/"r" keys. + +------------------------------------------------------------------------ +r1081 | const | 2002-04-23 20:02:45 +0700 (Tue, 23 Apr 2002) | 5 lines +Changed paths: + M /orig/trunk/vnc_javasrc/ButtonPanel.java + +Bugfix: keyboard focus could be set incorrectly. It was returned to +desktop even when windows such as Options or Clipboard were created. +This looked like new windows had appeared behind the authenticator or +desktop window, if the viewer itself was running in a separate window. + +------------------------------------------------------------------------ +r1080 | const | 2002-04-10 02:10:47 +0700 (Wed, 10 Apr 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncViewer.java + +Minor bugfix to prevent the "Refresh" button to disappear after the +"Disconnect" button changes to "Hide desktop". + +------------------------------------------------------------------------ +r1079 | const | 2002-04-10 02:05:52 +0700 (Wed, 10 Apr 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncViewer.java + +Previous bugfix was broken. + +------------------------------------------------------------------------ +r1078 | const | 2002-04-10 02:01:30 +0700 (Wed, 10 Apr 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncViewer.java + +Minor bugfix to prevent dumping exceptions on pressing "R"/"r" keys +over disconnected desktop. + +------------------------------------------------------------------------ +r1077 | const | 2002-04-10 01:53:08 +0700 (Wed, 10 Apr 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Now "R"/"r" keys can be used to request screen updates in view-only +mode. + +------------------------------------------------------------------------ +r1075 | const | 2002-04-09 02:17:45 +0700 (Tue, 09 Apr 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +"Show offline desktop" parameter documented. + +------------------------------------------------------------------------ +r1074 | const | 2002-04-09 02:12:57 +0700 (Tue, 09 Apr 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +"Show Controls" setting moved from OptionsFrame to VncViewer class. + +------------------------------------------------------------------------ +r1073 | const | 2002-04-09 02:04:48 +0700 (Tue, 09 Apr 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/ButtonPanel.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +New "Show Offline Desktop" parameter allowing the disktop to be still +displayed even after the remote side closed connection. + +------------------------------------------------------------------------ +r1072 | const | 2002-04-03 00:12:54 +0700 (Wed, 03 Apr 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/AuthPanel.java + +Disabling the password input field on activating connections. + +------------------------------------------------------------------------ +r1071 | const | 2002-04-02 22:38:36 +0700 (Tue, 02 Apr 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncViewer.java + +Reporting more meaningful messages on errors. + +------------------------------------------------------------------------ +r1065 | const | 2002-03-25 21:41:27 +0600 (Mon, 25 Mar 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncViewer.java + +A cosmetic change. + +------------------------------------------------------------------------ +r1034 | const | 2002-03-07 23:27:04 +0600 (Thu, 07 Mar 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Fixed bug causing NullPointerException in view-only mode with disabled +button panel. + +------------------------------------------------------------------------ +r1021 | const | 2002-02-14 21:20:30 +0600 (Thu, 14 Feb 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/ButtonPanel.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Made the "Ctrl-Alt-Del" button disabled in the view-only mode. + +------------------------------------------------------------------------ +r1020 | const | 2002-02-14 21:19:10 +0600 (Thu, 14 Feb 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncViewer.java + +Removed calls printing debugging output. + +------------------------------------------------------------------------ +r1019 | const | 2002-02-13 05:02:01 +0600 (Wed, 13 Feb 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Added new parameters "Defer screen updates", "Defer cursor updates", +"Defer update requests", documented in README. + +------------------------------------------------------------------------ +r1018 | const | 2002-02-13 03:03:33 +0600 (Wed, 13 Feb 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Made "Restricted colors" option dynamic. + +------------------------------------------------------------------------ +r1017 | const | 2002-02-13 02:36:54 +0600 (Wed, 13 Feb 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Code cleanups, preparing to make "Restricted colors" option dynamic. + +------------------------------------------------------------------------ +r1016 | const | 2002-02-12 23:32:06 +0600 (Tue, 12 Feb 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/ButtonPanel.java + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/README + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Documented applet parameters, updated copyright strings. + +------------------------------------------------------------------------ +r1015 | const | 2002-02-12 19:53:30 +0600 (Tue, 12 Feb 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Solved all issues with JPEG image loading. +Added more comments in the source code. + +------------------------------------------------------------------------ +r1014 | const | 2002-02-12 18:13:22 +0600 (Tue, 12 Feb 2002) | 7 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Solved problems with asynchronous JPEG image loading, although the +solution is not ideal yet. Now the ImageObserver interface is used +only to track loading of JPEG images, and is not used with drawImage() +method calls. +Draft scaling implementation appeared in previous CVS commit was +temporarily removed in this revision. + +------------------------------------------------------------------------ +r1013 | const | 2002-02-08 18:06:31 +0600 (Fri, 08 Feb 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Simple and inefficient scaling implementation, new "Scaling Factor" +parameter. + +------------------------------------------------------------------------ +r1011 | const | 2002-02-08 00:20:53 +0600 (Fri, 08 Feb 2002) | 11 lines +Changed paths: + M /orig/trunk/vnc_javasrc/ButtonPanel.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Preventing authentication retries when the PASSWORD parameter is used. +Closing windows and disconnecting on the applet shutdown. +Terminating the application properly on closing the authentication +window. +Packing the window on reporting errors when in a separate window; +this is necessary because it's possible that the window was empty. +Disconnecting on fatal errors. +Always forcing the keyboard focus go to the desktop on activating the +connection. +Code re-organizations and cleanups e.g. new tryAuthenticate() method. + +------------------------------------------------------------------------ +r1009 | const | 2002-01-31 00:25:27 +0600 (Thu, 31 Jan 2002) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +The frame size now should be limited by the screen size. +JPEG support improved, but drawing is still not reliable. +Minor code cleanups -- methods re-arranged. + +------------------------------------------------------------------------ +r1008 | const | 2002-01-31 00:22:22 +0600 (Thu, 31 Jan 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + +A small piece of debugging code removed. + +------------------------------------------------------------------------ +r1007 | const | 2002-01-30 19:47:03 +0600 (Wed, 30 Jan 2002) | 6 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Drawing model was changed again; now usual off-screen Image is used +for double-buffering instead of MemoryImageSource. +Preliminary implementation of JPEG support in the Tight decoder. +New "JPEG image quality" parameter and corresponding item in the +Options frame. + +------------------------------------------------------------------------ +r1006 | const | 2002-01-25 12:49:36 +0600 (Fri, 25 Jan 2002) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Bugfixes in the Tight decoder: recent changes broke 8-bit color mode. +Bugfixes in the XCursor encoding support: cursor colors were +interpreted incorrectly. + +------------------------------------------------------------------------ +r1005 | const | 2002-01-15 03:11:07 +0600 (Tue, 15 Jan 2002) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +24-bit Tight decoder finished. Now it parses 24-bit (not 32-bit!) +color samples correctly, and is able to decode data pre-processed with +the "Gradient" filter. + +------------------------------------------------------------------------ +r1004 | const | 2002-01-15 00:46:06 +0600 (Tue, 15 Jan 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Preliminary working support for 24-bit colors in the Tight decoder. + +------------------------------------------------------------------------ +r1003 | const | 2002-01-14 20:00:14 +0600 (Mon, 14 Jan 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + +Color format was not set correctly. + +------------------------------------------------------------------------ +r1002 | const | 2002-01-14 19:32:15 +0600 (Mon, 14 Jan 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Code cleanups: changes in rfb.is.read() and rfb.is.readFully() calls. + +------------------------------------------------------------------------ +r1001 | const | 2002-01-14 19:18:58 +0600 (Mon, 14 Jan 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/AuthPanel.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Support for 24-bit color in RichCursor encoding. + +------------------------------------------------------------------------ +r1000 | const | 2002-01-13 06:11:34 +0600 (Sun, 13 Jan 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Support for 24-bit colors. At this moment, all decoders support this +color mode, with two exceptions of Tight and RichCursor. + +------------------------------------------------------------------------ +r999 | const | 2002-01-13 05:57:09 +0600 (Sun, 13 Jan 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + +Removed a piece of code used for debugging. + +------------------------------------------------------------------------ +r998 | const | 2002-01-13 00:23:11 +0600 (Sun, 13 Jan 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/OptionsFrame.java + M /orig/trunk/vnc_javasrc/RfbProto.java + M /orig/trunk/vnc_javasrc/VncCanvas.java + +The "View Only" mode now can be turned on/off at any moment. + +------------------------------------------------------------------------ +r997 | const | 2002-01-12 22:12:33 +0600 (Sat, 12 Jan 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/RfbProto.java + +Insert key now can be passed to the remote side. + +------------------------------------------------------------------------ +r996 | const | 2002-01-12 20:32:36 +0600 (Sat, 12 Jan 2002) | 5 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Dramatically simplified and robust implementation of handling +XCursor/RichCursor encodings. +Enhancements and bugfixes for the "Open New Window" mode. +Other minor enhancements and code cleanups. + +------------------------------------------------------------------------ +r995 | const | 2002-01-12 00:36:25 +0600 (Sat, 12 Jan 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/ClipboardFrame.java + M /orig/trunk/vnc_javasrc/OptionsFrame.java + +Minor code enhancements. + +------------------------------------------------------------------------ +r994 | const | 2002-01-11 23:35:33 +0600 (Fri, 11 Jan 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Implemented scrolling of the desktop area, when the desktop is shown +in a separate window. + +------------------------------------------------------------------------ +r993 | const | 2002-01-11 18:51:16 +0600 (Fri, 11 Jan 2002) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/ClipboardFrame.java + M /orig/trunk/vnc_javasrc/OptionsFrame.java + +"Dismiss" buttons renamed to "Close". + +------------------------------------------------------------------------ +r992 | const | 2002-01-11 04:19:03 +0600 (Fri, 11 Jan 2002) | 5 lines +Changed paths: + M /orig/trunk/vnc_javasrc/ButtonPanel.java + M /orig/trunk/vnc_javasrc/VncViewer.java + +Changes in the button panel. Now keyboard focus moves back to the +authentication panel or to the desktop after pressing any button on +the panel. Additionally, keyboard focus should move to the desktop +automatically when VNC connection is established. + +------------------------------------------------------------------------ +r991 | const | 2002-01-11 03:53:10 +0600 (Fri, 11 Jan 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/ButtonPanel.java + +Implemented new "Refresh" button. Pressing it results sending a +non-incremental FramebufferUpdateRequest message to the server. + +------------------------------------------------------------------------ +r990 | const | 2002-01-11 03:51:25 +0600 (Fri, 11 Jan 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/VncCanvas.java + +Now the viewer adjusts its desktop/window size on desktop size changes +on the remote side (working support for NewFBSize pseudo-encoding). + +------------------------------------------------------------------------ +r989 | const | 2002-01-11 02:50:00 +0600 (Fri, 11 Jan 2002) | 4 lines +Changed paths: + A /orig/trunk/vnc_javasrc/AuthPanel.java + M /orig/trunk/vnc_javasrc/ButtonPanel.java + A /orig/trunk/vnc_javasrc/ClipboardFrame.java + M /orig/trunk/vnc_javasrc/Makefile + A /orig/trunk/vnc_javasrc/OptionsFrame.java + A /orig/trunk/vnc_javasrc/RfbProto.java + A /orig/trunk/vnc_javasrc/VncCanvas.java + A /orig/trunk/vnc_javasrc/VncViewer.java + D /orig/trunk/vnc_javasrc/authenticationPanel.java + D /orig/trunk/vnc_javasrc/clipboardFrame.java + M /orig/trunk/vnc_javasrc/dir.mk + M /orig/trunk/vnc_javasrc/hextile.vnc + M /orig/trunk/vnc_javasrc/index.vnc + M /orig/trunk/vnc_javasrc/noshared.vnc + D /orig/trunk/vnc_javasrc/optionsFrame.java + D /orig/trunk/vnc_javasrc/rfbProto.java + M /orig/trunk/vnc_javasrc/shared.vnc + M /orig/trunk/vnc_javasrc/tight.vnc + D /orig/trunk/vnc_javasrc/vncCanvas.java + D /orig/trunk/vnc_javasrc/vncviewer.java + M /orig/trunk/vnc_javasrc/zlib.vnc + +New "Open New Window" parameter was implemented, now the viewer can +work in a separate frame instead of running in the applet area. +Class names were capitalized, to reflect usual Java naming standards. + +------------------------------------------------------------------------ +r988 | const | 2002-01-11 00:22:08 +0600 (Fri, 11 Jan 2002) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/hextile.vnc + M /orig/trunk/vnc_javasrc/index.vnc + M /orig/trunk/vnc_javasrc/noshared.vnc + M /orig/trunk/vnc_javasrc/shared.vnc + M /orig/trunk/vnc_javasrc/tight.vnc + M /orig/trunk/vnc_javasrc/zlib.vnc + +Inserted a
tag to prevent www.tightvnc.com link appear to the +left of the applet area. + +------------------------------------------------------------------------ +r981 | const | 2001-12-18 03:32:28 +0600 (Tue, 18 Dec 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncviewer.java + +In application mode, terminate application on window close event. + +------------------------------------------------------------------------ +r980 | const | 2001-12-18 02:28:34 +0600 (Tue, 18 Dec 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncCanvas.java + +Performance fixes in CopyRect routine, and the FillLargeArea method. + +------------------------------------------------------------------------ +r979 | const | 2001-12-18 01:39:40 +0600 (Tue, 18 Dec 2001) | 2 lines +Changed paths: + A /orig/trunk/vnc_javasrc/ButtonPanel.java + M /orig/trunk/vnc_javasrc/Makefile + M /orig/trunk/vnc_javasrc/dir.mk + M /orig/trunk/vnc_javasrc/rfbProto.java + M /orig/trunk/vnc_javasrc/vncCanvas.java + M /orig/trunk/vnc_javasrc/vncviewer.java + +Converted to Java 1.1 event model. + +------------------------------------------------------------------------ +r978 | const | 2001-12-17 03:49:14 +0600 (Mon, 17 Dec 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncCanvas.java + +Got rid of calls to deprecated methods etc. + +------------------------------------------------------------------------ +r977 | const | 2001-12-17 03:37:38 +0600 (Mon, 17 Dec 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncviewer.java + +Minor code cleanups. + +------------------------------------------------------------------------ +r976 | const | 2001-12-17 03:37:10 +0600 (Mon, 17 Dec 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/authenticationPanel.java + +Converted to Java 1.1 event model. + +------------------------------------------------------------------------ +r975 | const | 2001-12-17 02:51:05 +0600 (Mon, 17 Dec 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/optionsFrame.java + +Converted to Java 1.1 event model. + +------------------------------------------------------------------------ +r974 | const | 2001-12-17 02:19:03 +0600 (Mon, 17 Dec 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/clipboardFrame.java + +Converted to Java 1.1 event model. + +------------------------------------------------------------------------ +r973 | const | 2001-12-17 00:17:20 +0600 (Mon, 17 Dec 2001) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/clipboardFrame.java + +Removed debugging code forgotten in the previous version. +Minor code cleanups and formating changes. + +------------------------------------------------------------------------ +r972 | const | 2001-12-17 00:00:08 +0600 (Mon, 17 Dec 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/authenticationPanel.java + M /orig/trunk/vnc_javasrc/clipboardFrame.java + M /orig/trunk/vnc_javasrc/optionsFrame.java + M /orig/trunk/vnc_javasrc/rfbProto.java + M /orig/trunk/vnc_javasrc/vncviewer.java + +Got rid of most calls to methods deprecated in Java 1.1. + +------------------------------------------------------------------------ +r971 | const | 2001-12-16 21:41:38 +0600 (Sun, 16 Dec 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncCanvas.java + +Beeping through java.awt.Toolkit on receiving Bell RFB message. + +------------------------------------------------------------------------ +r970 | const | 2001-12-16 21:33:19 +0600 (Sun, 16 Dec 2001) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncCanvas.java + +Drawing techniques have been changed: now all the painting is +performed in update() and paint() methods of the Canvas component. +This should solve painting problems under some JVM implementations. + +------------------------------------------------------------------------ +r969 | const | 2001-12-16 20:56:29 +0600 (Sun, 16 Dec 2001) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/Makefile + D /orig/trunk/vnc_javasrc/animatedMemoryImageSource.java + M /orig/trunk/vnc_javasrc/dir.mk + M /orig/trunk/vnc_javasrc/vncCanvas.java + +First step of converting the source to Java 1.1: got rid of +animatedMemoryImageSource class; using new setAnimated() method in the +standard MemoryImageSource class instead. + +------------------------------------------------------------------------ +r939 | const | 2001-09-16 14:06:15 +0700 (Sun, 16 Sep 2001) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/optionsFrame.java + M /orig/trunk/vnc_javasrc/rfbProto.java + M /orig/trunk/vnc_javasrc/vncCanvas.java + M /orig/trunk/vnc_javasrc/vncviewer.java + +Addition of new parameters PASSWORD, "Include Controls", and "View +Only", modified patch from Steve Kann. + +------------------------------------------------------------------------ +r901 | const | 2001-06-18 23:46:28 +0700 (Mon, 18 Jun 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Version string change. + +------------------------------------------------------------------------ +r899 | const | 2001-05-12 16:55:47 +0700 (Sat, 12 May 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncviewer.java + +(setEncodings): Possible NullPointerException fixed. + +------------------------------------------------------------------------ +r884 | const | 2001-03-07 14:06:46 +0600 (Wed, 07 Mar 2001) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncCanvas.java + +Initial "software cursor" position set to (0, 0) instead of (40, 40). +Minor code clean-up. + +------------------------------------------------------------------------ +r868 | const | 2001-02-16 04:45:56 +0600 (Fri, 16 Feb 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncCanvas.java + +Minor performance fix and tiny clean-ups in code and comments. + +------------------------------------------------------------------------ +r867 | const | 2001-02-16 03:29:49 +0600 (Fri, 16 Feb 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/clipboardFrame.java + M /orig/trunk/vnc_javasrc/optionsFrame.java + +Tiny changes after looking in the TridiaVNC CVS sources. + +------------------------------------------------------------------------ +r866 | const | 2001-02-16 02:48:15 +0600 (Fri, 16 Feb 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + +Version string changed. + +------------------------------------------------------------------------ +r865 | const | 2001-02-15 23:48:43 +0600 (Thu, 15 Feb 2001) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncCanvas.java + +A number of performance optimizations and code clean-ups for all +supported encodings. + +------------------------------------------------------------------------ +r863 | const | 2001-02-15 01:56:48 +0600 (Thu, 15 Feb 2001) | 9 lines +Changed paths: + M /orig/trunk/vnc_javasrc/optionsFrame.java + M /orig/trunk/vnc_javasrc/vncCanvas.java + +Drawing techniques changed: now all drawing is performed through the +rawPixelsImage object and the pixels[] array, paintImage is not used +any more. +Settings "Raw pixel drawing: Fast/Reliable" and "CopyRect: +Fast/Reliable" removed from the Options panel since they do not make +sense in new drawing model. +Currently drawing of solid-color areas is slow but this issue +hopefully will be fixed in next versions. + +------------------------------------------------------------------------ +r858 | const | 2001-02-08 07:06:24 +0600 (Thu, 08 Feb 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/rfbProto.java + M /orig/trunk/vnc_javasrc/vncCanvas.java + M /orig/trunk/vnc_javasrc/vncviewer.java + +Fixes for compilation on Java 2 platform, from Klaus Erber. + +------------------------------------------------------------------------ +r836 | const | 2001-01-28 16:58:51 +0600 (Sun, 28 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/README + M /orig/trunk/vnc_javasrc/optionsFrame.java + M /orig/trunk/vnc_javasrc/rfbProto.java + M /orig/trunk/vnc_javasrc/vncCanvas.java + +One more name added to copyright strings. ;-) + +------------------------------------------------------------------------ +r835 | const | 2001-01-28 16:51:43 +0600 (Sun, 28 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/hextile.vnc + M /orig/trunk/vnc_javasrc/index.vnc + M /orig/trunk/vnc_javasrc/noshared.vnc + M /orig/trunk/vnc_javasrc/shared.vnc + M /orig/trunk/vnc_javasrc/tight.vnc + M /orig/trunk/vnc_javasrc/zlib.vnc + +www.TridiaVNC.com links chanded to www.TightVNC.com. + +------------------------------------------------------------------------ +r834 | const | 2001-01-28 16:43:39 +0600 (Sun, 28 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/Makefile + A /orig/trunk/vnc_javasrc/hextile.vnc + A /orig/trunk/vnc_javasrc/noshared.vnc + A /orig/trunk/vnc_javasrc/tight.vnc + +More HTML templates for different default settings prepared. + +------------------------------------------------------------------------ +r833 | const | 2001-01-28 16:36:14 +0600 (Sun, 28 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/optionsFrame.java + +Tight encoding is now set by default. + +------------------------------------------------------------------------ +r832 | const | 2001-01-27 04:24:59 +0600 (Sat, 27 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncviewer.java + +Tiny formatting changes. + +------------------------------------------------------------------------ +r831 | const | 2001-01-27 03:11:22 +0600 (Sat, 27 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/authenticationPanel.java + M /orig/trunk/vnc_javasrc/vncviewer.java + +From TridiaVNC: set initial input focus to password field. + +------------------------------------------------------------------------ +r830 | const | 2001-01-27 02:58:39 +0600 (Sat, 27 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/Makefile + +Unneeded changes reverted. + +------------------------------------------------------------------------ +r829 | const | 2001-01-27 00:52:44 +0600 (Sat, 27 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncCanvas.java + +Many changes. Cursor shape updates should work in all modes. + +------------------------------------------------------------------------ +r826 | const | 2001-01-26 01:31:54 +0600 (Fri, 26 Jan 2001) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/optionsFrame.java + M /orig/trunk/vnc_javasrc/rfbProto.java + M /orig/trunk/vnc_javasrc/vncCanvas.java + +Support for EncodingLastRect added. +Bugfix: "Cursor shape updates: Ignore" option caused exceptions on +XCursor updates. + +------------------------------------------------------------------------ +r825 | const | 2001-01-26 01:10:59 +0600 (Fri, 26 Jan 2001) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/optionsFrame.java + M /orig/trunk/vnc_javasrc/vncCanvas.java + M /orig/trunk/vnc_javasrc/vncviewer.java + +RichCursor and XCursor encodings now work, but only for raw encoding. +Minor formatting fixes (spaces -> tabs). + +------------------------------------------------------------------------ +r824 | const | 2001-01-26 01:09:42 +0600 (Fri, 26 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/rfbProto.java + +Minor formatting fixes (spaces -> tabs). + +------------------------------------------------------------------------ +r823 | const | 2001-01-25 00:25:22 +0600 (Thu, 25 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncCanvas.java + +"Cursor shape updates: Ignore" option works for RichCursor encoding. + +------------------------------------------------------------------------ +r822 | const | 2001-01-24 23:55:22 +0600 (Wed, 24 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/optionsFrame.java + M /orig/trunk/vnc_javasrc/vncCanvas.java + +Non-finished RichCursor support, minor code cleanups. + +------------------------------------------------------------------------ +r820 | const | 2001-01-23 23:42:45 +0600 (Tue, 23 Jan 2001) | 4 lines +Changed paths: + M /orig/trunk/vnc_javasrc/optionsFrame.java + M /orig/trunk/vnc_javasrc/rfbProto.java + +"Cursor shape updates" item in options frame. +Minor bugfix: "Compression level" item remained enabled when raw +encoding was chosen after zlib or tight. + +------------------------------------------------------------------------ +r819 | const | 2001-01-23 22:02:50 +0600 (Tue, 23 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/optionsFrame.java + M /orig/trunk/vnc_javasrc/rfbProto.java + +Requesting compression level for tight and zlib encodings. + +------------------------------------------------------------------------ +r818 | const | 2001-01-22 23:22:03 +0600 (Mon, 22 Jan 2001) | 3 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncCanvas.java + +Major speed optimizations and code cleanups in tight encoding +implementation. + +------------------------------------------------------------------------ +r817 | const | 2001-01-22 20:10:50 +0600 (Mon, 22 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncCanvas.java + +More error checking. + +------------------------------------------------------------------------ +r816 | const | 2001-01-22 20:06:39 +0600 (Mon, 22 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/vncCanvas.java + +Error checking, code cleanups. + +------------------------------------------------------------------------ +r814 | const | 2001-01-19 12:53:17 +0600 (Fri, 19 Jan 2001) | 2 lines +Changed paths: + M /orig/trunk/vnc_javasrc/Makefile + M /orig/trunk/vnc_javasrc/optionsFrame.java + M /orig/trunk/vnc_javasrc/rfbProto.java + M /orig/trunk/vnc_javasrc/vncCanvas.java + +First version of Java vncviewer with tight encoding support. + +------------------------------------------------------------------------ +r725 | const | 2000-09-29 22:39:38 +0700 (Fri, 29 Sep 2000) | 2 lines +Changed paths: + A /orig/trunk/vnc_javasrc + A /orig/trunk/vnc_javasrc/DesCipher.java + A /orig/trunk/vnc_javasrc/LICENCE.TXT + A /orig/trunk/vnc_javasrc/Makefile + A /orig/trunk/vnc_javasrc/README + A /orig/trunk/vnc_javasrc/animatedMemoryImageSource.java + A /orig/trunk/vnc_javasrc/authenticationPanel.java + A /orig/trunk/vnc_javasrc/clipboardFrame.java + A /orig/trunk/vnc_javasrc/dir.mk + A /orig/trunk/vnc_javasrc/index.vnc + A /orig/trunk/vnc_javasrc/optionsFrame.java + A /orig/trunk/vnc_javasrc/rfbProto.java + A /orig/trunk/vnc_javasrc/shared.vnc + A /orig/trunk/vnc_javasrc/vncCanvas.java + A /orig/trunk/vnc_javasrc/vncviewer.java + A /orig/trunk/vnc_javasrc/zlib.vnc + +Initial revision + +------------------------------------------------------------------------ diff --git a/ClipboardFrame.java b/ClipboardFrame.java new file mode 100644 index 0000000..f0a5b8d --- /dev/null +++ b/ClipboardFrame.java @@ -0,0 +1,133 @@ +// +// Copyright (C) 2001 HorizonLive.com, Inc. All Rights Reserved. +// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. +// +// This is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this software; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. +// + +// +// Clipboard frame. +// + +import java.awt.*; +import java.awt.event.*; + +class ClipboardFrame extends Frame + implements WindowListener, ActionListener { + + TextArea textArea; + Button clearButton, closeButton; + String selection; + VncViewer viewer; + + // + // Constructor. + // + + ClipboardFrame(VncViewer v) { + super("TightVNC Clipboard"); + + viewer = v; + + GridBagLayout gridbag = new GridBagLayout(); + setLayout(gridbag); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.fill = GridBagConstraints.BOTH; + gbc.weighty = 1.0; + + textArea = new TextArea(5, 40); + gridbag.setConstraints(textArea, gbc); + add(textArea); + + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.weightx = 1.0; + gbc.weighty = 0.0; + gbc.gridwidth = 1; + + clearButton = new Button("Clear"); + gridbag.setConstraints(clearButton, gbc); + add(clearButton); + clearButton.addActionListener(this); + + closeButton = new Button("Close"); + gridbag.setConstraints(closeButton, gbc); + add(closeButton); + closeButton.addActionListener(this); + + pack(); + + addWindowListener(this); + } + + + // + // Set the cut text from the RFB server. + // + + void setCutText(String text) { + selection = text; + textArea.setText(text); + if (isVisible()) { + textArea.selectAll(); + } + } + + + // + // When the focus leaves the window, see if we have new cut text and + // if so send it to the RFB server. + // + + public void windowDeactivated (WindowEvent evt) { + if (selection != null && !selection.equals(textArea.getText())) { + selection = textArea.getText(); + viewer.setCutText(selection); + } + } + + // + // Close our window properly. + // + + public void windowClosing(WindowEvent evt) { + setVisible(false); + } + + // + // Ignore window events we're not interested in. + // + + public void windowActivated(WindowEvent evt) {} + public void windowOpened(WindowEvent evt) {} + public void windowClosed(WindowEvent evt) {} + public void windowIconified(WindowEvent evt) {} + public void windowDeiconified(WindowEvent evt) {} + + + // + // Respond to button presses + // + + public void actionPerformed(ActionEvent evt) { + if (evt.getSource() == clearButton) { + textArea.setText(""); + } else if (evt.getSource() == closeButton) { + setVisible(false); + } + } +} diff --git a/DesCipher.java b/DesCipher.java new file mode 100644 index 0000000..2b7b5f2 --- /dev/null +++ b/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 , 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 . 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/ + + +import java.io.*; + +/// The DES encryption method. +//

+// This is surprisingly fast, for pure Java. On a SPARC 20, wrapped +// in Acme.Crypto.EncryptedOutputStream or Acme.Crypto.EncryptedInputStream, +// it does around 7000 bytes/second. +//

+// Most of this code is by Dave Zimmerman , and is +// Copyright (c) 1996 Widget Workshop, Inc. See the source file for details. +//

+// Fetch the software.
+// Fetch the entire Acme package. +//

+// @see Des3Cipher +// @see EncryptedOutputStream +// @see EncryptedInputStream + +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/HTTPConnectSocket.java b/HTTPConnectSocket.java new file mode 100644 index 0000000..390571b --- /dev/null +++ b/HTTPConnectSocket.java @@ -0,0 +1,59 @@ +// +// Copyright (C) 2002 Constantin Kaplinsky, Inc. All Rights Reserved. +// +// This is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this software; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. +// + +// +// HTTPConnectSocket.java together with HTTPConnectSocketFactory.java +// implement an alternate way to connect to VNC servers via one or two +// HTTP proxies supporting the HTTP CONNECT method. +// + +import java.net.*; +import java.io.*; + +class HTTPConnectSocket extends Socket { + + public HTTPConnectSocket(String host, int port, + String proxyHost, int proxyPort) + throws IOException { + + // Connect to the specified HTTP proxy + super(proxyHost, proxyPort); + + // Send the CONNECT request + getOutputStream().write(("CONNECT " + host + ":" + port + + " HTTP/1.0\r\n\r\n").getBytes()); + + // Read the first line of the response + DataInputStream is = new DataInputStream(getInputStream()); + String str = is.readLine(); + + // Check the HTTP error code -- it should be "200" on success + if (!str.startsWith("HTTP/1.0 200 ")) { + if (str.startsWith("HTTP/1.0 ")) + str = str.substring(9); + throw new IOException("Proxy reports \"" + str + "\""); + } + + // Success -- skip remaining HTTP headers + do { + str = is.readLine(); + } while (str.length() != 0); + } +} + diff --git a/HTTPConnectSocketFactory.java b/HTTPConnectSocketFactory.java new file mode 100644 index 0000000..a9dbb76 --- /dev/null +++ b/HTTPConnectSocketFactory.java @@ -0,0 +1,86 @@ +// +// Copyright (C) 2002 Constantin Kaplinsky, Inc. All Rights Reserved. +// +// This is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this software; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. +// + +// +// HTTPConnectSocketFactory.java together with HTTPConnectSocket.java +// implement an alternate way to connect to VNC servers via one or two +// HTTP proxies supporting the HTTP CONNECT method. +// + +import java.applet.*; +import java.net.*; +import java.io.*; + +class HTTPConnectSocketFactory implements SocketFactory { + + public Socket createSocket(String host, int port, Applet applet) + throws IOException { + + return createSocket(host, port, + applet.getParameter("PROXYHOST1"), + applet.getParameter("PROXYPORT1")); + } + + public Socket createSocket(String host, int port, String[] args) + throws IOException { + + return createSocket(host, port, + readArg(args, "PROXYHOST1"), + readArg(args, "PROXYPORT1")); + } + + public Socket createSocket(String host, int port, + String proxyHost, String proxyPortStr) + throws IOException { + + int proxyPort = 0; + if (proxyPortStr != null) { + try { + proxyPort = Integer.parseInt(proxyPortStr); + } catch (NumberFormatException e) { } + } + + if (proxyHost == null || proxyPort == 0) { + System.out.println("Incomplete parameter list for HTTPConnectSocket"); + return new Socket(host, port); + } + + System.out.println("HTTP CONNECT via proxy " + proxyHost + + " port " + proxyPort); + HTTPConnectSocket s = + new HTTPConnectSocket(host, port, proxyHost, proxyPort); + + return (Socket)s; + } + + private String readArg(String[] args, String name) { + + for (int i = 0; i < args.length; i += 2) { + if (args[i].equalsIgnoreCase(name)) { + try { + return args[i+1]; + } catch (Exception e) { + return null; + } + } + } + return null; + } +} + diff --git a/InStream.java b/InStream.java new file mode 100644 index 0000000..16f7090 --- /dev/null +++ b/InStream.java @@ -0,0 +1,177 @@ +/* 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). +// + +abstract public class InStream { + + // check() ensures there is buffer data for at least one item of size + // itemSize bytes. Returns the number of items in the buffer (up to a + // maximum of nItems). + + public final int check(int itemSize, int nItems) throws Exception { + if (ptr + itemSize * nItems > end) { + if (ptr + itemSize > end) + return overrun(itemSize, nItems); + + nItems = (end - ptr) / itemSize; + } + return nItems; + } + + public final void check(int itemSize) throws Exception { + if (ptr + itemSize > end) + overrun(itemSize, 1); + } + + // readU/SN() methods read unsigned and signed N-bit integers. + + public final int readS8() throws Exception { + check(1); return b[ptr++]; + } + + public final int readS16() throws Exception { + check(2); int b0 = b[ptr++]; + int b1 = b[ptr++] & 0xff; return b0 << 8 | b1; + } + + public final int readS32() throws Exception { + check(4); int b0 = b[ptr++]; + int b1 = b[ptr++] & 0xff; + int b2 = b[ptr++] & 0xff; + int b3 = b[ptr++] & 0xff; + return b0 << 24 | b1 << 16 | b2 << 8 | b3; + } + + public final int readU8() throws Exception { + return readS8() & 0xff; + } + + public final int readU16() throws Exception { + return readS16() & 0xffff; + } + + public final int readU32() throws Exception { + return readS32() & 0xffffffff; + } + + // readString() reads a string - a U32 length followed by the data. + + public final String readString() throws Exception { + int len = readU32(); + if (len > maxStringLength) + throw new Exception("InStream max string length exceeded"); + + char[] str = new char[len]; + int i = 0; + while (i < len) { + int j = i + check(1, len - i); + while (i < j) { + str[i++] = (char)b[ptr++]; + } + } + + return new String(str); + } + + // maxStringLength protects against allocating a huge buffer. Set it + // higher if you need longer strings. + + public static int maxStringLength = 65535; + + public final void skip(int bytes) throws Exception { + while (bytes > 0) { + int n = check(1, bytes); + ptr += n; + bytes -= n; + } + } + + // readBytes() reads an exact number of bytes into an array at an offset. + + public void readBytes(byte[] data, int offset, int length) throws Exception { + int offsetEnd = offset + length; + while (offset < offsetEnd) { + int n = check(1, offsetEnd - offset); + System.arraycopy(b, ptr, data, offset, n); + ptr += n; + offset += n; + } + } + + // readOpaqueN() reads a quantity "without byte-swapping". Because java has + // no byte-ordering, we just use big-endian. + + public final int readOpaque8() throws Exception { + return readU8(); + } + + public final int readOpaque16() throws Exception { + return readU16(); + } + + public final int readOpaque32() throws Exception { + return readU32(); + } + + public final int readOpaque24A() throws Exception { + check(3); int b0 = b[ptr++]; + int b1 = b[ptr++]; int b2 = b[ptr++]; + return b0 << 24 | b1 << 16 | b2 << 8; + } + + public final int readOpaque24B() throws Exception { + check(3); int b0 = b[ptr++]; + int b1 = b[ptr++]; int b2 = b[ptr++]; + return b0 << 16 | b1 << 8 | b2; + } + + // pos() returns the position in the stream. + + abstract public int pos(); + + // bytesAvailable() returns true if at least one byte can be read from the + // stream without blocking. i.e. if false is returned then readU8() would + // block. + + public boolean bytesAvailable() { return end != ptr; } + + // getbuf(), getptr(), getend() and setptr() are "dirty" methods which allow + // you to manipulate the buffer directly. This is useful for a stream which + // is a wrapper around an underlying stream. + + public final byte[] getbuf() { return b; } + public final int getptr() { return ptr; } + public final int getend() { return end; } + public final void setptr(int p) { ptr = p; } + + // overrun() is implemented by a derived class to cope with buffer overrun. + // It ensures there are at least itemSize bytes of buffer data. Returns + // the number of items in the buffer (up to a maximum of nItems). itemSize + // is supposed to be "small" (a few bytes). + + abstract protected int overrun(int itemSize, int nItems) throws Exception; + + protected InStream() {} + protected byte[] b; + protected int ptr; + protected int end; +} diff --git a/LICENCE.TXT b/LICENCE.TXT new file mode 100644 index 0000000..ae3b531 --- /dev/null +++ b/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. + + + Copyright (C) 19yy + + 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. + + , 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/MANIFEST.MF b/MANIFEST.MF new file mode 100644 index 0000000..9ddbfbc --- /dev/null +++ b/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 +Main-Class: VncViewer diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..98c5121 --- /dev/null +++ b/Makefile @@ -0,0 +1,49 @@ +# +# Making the VNC applet. +# + +CP = cp +JC = javac +JCFLAGS = -target 1.1 +JAR = jar +ARCHIVE = VncViewer.jar +MANIFEST = MANIFEST.MF +PAGES = index.vnc +INSTALL_DIR = /usr/local/vnc/classes + +CLASSES = VncViewer.class RfbProto.class AuthPanel.class VncCanvas.class \ + VncCanvas2.class \ + OptionsFrame.class ClipboardFrame.class ButtonPanel.class \ + DesCipher.class CapabilityInfo.class CapsContainer.class \ + RecordingFrame.class SessionRecorder.class \ + SocketFactory.class HTTPConnectSocketFactory.class \ + VNCProxyConnectSocketFactory.class VNCProxyConnectSocket.class \ + HTTPConnectSocket.class ReloginPanel.class \ + InStream.class MemInStream.class ZlibInStream.class + +SOURCES = VncViewer.java RfbProto.java AuthPanel.java VncCanvas.java \ + VncCanvas2.java \ + OptionsFrame.java ClipboardFrame.java ButtonPanel.java \ + DesCipher.java CapabilityInfo.java CapsContainer.java \ + RecordingFrame.java SessionRecorder.java \ + SocketFactory.java HTTPConnectSocketFactory.java \ + VNCProxyConnectSocketFactory.java VNCProxyConnectSocket.java \ + HTTPConnectSocket.java ReloginPanel.java \ + InStream.java MemInStream.java ZlibInStream.java + +all: $(CLASSES) $(ARCHIVE) + +$(CLASSES): $(SOURCES) + $(JC) $(JCFLAGS) -O $(SOURCES) + +$(ARCHIVE): $(CLASSES) $(MANIFEST) + $(JAR) cfm $(ARCHIVE) $(MANIFEST) $(CLASSES) + +install: $(CLASSES) $(ARCHIVE) + $(CP) $(CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR) + +export:: $(CLASSES) $(ARCHIVE) $(PAGES) + @$(ExportJavaClasses) + +clean:: + $(RM) *.class *.jar diff --git a/MemInStream.java b/MemInStream.java new file mode 100644 index 0000000..9be98e1 --- /dev/null +++ b/MemInStream.java @@ -0,0 +1,32 @@ +/* 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. + */ + +public class MemInStream extends InStream { + + public MemInStream(byte[] data, int offset, int len) { + b = data; + ptr = offset; + end = offset + len; + } + + public int pos() { return ptr; } + + protected int overrun(int itemSize, int nItems) throws Exception { + throw new Exception("MemInStream overrun: end of stream"); + } +} diff --git a/OptionsFrame.java b/OptionsFrame.java new file mode 100644 index 0000000..701026a --- /dev/null +++ b/OptionsFrame.java @@ -0,0 +1,411 @@ +// +// Copyright (C) 2001 HorizonLive.com, Inc. All Rights Reserved. +// Copyright (C) 2001 Constantin Kaplinsky. All Rights Reserved. +// Copyright (C) 2000 Tridia Corporation. All Rights Reserved. +// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. +// +// This is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this software; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. +// + +// +// Options frame. +// +// This deals with all the options the user can play with. +// It sets the encodings array and some booleans. +// + +import java.awt.*; +import java.awt.event.*; + +class OptionsFrame extends Frame + implements WindowListener, ActionListener, ItemListener { + + static String[] names = { + "Encoding", + "Compression level", + "JPEG image quality", + "Cursor shape updates", + "Use CopyRect", + "Restricted colors", + "Mouse buttons 2 and 3", + "View only", + "Scale remote cursor", + "Share desktop", + }; + + static String[][] values = { + { "Auto", "Raw", "RRE", "CoRRE", "Hextile", "Zlib", "Tight", "ZRLE" }, + { "Default", "1", "2", "3", "4", "5", "6", "7", "8", "9" }, + { "JPEG off", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }, + { "Enable", "Ignore", "Disable" }, + { "Yes", "No" }, + { "Yes", "No" }, + { "Normal", "Reversed" }, + { "Yes", "No" }, + { "No", "50%", "75%", "125%", "150%" }, + { "Yes", "No" }, + }; + + final int + encodingIndex = 0, + compressLevelIndex = 1, + jpegQualityIndex = 2, + cursorUpdatesIndex = 3, + useCopyRectIndex = 4, + eightBitColorsIndex = 5, + mouseButtonIndex = 6, + viewOnlyIndex = 7, + scaleCursorIndex = 8, + shareDesktopIndex = 9; + + Label[] labels = new Label[names.length]; + Choice[] choices = new Choice[names.length]; + Button closeButton; + VncViewer viewer; + + + // + // The actual data which other classes look at: + // + + int preferredEncoding; + int compressLevel; + int jpegQuality; + boolean useCopyRect; + boolean requestCursorUpdates; + boolean ignoreCursorUpdates; + + boolean eightBitColors; + + boolean reverseMouseButtons2And3; + boolean shareDesktop; + boolean viewOnly; + int scaleCursor; + + boolean autoScale; + int scalingFactor; + + // + // Constructor. Set up the labels and choices from the names and values + // arrays. + // + + OptionsFrame(VncViewer v) { + super("TightVNC Options"); + + viewer = v; + + GridBagLayout gridbag = new GridBagLayout(); + setLayout(gridbag); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.BOTH; + + for (int i = 0; i < names.length; i++) { + labels[i] = new Label(names[i]); + gbc.gridwidth = 1; + gridbag.setConstraints(labels[i],gbc); + add(labels[i]); + + choices[i] = new Choice(); + gbc.gridwidth = GridBagConstraints.REMAINDER; + gridbag.setConstraints(choices[i],gbc); + add(choices[i]); + choices[i].addItemListener(this); + + for (int j = 0; j < values[i].length; j++) { + choices[i].addItem(values[i][j]); + } + } + + closeButton = new Button("Close"); + gbc.gridwidth = GridBagConstraints.REMAINDER; + gridbag.setConstraints(closeButton, gbc); + add(closeButton); + closeButton.addActionListener(this); + + pack(); + + addWindowListener(this); + + // Set up defaults + + choices[encodingIndex].select("Auto"); + choices[compressLevelIndex].select("Default"); + choices[jpegQualityIndex].select("6"); + choices[cursorUpdatesIndex].select("Enable"); + choices[useCopyRectIndex].select("Yes"); + choices[eightBitColorsIndex].select("No"); + choices[mouseButtonIndex].select("Normal"); + choices[viewOnlyIndex].select("No"); + choices[scaleCursorIndex].select("No"); + choices[shareDesktopIndex].select("Yes"); + + // But let them be overridden by parameters + + for (int i = 0; i < names.length; i++) { + String s = viewer.readParameter(names[i], false); + if (s != null) { + for (int j = 0; j < values[i].length; j++) { + if (s.equalsIgnoreCase(values[i][j])) { + choices[i].select(j); + } + } + } + } + + // FIXME: Provide some sort of GUI for "Scaling Factor". + + autoScale = false; + scalingFactor = 100; + String s = viewer.readParameter("Scaling Factor", false); + if (s != null) { + if (s.equalsIgnoreCase("Auto")) { + autoScale = true; + } else { + // Remove the '%' char at the end of string if present. + if (s.charAt(s.length() - 1) == '%') { + s = s.substring(0, s.length() - 1); + } + // Convert to an integer. + try { + scalingFactor = Integer.parseInt(s); + } + catch (NumberFormatException e) { + scalingFactor = 100; + } + // Make sure scalingFactor is in the range of [1..1000]. + if (scalingFactor < 1) { + scalingFactor = 1; + } else if (scalingFactor > 1000) { + scalingFactor = 1000; + } + } + } + + // Make the booleans and encodings array correspond to the state of the GUI + + setEncodings(); + setColorFormat(); + setOtherOptions(); + } + + + // + // Disable the shareDesktop option + // + + void disableShareDesktop() { + labels[shareDesktopIndex].setEnabled(false); + choices[shareDesktopIndex].setEnabled(false); + } + + + // + // setEncodings looks at the encoding, compression level, JPEG + // quality level, cursor shape updates and copyRect choices and sets + // corresponding variables properly. Then it calls the VncViewer's + // setEncodings method to send a SetEncodings message to the RFB + // server. + // + + void setEncodings() { + useCopyRect = choices[useCopyRectIndex].getSelectedItem().equals("Yes"); + + preferredEncoding = RfbProto.EncodingRaw; + boolean enableCompressLevel = false; + boolean enableQualityLevel = false; + + if (choices[encodingIndex].getSelectedItem().equals("RRE")) { + preferredEncoding = RfbProto.EncodingRRE; + } else if (choices[encodingIndex].getSelectedItem().equals("CoRRE")) { + preferredEncoding = RfbProto.EncodingCoRRE; + } else if (choices[encodingIndex].getSelectedItem().equals("Hextile")) { + preferredEncoding = RfbProto.EncodingHextile; + } else if (choices[encodingIndex].getSelectedItem().equals("ZRLE")) { + preferredEncoding = RfbProto.EncodingZRLE; + } else if (choices[encodingIndex].getSelectedItem().equals("Zlib")) { + preferredEncoding = RfbProto.EncodingZlib; + enableCompressLevel = true; + } else if (choices[encodingIndex].getSelectedItem().equals("Tight")) { + preferredEncoding = RfbProto.EncodingTight; + enableCompressLevel = true; + enableQualityLevel = !eightBitColors; + } else if (choices[encodingIndex].getSelectedItem().equals("Auto")) { + preferredEncoding = -1; + enableQualityLevel = !eightBitColors; + } + + // Handle compression level setting. + + try { + compressLevel = + Integer.parseInt(choices[compressLevelIndex].getSelectedItem()); + } + catch (NumberFormatException e) { + compressLevel = -1; + } + if (compressLevel < 1 || compressLevel > 9) { + compressLevel = -1; + } + labels[compressLevelIndex].setEnabled(enableCompressLevel); + choices[compressLevelIndex].setEnabled(enableCompressLevel); + + // Handle JPEG quality setting. + + try { + jpegQuality = + Integer.parseInt(choices[jpegQualityIndex].getSelectedItem()); + } + catch (NumberFormatException e) { + jpegQuality = -1; + } + if (jpegQuality < 0 || jpegQuality > 9) { + jpegQuality = -1; + } + labels[jpegQualityIndex].setEnabled(enableQualityLevel); + choices[jpegQualityIndex].setEnabled(enableQualityLevel); + + // Request cursor shape updates if necessary. + + requestCursorUpdates = + !choices[cursorUpdatesIndex].getSelectedItem().equals("Disable"); + + if (requestCursorUpdates) { + ignoreCursorUpdates = + choices[cursorUpdatesIndex].getSelectedItem().equals("Ignore"); + } + + viewer.setEncodings(); + } + + // + // setColorFormat sets eightBitColors variable depending on the GUI + // setting, causing switches between 8-bit and 24-bit colors mode if + // necessary. + // + + void setColorFormat() { + + eightBitColors = + choices[eightBitColorsIndex].getSelectedItem().equals("Yes"); + + boolean enableJPEG = !eightBitColors && + (choices[encodingIndex].getSelectedItem().equals("Tight") || + choices[encodingIndex].getSelectedItem().equals("Auto")); + + labels[jpegQualityIndex].setEnabled(enableJPEG); + choices[jpegQualityIndex].setEnabled(enableJPEG); + } + + // + // setOtherOptions looks at the "other" choices (ones which don't set the + // encoding or the color format) and sets the boolean flags appropriately. + // + + void setOtherOptions() { + + reverseMouseButtons2And3 + = choices[mouseButtonIndex].getSelectedItem().equals("Reversed"); + + viewOnly + = choices[viewOnlyIndex].getSelectedItem().equals("Yes"); + if (viewer.vc != null) + viewer.vc.enableInput(!viewOnly); + + shareDesktop + = choices[shareDesktopIndex].getSelectedItem().equals("Yes"); + + String scaleString = choices[scaleCursorIndex].getSelectedItem(); + if (scaleString.endsWith("%")) + scaleString = scaleString.substring(0, scaleString.length() - 1); + try { + scaleCursor = Integer.parseInt(scaleString); + } + catch (NumberFormatException e) { + scaleCursor = 0; + } + if (scaleCursor < 10 || scaleCursor > 500) { + scaleCursor = 0; + } + if (requestCursorUpdates && !ignoreCursorUpdates && !viewOnly) { + labels[scaleCursorIndex].setEnabled(true); + choices[scaleCursorIndex].setEnabled(true); + } else { + labels[scaleCursorIndex].setEnabled(false); + choices[scaleCursorIndex].setEnabled(false); + } + if (viewer.vc != null) + viewer.vc.createSoftCursor(); // update cursor scaling + } + + + // + // Respond to actions on Choice controls + // + + public void itemStateChanged(ItemEvent evt) { + Object source = evt.getSource(); + + if (source == choices[encodingIndex] || + source == choices[compressLevelIndex] || + source == choices[jpegQualityIndex] || + source == choices[cursorUpdatesIndex] || + source == choices[useCopyRectIndex]) { + + setEncodings(); + + if (source == choices[cursorUpdatesIndex]) { + setOtherOptions(); // update scaleCursor state + } + + } else if (source == choices[eightBitColorsIndex]) { + + setColorFormat(); + + } else if (source == choices[mouseButtonIndex] || + source == choices[shareDesktopIndex] || + source == choices[viewOnlyIndex] || + source == choices[scaleCursorIndex]) { + + setOtherOptions(); + } + } + + // + // Respond to button press + // + + public void actionPerformed(ActionEvent evt) { + if (evt.getSource() == closeButton) + setVisible(false); + } + + // + // Respond to window events + // + + public void windowClosing(WindowEvent evt) { + setVisible(false); + } + + public void windowActivated(WindowEvent evt) {} + public void windowDeactivated(WindowEvent evt) {} + public void windowOpened(WindowEvent evt) {} + public void windowClosed(WindowEvent evt) {} + public void windowIconified(WindowEvent evt) {} + public void windowDeiconified(WindowEvent evt) {} +} diff --git a/README b/README new file mode 100644 index 0000000..43ada68 --- /dev/null +++ b/README @@ -0,0 +1,493 @@ + + TightVNC Java Viewer version 1.3.9 + +====================================================================== + +This distribution is based on the standard VNC source and includes new +TightVNC-specific features and fixes, such as additional low-bandwidth +optimizations, major GUI improvements, and more. + + Copyright (C) 1999 AT&T Laboratories Cambridge. + Copyright (C) 2000 Tridia Corp. + Copyright (C) 2002-2003 RealVNC Ltd. + Copyright (C) 2001-2004 HorizonLive.com, Inc. + Copyright (C) 2000-2007 Constantin Kaplinsky + Copyright (C) 2000-2007 TightVNC Group + 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. TightVNC 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. + + +Compiling from the sources +========================== + +To compile all the .java files to .class files, simply do: + + % make all + +This will also generate a JAR (Java archive) file containing all the classes. +Most JVM (Java Virtual Machine) implementations are able to use either a set +of .class files, or the JAR archive. + + +Installation +============ + +There are three basic ways to use TightVNC Java viewer: + + 1. Running applet as part of TightVNC server installation. + + Both the Unix and Windows versions of TightVNC servers include small + built-in HTTP server which can serve Java viewer to Web clients. This + enables easy Web access to the shared desktop without need to install + any software on the client computer. Unix and Windows versions of + TightVNC servers are different in the way they store the .class and .jar + files: the Unix server (Xvnc) is able to serve any set of files present + in a particular directory, while the Windows server (WinVNC) has all the + .class and .jar files inside the WinVNC executable file. Therefore, for + Xvnc, it's enough to copy the files into a correct directory, but for + WinVNC, the server binaries should be rebuild if the built-in Java + viewer should be updated. + + To install the Java viewer under Xvnc, copy all the .class files, the + .jar file and the .vnc files to an installation directory (e.g. + /usr/local/vnc/classes): + + cp *.class *.jar *.vnc /usr/local/vnc/classes + + Also, make sure that the vncserver script is configured to point to the + installation directory (see the Xvnc manual page for the description of + the -httpd command-line option). + + 2. Running applet hosted on a standalone Web server. + + Another possibility to use the Java viewer is to install it under a + fully-functional HTTP server such as Apache or IIS. Obviously, this + method requires running an HTTP server, and due to the Java security + restrictions, it's also required that the server should be installed on + the same machine which is running the TightVNC server. In this case, + installation is simply copying the .class and .jar files into a + directory that is under control of the HTTP server. Also, an HTML page + should be created which will act as a the base document for the viewer + applet (see an example named index.html in this distribution). + + NOTE: Provided index.html page is an example only. Before using that + file, edit it with a text editor. See more information inside + index.html. + + 3. Running the viewer as a standalone application. + + Finally, the Java viewer can be executed locally on the client machine, + but this method requires installation of either JRE (Java Runtime + Environment) or JDK (Java Development Kit). If all the .class files are + in the current directory, the Java viewer can be executed like this, + from the command line: + + java VncViewer HOST vnchost PORT 5900 + + The parameters HOST and PORT are required, but there is a number of + optional parameters as well (see the Parameters section below). + +Parameters +========== + +TightVNC Java viewer supports a number of parameters allowing you to +customize its behavior. Most parameters directly correspond to the settings +found in the Options window. However, there are parameters that do not +correspond to those settings. For such parameters, you can see a note "no GUI +equivalent", in the documentation below. + +Parameters can be specified in one of the two ways, depending on how the Java +viewer is used: + + 1. When the Java viewer is run as an applet (embedded within an HTML + document), parameters should be specified in the HTML tags, + within the appropriate section. Here is an example: + + + + + + + 2. When run as a standalone application, the Java viewer reads parameters + from the command line. Command-line arguments should be specified in + pairs -- first goes parameter name, then parameter value. Here is a + command line example: + + java VncViewer HOST vnchost PORT 5901 "Scaling factor" 50 + +Both parameter names and their values are case-insensitive. The only +exception is the "PASSWORD" parameter, as VNC passwords are case-sensitive. + +Here is the complete list of parameters supported in TightVNC Java viewer: + +--> "HOST" (no GUI equivalent) + + Value: host name or IP address of the VNC server. + Default: in applet mode, the host from which the applet was loaded. + + This parameter tells the viewer which server to connect to. It's not + needed in the applet mode, because default Java security policy allow + connections from applets to the only one host anyway, and that is the + host from which the applet was loaded. However, this parameter is + required if the viewer is used as a standalone application. + +--> "PORT" (no GUI equivalent) + + Value: TCP port number on the VNC server. + Default: none. + + This parameter is required in all cases. Note that this port is not the + one used for HTTP connection from the browser, it is the port used for + RFB connection. Usually, VNC servers use ports 58xx for HTTP connections, + and ports 59xx for RFB connections. Thus, most likely, this parameter + should be set to something like 5900, 5901 etc. + +--> "PASSWORD" + + Value: session password in plain text. + Default: none, ask user. + + DO NOT EVER USE THIS PARAMETER, unless you really know what you are + doing. It's extremely dangerous from the security point of view. When + this parameter is set, the viewer won't ever ask for a password. + +--> "ENCPASSWORD" + + Value: encrypted session password in hex-ascii. + Default: none, ask user. + + The same as the "PASSWORD" parameter but DES-encrypted using a fixed key. + Its value should be represented in hex-ascii e.g. "494015f9a35e8b22". + This parameter has higher priority over the "PASSWORD" parameter. DO NOT + EVER USE THIS PARAMETER, unless you really know what you are doing. It's + extremely dangerous from the security point of view, and encryption does + not actually help here since the decryption key is always known. + +--> "Encoding" + + Values: "Auto", "Raw", "RRE", "CoRRE", "Hextile", "ZRLE", "Zlib", "Tight". + Default: "Auto". + + The preferred encoding. If the value is "Auto", then the viewer will + continuously estimate average network throughput and request encodings + that are appropriate for current connection speed. "Hextile" is an + encoding that was designed for fast networks, while "Tight" is better + suited for low-bandwidth connections. From the other side, "Tight" + decoder in the TightVNC Java viewer seems to be more efficient than + "Hextile" decoder so it may be ok for fast networks too. "ZRLE" encoding + is similar to "Tight", but it does not support JPEG compression and + compression levels. Unlike "Tight" encoding, "ZRLE" is supported in + recent versions of RealVNC products. Other encodings are not efficient + and provided for compatibility reasons. + +--> "Compression level" + + Values: "Default", "1", "2", "3", "4", "5", "6", "7", "8", "9". + Default: "Default". ;-) + + Use specified compression level for "Tight" and "Zlib" encodings. Level 1 + uses minimum of CPU time on the server but achieves weak compression + ratios. Level 9 offers best compression but may be slow in terms of CPU + time consumption on the server side. Use high levels with very slow + network connections, and low levels when working over higher-speed + networks. The "Default" value means that the server's default compression + level should be used. + +--> "JPEG image quality" + + Values: "JPEG off", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9". + Default: "6". + + Use the specified image quality level in "Tight" encoding. Quality level + 0 denotes bad image quality but very impressive compression ratios, while + level 9 offers very good image quality at lower compression ratios. If + the value is "JPEG off", the server will not use lossy JPEG compression + in "Tight" encoding. + +--> "Cursor shape updates" + + Values: "Enable", "Ignore", "Disable". + Default: "Enable". + + Cursor shape updates is a protocol extension used to handle remote cursor + movements locally on the client side, saving bandwidth and eliminating + delays in mouse pointer movement. Note that current implementation of + cursor shape updates does not allow a client to track mouse cursor + position at the server side. This means that clients would not see mouse + cursor movements if mouse was moved either locally on the server, or by + another remote VNC client. Set this parameter to "Disable" if you always + want to see real cursor position on the remote side. Setting this option + to "Ignore" is similar to "Enable" but the remote cursor will not be + visible at all. This can be a reasonable setting if you don't care about + cursor shape and don't want to see two mouse cursors, one above another. + +--> "Use CopyRect" + + Values: "Yes", "No". + Default: "Yes". + + The "CopyRect" encoding saves bandwidth and drawing time when parts of + the remote screen are moving around. Most likely, you don't want to + change this setting. + +--> "Restricted colors" + + Values: "Yes", "No". + Default: "No". + + If set to "No", then 24-bit color format is used to represent pixel data. + If set to "Yes", then only 8 bits are used to represent each pixel. 8-bit + color format can save bandwidth, but colors may look very inaccurate. + +--> "Mouse buttons 2 and 3" + + Values: "Normal", "Reversed". + Default: "Normal". + + If set to "Reversed", then right mouse button (button 2) will act as it + was middle mouse button (button 3), and vice versa. + +--> "View only" + + Values: "Yes", "No". + Default: "No". + + If set to "Yes", then all keyboard and mouse events in the desktop window + will be silently ignored and will not be passed to the remote side. + +--> "Scale remote cursor" + + Values: "No", "50%", "75%", "125%", "150%". + Default: "No". + + If a percentage value is specified, the remote cursor is reduced + or enlarged accordingly. Scaling takes place only when "View only" + is set to "No", and "Cursor shape updates" is set to "Enable". + +--> "Share desktop" + + Values: "Yes", "No". + Default: "Yes". + + Share the connection with other clients on the same VNC server. The exact + behaviour in each case depends on the server configuration. + +--> "Open new window" (no GUI equivalent, applicable only in the applet mode) + + Values: "Yes", "No". + Default: "No". + + Operate in a separate window. This makes possible resizing the desktop, + and adds scroll bars when necessary. If the server supports variable + desktop size, the window will resize automatically when remote desktop + size changes. + +--> "Scaling factor" (no GUI equivalent) + + Value: an integer in the range of [1..1000], or the string "auto". + Default: "100". + + Scale local representation of the remote desktop. The value is + interpreted as scaling factor in percents. The default value of 100% + corresponds to the original framebuffer size. Values below 100 reduce + image size, values above 100 enlarge the image proportionally. If the + parameter is set to "auto", automatic scaling is performed. Auto-scaling + tries to choose scaling factor such way that the whole remote framebuffer + will fit on the local screen. Currently, auto-scaling is supported only + when the remote desktop is shown in a separate frame (always true in the + application mode, and also in the applet mode with "Open new window" + parameter set to "yes"). + +--> "Show controls" (no GUI equivalent) + + Values: "Yes", "No". + Default: "Yes". + + Set to "No" if you want to get rid of that button panel at the top. + +--> "Offer relogin" (no GUI equivalent, not applicable in the applet mode) + + Values: "Yes", "No". + Default: "Yes". + + If set to "No", the buttons "Login again" and "Close window" won't be + shown on disconnects or after an error has occured. + +--> "Show offline desktop" (no GUI equivalent) + + Values: "Yes", "No". + Default: "No". + + If set to "Yes", the viewer would continue to display desktop even + if the remote side has closed the connection. In this case, if the + button panel is enabled, then the "Disconnect" button would be + changed to "Hide desktop" after the connection is lost. + +--> "Defer screen updates" (no GUI equivalent) + + Value: time in milliseconds. + Default: "20". + + When updating the desktop contents after receiving an update from server, + schedule repaint within the specified number of milliseconds. Small delay + helps to coalesce several small updates into one drawing operation, + improving CPU usage. Set this parameter to 0 to disable deferred updates. + +--> "Defer cursor updates" (no GUI equivalent) + + Value: time in milliseconds. + Default: "10". + + When updating the desktop after moving the mouse, schedule repaint within + the specified number of milliseconds. This setting makes sense only when + "Cursor shape updates" parameter is set to "Enable". Small delay helps to + coalesce several small updates into one drawing operation, improving CPU + usage. Set this parameter to 0 to disable deferred cursor updates. + +--> "Defer update requests" (no GUI equivalent) + + Value: time in milliseconds. + Default: "50". + + After processing an update received from server, wait for the specified + number of milliseconds before requesting next screen update. Such delay + will end immediately on every mouse or keyboard event if not in the "view + only" mode. Small delay helps the server to coalesce several small + updates into one framebuffer update, improving both bandwidth and CPU + usage. Increasing the parameter value does not affect responsiveness on + mouse and keyboard events, but causes delays in updating the screen when + there is no mouse and keyboard activity on the client side. + +--> "SocketFactory" (no GUI equivalent) + + Value: name of the class. + Default: none. + + This option provides the way to define an alternate I/O implementation. + The dynamically referenced class must implement a SocketFactory + interface, and create a Socket, as configured by this parameter. See the + source in SocketFactory.java. + + +RECORDING VNC SESSIONS +====================== + +Current version of the TightVNC Java viewer is able to record VNC (RFB) +sessions in files for later playback. The data format in saved session files +is compatible with the rfbproxy program written by Tim Waugh. Most important +thing about session recording is that it's supported only if Java security +manager allows access to local filesystem. Typically, it would not work for +unsigned applets. To use this feature, either use TightVNC Java viewer as a +standalone application (Java Runtime Environment or Java Development Kit +should be installed), or as a signed applet. The code checks if it's possible +to support session recording, and if everything's fine, the new "Record" +button should appear in the button panel. Pressing this button opens new +window which controls session recording. The GUI is pretty self-explained. + +Other important facts about session recording: + +--> All sessions are recorded in the 24-bit color format. If you use + restricted colors (8-bit format), it will be temporarly switched to + 24-bit mode during session recording. + +--> All sessions are recorded with cursor shape updates turned off. This is + necessary to represent remote cursor movements in recorded sessions. + +--> Closing and re-opening the recording control window does not affect the + recording. It's not necessary to keep that window open during recording a + session. + +--> Avoid using Zlib and ZRLE encodings when recording sessions. If you have + started recording BEFORE opening a VNC session, then you are ok. But + otherwise, all Zlib-encoded updates will be saved Raw-encoded (that is, + without compression at all). The case with ZRLE is even worse -- ZRLE + updates will not be saved at all, so the resulting session file may be + corrupted. Zlib decoding depends on the pixel data received earlier, thus + saving the data received from the server at an arbitrary moment is not + sufficient to decompress it correctly. And there is no way to tell Zlib + or ZRLE decoder to reset decompressor's state -- that's a limitation of + these encoders. The viewer could re-compress raw pixel data again before + saving Zlib-encoded sessions, but unfortunately Java API does not allow + to flush zlib data streams making it impossible to save Zlib-encoded RFB + pixel data without using native code. + +--> Usually, Tight encoding is the most suitable one for session recording, + but some of the issues described above for the Zlib encoding affect the + Tight encoding as well. Unlike Zlib sessions, Tight-encoded sessions are + always saved Tight-encoded, but the viewer has to re-compress parts of + data to synchronize encoder's and decoder's zlib streams. And, due to + Java zlib API limitations, zlib streams' states have to be reset on each + compressed rectangle, causing compression ratios to be lower than in the + original VNC session. If you want to achieve the best possible + performance, turn recording on BEFORE connecting to the VNC server, + otherwise CPU usage and compression ratios may be notably less efficient. + + +HINTS +===== + +--> To refresh remote desktop in the view-only mode, press "r" or "R" + on the keyboard. + + +ACKNOWLEDGEMENTS +================ + +This distribution contains Java DES software by Dave Zimmerman + and Jef Poskanzer . 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 . 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/RecordingFrame.java b/RecordingFrame.java new file mode 100644 index 0000000..ba53a84 --- /dev/null +++ b/RecordingFrame.java @@ -0,0 +1,311 @@ +// +// Copyright (C) 2002 Constantin Kaplinsky. 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. +// + +// +// Recording frame. It allows to control recording RFB sessions into +// FBS (FrameBuffer Stream) files. +// + +import java.io.*; +import java.awt.*; +import java.awt.event.*; + +class RecordingFrame extends Frame + implements WindowListener, ActionListener { + + boolean recording; + + TextField fnameField; + Button browseButton; + + Label statusLabel; + + Button recordButton, nextButton, closeButton; + VncViewer viewer; + + // + // Check if current security manager allows to create a + // RecordingFrame object. + // + + public static boolean checkSecurity() { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + try { + security.checkPropertyAccess("user.dir"); + security.checkPropertyAccess("file.separator"); + // Work around (rare) checkPropertyAccess bug + System.getProperty("user.dir"); + } catch (SecurityException e) { + System.out.println("SecurityManager restricts session recording."); + return false; + } + } + return true; + } + + // + // Constructor. + // + + RecordingFrame(VncViewer v) { + super("TightVNC Session Recording"); + + viewer = v; + + // Determine initial filename for next saved session. + // FIXME: Check SecurityManager. + + String fname = nextNewFilename(System.getProperty("user.dir") + + System.getProperty("file.separator") + + "vncsession.fbs"); + + // Construct new panel with file name field and "Browse" button. + + Panel fnamePanel = new Panel(); + GridBagLayout fnameGridbag = new GridBagLayout(); + fnamePanel.setLayout(fnameGridbag); + + GridBagConstraints fnameConstraints = new GridBagConstraints(); + fnameConstraints.gridwidth = GridBagConstraints.RELATIVE; + fnameConstraints.fill = GridBagConstraints.BOTH; + fnameConstraints.weightx = 4.0; + + fnameField = new TextField(fname, 64); + fnameGridbag.setConstraints(fnameField, fnameConstraints); + fnamePanel.add(fnameField); + fnameField.addActionListener(this); + + fnameConstraints.gridwidth = GridBagConstraints.REMAINDER; + fnameConstraints.weightx = 1.0; + + browseButton = new Button("Browse"); + fnameGridbag.setConstraints(browseButton, fnameConstraints); + fnamePanel.add(browseButton); + browseButton.addActionListener(this); + + // Construct the frame. + + GridBagLayout gridbag = new GridBagLayout(); + setLayout(gridbag); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.fill = GridBagConstraints.BOTH; + gbc.weighty = 1.0; + gbc.insets = new Insets(10, 0, 0, 0); + + Label helpLabel = + new Label("File name to save next recorded session in:", Label.CENTER); + gridbag.setConstraints(helpLabel, gbc); + add(helpLabel); + + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.weighty = 0.0; + gbc.insets = new Insets(0, 0, 0, 0); + + gridbag.setConstraints(fnamePanel, gbc); + add(fnamePanel); + + gbc.fill = GridBagConstraints.BOTH; + gbc.weighty = 1.0; + gbc.insets = new Insets(10, 0, 10, 0); + + statusLabel = new Label("", Label.CENTER); + gridbag.setConstraints(statusLabel, gbc); + add(statusLabel); + + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.weightx = 1.0; + gbc.weighty = 0.0; + gbc.gridwidth = 1; + gbc.insets = new Insets(0, 0, 0, 0); + + recordButton = new Button("Record"); + gridbag.setConstraints(recordButton, gbc); + add(recordButton); + recordButton.addActionListener(this); + + nextButton = new Button("Next file"); + gridbag.setConstraints(nextButton, gbc); + add(nextButton); + nextButton.addActionListener(this); + + closeButton = new Button("Close"); + gridbag.setConstraints(closeButton, gbc); + add(closeButton); + closeButton.addActionListener(this); + + // Set correct text, font and color for the statusLabel. + stopRecording(); + + pack(); + + addWindowListener(this); + } + + // + // If the given string ends with ".NNN" where NNN is a decimal + // number, increase this number by one. Otherwise, append ".001" + // to the given string. + // + + protected String nextFilename(String fname) { + int len = fname.length(); + int suffixPos = len; + int suffixNum = 1; + + if (len > 4 && fname.charAt(len - 4) == '.') { + try { + suffixNum = Integer.parseInt(fname.substring(len - 3, len)) + 1; + suffixPos = len - 4; + } catch (NumberFormatException e) { } + } + + char[] zeroes = {'0', '0', '0'}; + String suffix = String.valueOf(suffixNum); + if (suffix.length() < 3) { + suffix = new String(zeroes, 0, 3 - suffix.length()) + suffix; + } + + return fname.substring(0, suffixPos) + '.' + suffix; + } + + // + // Find next name of a file which does not exist yet. + // + + protected String nextNewFilename(String fname) { + String newName = fname; + File f; + try { + do { + newName = nextFilename(newName); + f = new File(newName); + } while (f.exists()); + } catch (SecurityException e) { } + + return newName; + } + + // + // Let the user choose a file name showing a FileDialog. + // + + protected boolean browseFile() { + File currentFile = new File(fnameField.getText()); + + FileDialog fd = + new FileDialog(this, "Save next session as...", FileDialog.SAVE); + fd.setDirectory(currentFile.getParent()); + fd.setVisible(true); + if (fd.getFile() != null) { + String newDir = fd.getDirectory(); + String sep = System.getProperty("file.separator"); + if (newDir.length() > 0) { + if (!sep.equals(newDir.substring(newDir.length() - sep.length()))) + newDir += sep; + } + String newFname = newDir + fd.getFile(); + if (newFname.equals(fnameField.getText())) { + fnameField.setText(newFname); + return true; + } + } + return false; + } + + // + // Start recording. + // + + public void startRecording() { + statusLabel.setText("Status: Recording..."); + statusLabel.setFont(new Font("Helvetica", Font.BOLD, 12)); + statusLabel.setForeground(Color.red); + recordButton.setLabel("Stop recording"); + + recording = true; + + viewer.setRecordingStatus(fnameField.getText()); + } + + // + // Stop recording. + // + + public void stopRecording() { + statusLabel.setText("Status: Not recording."); + statusLabel.setFont(new Font("Helvetica", Font.PLAIN, 12)); + statusLabel.setForeground(Color.black); + recordButton.setLabel("Record"); + + recording = false; + + viewer.setRecordingStatus(null); + } + + // + // Close our window properly. + // + + public void windowClosing(WindowEvent evt) { + setVisible(false); + } + + // + // Ignore window events we're not interested in. + // + + public void windowActivated(WindowEvent evt) {} + public void windowDeactivated (WindowEvent evt) {} + public void windowOpened(WindowEvent evt) {} + public void windowClosed(WindowEvent evt) {} + public void windowIconified(WindowEvent evt) {} + public void windowDeiconified(WindowEvent evt) {} + + + // + // Respond to button presses + // + + public void actionPerformed(ActionEvent evt) { + if (evt.getSource() == browseButton) { + if (browseFile() && recording) + startRecording(); + + } else if (evt.getSource() == recordButton) { + if (!recording) { + startRecording(); + } else { + stopRecording(); + fnameField.setText(nextNewFilename(fnameField.getText())); + } + + } else if (evt.getSource() == nextButton) { + fnameField.setText(nextNewFilename(fnameField.getText())); + if (recording) + startRecording(); + + } else if (evt.getSource() == closeButton) { + setVisible(false); + + } + } +} diff --git a/ReloginPanel.java b/ReloginPanel.java new file mode 100644 index 0000000..c70fc3f --- /dev/null +++ b/ReloginPanel.java @@ -0,0 +1,65 @@ +// +// Copyright (C) 2002 Cendio Systems. All Rights Reserved. +// Copyright (C) 2002 Constantin Kaplinsky. 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. +// + +// +// ReloginPanel class implements panel with a button for logging in again, +// after fatal errors or disconnect +// + + +import java.awt.*; +import java.awt.event.*; +import java.applet.*; + +// +// The panel which implements the Relogin button +// + +class ReloginPanel extends Panel implements ActionListener { + Button reloginButton; + Button closeButton; + VncViewer viewer; + + // + // Constructor. + // + public ReloginPanel(VncViewer v) { + viewer = v; + setLayout(new FlowLayout(FlowLayout.CENTER)); + reloginButton = new Button("Login again"); + add(reloginButton); + reloginButton.addActionListener(this); + if (viewer.inSeparateFrame) { + closeButton = new Button("Close window"); + add(closeButton); + closeButton.addActionListener(this); + } + } + + // + // This method is called when a button is pressed. + // + public synchronized void actionPerformed(ActionEvent evt) { + if (viewer.inSeparateFrame) + viewer.vncFrame.dispose(); + if (evt.getSource() == reloginButton) + viewer.getAppletContext().showDocument(viewer.getDocumentBase()); + } +} diff --git a/RfbProto.java b/RfbProto.java new file mode 100644 index 0000000..1ca25c0 --- /dev/null +++ b/RfbProto.java @@ -0,0 +1,1312 @@ +// +// Copyright (C) 2001-2004 HorizonLive.com, Inc. All Rights Reserved. +// Copyright (C) 2001-2006 Constantin Kaplinsky. All Rights Reserved. +// Copyright (C) 2000 Tridia Corporation. All Rights Reserved. +// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. +// +// This is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this software; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. +// + +// +// RfbProto.java +// + +import java.io.*; +import java.awt.*; +import java.awt.event.*; +import java.net.Socket; +import java.util.zip.*; + +class RfbProto { + + final static String + versionMsg_3_3 = "RFB 003.003\n", + versionMsg_3_7 = "RFB 003.007\n", + versionMsg_3_8 = "RFB 003.008\n"; + + // Vendor signatures: standard VNC/RealVNC, TridiaVNC, and TightVNC + final static String + StandardVendor = "STDV", + TridiaVncVendor = "TRDV", + TightVncVendor = "TGHT"; + + // Security types + final static int + SecTypeInvalid = 0, + SecTypeNone = 1, + SecTypeVncAuth = 2, + SecTypeTight = 16; + + // Supported tunneling types + final static int + NoTunneling = 0; + final static String + SigNoTunneling = "NOTUNNEL"; + + // Supported authentication types + final static int + AuthNone = 1, + AuthVNC = 2, + AuthUnixLogin = 129; + final static String + SigAuthNone = "NOAUTH__", + SigAuthVNC = "VNCAUTH_", + SigAuthUnixLogin = "ULGNAUTH"; + + // VNC authentication results + final static int + VncAuthOK = 0, + VncAuthFailed = 1, + VncAuthTooMany = 2; + + // Server-to-client messages + final static int + FramebufferUpdate = 0, + SetColourMapEntries = 1, + Bell = 2, + ServerCutText = 3; + + // Client-to-server messages + final static int + SetPixelFormat = 0, + FixColourMapEntries = 1, + SetEncodings = 2, + FramebufferUpdateRequest = 3, + KeyboardEvent = 4, + PointerEvent = 5, + ClientCutText = 6; + + // Supported encodings and pseudo-encodings + final static int + EncodingRaw = 0, + EncodingCopyRect = 1, + EncodingRRE = 2, + EncodingCoRRE = 4, + EncodingHextile = 5, + EncodingZlib = 6, + EncodingTight = 7, + EncodingZRLE = 16, + EncodingCompressLevel0 = 0xFFFFFF00, + EncodingQualityLevel0 = 0xFFFFFFE0, + EncodingXCursor = 0xFFFFFF10, + EncodingRichCursor = 0xFFFFFF11, + EncodingPointerPos = 0xFFFFFF18, + EncodingLastRect = 0xFFFFFF20, + EncodingNewFBSize = 0xFFFFFF21; + final static String + SigEncodingRaw = "RAW_____", + SigEncodingCopyRect = "COPYRECT", + SigEncodingRRE = "RRE_____", + SigEncodingCoRRE = "CORRE___", + SigEncodingHextile = "HEXTILE_", + SigEncodingZlib = "ZLIB____", + SigEncodingTight = "TIGHT___", + SigEncodingZRLE = "ZRLE____", + SigEncodingCompressLevel0 = "COMPRLVL", + SigEncodingQualityLevel0 = "JPEGQLVL", + SigEncodingXCursor = "X11CURSR", + SigEncodingRichCursor = "RCHCURSR", + SigEncodingPointerPos = "POINTPOS", + SigEncodingLastRect = "LASTRECT", + SigEncodingNewFBSize = "NEWFBSIZ"; + + final static int MaxNormalEncoding = 255; + + // Contstants used in the Hextile decoder + final static int + HextileRaw = 1, + HextileBackgroundSpecified = 2, + HextileForegroundSpecified = 4, + HextileAnySubrects = 8, + HextileSubrectsColoured = 16; + + // Contstants used in the Tight decoder + final static int TightMinToCompress = 12; + final static int + TightExplicitFilter = 0x04, + TightFill = 0x08, + TightJpeg = 0x09, + TightMaxSubencoding = 0x09, + TightFilterCopy = 0x00, + TightFilterPalette = 0x01, + TightFilterGradient = 0x02; + + + String host; + int port; + Socket sock; + DataInputStream is; + OutputStream os; + SessionRecorder rec; + boolean inNormalProtocol = false; + VncViewer viewer; + + // Java on UNIX does not call keyPressed() on some keys, for example + // swedish keys To prevent our workaround to produce duplicate + // keypresses on JVMs that actually works, keep track of if + // keyPressed() for a "broken" key was called or not. + boolean brokenKeyPressed = false; + + // This will be set to true on the first framebuffer update + // containing Zlib-, ZRLE- or Tight-encoded data. + boolean wereZlibUpdates = false; + + // This will be set to false if the startSession() was called after + // we have received at least one Zlib-, ZRLE- or Tight-encoded + // framebuffer update. + boolean recordFromBeginning = true; + + // This fields are needed to show warnings about inefficiently saved + // sessions only once per each saved session file. + boolean zlibWarningShown; + boolean tightWarningShown; + + // Before starting to record each saved session, we set this field + // to 0, and increment on each framebuffer update. We don't flush + // the SessionRecorder data into the file before the second update. + // This allows us to write initial framebuffer update with zero + // timestamp, to let the player show initial desktop before + // playback. + int numUpdatesInSession; + + // Measuring network throughput. + boolean timing; + long timeWaitedIn100us; + long timedKbits; + + // Protocol version and TightVNC-specific protocol options. + int serverMajor, serverMinor; + int clientMajor, clientMinor; + boolean protocolTightVNC; + CapsContainer tunnelCaps, authCaps; + CapsContainer serverMsgCaps, clientMsgCaps; + CapsContainer encodingCaps; + + // If true, informs that the RFB socket was closed. + private boolean closed; + + // + // Constructor. Make TCP connection to RFB server. + // + + RfbProto(String h, int p, VncViewer v) throws IOException { + viewer = v; + host = h; + port = p; + + if (viewer.socketFactory == null) { + sock = new Socket(host, port); + } else { + try { + Class factoryClass = Class.forName(viewer.socketFactory); + SocketFactory factory = (SocketFactory)factoryClass.newInstance(); + if (viewer.inAnApplet) + sock = factory.createSocket(host, port, viewer); + else + sock = factory.createSocket(host, port, viewer.mainArgs); + } catch(Exception e) { + e.printStackTrace(); + throw new IOException(e.getMessage()); + } + } + is = new DataInputStream(new BufferedInputStream(sock.getInputStream(), + 16384)); + os = sock.getOutputStream(); + + timing = false; + timeWaitedIn100us = 5; + timedKbits = 0; + } + + + synchronized void close() { + try { + sock.close(); + closed = true; + System.out.println("RFB socket closed"); + if (rec != null) { + rec.close(); + rec = null; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + synchronized boolean closed() { + return closed; + } + + // + // Read server's protocol version message + // + + void readVersionMsg() throws Exception { + + byte[] b = new byte[12]; + + readFully(b); + + if ((b[0] != 'R') || (b[1] != 'F') || (b[2] != 'B') || (b[3] != ' ') + || (b[4] < '0') || (b[4] > '9') || (b[5] < '0') || (b[5] > '9') + || (b[6] < '0') || (b[6] > '9') || (b[7] != '.') + || (b[8] < '0') || (b[8] > '9') || (b[9] < '0') || (b[9] > '9') + || (b[10] < '0') || (b[10] > '9') || (b[11] != '\n')) + { + throw new Exception("Host " + host + " port " + port + + " is not an RFB server"); + } + + serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0'); + serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0'); + + if (serverMajor < 3) { + throw new Exception("RFB server does not support protocol version 3"); + } + } + + + // + // Write our protocol version message + // + + void writeVersionMsg() throws IOException { + clientMajor = 3; + if (serverMajor > 3 || serverMinor >= 8) { + clientMinor = 8; + os.write(versionMsg_3_8.getBytes()); + } else if (serverMinor >= 7) { + clientMinor = 7; + os.write(versionMsg_3_7.getBytes()); + } else { + clientMinor = 3; + os.write(versionMsg_3_3.getBytes()); + } + protocolTightVNC = false; + } + + + // + // Negotiate the authentication scheme. + // + + int negotiateSecurity() throws Exception { + return (clientMinor >= 7) ? + selectSecurityType() : readSecurityType(); + } + + // + // Read security type from the server (protocol version 3.3). + // + + int readSecurityType() throws Exception { + int secType = is.readInt(); + + switch (secType) { + case SecTypeInvalid: + readConnFailedReason(); + return SecTypeInvalid; // should never be executed + case SecTypeNone: + case SecTypeVncAuth: + return secType; + default: + throw new Exception("Unknown security type from RFB server: " + secType); + } + } + + // + // Select security type from the server's list (protocol versions 3.7/3.8). + // + + int selectSecurityType() throws Exception { + int secType = SecTypeInvalid; + + // Read the list of secutiry types. + int nSecTypes = is.readUnsignedByte(); + if (nSecTypes == 0) { + readConnFailedReason(); + return SecTypeInvalid; // should never be executed + } + byte[] secTypes = new byte[nSecTypes]; + readFully(secTypes); + + // Find out if the server supports TightVNC protocol extensions + for (int i = 0; i < nSecTypes; i++) { + if (secTypes[i] == SecTypeTight) { + protocolTightVNC = true; + os.write(SecTypeTight); + return SecTypeTight; + } + } + + // Find first supported security type. + for (int i = 0; i < nSecTypes; i++) { + if (secTypes[i] == SecTypeNone || secTypes[i] == SecTypeVncAuth) { + secType = secTypes[i]; + break; + } + } + + if (secType == SecTypeInvalid) { + throw new Exception("Server did not offer supported security type"); + } else { + os.write(secType); + } + + return secType; + } + + // + // Perform "no authentication". + // + + void authenticateNone() throws Exception { + if (clientMinor >= 8) + readSecurityResult("No authentication"); + } + + // + // Perform standard VNC Authentication. + // + + void authenticateVNC(String pw) throws Exception { + byte[] challenge = new byte[16]; + readFully(challenge); + + if (pw.length() > 8) + pw = pw.substring(0, 8); // Truncate to 8 chars + + // Truncate password on the first zero byte. + int firstZero = pw.indexOf(0); + if (firstZero != -1) + pw = pw.substring(0, firstZero); + + byte[] key = {0, 0, 0, 0, 0, 0, 0, 0}; + System.arraycopy(pw.getBytes(), 0, key, 0, pw.length()); + + DesCipher des = new DesCipher(key); + + des.encrypt(challenge, 0, challenge, 0); + des.encrypt(challenge, 8, challenge, 8); + + os.write(challenge); + + readSecurityResult("VNC authentication"); + } + + // + // Read security result. + // Throws an exception on authentication failure. + // + + void readSecurityResult(String authType) throws Exception { + int securityResult = is.readInt(); + + switch (securityResult) { + case VncAuthOK: + System.out.println(authType + ": success"); + break; + case VncAuthFailed: + if (clientMinor >= 8) + readConnFailedReason(); + throw new Exception(authType + ": failed"); + case VncAuthTooMany: + throw new Exception(authType + ": failed, too many tries"); + default: + throw new Exception(authType + ": unknown result " + securityResult); + } + } + + // + // Read the string describing the reason for a connection failure, + // and throw an exception. + // + + void readConnFailedReason() throws Exception { + int reasonLen = is.readInt(); + byte[] reason = new byte[reasonLen]; + readFully(reason); + throw new Exception(new String(reason)); + } + + // + // Initialize capability lists (TightVNC protocol extensions). + // + + void initCapabilities() { + tunnelCaps = new CapsContainer(); + authCaps = new CapsContainer(); + serverMsgCaps = new CapsContainer(); + clientMsgCaps = new CapsContainer(); + encodingCaps = new CapsContainer(); + + // Supported authentication methods + authCaps.add(AuthNone, StandardVendor, SigAuthNone, + "No authentication"); + authCaps.add(AuthVNC, StandardVendor, SigAuthVNC, + "Standard VNC password authentication"); + + // Supported encoding types + encodingCaps.add(EncodingCopyRect, StandardVendor, + SigEncodingCopyRect, "Standard CopyRect encoding"); + encodingCaps.add(EncodingRRE, StandardVendor, + SigEncodingRRE, "Standard RRE encoding"); + encodingCaps.add(EncodingCoRRE, StandardVendor, + SigEncodingCoRRE, "Standard CoRRE encoding"); + encodingCaps.add(EncodingHextile, StandardVendor, + SigEncodingHextile, "Standard Hextile encoding"); + encodingCaps.add(EncodingZRLE, StandardVendor, + SigEncodingZRLE, "Standard ZRLE encoding"); + encodingCaps.add(EncodingZlib, TridiaVncVendor, + SigEncodingZlib, "Zlib encoding"); + encodingCaps.add(EncodingTight, TightVncVendor, + SigEncodingTight, "Tight encoding"); + + // Supported pseudo-encoding types + encodingCaps.add(EncodingCompressLevel0, TightVncVendor, + SigEncodingCompressLevel0, "Compression level"); + encodingCaps.add(EncodingQualityLevel0, TightVncVendor, + SigEncodingQualityLevel0, "JPEG quality level"); + encodingCaps.add(EncodingXCursor, TightVncVendor, + SigEncodingXCursor, "X-style cursor shape update"); + encodingCaps.add(EncodingRichCursor, TightVncVendor, + SigEncodingRichCursor, "Rich-color cursor shape update"); + encodingCaps.add(EncodingPointerPos, TightVncVendor, + SigEncodingPointerPos, "Pointer position update"); + encodingCaps.add(EncodingLastRect, TightVncVendor, + SigEncodingLastRect, "LastRect protocol extension"); + encodingCaps.add(EncodingNewFBSize, TightVncVendor, + SigEncodingNewFBSize, "Framebuffer size change"); + } + + // + // Setup tunneling (TightVNC protocol extensions) + // + + void setupTunneling() throws IOException { + int nTunnelTypes = is.readInt(); + if (nTunnelTypes != 0) { + readCapabilityList(tunnelCaps, nTunnelTypes); + + // We don't support tunneling yet. + writeInt(NoTunneling); + } + } + + // + // Negotiate authentication scheme (TightVNC protocol extensions) + // + + int negotiateAuthenticationTight() throws Exception { + int nAuthTypes = is.readInt(); + if (nAuthTypes == 0) + return AuthNone; + + readCapabilityList(authCaps, nAuthTypes); + for (int i = 0; i < authCaps.numEnabled(); i++) { + int authType = authCaps.getByOrder(i); + if (authType == AuthNone || authType == AuthVNC) { + writeInt(authType); + return authType; + } + } + throw new Exception("No suitable authentication scheme found"); + } + + // + // Read a capability list (TightVNC protocol extensions) + // + + void readCapabilityList(CapsContainer caps, int count) throws IOException { + int code; + byte[] vendor = new byte[4]; + byte[] name = new byte[8]; + for (int i = 0; i < count; i++) { + code = is.readInt(); + readFully(vendor); + readFully(name); + caps.enable(new CapabilityInfo(code, vendor, name)); + } + } + + // + // Write a 32-bit integer into the output stream. + // + + void writeInt(int value) throws IOException { + byte[] b = new byte[4]; + b[0] = (byte) ((value >> 24) & 0xff); + b[1] = (byte) ((value >> 16) & 0xff); + b[2] = (byte) ((value >> 8) & 0xff); + b[3] = (byte) (value & 0xff); + os.write(b); + } + + // + // Write the client initialisation message + // + + void writeClientInit() throws IOException { + if (viewer.options.shareDesktop) { + os.write(1); + } else { + os.write(0); + } + viewer.options.disableShareDesktop(); + } + + + // + // Read the server initialisation message + // + + String desktopName; + int framebufferWidth, framebufferHeight; + int bitsPerPixel, depth; + boolean bigEndian, trueColour; + int redMax, greenMax, blueMax, redShift, greenShift, blueShift; + + void readServerInit() throws IOException { + framebufferWidth = is.readUnsignedShort(); + framebufferHeight = is.readUnsignedShort(); + bitsPerPixel = is.readUnsignedByte(); + depth = is.readUnsignedByte(); + bigEndian = (is.readUnsignedByte() != 0); + trueColour = (is.readUnsignedByte() != 0); + redMax = is.readUnsignedShort(); + greenMax = is.readUnsignedShort(); + blueMax = is.readUnsignedShort(); + redShift = is.readUnsignedByte(); + greenShift = is.readUnsignedByte(); + blueShift = is.readUnsignedByte(); + byte[] pad = new byte[3]; + readFully(pad); + int nameLength = is.readInt(); + byte[] name = new byte[nameLength]; + readFully(name); + desktopName = new String(name); + + // Read interaction capabilities (TightVNC protocol extensions) + if (protocolTightVNC) { + int nServerMessageTypes = is.readUnsignedShort(); + int nClientMessageTypes = is.readUnsignedShort(); + int nEncodingTypes = is.readUnsignedShort(); + is.readUnsignedShort(); + readCapabilityList(serverMsgCaps, nServerMessageTypes); + readCapabilityList(clientMsgCaps, nClientMessageTypes); + readCapabilityList(encodingCaps, nEncodingTypes); + } + + inNormalProtocol = true; + } + + + // + // Create session file and write initial protocol messages into it. + // + + void startSession(String fname) throws IOException { + rec = new SessionRecorder(fname); + rec.writeHeader(); + rec.write(versionMsg_3_3.getBytes()); + rec.writeIntBE(SecTypeNone); + rec.writeShortBE(framebufferWidth); + rec.writeShortBE(framebufferHeight); + byte[] fbsServerInitMsg = { + 32, 24, 0, 1, 0, + (byte)0xFF, 0, (byte)0xFF, 0, (byte)0xFF, + 16, 8, 0, 0, 0, 0 + }; + rec.write(fbsServerInitMsg); + rec.writeIntBE(desktopName.length()); + rec.write(desktopName.getBytes()); + numUpdatesInSession = 0; + + // FIXME: If there were e.g. ZRLE updates only, that should not + // affect recording of Zlib and Tight updates. So, actually + // we should maintain separate flags for Zlib, ZRLE and + // Tight, instead of one ``wereZlibUpdates'' variable. + // + if (wereZlibUpdates) + recordFromBeginning = false; + + zlibWarningShown = false; + tightWarningShown = false; + } + + // + // Close session file. + // + + void closeSession() throws IOException { + if (rec != null) { + rec.close(); + rec = null; + } + } + + + // + // Set new framebuffer size + // + + void setFramebufferSize(int width, int height) { + framebufferWidth = width; + framebufferHeight = height; + } + + + // + // Read the server message type + // + + int readServerMessageType() throws IOException { + int msgType = is.readUnsignedByte(); + + // If the session is being recorded: + if (rec != null) { + if (msgType == Bell) { // Save Bell messages in session files. + rec.writeByte(msgType); + if (numUpdatesInSession > 0) + rec.flush(); + } + } + + return msgType; + } + + + // + // Read a FramebufferUpdate message + // + + int updateNRects; + + void readFramebufferUpdate() throws IOException { + is.readByte(); + updateNRects = is.readUnsignedShort(); + + // If the session is being recorded: + if (rec != null) { + rec.writeByte(FramebufferUpdate); + rec.writeByte(0); + rec.writeShortBE(updateNRects); + } + + numUpdatesInSession++; + } + + // Read a FramebufferUpdate rectangle header + + int updateRectX, updateRectY, updateRectW, updateRectH, updateRectEncoding; + + void readFramebufferUpdateRectHdr() throws Exception { + updateRectX = is.readUnsignedShort(); + updateRectY = is.readUnsignedShort(); + updateRectW = is.readUnsignedShort(); + updateRectH = is.readUnsignedShort(); + updateRectEncoding = is.readInt(); + + if (updateRectEncoding == EncodingZlib || + updateRectEncoding == EncodingZRLE || + updateRectEncoding == EncodingTight) + wereZlibUpdates = true; + + // If the session is being recorded: + if (rec != null) { + if (numUpdatesInSession > 1) + rec.flush(); // Flush the output on each rectangle. + rec.writeShortBE(updateRectX); + rec.writeShortBE(updateRectY); + rec.writeShortBE(updateRectW); + rec.writeShortBE(updateRectH); + if (updateRectEncoding == EncodingZlib && !recordFromBeginning) { + // Here we cannot write Zlib-encoded rectangles because the + // decoder won't be able to reproduce zlib stream state. + if (!zlibWarningShown) { + System.out.println("Warning: Raw encoding will be used " + + "instead of Zlib in recorded session."); + zlibWarningShown = true; + } + rec.writeIntBE(EncodingRaw); + } else { + rec.writeIntBE(updateRectEncoding); + if (updateRectEncoding == EncodingTight && !recordFromBeginning && + !tightWarningShown) { + System.out.println("Warning: Re-compressing Tight-encoded " + + "updates for session recording."); + tightWarningShown = true; + } + } + } + + if (updateRectEncoding < 0 || updateRectEncoding > MaxNormalEncoding) + return; + + if (updateRectX + updateRectW > framebufferWidth || + updateRectY + updateRectH > framebufferHeight) { + throw new Exception("Framebuffer update rectangle too large: " + + updateRectW + "x" + updateRectH + " at (" + + updateRectX + "," + updateRectY + ")"); + } + } + + // Read CopyRect source X and Y. + + int copyRectSrcX, copyRectSrcY; + + void readCopyRect() throws IOException { + copyRectSrcX = is.readUnsignedShort(); + copyRectSrcY = is.readUnsignedShort(); + + // If the session is being recorded: + if (rec != null) { + rec.writeShortBE(copyRectSrcX); + rec.writeShortBE(copyRectSrcY); + } + } + + + // + // Read a ServerCutText message + // + + String readServerCutText() throws IOException { + byte[] pad = new byte[3]; + readFully(pad); + int len = is.readInt(); + byte[] text = new byte[len]; + readFully(text); + return new String(text); + } + + + // + // Read an integer in compact representation (1..3 bytes). + // Such format is used as a part of the Tight encoding. + // Also, this method records data if session recording is active and + // the viewer's recordFromBeginning variable is set to true. + // + + int readCompactLen() throws IOException { + int[] portion = new int[3]; + portion[0] = is.readUnsignedByte(); + int byteCount = 1; + int len = portion[0] & 0x7F; + if ((portion[0] & 0x80) != 0) { + portion[1] = is.readUnsignedByte(); + byteCount++; + len |= (portion[1] & 0x7F) << 7; + if ((portion[1] & 0x80) != 0) { + portion[2] = is.readUnsignedByte(); + byteCount++; + len |= (portion[2] & 0xFF) << 14; + } + } + + if (rec != null && recordFromBeginning) + for (int i = 0; i < byteCount; i++) + rec.writeByte(portion[i]); + + return len; + } + + + // + // Write a FramebufferUpdateRequest message + // + + void writeFramebufferUpdateRequest(int x, int y, int w, int h, + boolean incremental) + throws IOException + { + byte[] b = new byte[10]; + + b[0] = (byte) FramebufferUpdateRequest; + b[1] = (byte) (incremental ? 1 : 0); + b[2] = (byte) ((x >> 8) & 0xff); + b[3] = (byte) (x & 0xff); + b[4] = (byte) ((y >> 8) & 0xff); + b[5] = (byte) (y & 0xff); + b[6] = (byte) ((w >> 8) & 0xff); + b[7] = (byte) (w & 0xff); + b[8] = (byte) ((h >> 8) & 0xff); + b[9] = (byte) (h & 0xff); + + os.write(b); + } + + + // + // Write a SetPixelFormat message + // + + void writeSetPixelFormat(int bitsPerPixel, int depth, boolean bigEndian, + boolean trueColour, + int redMax, int greenMax, int blueMax, + int redShift, int greenShift, int blueShift) + throws IOException + { + byte[] b = new byte[20]; + + b[0] = (byte) SetPixelFormat; + b[4] = (byte) bitsPerPixel; + b[5] = (byte) depth; + b[6] = (byte) (bigEndian ? 1 : 0); + b[7] = (byte) (trueColour ? 1 : 0); + b[8] = (byte) ((redMax >> 8) & 0xff); + b[9] = (byte) (redMax & 0xff); + b[10] = (byte) ((greenMax >> 8) & 0xff); + b[11] = (byte) (greenMax & 0xff); + b[12] = (byte) ((blueMax >> 8) & 0xff); + b[13] = (byte) (blueMax & 0xff); + b[14] = (byte) redShift; + b[15] = (byte) greenShift; + b[16] = (byte) blueShift; + + os.write(b); + } + + + // + // Write a FixColourMapEntries message. The values in the red, green and + // blue arrays are from 0 to 65535. + // + + void writeFixColourMapEntries(int firstColour, int nColours, + int[] red, int[] green, int[] blue) + throws IOException + { + byte[] b = new byte[6 + nColours * 6]; + + b[0] = (byte) FixColourMapEntries; + b[2] = (byte) ((firstColour >> 8) & 0xff); + b[3] = (byte) (firstColour & 0xff); + b[4] = (byte) ((nColours >> 8) & 0xff); + b[5] = (byte) (nColours & 0xff); + + for (int i = 0; i < nColours; i++) { + b[6 + i * 6] = (byte) ((red[i] >> 8) & 0xff); + b[6 + i * 6 + 1] = (byte) (red[i] & 0xff); + b[6 + i * 6 + 2] = (byte) ((green[i] >> 8) & 0xff); + b[6 + i * 6 + 3] = (byte) (green[i] & 0xff); + b[6 + i * 6 + 4] = (byte) ((blue[i] >> 8) & 0xff); + b[6 + i * 6 + 5] = (byte) (blue[i] & 0xff); + } + + os.write(b); + } + + + // + // Write a SetEncodings message + // + + void writeSetEncodings(int[] encs, int len) throws IOException { + byte[] b = new byte[4 + 4 * len]; + + b[0] = (byte) SetEncodings; + b[2] = (byte) ((len >> 8) & 0xff); + b[3] = (byte) (len & 0xff); + + for (int i = 0; i < len; i++) { + b[4 + 4 * i] = (byte) ((encs[i] >> 24) & 0xff); + b[5 + 4 * i] = (byte) ((encs[i] >> 16) & 0xff); + b[6 + 4 * i] = (byte) ((encs[i] >> 8) & 0xff); + b[7 + 4 * i] = (byte) (encs[i] & 0xff); + } + + os.write(b); + } + + + // + // Write a ClientCutText message + // + + void writeClientCutText(String text) throws IOException { + byte[] b = new byte[8 + text.length()]; + + b[0] = (byte) ClientCutText; + b[4] = (byte) ((text.length() >> 24) & 0xff); + b[5] = (byte) ((text.length() >> 16) & 0xff); + b[6] = (byte) ((text.length() >> 8) & 0xff); + b[7] = (byte) (text.length() & 0xff); + + System.arraycopy(text.getBytes(), 0, b, 8, text.length()); + + os.write(b); + } + + + // + // A buffer for putting pointer and keyboard events before being sent. This + // is to ensure that multiple RFB events generated from a single Java Event + // will all be sent in a single network packet. The maximum possible + // length is 4 modifier down events, a single key event followed by 4 + // modifier up events i.e. 9 key events or 72 bytes. + // + + byte[] eventBuf = new byte[72]; + int eventBufLen; + + + // Useful shortcuts for modifier masks. + + final static int CTRL_MASK = InputEvent.CTRL_MASK; + final static int SHIFT_MASK = InputEvent.SHIFT_MASK; + final static int META_MASK = InputEvent.META_MASK; + final static int ALT_MASK = InputEvent.ALT_MASK; + + + // + // Write a pointer event message. We may need to send modifier key events + // around it to set the correct modifier state. + // + + int pointerMask = 0; + + void writePointerEvent(MouseEvent evt) throws IOException { + int modifiers = evt.getModifiers(); + + int mask2 = 2; + int mask3 = 4; + if (viewer.options.reverseMouseButtons2And3) { + mask2 = 4; + mask3 = 2; + } + + // Note: For some reason, AWT does not set BUTTON1_MASK on left + // button presses. Here we think that it was the left button if + // modifiers do not include BUTTON2_MASK or BUTTON3_MASK. + + if (evt.getID() == MouseEvent.MOUSE_PRESSED) { + if ((modifiers & InputEvent.BUTTON2_MASK) != 0) { + pointerMask = mask2; + modifiers &= ~ALT_MASK; + } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { + pointerMask = mask3; + modifiers &= ~META_MASK; + } else { + pointerMask = 1; + } + } else if (evt.getID() == MouseEvent.MOUSE_RELEASED) { + pointerMask = 0; + if ((modifiers & InputEvent.BUTTON2_MASK) != 0) { + modifiers &= ~ALT_MASK; + } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { + modifiers &= ~META_MASK; + } + } + + eventBufLen = 0; + writeModifierKeyEvents(modifiers); + + int x = evt.getX(); + int y = evt.getY(); + + if (x < 0) x = 0; + if (y < 0) y = 0; + + eventBuf[eventBufLen++] = (byte) PointerEvent; + eventBuf[eventBufLen++] = (byte) pointerMask; + eventBuf[eventBufLen++] = (byte) ((x >> 8) & 0xff); + eventBuf[eventBufLen++] = (byte) (x & 0xff); + eventBuf[eventBufLen++] = (byte) ((y >> 8) & 0xff); + eventBuf[eventBufLen++] = (byte) (y & 0xff); + + // + // Always release all modifiers after an "up" event + // + + if (pointerMask == 0) { + writeModifierKeyEvents(0); + } + + os.write(eventBuf, 0, eventBufLen); + } + + + // + // Write a key event message. We may need to send modifier key events + // around it to set the correct modifier state. Also we need to translate + // from the Java key values to the X keysym values used by the RFB protocol. + // + + void writeKeyEvent(KeyEvent evt) throws IOException { + + int keyChar = evt.getKeyChar(); + + // + // Ignore event if only modifiers were pressed. + // + + // Some JVMs return 0 instead of CHAR_UNDEFINED in getKeyChar(). + if (keyChar == 0) + keyChar = KeyEvent.CHAR_UNDEFINED; + + if (keyChar == KeyEvent.CHAR_UNDEFINED) { + int code = evt.getKeyCode(); + if (code == KeyEvent.VK_CONTROL || code == KeyEvent.VK_SHIFT || + code == KeyEvent.VK_META || code == KeyEvent.VK_ALT) + return; + } + + // + // Key press or key release? + // + + boolean down = (evt.getID() == KeyEvent.KEY_PRESSED); + + int key; + if (evt.isActionKey()) { + + // + // An action key should be one of the following. + // If not then just ignore the event. + // + + switch(evt.getKeyCode()) { + case KeyEvent.VK_HOME: key = 0xff50; break; + case KeyEvent.VK_LEFT: key = 0xff51; break; + case KeyEvent.VK_UP: key = 0xff52; break; + case KeyEvent.VK_RIGHT: key = 0xff53; break; + case KeyEvent.VK_DOWN: key = 0xff54; break; + case KeyEvent.VK_PAGE_UP: key = 0xff55; break; + case KeyEvent.VK_PAGE_DOWN: key = 0xff56; break; + case KeyEvent.VK_END: key = 0xff57; break; + case KeyEvent.VK_INSERT: key = 0xff63; break; + case KeyEvent.VK_F1: key = 0xffbe; break; + case KeyEvent.VK_F2: key = 0xffbf; break; + case KeyEvent.VK_F3: key = 0xffc0; break; + case KeyEvent.VK_F4: key = 0xffc1; break; + case KeyEvent.VK_F5: key = 0xffc2; break; + case KeyEvent.VK_F6: key = 0xffc3; break; + case KeyEvent.VK_F7: key = 0xffc4; break; + case KeyEvent.VK_F8: key = 0xffc5; break; + case KeyEvent.VK_F9: key = 0xffc6; break; + case KeyEvent.VK_F10: key = 0xffc7; break; + case KeyEvent.VK_F11: key = 0xffc8; break; + case KeyEvent.VK_F12: key = 0xffc9; break; + default: + return; + } + + } else { + + // + // A "normal" key press. Ordinary ASCII characters go straight through. + // For CTRL-, CTRL is sent separately so just send . + // Backspace, tab, return, escape and delete have special keysyms. + // Anything else we ignore. + // + + key = keyChar; + + if (key < 0x20) { + if (evt.isControlDown()) { + key += 0x60; + } else { + switch(key) { + case KeyEvent.VK_BACK_SPACE: key = 0xff08; break; + case KeyEvent.VK_TAB: key = 0xff09; break; + case KeyEvent.VK_ENTER: key = 0xff0d; break; + case KeyEvent.VK_ESCAPE: key = 0xff1b; break; + } + } + } else if (key == 0x7f) { + // Delete + key = 0xffff; + } else if (key > 0xff) { + // JDK1.1 on X incorrectly passes some keysyms straight through, + // so we do too. JDK1.1.4 seems to have fixed this. + // The keysyms passed are 0xff00 .. XK_BackSpace .. XK_Delete + // Also, we pass through foreign currency keysyms (0x20a0..0x20af). + if ((key < 0xff00 || key > 0xffff) && + !(key >= 0x20a0 && key <= 0x20af)) + return; + } + } + + // Fake keyPresses for keys that only generates keyRelease events + if ((key == 0xe5) || (key == 0xc5) || // XK_aring / XK_Aring + (key == 0xe4) || (key == 0xc4) || // XK_adiaeresis / XK_Adiaeresis + (key == 0xf6) || (key == 0xd6) || // XK_odiaeresis / XK_Odiaeresis + (key == 0xa7) || (key == 0xbd) || // XK_section / XK_onehalf + (key == 0xa3)) { // XK_sterling + // Make sure we do not send keypress events twice on platforms + // with correct JVMs (those that actually report KeyPress for all + // keys) + if (down) + brokenKeyPressed = true; + + if (!down && !brokenKeyPressed) { + // We've got a release event for this key, but haven't received + // a press. Fake it. + eventBufLen = 0; + writeModifierKeyEvents(evt.getModifiers()); + writeKeyEvent(key, true); + os.write(eventBuf, 0, eventBufLen); + } + + if (!down) + brokenKeyPressed = false; + } + + eventBufLen = 0; + writeModifierKeyEvents(evt.getModifiers()); + writeKeyEvent(key, down); + + // Always release all modifiers after an "up" event + if (!down) + writeModifierKeyEvents(0); + + os.write(eventBuf, 0, eventBufLen); + } + + + // + // Add a raw key event with the given X keysym to eventBuf. + // + + void writeKeyEvent(int keysym, boolean down) { + eventBuf[eventBufLen++] = (byte) KeyboardEvent; + eventBuf[eventBufLen++] = (byte) (down ? 1 : 0); + eventBuf[eventBufLen++] = (byte) 0; + eventBuf[eventBufLen++] = (byte) 0; + eventBuf[eventBufLen++] = (byte) ((keysym >> 24) & 0xff); + eventBuf[eventBufLen++] = (byte) ((keysym >> 16) & 0xff); + eventBuf[eventBufLen++] = (byte) ((keysym >> 8) & 0xff); + eventBuf[eventBufLen++] = (byte) (keysym & 0xff); + } + + + // + // Write key events to set the correct modifier state. + // + + int oldModifiers = 0; + + void writeModifierKeyEvents(int newModifiers) { + if ((newModifiers & CTRL_MASK) != (oldModifiers & CTRL_MASK)) + writeKeyEvent(0xffe3, (newModifiers & CTRL_MASK) != 0); + + if ((newModifiers & SHIFT_MASK) != (oldModifiers & SHIFT_MASK)) + writeKeyEvent(0xffe1, (newModifiers & SHIFT_MASK) != 0); + + if ((newModifiers & META_MASK) != (oldModifiers & META_MASK)) + writeKeyEvent(0xffe7, (newModifiers & META_MASK) != 0); + + if ((newModifiers & ALT_MASK) != (oldModifiers & ALT_MASK)) + writeKeyEvent(0xffe9, (newModifiers & ALT_MASK) != 0); + + oldModifiers = newModifiers; + } + + + // + // Compress and write the data into the recorded session file. This + // method assumes the recording is on (rec != null). + // + + void recordCompressedData(byte[] data, int off, int len) throws IOException { + Deflater deflater = new Deflater(); + deflater.setInput(data, off, len); + int bufSize = len + len / 100 + 12; + byte[] buf = new byte[bufSize]; + deflater.finish(); + int compressedSize = deflater.deflate(buf); + recordCompactLen(compressedSize); + rec.write(buf, 0, compressedSize); + } + + void recordCompressedData(byte[] data) throws IOException { + recordCompressedData(data, 0, data.length); + } + + // + // Write an integer in compact representation (1..3 bytes) into the + // recorded session file. This method assumes the recording is on + // (rec != null). + // + + void recordCompactLen(int len) throws IOException { + byte[] buf = new byte[3]; + int bytes = 0; + buf[bytes++] = (byte)(len & 0x7F); + if (len > 0x7F) { + buf[bytes-1] |= 0x80; + buf[bytes++] = (byte)(len >> 7 & 0x7F); + if (len > 0x3FFF) { + buf[bytes-1] |= 0x80; + buf[bytes++] = (byte)(len >> 14 & 0xFF); + } + } + rec.write(buf, 0, bytes); + } + + 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; + } + + public void readFully(byte b[]) throws IOException { + readFully(b, 0, b.length); + } + + public void readFully(byte b[], int off, int len) throws IOException { + long before = 0; + if (timing) + before = System.currentTimeMillis(); + + is.readFully(b, off, len); + + if (timing) { + long after = System.currentTimeMillis(); + long newTimeWaited = (after - before) * 10; + int newKbits = len * 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; + } + } + +} diff --git a/SessionRecorder.java b/SessionRecorder.java new file mode 100644 index 0000000..a02ce98 --- /dev/null +++ b/SessionRecorder.java @@ -0,0 +1,193 @@ +// +// Copyright (C) 2002 Constantin Kaplinsky. 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. +// + +// +// SessionRecorder is a class to write FBS (FrameBuffer Stream) files. +// FBS files are used to save RFB sessions for later playback. +// + +import java.io.*; + +class SessionRecorder { + + protected FileOutputStream f; + protected DataOutputStream df; + protected long startTime, lastTimeOffset; + + protected byte[] buffer; + protected int bufferSize; + protected int bufferBytes; + + public SessionRecorder(String name, int bufsize) throws IOException { + f = new FileOutputStream(name); + df = new DataOutputStream(f); + startTime = System.currentTimeMillis(); + lastTimeOffset = 0; + + bufferSize = bufsize; + bufferBytes = 0; + buffer = new byte[bufferSize]; + } + + public SessionRecorder(String name) throws IOException { + this(name, 65536); + } + + // + // Close the file, free resources. + // + + public void close() throws IOException { + try { + flush(); + } catch (IOException e) { + } + + df = null; + f.close(); + f = null; + buffer = null; + } + + // + // Write the FBS file header as defined in the rfbproxy utility. + // + + public void writeHeader() throws IOException { + df.write("FBS 001.000\n".getBytes()); + } + + // + // Write one byte. + // + + public void writeByte(int b) throws IOException { + prepareWriting(); + buffer[bufferBytes++] = (byte)b; + } + + // + // Write 16-bit value, big-endian. + // + + public void writeShortBE(int v) throws IOException { + prepareWriting(); + buffer[bufferBytes++] = (byte)(v >> 8); + buffer[bufferBytes++] = (byte)v; + } + + // + // Write 32-bit value, big-endian. + // + + public void writeIntBE(int v) throws IOException { + prepareWriting(); + buffer[bufferBytes] = (byte)(v >> 24); + buffer[bufferBytes + 1] = (byte)(v >> 16); + buffer[bufferBytes + 2] = (byte)(v >> 8); + buffer[bufferBytes + 3] = (byte)v; + bufferBytes += 4; + } + + // + // Write 16-bit value, little-endian. + // + + public void writeShortLE(int v) throws IOException { + prepareWriting(); + buffer[bufferBytes++] = (byte)v; + buffer[bufferBytes++] = (byte)(v >> 8); + } + + // + // Write 32-bit value, little-endian. + // + + public void writeIntLE(int v) throws IOException { + prepareWriting(); + buffer[bufferBytes] = (byte)v; + buffer[bufferBytes + 1] = (byte)(v >> 8); + buffer[bufferBytes + 2] = (byte)(v >> 16); + buffer[bufferBytes + 3] = (byte)(v >> 24); + bufferBytes += 4; + } + + // + // Write byte arrays. + // + + public void write(byte b[], int off, int len) throws IOException { + prepareWriting(); + while (len > 0) { + if (bufferBytes > bufferSize - 4) + flush(false); + + int partLen; + if (bufferBytes + len > bufferSize) { + partLen = bufferSize - bufferBytes; + } else { + partLen = len; + } + System.arraycopy(b, off, buffer, bufferBytes, partLen); + bufferBytes += partLen; + off += partLen; + len -= partLen; + } + } + + public void write(byte b[]) throws IOException { + write(b, 0, b.length); + } + + // + // Flush the output. This method saves buffered data in the + // underlying file object adding data sizes and timestamps. If the + // updateTimeOffset is set to false, then the current time offset + // will not be changed for next write operation. + // + + public void flush(boolean updateTimeOffset) throws IOException { + if (bufferBytes > 0) { + df.writeInt(bufferBytes); + df.write(buffer, 0, (bufferBytes + 3) & 0x7FFFFFFC); + df.writeInt((int)lastTimeOffset); + bufferBytes = 0; + if (updateTimeOffset) + lastTimeOffset = -1; + } + } + + public void flush() throws IOException { + flush(true); + } + + // + // Before writing any data, remember time offset and flush the + // buffer before it becomes full. + // + + protected void prepareWriting() throws IOException { + if (lastTimeOffset == -1) + lastTimeOffset = System.currentTimeMillis() - startTime; + if (bufferBytes > bufferSize - 4) + flush(false); + } + +} + diff --git a/SocketFactory.java b/SocketFactory.java new file mode 100644 index 0000000..8d4b88f --- /dev/null +++ b/SocketFactory.java @@ -0,0 +1,36 @@ +// +// Copyright (C) 2002 HorizonLive.com, Inc. All Rights Reserved. +// +// This is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this software; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. +// + +// +// SocketFactory.java describes an interface used to substitute the +// standard Socket class by its alternative implementations. +// + +import java.applet.*; +import java.net.*; +import java.io.*; + +public interface SocketFactory { + + public Socket createSocket(String host, int port, Applet applet) + throws IOException; + + public Socket createSocket(String host, int port, String[] args) + throws IOException; +} diff --git a/VNCProxyConnectSocket.java b/VNCProxyConnectSocket.java new file mode 100644 index 0000000..595acd5 --- /dev/null +++ b/VNCProxyConnectSocket.java @@ -0,0 +1,61 @@ +// +// Copyright (C) 2002 Constantin Kaplinsky, Inc. All Rights Reserved. +// Copyright 2007 MIT Student Information Processing Board +// +// 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. +// + +// +// VNCProxySocket.java together with VNCProxySocketFactory.java +// implement an alternate way to connect to VNC servers via one or two +// VNCProxy proxies supporting the VNCProxy VNCCONNECT method. +// + +import java.net.*; +import java.io.*; + +class VNCProxyConnectSocket extends Socket { + + public VNCProxyConnectSocket(String host, int port, + String vmname, String authtoken) + throws IOException { + + // Connect to the specified HTTP proxy + super(host, port); + + // Send the CONNECT request + getOutputStream().write(("CONNECTVNC " + vmname + + " VNCProxy/1.0\r\nAuth-token: " + authtoken + + "\r\n\r\n").getBytes()); + + // Read the first line of the response + DataInputStream is = new DataInputStream(getInputStream()); + String str = is.readLine(); + + // Check the HTTP error code -- it should be "200" on success + if (!str.startsWith("VNCProxy/1.0 200 ")) { + if (str.startsWith("VNCProxy/1.0 ")) + str = str.substring(13); + throw new IOException("Proxy reports \"" + str + "\""); + } + + // Success -- skip remaining HTTP headers + do { + str = is.readLine(); + } while (str.length() != 0); + } +} + diff --git a/VNCProxyConnectSocketFactory.java b/VNCProxyConnectSocketFactory.java new file mode 100644 index 0000000..c0386f1 --- /dev/null +++ b/VNCProxyConnectSocketFactory.java @@ -0,0 +1,80 @@ +// +// Copyright (C) 2002 Constantin Kaplinsky, Inc. All Rights Reserved. +// Copyright 2007 MIT Student Information Processing Board +// +// 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. +// + +// +// VNCProxyConnectSocketFactory.java together with VNCProxyConnectSocket.java +// implement an alternate way to connect to VNC servers via one or two +// VNCProxy proxies supporting the VNCProxy CONNECT method. +// + +import java.applet.*; +import java.net.*; +import java.io.*; + +class VNCProxyConnectSocketFactory implements SocketFactory { + + public Socket createSocket(String host, int port, Applet applet) + throws IOException { + + return createSocket(host, port, + applet.getParameter("VMNAME"), + applet.getParameter("AUTHTOKEN")); + } + + public Socket createSocket(String host, int port, String[] args) + throws IOException { + + return createSocket(host, port, + readArg(args, "VMNAME"), + readArg(args, "AUTHTOKEN")); + } + + public Socket createSocket(String host, int port, + String vmname, String authtoken) + throws IOException { + + if (vmname == null || authtoken == null) { + System.out.println("Incomplete parameter list for VNCProxyConnectSocket"); + return new Socket(host, port); + } + + System.out.println("VNCProxy CONNECT via proxy " + host + + " port " + port + " to vm " + vmname); + VNCProxyConnectSocket s = + new VNCProxyConnectSocket(host, port, vmname, authtoken); + + return (Socket)s; + } + + private String readArg(String[] args, String name) { + + for (int i = 0; i < args.length; i += 2) { + if (args[i].equalsIgnoreCase(name)) { + try { + return args[i+1]; + } catch (Exception e) { + return null; + } + } + } + return null; + } +} + diff --git a/VncCanvas.java b/VncCanvas.java new file mode 100644 index 0000000..df84409 --- /dev/null +++ b/VncCanvas.java @@ -0,0 +1,1803 @@ +// +// Copyright (C) 2004 Horizon Wimba. All Rights Reserved. +// Copyright (C) 2001-2003 HorizonLive.com, Inc. All Rights Reserved. +// Copyright (C) 2001,2002 Constantin Kaplinsky. All Rights Reserved. +// Copyright (C) 2000 Tridia Corporation. All Rights Reserved. +// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. +// +// This is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this software; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. +// + +import java.awt.*; +import java.awt.event.*; +import java.awt.image.*; +import java.io.*; +import java.lang.*; +import java.util.zip.*; + + +// +// VncCanvas is a subclass of Canvas which draws a VNC desktop on it. +// + +class VncCanvas extends Canvas + implements KeyListener, MouseListener, MouseMotionListener { + + VncViewer viewer; + RfbProto rfb; + ColorModel cm8, cm24; + Color[] colors; + int bytesPixel; + + int maxWidth = 0, maxHeight = 0; + int scalingFactor; + int scaledWidth, scaledHeight; + + Image memImage; + Graphics memGraphics; + + Image rawPixelsImage; + MemoryImageSource pixelsSource; + byte[] pixels8; + int[] pixels24; + + // ZRLE encoder's data. + byte[] zrleBuf; + int zrleBufLen = 0; + byte[] zrleTilePixels8; + int[] zrleTilePixels24; + ZlibInStream zrleInStream; + boolean zrleRecWarningShown = false; + + // Zlib encoder's data. + byte[] zlibBuf; + int zlibBufLen = 0; + Inflater zlibInflater; + + // Tight encoder's data. + final static int tightZlibBufferSize = 512; + Inflater[] tightInflaters; + + // Since JPEG images are loaded asynchronously, we have to remember + // their position in the framebuffer. Also, this jpegRect object is + // used for synchronization between the rfbThread and a JVM's thread + // which decodes and loads JPEG images. + Rectangle jpegRect; + + // True if we process keyboard and mouse events. + boolean inputEnabled; + + // + // The constructors. + // + + public VncCanvas(VncViewer v, int maxWidth_, int maxHeight_) + throws IOException { + + viewer = v; + maxWidth = maxWidth_; + maxHeight = maxHeight_; + + rfb = viewer.rfb; + scalingFactor = viewer.options.scalingFactor; + + tightInflaters = new Inflater[4]; + + cm8 = new DirectColorModel(8, 7, (7 << 3), (3 << 6)); + cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF); + + colors = new Color[256]; + for (int i = 0; i < 256; i++) + colors[i] = new Color(cm8.getRGB(i)); + + setPixelFormat(); + + inputEnabled = false; + if (!viewer.options.viewOnly) + enableInput(true); + + // Keyboard listener is enabled even in view-only mode, to catch + // 'r' or 'R' key presses used to request screen update. + addKeyListener(this); + } + + public VncCanvas(VncViewer v) throws IOException { + this(v, 0, 0); + } + + // + // 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); + } + + // + // All painting is performed here. + // + + public void update(Graphics g) { + paint(g); + } + + public void paint(Graphics g) { + synchronized(memImage) { + if (rfb.framebufferWidth == scaledWidth) { + g.drawImage(memImage, 0, 0, null); + } else { + paintScaledFrameBuffer(g); + } + } + if (showSoftCursor) { + int x0 = cursorX - hotX, y0 = cursorY - hotY; + Rectangle r = new Rectangle(x0, y0, cursorWidth, cursorHeight); + if (r.intersects(g.getClipBounds())) { + g.drawImage(softCursor, x0, y0, null); + } + } + } + + public void paintScaledFrameBuffer(Graphics g) { + g.drawImage(memImage, 0, 0, scaledWidth, scaledHeight, null); + } + + // + // Override the ImageObserver interface method to handle drawing of + // JPEG-encoded data. + // + + public boolean imageUpdate(Image img, int infoflags, + int x, int y, int width, int height) { + if ((infoflags & (ALLBITS | ABORT)) == 0) { + return true; // We need more image data. + } else { + // If the whole image is available, draw it now. + if ((infoflags & ALLBITS) != 0) { + if (jpegRect != null) { + synchronized(jpegRect) { + memGraphics.drawImage(img, jpegRect.x, jpegRect.y, null); + scheduleRepaint(jpegRect.x, jpegRect.y, + jpegRect.width, jpegRect.height); + jpegRect.notify(); + } + } + } + return false; // All image data was processed. + } + } + + // + // Start/stop receiving mouse events. Keyboard events are received + // even in view-only mode, because we want to map the 'r' key to the + // screen refreshing function. + // + + public synchronized void enableInput(boolean enable) { + if (enable && !inputEnabled) { + inputEnabled = true; + addMouseListener(this); + addMouseMotionListener(this); + if (viewer.showControls) { + viewer.buttonPanel.enableRemoteAccessControls(true); + } + createSoftCursor(); // scaled cursor + } else if (!enable && inputEnabled) { + inputEnabled = false; + removeMouseListener(this); + removeMouseMotionListener(this); + if (viewer.showControls) { + viewer.buttonPanel.enableRemoteAccessControls(false); + } + createSoftCursor(); // non-scaled cursor + } + } + + public void setPixelFormat() throws IOException { + if (viewer.options.eightBitColors) { + rfb.writeSetPixelFormat(8, 8, false, true, 7, 7, 3, 0, 3, 6); + bytesPixel = 1; + } else { + rfb.writeSetPixelFormat(32, 24, false, true, 255, 255, 255, 16, 8, 0); + bytesPixel = 4; + } + updateFramebufferSize(); + } + + void updateFramebufferSize() { + + // Useful shortcuts. + int fbWidth = rfb.framebufferWidth; + int fbHeight = rfb.framebufferHeight; + + // Calculate scaling factor for auto scaling. + if (maxWidth > 0 && maxHeight > 0) { + int f1 = maxWidth * 100 / fbWidth; + int f2 = maxHeight * 100 / fbHeight; + scalingFactor = Math.min(f1, f2); + if (scalingFactor > 100) + scalingFactor = 100; + System.out.println("Scaling desktop at " + scalingFactor + "%"); + } + + // Update scaled framebuffer geometry. + scaledWidth = (fbWidth * scalingFactor + 50) / 100; + scaledHeight = (fbHeight * scalingFactor + 50) / 100; + + // Create new off-screen image either if it does not exist, or if + // its geometry should be changed. It's not necessary to replace + // existing image if only pixel format should be changed. + if (memImage == null) { + memImage = viewer.vncContainer.createImage(fbWidth, fbHeight); + memGraphics = memImage.getGraphics(); + } else if (memImage.getWidth(null) != fbWidth || + memImage.getHeight(null) != fbHeight) { + synchronized(memImage) { + memImage = viewer.vncContainer.createImage(fbWidth, fbHeight); + memGraphics = memImage.getGraphics(); + } + } + + // Images with raw pixels should be re-allocated on every change + // of geometry or pixel format. + if (bytesPixel == 1) { + + pixels24 = null; + pixels8 = new byte[fbWidth * fbHeight]; + + pixelsSource = + new MemoryImageSource(fbWidth, fbHeight, cm8, pixels8, 0, fbWidth); + + zrleTilePixels24 = null; + zrleTilePixels8 = new byte[64 * 64]; + + } else { + + pixels8 = null; + pixels24 = new int[fbWidth * fbHeight]; + + pixelsSource = + new MemoryImageSource(fbWidth, fbHeight, cm24, pixels24, 0, fbWidth); + + zrleTilePixels8 = null; + zrleTilePixels24 = new int[64 * 64]; + + } + pixelsSource.setAnimated(true); + rawPixelsImage = Toolkit.getDefaultToolkit().createImage(pixelsSource); + + // Update the size of desktop containers. + if (viewer.inSeparateFrame) { + if (viewer.desktopScrollPane != null) + resizeDesktopFrame(); + } else { + setSize(scaledWidth, scaledHeight); + } + viewer.moveFocusToDesktop(); + } + + void resizeDesktopFrame() { + setSize(scaledWidth, scaledHeight); + + // FIXME: Find a better way to determine correct size of a + // ScrollPane. -- const + Insets insets = viewer.desktopScrollPane.getInsets(); + viewer.desktopScrollPane.setSize(scaledWidth + + 2 * Math.min(insets.left, insets.right), + scaledHeight + + 2 * Math.min(insets.top, insets.bottom)); + + viewer.vncFrame.pack(); + + // Try to limit the frame size to the screen size. + + Dimension screenSize = viewer.vncFrame.getToolkit().getScreenSize(); + Dimension frameSize = viewer.vncFrame.getSize(); + Dimension newSize = frameSize; + + // Reduce Screen Size by 30 pixels in each direction; + // This is a (poor) attempt to account for + // 1) Menu bar on Macintosh (should really also account for + // Dock on OSX). Usually 22px on top of screen. + // 2) Taxkbar on Windows (usually about 28 px on bottom) + // 3) Other obstructions. + + screenSize.height -= 30; + screenSize.width -= 30; + + boolean needToResizeFrame = false; + if (frameSize.height > screenSize.height) { + newSize.height = screenSize.height; + needToResizeFrame = true; + } + if (frameSize.width > screenSize.width) { + newSize.width = screenSize.width; + needToResizeFrame = true; + } + if (needToResizeFrame) { + viewer.vncFrame.setSize(newSize); + } + + viewer.desktopScrollPane.doLayout(); + } + + // + // processNormalProtocol() - executed by the rfbThread to deal with the + // RFB socket. + // + + public void processNormalProtocol() throws Exception { + + // Start/stop session recording if necessary. + viewer.checkRecordingStatus(); + + rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth, + rfb.framebufferHeight, false); + + // + // main dispatch loop + // + + while (true) { + + // Read message type from the server. + int msgType = rfb.readServerMessageType(); + + // Process the message depending on its type. + switch (msgType) { + case RfbProto.FramebufferUpdate: + rfb.readFramebufferUpdate(); + + boolean cursorPosReceived = false; + + for (int i = 0; i < rfb.updateNRects; i++) { + rfb.readFramebufferUpdateRectHdr(); + int rx = rfb.updateRectX, ry = rfb.updateRectY; + int rw = rfb.updateRectW, rh = rfb.updateRectH; + + if (rfb.updateRectEncoding == rfb.EncodingLastRect) + break; + + if (rfb.updateRectEncoding == rfb.EncodingNewFBSize) { + rfb.setFramebufferSize(rw, rh); + updateFramebufferSize(); + break; + } + + if (rfb.updateRectEncoding == rfb.EncodingXCursor || + rfb.updateRectEncoding == rfb.EncodingRichCursor) { + handleCursorShapeUpdate(rfb.updateRectEncoding, rx, ry, rw, rh); + continue; + } + + if (rfb.updateRectEncoding == rfb.EncodingPointerPos) { + softCursorMove(rx, ry); + cursorPosReceived = true; + continue; + } + + rfb.startTiming(); + + switch (rfb.updateRectEncoding) { + case RfbProto.EncodingRaw: + handleRawRect(rx, ry, rw, rh); + break; + case RfbProto.EncodingCopyRect: + handleCopyRect(rx, ry, rw, rh); + break; + case RfbProto.EncodingRRE: + handleRRERect(rx, ry, rw, rh); + break; + case RfbProto.EncodingCoRRE: + handleCoRRERect(rx, ry, rw, rh); + break; + case RfbProto.EncodingHextile: + handleHextileRect(rx, ry, rw, rh); + break; + case RfbProto.EncodingZRLE: + handleZRLERect(rx, ry, rw, rh); + break; + case RfbProto.EncodingZlib: + handleZlibRect(rx, ry, rw, rh); + break; + case RfbProto.EncodingTight: + handleTightRect(rx, ry, rw, rh); + break; + default: + throw new Exception("Unknown RFB rectangle encoding " + + rfb.updateRectEncoding); + } + + rfb.stopTiming(); + } + + boolean fullUpdateNeeded = false; + + // Start/stop session recording if necessary. Request full + // update if a new session file was opened. + if (viewer.checkRecordingStatus()) + fullUpdateNeeded = true; + + // Defer framebuffer update request if necessary. But wake up + // immediately on keyboard or mouse event. Also, don't sleep + // if there is some data to receive, or if the last update + // included a PointerPos message. + if (viewer.deferUpdateRequests > 0 && + rfb.is.available() == 0 && !cursorPosReceived) { + synchronized(rfb) { + try { + rfb.wait(viewer.deferUpdateRequests); + } catch (InterruptedException e) { + } + } + } + + // Before requesting framebuffer update, check if the pixel + // format should be changed. If it should, request full update + // instead of an incremental one. + if (viewer.options.eightBitColors != (bytesPixel == 1)) { + setPixelFormat(); + fullUpdateNeeded = true; + } + + viewer.autoSelectEncodings(); + + rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth, + rfb.framebufferHeight, + !fullUpdateNeeded); + + break; + + case RfbProto.SetColourMapEntries: + throw new Exception("Can't handle SetColourMapEntries message"); + + case RfbProto.Bell: + Toolkit.getDefaultToolkit().beep(); + break; + + case RfbProto.ServerCutText: + String s = rfb.readServerCutText(); + viewer.clipboard.setCutText(s); + break; + + default: + throw new Exception("Unknown RFB message type " + msgType); + } + } + } + + + // + // Handle a raw rectangle. The second form with paint==false is used + // by the Hextile decoder for raw-encoded tiles. + // + + void handleRawRect(int x, int y, int w, int h) throws IOException { + handleRawRect(x, y, w, h, true); + } + + void handleRawRect(int x, int y, int w, int h, boolean paint) + throws IOException { + + if (bytesPixel == 1) { + for (int dy = y; dy < y + h; dy++) { + rfb.readFully(pixels8, dy * rfb.framebufferWidth + x, w); + if (rfb.rec != null) { + rfb.rec.write(pixels8, dy * rfb.framebufferWidth + x, w); + } + } + } else { + byte[] buf = new byte[w * 4]; + int i, offset; + for (int dy = y; dy < y + h; dy++) { + rfb.readFully(buf); + if (rfb.rec != null) { + rfb.rec.write(buf); + } + offset = dy * rfb.framebufferWidth + x; + for (i = 0; i < w; i++) { + pixels24[offset + i] = + (buf[i * 4 + 2] & 0xFF) << 16 | + (buf[i * 4 + 1] & 0xFF) << 8 | + (buf[i * 4] & 0xFF); + } + } + } + + handleUpdatedPixels(x, y, w, h); + if (paint) + scheduleRepaint(x, y, w, h); + } + + // + // Handle a CopyRect rectangle. + // + + void handleCopyRect(int x, int y, int w, int h) throws IOException { + + rfb.readCopyRect(); + memGraphics.copyArea(rfb.copyRectSrcX, rfb.copyRectSrcY, w, h, + x - rfb.copyRectSrcX, y - rfb.copyRectSrcY); + + scheduleRepaint(x, y, w, h); + } + + // + // Handle an RRE-encoded rectangle. + // + + void handleRRERect(int x, int y, int w, int h) throws IOException { + + int nSubrects = rfb.is.readInt(); + + byte[] bg_buf = new byte[bytesPixel]; + rfb.readFully(bg_buf); + Color pixel; + if (bytesPixel == 1) { + pixel = colors[bg_buf[0] & 0xFF]; + } else { + pixel = new Color(bg_buf[2] & 0xFF, bg_buf[1] & 0xFF, bg_buf[0] & 0xFF); + } + memGraphics.setColor(pixel); + memGraphics.fillRect(x, y, w, h); + + byte[] buf = new byte[nSubrects * (bytesPixel + 8)]; + rfb.readFully(buf); + DataInputStream ds = new DataInputStream(new ByteArrayInputStream(buf)); + + if (rfb.rec != null) { + rfb.rec.writeIntBE(nSubrects); + rfb.rec.write(bg_buf); + rfb.rec.write(buf); + } + + int sx, sy, sw, sh; + + for (int j = 0; j < nSubrects; j++) { + if (bytesPixel == 1) { + pixel = colors[ds.readUnsignedByte()]; + } else { + ds.skip(4); + pixel = new Color(buf[j*12+2] & 0xFF, + buf[j*12+1] & 0xFF, + buf[j*12] & 0xFF); + } + sx = x + ds.readUnsignedShort(); + sy = y + ds.readUnsignedShort(); + sw = ds.readUnsignedShort(); + sh = ds.readUnsignedShort(); + + memGraphics.setColor(pixel); + memGraphics.fillRect(sx, sy, sw, sh); + } + + scheduleRepaint(x, y, w, h); + } + + // + // Handle a CoRRE-encoded rectangle. + // + + void handleCoRRERect(int x, int y, int w, int h) throws IOException { + int nSubrects = rfb.is.readInt(); + + byte[] bg_buf = new byte[bytesPixel]; + rfb.readFully(bg_buf); + Color pixel; + if (bytesPixel == 1) { + pixel = colors[bg_buf[0] & 0xFF]; + } else { + pixel = new Color(bg_buf[2] & 0xFF, bg_buf[1] & 0xFF, bg_buf[0] & 0xFF); + } + memGraphics.setColor(pixel); + memGraphics.fillRect(x, y, w, h); + + byte[] buf = new byte[nSubrects * (bytesPixel + 4)]; + rfb.readFully(buf); + + if (rfb.rec != null) { + rfb.rec.writeIntBE(nSubrects); + rfb.rec.write(bg_buf); + rfb.rec.write(buf); + } + + int sx, sy, sw, sh; + int i = 0; + + for (int j = 0; j < nSubrects; j++) { + if (bytesPixel == 1) { + pixel = colors[buf[i++] & 0xFF]; + } else { + pixel = new Color(buf[i+2] & 0xFF, buf[i+1] & 0xFF, buf[i] & 0xFF); + i += 4; + } + sx = x + (buf[i++] & 0xFF); + sy = y + (buf[i++] & 0xFF); + sw = buf[i++] & 0xFF; + sh = buf[i++] & 0xFF; + + memGraphics.setColor(pixel); + memGraphics.fillRect(sx, sy, sw, sh); + } + + scheduleRepaint(x, y, w, h); + } + + // + // Handle a Hextile-encoded rectangle. + // + + // These colors should be kept between handleHextileSubrect() calls. + private Color hextile_bg, hextile_fg; + + void handleHextileRect(int x, int y, int w, int h) throws IOException { + + hextile_bg = new Color(0); + hextile_fg = new Color(0); + + for (int ty = y; ty < y + h; ty += 16) { + int th = 16; + if (y + h - ty < 16) + th = y + h - ty; + + for (int tx = x; tx < x + w; tx += 16) { + int tw = 16; + if (x + w - tx < 16) + tw = x + w - tx; + + handleHextileSubrect(tx, ty, tw, th); + } + + // Finished with a row of tiles, now let's show it. + scheduleRepaint(x, y, w, h); + } + } + + // + // Handle one tile in the Hextile-encoded data. + // + + void handleHextileSubrect(int tx, int ty, int tw, int th) + throws IOException { + + int subencoding = rfb.is.readUnsignedByte(); + if (rfb.rec != null) { + rfb.rec.writeByte(subencoding); + } + + // Is it a raw-encoded sub-rectangle? + if ((subencoding & rfb.HextileRaw) != 0) { + handleRawRect(tx, ty, tw, th, false); + return; + } + + // Read and draw the background if specified. + byte[] cbuf = new byte[bytesPixel]; + if ((subencoding & rfb.HextileBackgroundSpecified) != 0) { + rfb.readFully(cbuf); + if (bytesPixel == 1) { + hextile_bg = colors[cbuf[0] & 0xFF]; + } else { + hextile_bg = new Color(cbuf[2] & 0xFF, cbuf[1] & 0xFF, cbuf[0] & 0xFF); + } + if (rfb.rec != null) { + rfb.rec.write(cbuf); + } + } + memGraphics.setColor(hextile_bg); + memGraphics.fillRect(tx, ty, tw, th); + + // Read the foreground color if specified. + if ((subencoding & rfb.HextileForegroundSpecified) != 0) { + rfb.readFully(cbuf); + if (bytesPixel == 1) { + hextile_fg = colors[cbuf[0] & 0xFF]; + } else { + hextile_fg = new Color(cbuf[2] & 0xFF, cbuf[1] & 0xFF, cbuf[0] & 0xFF); + } + if (rfb.rec != null) { + rfb.rec.write(cbuf); + } + } + + // Done with this tile if there is no sub-rectangles. + if ((subencoding & rfb.HextileAnySubrects) == 0) + return; + + int nSubrects = rfb.is.readUnsignedByte(); + int bufsize = nSubrects * 2; + if ((subencoding & rfb.HextileSubrectsColoured) != 0) { + bufsize += nSubrects * bytesPixel; + } + byte[] buf = new byte[bufsize]; + rfb.readFully(buf); + if (rfb.rec != null) { + rfb.rec.writeByte(nSubrects); + rfb.rec.write(buf); + } + + int b1, b2, sx, sy, sw, sh; + int i = 0; + + if ((subencoding & rfb.HextileSubrectsColoured) == 0) { + + // Sub-rectangles are all of the same color. + memGraphics.setColor(hextile_fg); + for (int j = 0; j < nSubrects; j++) { + b1 = buf[i++] & 0xFF; + b2 = buf[i++] & 0xFF; + sx = tx + (b1 >> 4); + sy = ty + (b1 & 0xf); + sw = (b2 >> 4) + 1; + sh = (b2 & 0xf) + 1; + memGraphics.fillRect(sx, sy, sw, sh); + } + } else if (bytesPixel == 1) { + + // BGR233 (8-bit color) version for colored sub-rectangles. + for (int j = 0; j < nSubrects; j++) { + hextile_fg = colors[buf[i++] & 0xFF]; + b1 = buf[i++] & 0xFF; + b2 = buf[i++] & 0xFF; + sx = tx + (b1 >> 4); + sy = ty + (b1 & 0xf); + sw = (b2 >> 4) + 1; + sh = (b2 & 0xf) + 1; + memGraphics.setColor(hextile_fg); + memGraphics.fillRect(sx, sy, sw, sh); + } + + } else { + + // Full-color (24-bit) version for colored sub-rectangles. + for (int j = 0; j < nSubrects; j++) { + hextile_fg = new Color(buf[i+2] & 0xFF, + buf[i+1] & 0xFF, + buf[i] & 0xFF); + i += 4; + b1 = buf[i++] & 0xFF; + b2 = buf[i++] & 0xFF; + sx = tx + (b1 >> 4); + sy = ty + (b1 & 0xf); + sw = (b2 >> 4) + 1; + sh = (b2 & 0xf) + 1; + memGraphics.setColor(hextile_fg); + memGraphics.fillRect(sx, sy, sw, sh); + } + + } + } + + // + // Handle a ZRLE-encoded rectangle. + // + // FIXME: Currently, session recording is not fully supported for ZRLE. + // + + void handleZRLERect(int x, int y, int w, int h) throws Exception { + + if (zrleInStream == null) + zrleInStream = new ZlibInStream(); + + int nBytes = rfb.is.readInt(); + if (nBytes > 64 * 1024 * 1024) + throw new Exception("ZRLE decoder: illegal compressed data size"); + + if (zrleBuf == null || zrleBufLen < nBytes) { + zrleBufLen = nBytes + 4096; + zrleBuf = new byte[zrleBufLen]; + } + + // FIXME: Do not wait for all the data before decompression. + rfb.readFully(zrleBuf, 0, nBytes); + + if (rfb.rec != null) { + if (rfb.recordFromBeginning) { + rfb.rec.writeIntBE(nBytes); + rfb.rec.write(zrleBuf, 0, nBytes); + } else if (!zrleRecWarningShown) { + System.out.println("Warning: ZRLE session can be recorded" + + " only from the beginning"); + System.out.println("Warning: Recorded file may be corrupted"); + zrleRecWarningShown = true; + } + } + + zrleInStream.setUnderlying(new MemInStream(zrleBuf, 0, nBytes), nBytes); + + for (int ty = y; ty < y+h; ty += 64) { + + int th = Math.min(y+h-ty, 64); + + for (int tx = x; tx < x+w; tx += 64) { + + int tw = Math.min(x+w-tx, 64); + + int mode = zrleInStream.readU8(); + boolean rle = (mode & 128) != 0; + int palSize = mode & 127; + int[] palette = new int[128]; + + readZrlePalette(palette, palSize); + + if (palSize == 1) { + int pix = palette[0]; + Color c = (bytesPixel == 1) ? + colors[pix] : new Color(0xFF000000 | pix); + memGraphics.setColor(c); + memGraphics.fillRect(tx, ty, tw, th); + continue; + } + + if (!rle) { + if (palSize == 0) { + readZrleRawPixels(tw, th); + } else { + readZrlePackedPixels(tw, th, palette, palSize); + } + } else { + if (palSize == 0) { + readZrlePlainRLEPixels(tw, th); + } else { + readZrlePackedRLEPixels(tw, th, palette); + } + } + handleUpdatedZrleTile(tx, ty, tw, th); + } + } + + zrleInStream.reset(); + + scheduleRepaint(x, y, w, h); + } + + int readPixel(InStream is) throws Exception { + int pix; + if (bytesPixel == 1) { + pix = is.readU8(); + } else { + int p1 = is.readU8(); + int p2 = is.readU8(); + int p3 = is.readU8(); + pix = (p3 & 0xFF) << 16 | (p2 & 0xFF) << 8 | (p1 & 0xFF); + } + return pix; + } + + void readPixels(InStream is, int[] dst, int count) throws Exception { + int pix; + if (bytesPixel == 1) { + byte[] buf = new byte[count]; + is.readBytes(buf, 0, count); + for (int i = 0; i < count; i++) { + dst[i] = (int)buf[i] & 0xFF; + } + } else { + byte[] buf = new byte[count * 3]; + is.readBytes(buf, 0, count * 3); + for (int i = 0; i < count; i++) { + dst[i] = ((buf[i*3+2] & 0xFF) << 16 | + (buf[i*3+1] & 0xFF) << 8 | + (buf[i*3] & 0xFF)); + } + } + } + + void readZrlePalette(int[] palette, int palSize) throws Exception { + readPixels(zrleInStream, palette, palSize); + } + + void readZrleRawPixels(int tw, int th) throws Exception { + if (bytesPixel == 1) { + zrleInStream.readBytes(zrleTilePixels8, 0, tw * th); + } else { + readPixels(zrleInStream, zrleTilePixels24, tw * th); /// + } + } + + void readZrlePackedPixels(int tw, int th, int[] palette, int palSize) + throws Exception { + + int bppp = ((palSize > 16) ? 8 : + ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1))); + int ptr = 0; + + for (int i = 0; i < th; i++) { + int eol = ptr + tw; + int b = 0; + int nbits = 0; + + while (ptr < eol) { + if (nbits == 0) { + b = zrleInStream.readU8(); + nbits = 8; + } + nbits -= bppp; + int index = (b >> nbits) & ((1 << bppp) - 1) & 127; + if (bytesPixel == 1) { + zrleTilePixels8[ptr++] = (byte)palette[index]; + } else { + zrleTilePixels24[ptr++] = palette[index]; + } + } + } + } + + void readZrlePlainRLEPixels(int tw, int th) throws Exception { + int ptr = 0; + int end = ptr + tw * th; + while (ptr < end) { + int pix = readPixel(zrleInStream); + int len = 1; + int b; + do { + b = zrleInStream.readU8(); + len += b; + } while (b == 255); + + if (!(len <= end - ptr)) + throw new Exception("ZRLE decoder: assertion failed" + + " (len <= end-ptr)"); + + if (bytesPixel == 1) { + while (len-- > 0) zrleTilePixels8[ptr++] = (byte)pix; + } else { + while (len-- > 0) zrleTilePixels24[ptr++] = pix; + } + } + } + + void readZrlePackedRLEPixels(int tw, int th, int[] palette) + throws Exception { + + int ptr = 0; + int end = ptr + tw * th; + while (ptr < end) { + int index = zrleInStream.readU8(); + int len = 1; + if ((index & 128) != 0) { + int b; + do { + b = zrleInStream.readU8(); + len += b; + } while (b == 255); + + if (!(len <= end - ptr)) + throw new Exception("ZRLE decoder: assertion failed" + + " (len <= end - ptr)"); + } + + index &= 127; + int pix = palette[index]; + + if (bytesPixel == 1) { + while (len-- > 0) zrleTilePixels8[ptr++] = (byte)pix; + } else { + while (len-- > 0) zrleTilePixels24[ptr++] = pix; + } + } + } + + // + // Copy pixels from zrleTilePixels8 or zrleTilePixels24, then update. + // + + void handleUpdatedZrleTile(int x, int y, int w, int h) { + Object src, dst; + if (bytesPixel == 1) { + src = zrleTilePixels8; dst = pixels8; + } else { + src = zrleTilePixels24; dst = pixels24; + } + int offsetSrc = 0; + int offsetDst = (y * rfb.framebufferWidth + x); + for (int j = 0; j < h; j++) { + System.arraycopy(src, offsetSrc, dst, offsetDst, w); + offsetSrc += w; + offsetDst += rfb.framebufferWidth; + } + handleUpdatedPixels(x, y, w, h); + } + + // + // Handle a Zlib-encoded rectangle. + // + + void handleZlibRect(int x, int y, int w, int h) throws Exception { + + int nBytes = rfb.is.readInt(); + + if (zlibBuf == null || zlibBufLen < nBytes) { + zlibBufLen = nBytes * 2; + zlibBuf = new byte[zlibBufLen]; + } + + rfb.readFully(zlibBuf, 0, nBytes); + + if (rfb.rec != null && rfb.recordFromBeginning) { + rfb.rec.writeIntBE(nBytes); + rfb.rec.write(zlibBuf, 0, nBytes); + } + + if (zlibInflater == null) { + zlibInflater = new Inflater(); + } + zlibInflater.setInput(zlibBuf, 0, nBytes); + + if (bytesPixel == 1) { + for (int dy = y; dy < y + h; dy++) { + zlibInflater.inflate(pixels8, dy * rfb.framebufferWidth + x, w); + if (rfb.rec != null && !rfb.recordFromBeginning) + rfb.rec.write(pixels8, dy * rfb.framebufferWidth + x, w); + } + } else { + byte[] buf = new byte[w * 4]; + int i, offset; + for (int dy = y; dy < y + h; dy++) { + zlibInflater.inflate(buf); + offset = dy * rfb.framebufferWidth + x; + for (i = 0; i < w; i++) { + pixels24[offset + i] = + (buf[i * 4 + 2] & 0xFF) << 16 | + (buf[i * 4 + 1] & 0xFF) << 8 | + (buf[i * 4] & 0xFF); + } + if (rfb.rec != null && !rfb.recordFromBeginning) + rfb.rec.write(buf); + } + } + + handleUpdatedPixels(x, y, w, h); + scheduleRepaint(x, y, w, h); + } + + // + // Handle a Tight-encoded rectangle. + // + + void handleTightRect(int x, int y, int w, int h) throws Exception { + + int comp_ctl = rfb.is.readUnsignedByte(); + if (rfb.rec != null) { + if (rfb.recordFromBeginning || + comp_ctl == (rfb.TightFill << 4) || + comp_ctl == (rfb.TightJpeg << 4)) { + // Send data exactly as received. + rfb.rec.writeByte(comp_ctl); + } else { + // Tell the decoder to flush each of the four zlib streams. + rfb.rec.writeByte(comp_ctl | 0x0F); + } + } + + // Flush zlib streams if we are told by the server to do so. + for (int stream_id = 0; stream_id < 4; stream_id++) { + if ((comp_ctl & 1) != 0 && tightInflaters[stream_id] != null) { + tightInflaters[stream_id] = null; + } + comp_ctl >>= 1; + } + + // Check correctness of subencoding value. + if (comp_ctl > rfb.TightMaxSubencoding) { + throw new Exception("Incorrect tight subencoding: " + comp_ctl); + } + + // Handle solid-color rectangles. + if (comp_ctl == rfb.TightFill) { + + if (bytesPixel == 1) { + int idx = rfb.is.readUnsignedByte(); + memGraphics.setColor(colors[idx]); + if (rfb.rec != null) { + rfb.rec.writeByte(idx); + } + } else { + byte[] buf = new byte[3]; + rfb.readFully(buf); + if (rfb.rec != null) { + rfb.rec.write(buf); + } + Color bg = new Color(0xFF000000 | (buf[0] & 0xFF) << 16 | + (buf[1] & 0xFF) << 8 | (buf[2] & 0xFF)); + memGraphics.setColor(bg); + } + memGraphics.fillRect(x, y, w, h); + scheduleRepaint(x, y, w, h); + return; + + } + + if (comp_ctl == rfb.TightJpeg) { + + // Read JPEG data. + byte[] jpegData = new byte[rfb.readCompactLen()]; + rfb.readFully(jpegData); + if (rfb.rec != null) { + if (!rfb.recordFromBeginning) { + rfb.recordCompactLen(jpegData.length); + } + rfb.rec.write(jpegData); + } + + // Create an Image object from the JPEG data. + Image jpegImage = Toolkit.getDefaultToolkit().createImage(jpegData); + + // Remember the rectangle where the image should be drawn. + jpegRect = new Rectangle(x, y, w, h); + + // Let the imageUpdate() method do the actual drawing, here just + // wait until the image is fully loaded and drawn. + synchronized(jpegRect) { + Toolkit.getDefaultToolkit().prepareImage(jpegImage, -1, -1, this); + try { + // Wait no longer than three seconds. + jpegRect.wait(3000); + } catch (InterruptedException e) { + throw new Exception("Interrupted while decoding JPEG image"); + } + } + + // Done, jpegRect is not needed any more. + jpegRect = null; + return; + + } + + // Read filter id and parameters. + int numColors = 0, rowSize = w; + byte[] palette8 = new byte[2]; + int[] palette24 = new int[256]; + boolean useGradient = false; + if ((comp_ctl & rfb.TightExplicitFilter) != 0) { + int filter_id = rfb.is.readUnsignedByte(); + if (rfb.rec != null) { + rfb.rec.writeByte(filter_id); + } + if (filter_id == rfb.TightFilterPalette) { + numColors = rfb.is.readUnsignedByte() + 1; + if (rfb.rec != null) { + rfb.rec.writeByte(numColors - 1); + } + if (bytesPixel == 1) { + if (numColors != 2) { + throw new Exception("Incorrect tight palette size: " + numColors); + } + rfb.readFully(palette8); + if (rfb.rec != null) { + rfb.rec.write(palette8); + } + } else { + byte[] buf = new byte[numColors * 3]; + rfb.readFully(buf); + if (rfb.rec != null) { + rfb.rec.write(buf); + } + for (int i = 0; i < numColors; i++) { + palette24[i] = ((buf[i * 3] & 0xFF) << 16 | + (buf[i * 3 + 1] & 0xFF) << 8 | + (buf[i * 3 + 2] & 0xFF)); + } + } + if (numColors == 2) + rowSize = (w + 7) / 8; + } else if (filter_id == rfb.TightFilterGradient) { + useGradient = true; + } else if (filter_id != rfb.TightFilterCopy) { + throw new Exception("Incorrect tight filter id: " + filter_id); + } + } + if (numColors == 0 && bytesPixel == 4) + rowSize *= 3; + + // Read, optionally uncompress and decode data. + int dataSize = h * rowSize; + if (dataSize < rfb.TightMinToCompress) { + // Data size is small - not compressed with zlib. + if (numColors != 0) { + // Indexed colors. + byte[] indexedData = new byte[dataSize]; + rfb.readFully(indexedData); + if (rfb.rec != null) { + rfb.rec.write(indexedData); + } + if (numColors == 2) { + // Two colors. + if (bytesPixel == 1) { + decodeMonoData(x, y, w, h, indexedData, palette8); + } else { + decodeMonoData(x, y, w, h, indexedData, palette24); + } + } else { + // 3..255 colors (assuming bytesPixel == 4). + int i = 0; + for (int dy = y; dy < y + h; dy++) { + for (int dx = x; dx < x + w; dx++) { + pixels24[dy * rfb.framebufferWidth + dx] = + palette24[indexedData[i++] & 0xFF]; + } + } + } + } else if (useGradient) { + // "Gradient"-processed data + byte[] buf = new byte[w * h * 3]; + rfb.readFully(buf); + if (rfb.rec != null) { + rfb.rec.write(buf); + } + decodeGradientData(x, y, w, h, buf); + } else { + // Raw truecolor data. + if (bytesPixel == 1) { + for (int dy = y; dy < y + h; dy++) { + rfb.readFully(pixels8, dy * rfb.framebufferWidth + x, w); + if (rfb.rec != null) { + rfb.rec.write(pixels8, dy * rfb.framebufferWidth + x, w); + } + } + } else { + byte[] buf = new byte[w * 3]; + int i, offset; + for (int dy = y; dy < y + h; dy++) { + rfb.readFully(buf); + if (rfb.rec != null) { + rfb.rec.write(buf); + } + offset = dy * rfb.framebufferWidth + x; + for (i = 0; i < w; i++) { + pixels24[offset + i] = + (buf[i * 3] & 0xFF) << 16 | + (buf[i * 3 + 1] & 0xFF) << 8 | + (buf[i * 3 + 2] & 0xFF); + } + } + } + } + } else { + // Data was compressed with zlib. + int zlibDataLen = rfb.readCompactLen(); + byte[] zlibData = new byte[zlibDataLen]; + rfb.readFully(zlibData); + if (rfb.rec != null && rfb.recordFromBeginning) { + rfb.rec.write(zlibData); + } + int stream_id = comp_ctl & 0x03; + if (tightInflaters[stream_id] == null) { + tightInflaters[stream_id] = new Inflater(); + } + Inflater myInflater = tightInflaters[stream_id]; + myInflater.setInput(zlibData); + byte[] buf = new byte[dataSize]; + myInflater.inflate(buf); + if (rfb.rec != null && !rfb.recordFromBeginning) { + rfb.recordCompressedData(buf); + } + + if (numColors != 0) { + // Indexed colors. + if (numColors == 2) { + // Two colors. + if (bytesPixel == 1) { + decodeMonoData(x, y, w, h, buf, palette8); + } else { + decodeMonoData(x, y, w, h, buf, palette24); + } + } else { + // More than two colors (assuming bytesPixel == 4). + int i = 0; + for (int dy = y; dy < y + h; dy++) { + for (int dx = x; dx < x + w; dx++) { + pixels24[dy * rfb.framebufferWidth + dx] = + palette24[buf[i++] & 0xFF]; + } + } + } + } else if (useGradient) { + // Compressed "Gradient"-filtered data (assuming bytesPixel == 4). + decodeGradientData(x, y, w, h, buf); + } else { + // Compressed truecolor data. + if (bytesPixel == 1) { + int destOffset = y * rfb.framebufferWidth + x; + for (int dy = 0; dy < h; dy++) { + System.arraycopy(buf, dy * w, pixels8, destOffset, w); + destOffset += rfb.framebufferWidth; + } + } else { + int srcOffset = 0; + int destOffset, i; + for (int dy = 0; dy < h; dy++) { + myInflater.inflate(buf); + destOffset = (y + dy) * rfb.framebufferWidth + x; + for (i = 0; i < w; i++) { + pixels24[destOffset + i] = + (buf[srcOffset] & 0xFF) << 16 | + (buf[srcOffset + 1] & 0xFF) << 8 | + (buf[srcOffset + 2] & 0xFF); + srcOffset += 3; + } + } + } + } + } + + handleUpdatedPixels(x, y, w, h); + scheduleRepaint(x, y, w, h); + } + + // + // Decode 1bpp-encoded bi-color rectangle (8-bit and 24-bit versions). + // + + void decodeMonoData(int x, int y, int w, int h, byte[] src, byte[] palette) { + + int dx, dy, n; + int i = y * rfb.framebufferWidth + x; + int rowBytes = (w + 7) / 8; + byte b; + + for (dy = 0; dy < h; dy++) { + for (dx = 0; dx < w / 8; dx++) { + b = src[dy*rowBytes+dx]; + for (n = 7; n >= 0; n--) + pixels8[i++] = palette[b >> n & 1]; + } + for (n = 7; n >= 8 - w % 8; n--) { + pixels8[i++] = palette[src[dy*rowBytes+dx] >> n & 1]; + } + i += (rfb.framebufferWidth - w); + } + } + + void decodeMonoData(int x, int y, int w, int h, byte[] src, int[] palette) { + + int dx, dy, n; + int i = y * rfb.framebufferWidth + x; + int rowBytes = (w + 7) / 8; + byte b; + + for (dy = 0; dy < h; dy++) { + for (dx = 0; dx < w / 8; dx++) { + b = src[dy*rowBytes+dx]; + for (n = 7; n >= 0; n--) + pixels24[i++] = palette[b >> n & 1]; + } + for (n = 7; n >= 8 - w % 8; n--) { + pixels24[i++] = palette[src[dy*rowBytes+dx] >> n & 1]; + } + i += (rfb.framebufferWidth - w); + } + } + + // + // Decode data processed with the "Gradient" filter. + // + + void decodeGradientData (int x, int y, int w, int h, byte[] buf) { + + int dx, dy, c; + byte[] prevRow = new byte[w * 3]; + byte[] thisRow = new byte[w * 3]; + byte[] pix = new byte[3]; + int[] est = new int[3]; + + int offset = y * rfb.framebufferWidth + x; + + for (dy = 0; dy < h; dy++) { + + /* First pixel in a row */ + for (c = 0; c < 3; c++) { + pix[c] = (byte)(prevRow[c] + buf[dy * w * 3 + c]); + thisRow[c] = pix[c]; + } + pixels24[offset++] = + (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF); + + /* Remaining pixels of a row */ + for (dx = 1; dx < w; dx++) { + for (c = 0; c < 3; c++) { + est[c] = ((prevRow[dx * 3 + c] & 0xFF) + (pix[c] & 0xFF) - + (prevRow[(dx-1) * 3 + c] & 0xFF)); + if (est[c] > 0xFF) { + est[c] = 0xFF; + } else if (est[c] < 0x00) { + est[c] = 0x00; + } + pix[c] = (byte)(est[c] + buf[(dy * w + dx) * 3 + c]); + thisRow[dx * 3 + c] = pix[c]; + } + pixels24[offset++] = + (pix[0] & 0xFF) << 16 | (pix[1] & 0xFF) << 8 | (pix[2] & 0xFF); + } + + System.arraycopy(thisRow, 0, prevRow, 0, w * 3); + offset += (rfb.framebufferWidth - w); + } + } + + // + // Display newly updated area of pixels. + // + + void handleUpdatedPixels(int x, int y, int w, int h) { + + // Draw updated pixels of the off-screen image. + pixelsSource.newPixels(x, y, w, h); + memGraphics.setClip(x, y, w, h); + memGraphics.drawImage(rawPixelsImage, 0, 0, null); + memGraphics.setClip(0, 0, rfb.framebufferWidth, rfb.framebufferHeight); + } + + // + // Tell JVM to repaint specified desktop area. + // + + void scheduleRepaint(int x, int y, int w, int h) { + // Request repaint, deferred if necessary. + if (rfb.framebufferWidth == scaledWidth) { + repaint(viewer.deferScreenUpdates, x, y, w, h); + } else { + int sx = x * scalingFactor / 100; + int sy = y * scalingFactor / 100; + int sw = ((x + w) * scalingFactor + 49) / 100 - sx + 1; + int sh = ((y + h) * scalingFactor + 49) / 100 - sy + 1; + repaint(viewer.deferScreenUpdates, sx, sy, sw, sh); + } + } + + // + // Handle events. + // + + public void keyPressed(KeyEvent evt) { + processLocalKeyEvent(evt); + } + public void keyReleased(KeyEvent evt) { + processLocalKeyEvent(evt); + } + public void keyTyped(KeyEvent evt) { + evt.consume(); + } + + public void mousePressed(MouseEvent evt) { + processLocalMouseEvent(evt, false); + } + public void mouseReleased(MouseEvent evt) { + processLocalMouseEvent(evt, false); + } + public void mouseMoved(MouseEvent evt) { + processLocalMouseEvent(evt, true); + } + public void mouseDragged(MouseEvent evt) { + processLocalMouseEvent(evt, true); + } + + public void processLocalKeyEvent(KeyEvent evt) { + if (viewer.rfb != null && rfb.inNormalProtocol) { + if (!inputEnabled) { + if ((evt.getKeyChar() == 'r' || evt.getKeyChar() == 'R') && + evt.getID() == KeyEvent.KEY_PRESSED ) { + // Request screen update. + try { + rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth, + rfb.framebufferHeight, false); + } catch (IOException e) { + e.printStackTrace(); + } + } + } else { + // Input enabled. + synchronized(rfb) { + try { + rfb.writeKeyEvent(evt); + } catch (Exception e) { + e.printStackTrace(); + } + rfb.notify(); + } + } + } + // Don't ever pass keyboard events to AWT for default processing. + // Otherwise, pressing Tab would switch focus to ButtonPanel etc. + evt.consume(); + } + + public void processLocalMouseEvent(MouseEvent evt, boolean moved) { + if (viewer.rfb != null && rfb.inNormalProtocol) { + if (moved) { + softCursorMove(evt.getX(), evt.getY()); + } + if (rfb.framebufferWidth != scaledWidth) { + int sx = (evt.getX() * 100 + scalingFactor/2) / scalingFactor; + int sy = (evt.getY() * 100 + scalingFactor/2) / scalingFactor; + evt.translatePoint(sx - evt.getX(), sy - evt.getY()); + } + synchronized(rfb) { + try { + rfb.writePointerEvent(evt); + } catch (Exception e) { + e.printStackTrace(); + } + rfb.notify(); + } + } + } + + // + // Ignored events. + // + + public void mouseClicked(MouseEvent evt) {} + public void mouseEntered(MouseEvent evt) {} + public void mouseExited(MouseEvent evt) {} + + + ////////////////////////////////////////////////////////////////// + // + // Handle cursor shape updates (XCursor and RichCursor encodings). + // + + boolean showSoftCursor = false; + + MemoryImageSource softCursorSource; + Image softCursor; + + int cursorX = 0, cursorY = 0; + int cursorWidth, cursorHeight; + int origCursorWidth, origCursorHeight; + int hotX, hotY; + int origHotX, origHotY; + + // + // Handle cursor shape update (XCursor and RichCursor encodings). + // + + synchronized void + handleCursorShapeUpdate(int encodingType, + int xhot, int yhot, int width, int height) + throws IOException { + + softCursorFree(); + + if (width * height == 0) + return; + + // Ignore cursor shape data if requested by user. + if (viewer.options.ignoreCursorUpdates) { + int bytesPerRow = (width + 7) / 8; + int bytesMaskData = bytesPerRow * height; + + if (encodingType == rfb.EncodingXCursor) { + rfb.is.skipBytes(6 + bytesMaskData * 2); + } else { + // rfb.EncodingRichCursor + rfb.is.skipBytes(width * height + bytesMaskData); + } + return; + } + + // Decode cursor pixel data. + softCursorSource = decodeCursorShape(encodingType, width, height); + + // Set original (non-scaled) cursor dimensions. + origCursorWidth = width; + origCursorHeight = height; + origHotX = xhot; + origHotY = yhot; + + // Create off-screen cursor image. + createSoftCursor(); + + // Show the cursor. + showSoftCursor = true; + repaint(viewer.deferCursorUpdates, + cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight); + } + + // + // decodeCursorShape(). Decode cursor pixel data and return + // corresponding MemoryImageSource instance. + // + + synchronized MemoryImageSource + decodeCursorShape(int encodingType, int width, int height) + throws IOException { + + int bytesPerRow = (width + 7) / 8; + int bytesMaskData = bytesPerRow * height; + + int[] softCursorPixels = new int[width * height]; + + if (encodingType == rfb.EncodingXCursor) { + + // Read foreground and background colors of the cursor. + byte[] rgb = new byte[6]; + rfb.readFully(rgb); + int[] colors = { (0xFF000000 | (rgb[3] & 0xFF) << 16 | + (rgb[4] & 0xFF) << 8 | (rgb[5] & 0xFF)), + (0xFF000000 | (rgb[0] & 0xFF) << 16 | + (rgb[1] & 0xFF) << 8 | (rgb[2] & 0xFF)) }; + + // Read pixel and mask data. + byte[] pixBuf = new byte[bytesMaskData]; + rfb.readFully(pixBuf); + byte[] maskBuf = new byte[bytesMaskData]; + rfb.readFully(maskBuf); + + // Decode pixel data into softCursorPixels[]. + byte pixByte, maskByte; + int x, y, n, result; + int i = 0; + for (y = 0; y < height; y++) { + for (x = 0; x < width / 8; x++) { + pixByte = pixBuf[y * bytesPerRow + x]; + maskByte = maskBuf[y * bytesPerRow + x]; + for (n = 7; n >= 0; n--) { + if ((maskByte >> n & 1) != 0) { + result = colors[pixByte >> n & 1]; + } else { + result = 0; // Transparent pixel + } + softCursorPixels[i++] = result; + } + } + for (n = 7; n >= 8 - width % 8; n--) { + if ((maskBuf[y * bytesPerRow + x] >> n & 1) != 0) { + result = colors[pixBuf[y * bytesPerRow + x] >> n & 1]; + } else { + result = 0; // Transparent pixel + } + softCursorPixels[i++] = result; + } + } + + } else { + // encodingType == rfb.EncodingRichCursor + + // Read pixel and mask data. + byte[] pixBuf = new byte[width * height * bytesPixel]; + rfb.readFully(pixBuf); + byte[] maskBuf = new byte[bytesMaskData]; + rfb.readFully(maskBuf); + + // Decode pixel data into softCursorPixels[]. + byte pixByte, maskByte; + int x, y, n, result; + int i = 0; + for (y = 0; y < height; y++) { + for (x = 0; x < width / 8; x++) { + maskByte = maskBuf[y * bytesPerRow + x]; + for (n = 7; n >= 0; n--) { + if ((maskByte >> n & 1) != 0) { + if (bytesPixel == 1) { + result = cm8.getRGB(pixBuf[i]); + } else { + result = 0xFF000000 | + (pixBuf[i * 4 + 2] & 0xFF) << 16 | + (pixBuf[i * 4 + 1] & 0xFF) << 8 | + (pixBuf[i * 4] & 0xFF); + } + } else { + result = 0; // Transparent pixel + } + softCursorPixels[i++] = result; + } + } + for (n = 7; n >= 8 - width % 8; n--) { + if ((maskBuf[y * bytesPerRow + x] >> n & 1) != 0) { + if (bytesPixel == 1) { + result = cm8.getRGB(pixBuf[i]); + } else { + result = 0xFF000000 | + (pixBuf[i * 4 + 2] & 0xFF) << 16 | + (pixBuf[i * 4 + 1] & 0xFF) << 8 | + (pixBuf[i * 4] & 0xFF); + } + } else { + result = 0; // Transparent pixel + } + softCursorPixels[i++] = result; + } + } + + } + + return new MemoryImageSource(width, height, softCursorPixels, 0, width); + } + + // + // createSoftCursor(). Assign softCursor new Image (scaled if necessary). + // Uses softCursorSource as a source for new cursor image. + // + + synchronized void + createSoftCursor() { + + if (softCursorSource == null) + return; + + int scaleCursor = viewer.options.scaleCursor; + if (scaleCursor == 0 || !inputEnabled) + scaleCursor = 100; + + // Save original cursor coordinates. + int x = cursorX - hotX; + int y = cursorY - hotY; + int w = cursorWidth; + int h = cursorHeight; + + cursorWidth = (origCursorWidth * scaleCursor + 50) / 100; + cursorHeight = (origCursorHeight * scaleCursor + 50) / 100; + hotX = (origHotX * scaleCursor + 50) / 100; + hotY = (origHotY * scaleCursor + 50) / 100; + softCursor = Toolkit.getDefaultToolkit().createImage(softCursorSource); + + if (scaleCursor != 100) { + softCursor = softCursor.getScaledInstance(cursorWidth, cursorHeight, + Image.SCALE_SMOOTH); + } + + if (showSoftCursor) { + // Compute screen area to update. + x = Math.min(x, cursorX - hotX); + y = Math.min(y, cursorY - hotY); + w = Math.max(w, cursorWidth); + h = Math.max(h, cursorHeight); + + repaint(viewer.deferCursorUpdates, x, y, w, h); + } + } + + // + // softCursorMove(). Moves soft cursor into a particular location. + // + + synchronized void softCursorMove(int x, int y) { + int oldX = cursorX; + int oldY = cursorY; + cursorX = x; + cursorY = y; + if (showSoftCursor) { + repaint(viewer.deferCursorUpdates, + oldX - hotX, oldY - hotY, cursorWidth, cursorHeight); + repaint(viewer.deferCursorUpdates, + cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight); + } + } + + // + // softCursorFree(). Remove soft cursor, dispose resources. + // + + synchronized void softCursorFree() { + if (showSoftCursor) { + showSoftCursor = false; + softCursor = null; + softCursorSource = null; + + repaint(viewer.deferCursorUpdates, + cursorX - hotX, cursorY - hotY, cursorWidth, cursorHeight); + } + } +} diff --git a/VncCanvas2.java b/VncCanvas2.java new file mode 100644 index 0000000..34c57f7 --- /dev/null +++ b/VncCanvas2.java @@ -0,0 +1,63 @@ +// +// Copyright (C) 2006 Constantin Kaplinsky. 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. +// + +import java.awt.*; +import java.io.*; + +// +// VncCanvas2 is a special version of VncCanvas which may use Java 2 API. +// + +class VncCanvas2 extends VncCanvas { + + public VncCanvas2(VncViewer v) throws IOException { + super(v); + disableFocusTraversalKeys(); + } + + public VncCanvas2(VncViewer v, int maxWidth_, int maxHeight_) + throws IOException { + + super(v, maxWidth_, maxHeight_); + disableFocusTraversalKeys(); + } + + public void paintScaledFrameBuffer(Graphics g) { + Graphics2D g2d = (Graphics2D)g; + g2d.setRenderingHint(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + g2d.drawImage(memImage, 0, 0, scaledWidth, scaledHeight, null); + } + + // + // Try to disable focus traversal keys (JVMs 1.4 and higher). + // + + private void disableFocusTraversalKeys() { + try { + Class[] argClasses = { Boolean.TYPE }; + java.lang.reflect.Method method = + getClass().getMethod("setFocusTraversalKeysEnabled", argClasses); + Object[] argObjects = { new Boolean(false) }; + method.invoke(this, argObjects); + } catch (Exception e) {} + } + +} + diff --git a/VncViewer.java b/VncViewer.java new file mode 100644 index 0000000..824f7eb --- /dev/null +++ b/VncViewer.java @@ -0,0 +1,972 @@ +// +// Copyright (C) 2001-2004 HorizonLive.com, Inc. All Rights Reserved. +// Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved. +// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. +// +// This is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this software; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. +// + +// +// VncViewer.java - the VNC viewer applet. This class mainly just sets up the +// user interface, leaving it to the VncCanvas to do the actual rendering of +// a VNC desktop. +// + +import java.awt.*; +import java.awt.event.*; +import java.io.*; +import java.net.*; + +public class VncViewer extends java.applet.Applet + implements java.lang.Runnable, WindowListener { + + boolean inAnApplet = true; + boolean inSeparateFrame = false; + + // + // main() is called when run as a java program from the command line. + // It simply runs the applet inside a newly-created frame. + // + + public static void main(String[] argv) { + VncViewer v = new VncViewer(); + v.mainArgs = argv; + v.inAnApplet = false; + v.inSeparateFrame = true; + + v.init(); + v.start(); + } + + String[] mainArgs; + + RfbProto rfb; + Thread rfbThread; + + Frame vncFrame; + Container vncContainer; + ScrollPane desktopScrollPane; + GridBagLayout gridbag; + ButtonPanel buttonPanel; + Label connStatusLabel; + VncCanvas vc; + OptionsFrame options; + ClipboardFrame clipboard; + RecordingFrame rec; + + // Control session recording. + Object recordingSync; + String sessionFileName; + boolean recordingActive; + boolean recordingStatusChanged; + String cursorUpdatesDef; + String eightBitColorsDef; + + // Variables read from parameter values. + String socketFactory; + String host; + int port; + String passwordParam; + boolean showControls; + boolean offerRelogin; + boolean showOfflineDesktop; + int deferScreenUpdates; + int deferCursorUpdates; + int deferUpdateRequests; + + // Reference to this applet for inter-applet communication. + public static java.applet.Applet refApplet; + + // + // init() + // + + public void init() { + + readParameters(); + + refApplet = this; + + if (inSeparateFrame) { + vncFrame = new Frame("TightVNC"); + if (!inAnApplet) { + vncFrame.add("Center", this); + } + vncContainer = vncFrame; + } else { + vncContainer = this; + } + + recordingSync = new Object(); + + options = new OptionsFrame(this); + clipboard = new ClipboardFrame(this); + if (RecordingFrame.checkSecurity()) + rec = new RecordingFrame(this); + + sessionFileName = null; + recordingActive = false; + recordingStatusChanged = false; + cursorUpdatesDef = null; + eightBitColorsDef = null; + + if (inSeparateFrame) + vncFrame.addWindowListener(this); + + rfbThread = new Thread(this); + rfbThread.start(); + } + + public void update(Graphics g) { + } + + // + // run() - executed by the rfbThread to deal with the RFB socket. + // + + public void run() { + + gridbag = new GridBagLayout(); + vncContainer.setLayout(gridbag); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.anchor = GridBagConstraints.NORTHWEST; + + if (showControls) { + buttonPanel = new ButtonPanel(this); + gridbag.setConstraints(buttonPanel, gbc); + vncContainer.add(buttonPanel); + } + + try { + connectAndAuthenticate(); + doProtocolInitialisation(); + + // FIXME: Use auto-scaling not only in a separate frame. + if (options.autoScale && inSeparateFrame) { + Dimension screenSize; + try { + screenSize = vncContainer.getToolkit().getScreenSize(); + } catch (Exception e) { + screenSize = new Dimension(0, 0); + } + createCanvas(screenSize.width - 32, screenSize.height - 32); + } else { + createCanvas(0, 0); + } + + gbc.weightx = 1.0; + gbc.weighty = 1.0; + + if (inSeparateFrame) { + + // Create a panel which itself is resizeable and can hold + // non-resizeable VncCanvas component at the top left corner. + Panel canvasPanel = new Panel(); + canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); + canvasPanel.add(vc); + + // Create a ScrollPane which will hold a panel with VncCanvas + // inside. + desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED); + gbc.fill = GridBagConstraints.BOTH; + gridbag.setConstraints(desktopScrollPane, gbc); + desktopScrollPane.add(canvasPanel); + + // Finally, add our ScrollPane to the Frame window. + vncFrame.add(desktopScrollPane); + vncFrame.setTitle(rfb.desktopName); + vncFrame.pack(); + vc.resizeDesktopFrame(); + + } else { + + // Just add the VncCanvas component to the Applet. + gridbag.setConstraints(vc, gbc); + add(vc); + validate(); + + } + + if (showControls) + buttonPanel.enableButtons(); + + moveFocusToDesktop(); + processNormalProtocol(); + + } catch (NoRouteToHostException e) { + fatalError("Network error: no route to server: " + host, e); + } catch (UnknownHostException e) { + fatalError("Network error: server name unknown: " + host, e); + } catch (ConnectException e) { + fatalError("Network error: could not connect to server: " + + host + ":" + port, e); + } catch (EOFException e) { + if (showOfflineDesktop) { + e.printStackTrace(); + System.out.println("Network error: remote side closed connection"); + if (vc != null) { + vc.enableInput(false); + } + if (inSeparateFrame) { + vncFrame.setTitle(rfb.desktopName + " [disconnected]"); + } + if (rfb != null && !rfb.closed()) + rfb.close(); + if (showControls && buttonPanel != null) { + buttonPanel.disableButtonsOnDisconnect(); + if (inSeparateFrame) { + vncFrame.pack(); + } else { + validate(); + } + } + } else { + fatalError("Network error: remote side closed connection", e); + } + } catch (IOException e) { + String str = e.getMessage(); + if (str != null && str.length() != 0) { + fatalError("Network Error: " + str, e); + } else { + fatalError(e.toString(), e); + } + } catch (Exception e) { + String str = e.getMessage(); + if (str != null && str.length() != 0) { + fatalError("Error: " + str, e); + } else { + fatalError(e.toString(), e); + } + } + + } + + // + // Create a VncCanvas instance. + // + + void createCanvas(int maxWidth, int maxHeight) throws IOException { + // Determine if Java 2D API is available and use a special + // version of VncCanvas if it is present. + vc = null; + try { + // This throws ClassNotFoundException if there is no Java 2D API. + Class cl = Class.forName("java.awt.Graphics2D"); + // If we could load Graphics2D class, then we can use VncCanvas2D. + cl = Class.forName("VncCanvas2"); + Class[] argClasses = { this.getClass(), Integer.TYPE, Integer.TYPE }; + java.lang.reflect.Constructor cstr = cl.getConstructor(argClasses); + Object[] argObjects = + { this, new Integer(maxWidth), new Integer(maxHeight) }; + vc = (VncCanvas)cstr.newInstance(argObjects); + } catch (Exception e) { + System.out.println("Warning: Java 2D API is not available"); + } + + // If we failed to create VncCanvas2D, use old VncCanvas. + if (vc == null) + vc = new VncCanvas(this, maxWidth, maxHeight); + } + + + // + // Process RFB socket messages. + // If the rfbThread is being stopped, ignore any exceptions, + // otherwise rethrow the exception so it can be handled. + // + + void processNormalProtocol() throws Exception { + try { + vc.processNormalProtocol(); + } catch (Exception e) { + if (rfbThread == null) { + System.out.println("Ignoring RFB socket exceptions" + + " because applet is stopping"); + } else { + throw e; + } + } + } + + + // + // Connect to the RFB server and authenticate the user. + // + + void connectAndAuthenticate() throws Exception + { + showConnectionStatus("Initializing..."); + if (inSeparateFrame) { + vncFrame.pack(); + vncFrame.show(); + } else { + validate(); + } + + showConnectionStatus("Connecting to " + host + ", port " + port + "..."); + + rfb = new RfbProto(host, port, this); + showConnectionStatus("Connected to server"); + + rfb.readVersionMsg(); + showConnectionStatus("RFB server supports protocol version " + + rfb.serverMajor + "." + rfb.serverMinor); + + rfb.writeVersionMsg(); + showConnectionStatus("Using RFB protocol version " + + rfb.clientMajor + "." + rfb.clientMinor); + + int secType = rfb.negotiateSecurity(); + int authType; + if (secType == RfbProto.SecTypeTight) { + showConnectionStatus("Enabling TightVNC protocol extensions"); + rfb.initCapabilities(); + rfb.setupTunneling(); + authType = rfb.negotiateAuthenticationTight(); + } else { + authType = secType; + } + + switch (authType) { + case RfbProto.AuthNone: + showConnectionStatus("No authentication needed"); + rfb.authenticateNone(); + break; + case RfbProto.AuthVNC: + showConnectionStatus("Performing standard VNC authentication"); + if (passwordParam != null) { + rfb.authenticateVNC(passwordParam); + } else { + String pw = askPassword(); + rfb.authenticateVNC(pw); + } + break; + default: + throw new Exception("Unknown authentication scheme " + authType); + } + } + + + // + // Show a message describing the connection status. + // To hide the connection status label, use (msg == null). + // + + void showConnectionStatus(String msg) + { + if (msg == null) { + if (vncContainer.isAncestorOf(connStatusLabel)) { + vncContainer.remove(connStatusLabel); + } + return; + } + + System.out.println(msg); + + if (connStatusLabel == null) { + connStatusLabel = new Label("Status: " + msg); + connStatusLabel.setFont(new Font("Helvetica", Font.PLAIN, 12)); + } else { + connStatusLabel.setText("Status: " + msg); + } + + if (!vncContainer.isAncestorOf(connStatusLabel)) { + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.anchor = GridBagConstraints.NORTHWEST; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.insets = new Insets(20, 30, 20, 30); + gridbag.setConstraints(connStatusLabel, gbc); + vncContainer.add(connStatusLabel); + } + + if (inSeparateFrame) { + vncFrame.pack(); + } else { + validate(); + } + } + + + // + // Show an authentication panel. + // + + String askPassword() throws Exception + { + showConnectionStatus(null); + + AuthPanel authPanel = new AuthPanel(this); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.anchor = GridBagConstraints.NORTHWEST; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.ipadx = 100; + gbc.ipady = 50; + gridbag.setConstraints(authPanel, gbc); + vncContainer.add(authPanel); + + if (inSeparateFrame) { + vncFrame.pack(); + } else { + validate(); + } + + authPanel.moveFocusToDefaultField(); + String pw = authPanel.getPassword(); + vncContainer.remove(authPanel); + + return pw; + } + + + // + // Do the rest of the protocol initialisation. + // + + void doProtocolInitialisation() throws IOException + { + rfb.writeClientInit(); + rfb.readServerInit(); + + System.out.println("Desktop name is " + rfb.desktopName); + System.out.println("Desktop size is " + rfb.framebufferWidth + " x " + + rfb.framebufferHeight); + + setEncodings(); + + showConnectionStatus(null); + } + + + // + // Send current encoding list to the RFB server. + // + + int[] encodingsSaved; + int nEncodingsSaved; + + void setEncodings() { setEncodings(false); } + void autoSelectEncodings() { setEncodings(true); } + + void setEncodings(boolean autoSelectOnly) { + if (options == null || rfb == null || !rfb.inNormalProtocol) + return; + + int preferredEncoding = options.preferredEncoding; + if (preferredEncoding == -1) { + long kbitsPerSecond = rfb.kbitsPerSecond(); + if (nEncodingsSaved < 1) { + // Choose Tight or ZRLE encoding for the very first update. + System.out.println("Using Tight/ZRLE encodings"); + preferredEncoding = RfbProto.EncodingTight; + } else if (kbitsPerSecond > 2000 && + encodingsSaved[0] != RfbProto.EncodingHextile) { + // Switch to Hextile if the connection speed is above 2Mbps. + System.out.println("Throughput " + kbitsPerSecond + + " kbit/s - changing to Hextile encoding"); + preferredEncoding = RfbProto.EncodingHextile; + } else if (kbitsPerSecond < 1000 && + encodingsSaved[0] != RfbProto.EncodingTight) { + // Switch to Tight/ZRLE if the connection speed is below 1Mbps. + System.out.println("Throughput " + kbitsPerSecond + + " kbit/s - changing to Tight/ZRLE encodings"); + preferredEncoding = RfbProto.EncodingTight; + } else { + // Don't change the encoder. + if (autoSelectOnly) + return; + preferredEncoding = encodingsSaved[0]; + } + } else { + // Auto encoder selection is not enabled. + if (autoSelectOnly) + return; + } + + int[] encodings = new int[20]; + int nEncodings = 0; + + encodings[nEncodings++] = preferredEncoding; + if (options.useCopyRect) { + encodings[nEncodings++] = RfbProto.EncodingCopyRect; + } + + if (preferredEncoding != RfbProto.EncodingTight) { + encodings[nEncodings++] = RfbProto.EncodingTight; + } + if (preferredEncoding != RfbProto.EncodingZRLE) { + encodings[nEncodings++] = RfbProto.EncodingZRLE; + } + if (preferredEncoding != RfbProto.EncodingHextile) { + encodings[nEncodings++] = RfbProto.EncodingHextile; + } + if (preferredEncoding != RfbProto.EncodingZlib) { + encodings[nEncodings++] = RfbProto.EncodingZlib; + } + if (preferredEncoding != RfbProto.EncodingCoRRE) { + encodings[nEncodings++] = RfbProto.EncodingCoRRE; + } + if (preferredEncoding != RfbProto.EncodingRRE) { + encodings[nEncodings++] = RfbProto.EncodingRRE; + } + + if (options.compressLevel >= 0 && options.compressLevel <= 9) { + encodings[nEncodings++] = + RfbProto.EncodingCompressLevel0 + options.compressLevel; + } + if (options.jpegQuality >= 0 && options.jpegQuality <= 9) { + encodings[nEncodings++] = + RfbProto.EncodingQualityLevel0 + options.jpegQuality; + } + + if (options.requestCursorUpdates) { + encodings[nEncodings++] = RfbProto.EncodingXCursor; + encodings[nEncodings++] = RfbProto.EncodingRichCursor; + if (!options.ignoreCursorUpdates) + encodings[nEncodings++] = RfbProto.EncodingPointerPos; + } + + encodings[nEncodings++] = RfbProto.EncodingLastRect; + encodings[nEncodings++] = RfbProto.EncodingNewFBSize; + + boolean encodingsWereChanged = false; + if (nEncodings != nEncodingsSaved) { + encodingsWereChanged = true; + } else { + for (int i = 0; i < nEncodings; i++) { + if (encodings[i] != encodingsSaved[i]) { + encodingsWereChanged = true; + break; + } + } + } + + if (encodingsWereChanged) { + try { + rfb.writeSetEncodings(encodings, nEncodings); + if (vc != null) { + vc.softCursorFree(); + } + } catch (Exception e) { + e.printStackTrace(); + } + encodingsSaved = encodings; + nEncodingsSaved = nEncodings; + } + } + + + // + // setCutText() - send the given cut text to the RFB server. + // + + void setCutText(String text) { + try { + if (rfb != null && rfb.inNormalProtocol) { + rfb.writeClientCutText(text); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + + // + // Order change in session recording status. To stop recording, pass + // null in place of the fname argument. + // + + void setRecordingStatus(String fname) { + synchronized(recordingSync) { + sessionFileName = fname; + recordingStatusChanged = true; + } + } + + // + // Start or stop session recording. Returns true if this method call + // causes recording of a new session. + // + + boolean checkRecordingStatus() throws IOException { + synchronized(recordingSync) { + if (recordingStatusChanged) { + recordingStatusChanged = false; + if (sessionFileName != null) { + startRecording(); + return true; + } else { + stopRecording(); + } + } + } + return false; + } + + // + // Start session recording. + // + + protected void startRecording() throws IOException { + synchronized(recordingSync) { + if (!recordingActive) { + // Save settings to restore them after recording the session. + cursorUpdatesDef = + options.choices[options.cursorUpdatesIndex].getSelectedItem(); + eightBitColorsDef = + options.choices[options.eightBitColorsIndex].getSelectedItem(); + // Set options to values suitable for recording. + options.choices[options.cursorUpdatesIndex].select("Disable"); + options.choices[options.cursorUpdatesIndex].setEnabled(false); + options.setEncodings(); + options.choices[options.eightBitColorsIndex].select("No"); + options.choices[options.eightBitColorsIndex].setEnabled(false); + options.setColorFormat(); + } else { + rfb.closeSession(); + } + + System.out.println("Recording the session in " + sessionFileName); + rfb.startSession(sessionFileName); + recordingActive = true; + } + } + + // + // Stop session recording. + // + + protected void stopRecording() throws IOException { + synchronized(recordingSync) { + if (recordingActive) { + // Restore options. + options.choices[options.cursorUpdatesIndex].select(cursorUpdatesDef); + options.choices[options.cursorUpdatesIndex].setEnabled(true); + options.setEncodings(); + options.choices[options.eightBitColorsIndex].select(eightBitColorsDef); + options.choices[options.eightBitColorsIndex].setEnabled(true); + options.setColorFormat(); + + rfb.closeSession(); + System.out.println("Session recording stopped."); + } + sessionFileName = null; + recordingActive = false; + } + } + + + // + // readParameters() - read parameters from the html source or from the + // command line. On the command line, the arguments are just a sequence of + // param_name/param_value pairs where the names and values correspond to + // those expected in the html applet tag source. + // + + void readParameters() { + host = readParameter("HOST", !inAnApplet); + if (host == null) { + host = getCodeBase().getHost(); + if (host.equals("")) { + fatalError("HOST parameter not specified"); + } + } + + String str = readParameter("PORT", true); + port = Integer.parseInt(str); + + // Read "ENCPASSWORD" or "PASSWORD" parameter if specified. + readPasswordParameters(); + + if (inAnApplet) { + str = readParameter("Open New Window", false); + if (str != null && str.equalsIgnoreCase("Yes")) + inSeparateFrame = true; + } + + // "Show Controls" set to "No" disables button panel. + showControls = true; + str = readParameter("Show Controls", false); + if (str != null && str.equalsIgnoreCase("No")) + showControls = false; + + // "Offer Relogin" set to "No" disables "Login again" and "Close + // window" buttons under error messages in applet mode. + offerRelogin = true; + str = readParameter("Offer Relogin", false); + if (str != null && str.equalsIgnoreCase("No")) + offerRelogin = false; + + // Do we continue showing desktop on remote disconnect? + showOfflineDesktop = false; + str = readParameter("Show Offline Desktop", false); + if (str != null && str.equalsIgnoreCase("Yes")) + showOfflineDesktop = true; + + // Fine tuning options. + deferScreenUpdates = readIntParameter("Defer screen updates", 20); + deferCursorUpdates = readIntParameter("Defer cursor updates", 10); + deferUpdateRequests = readIntParameter("Defer update requests", 50); + + // SocketFactory. + socketFactory = readParameter("SocketFactory", false); + } + + // + // Read password parameters. If an "ENCPASSWORD" parameter is set, + // then decrypt the password into the passwordParam string. Otherwise, + // try to read the "PASSWORD" parameter directly to passwordParam. + // + + private void readPasswordParameters() { + String encPasswordParam = readParameter("ENCPASSWORD", false); + if (encPasswordParam == null) { + passwordParam = readParameter("PASSWORD", false); + } else { + // ENCPASSWORD is hexascii-encoded. Decode. + byte[] pw = {0, 0, 0, 0, 0, 0, 0, 0}; + int len = encPasswordParam.length() / 2; + if (len > 8) + len = 8; + for (int i = 0; i < len; i++) { + String hex = encPasswordParam.substring(i*2, i*2+2); + Integer x = new Integer(Integer.parseInt(hex, 16)); + pw[i] = x.byteValue(); + } + // Decrypt the password. + byte[] key = {23, 82, 107, 6, 35, 78, 88, 7}; + DesCipher des = new DesCipher(key); + des.decrypt(pw, 0, pw, 0); + passwordParam = new String(pw); + } + } + + public String readParameter(String name, boolean required) { + if (inAnApplet) { + String s = getParameter(name); + if ((s == null) && required) { + fatalError(name + " parameter not specified"); + } + return s; + } + + for (int i = 0; i < mainArgs.length; i += 2) { + if (mainArgs[i].equalsIgnoreCase(name)) { + try { + return mainArgs[i+1]; + } catch (Exception e) { + if (required) { + fatalError(name + " parameter not specified"); + } + return null; + } + } + } + if (required) { + fatalError(name + " parameter not specified"); + } + return null; + } + + int readIntParameter(String name, int defaultValue) { + String str = readParameter(name, false); + int result = defaultValue; + if (str != null) { + try { + result = Integer.parseInt(str); + } catch (NumberFormatException e) { } + } + return result; + } + + // + // moveFocusToDesktop() - move keyboard focus either to VncCanvas. + // + + void moveFocusToDesktop() { + if (vncContainer != null) { + if (vc != null && vncContainer.isAncestorOf(vc)) + vc.requestFocus(); + } + } + + // + // disconnect() - close connection to server. + // + + synchronized public void disconnect() { + System.out.println("Disconnect"); + + if (rfb != null && !rfb.closed()) + rfb.close(); + options.dispose(); + clipboard.dispose(); + if (rec != null) + rec.dispose(); + + if (inAnApplet) { + showMessage("Disconnected"); + } else { + System.exit(0); + } + } + + // + // fatalError() - print out a fatal error message. + // FIXME: Do we really need two versions of the fatalError() method? + // + + synchronized public void fatalError(String str) { + System.out.println(str); + + if (inAnApplet) { + // vncContainer null, applet not inited, + // can not present the error to the user. + Thread.currentThread().stop(); + } else { + System.exit(1); + } + } + + synchronized public void fatalError(String str, Exception e) { + + if (rfb != null && rfb.closed()) { + // Not necessary to show error message if the error was caused + // by I/O problems after the rfb.close() method call. + System.out.println("RFB thread finished"); + return; + } + + System.out.println(str); + e.printStackTrace(); + + if (rfb != null) + rfb.close(); + + if (inAnApplet) { + showMessage(str); + } else { + System.exit(1); + } + } + + // + // Show message text and optionally "Relogin" and "Close" buttons. + // + + void showMessage(String msg) { + vncContainer.removeAll(); + + Label errLabel = new Label(msg, Label.CENTER); + errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12)); + + if (offerRelogin) { + + Panel gridPanel = new Panel(new GridLayout(0, 1)); + Panel outerPanel = new Panel(new FlowLayout(FlowLayout.LEFT)); + outerPanel.add(gridPanel); + vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 16)); + vncContainer.add(outerPanel); + Panel textPanel = new Panel(new FlowLayout(FlowLayout.CENTER)); + textPanel.add(errLabel); + gridPanel.add(textPanel); + gridPanel.add(new ReloginPanel(this)); + + } else { + + vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30)); + vncContainer.add(errLabel); + + } + + if (inSeparateFrame) { + vncFrame.pack(); + } else { + validate(); + } + } + + // + // Stop the applet. + // Main applet thread will terminate on first exception + // after seeing that rfbThread has been set to null. + // + + public void stop() { + System.out.println("Stopping applet"); + rfbThread = null; + } + + // + // This method is called before the applet is destroyed. + // + + public void destroy() { + System.out.println("Destroying applet"); + + vncContainer.removeAll(); + options.dispose(); + clipboard.dispose(); + if (rec != null) + rec.dispose(); + if (rfb != null && !rfb.closed()) + rfb.close(); + if (inSeparateFrame) + vncFrame.dispose(); + } + + // + // Start/stop receiving mouse events. + // + + public void enableInput(boolean enable) { + vc.enableInput(enable); + } + + // + // Close application properly on window close event. + // + + public void windowClosing(WindowEvent evt) { + System.out.println("Closing window"); + if (rfb != null) + disconnect(); + + vncContainer.hide(); + + if (!inAnApplet) { + System.exit(0); + } + } + + // + // Ignore window events we're not interested in. + // + + public void windowActivated(WindowEvent evt) {} + public void windowDeactivated (WindowEvent evt) {} + public void windowOpened(WindowEvent evt) {} + public void windowClosed(WindowEvent evt) {} + public void windowIconified(WindowEvent evt) {} + public void windowDeiconified(WindowEvent evt) {} +} diff --git a/WhatsNew b/WhatsNew new file mode 100644 index 0000000..c658c62 --- /dev/null +++ b/WhatsNew @@ -0,0 +1,930 @@ ++--------------------------------------------------------------------+ +| This is a brief summary of changes introduced in each TightVNC | +| release. For more details, please see ChangeLog files included | +| in TightVNC source and binary archives. | ++--------------------------------------------------------------------+ + +* TightVNC 1.3.9 + + - All platforms: Added support for the standard RFB protocol version + 3.8 with TightVNC extensions. + + - All platforms: Made "host:port" parsing maximally compatible with + VNC4. Interpreting a number in host names like somehost:5900 as an + actual port number if it's not in the range [0..99]. + + - Windows Server: Various user interface enhancements - changes in + GUI labels, tray icon with a red border when incoming connections + are not possible for any reason, more information in the tray icon + tip, smarter logic in displaying the Properties dialog, and more. + + - Windows Server: Fixed a problem introduced in TightVNC 1.3.8 - + default passwords were not respected if user passwords were not + set. + + - Windows Server: Slightly improved handling of passwords. One of + the notable changes is that now it's enough to enter a view-only + password without providing primary password. + + - Windows Server: Fixed problems with running WinVNC service and + Terminal Services. When a Remote Desktop (RDP) client connected to + the console, WinVNC showed black screen and did not restore normal + operations even on disconnection of that RDP client. Now, we + always share the console correctly, and disable simultaneous RDP + and VNC sessions. The changes were ported from VNC 4.1.2. + + - Windows Server: Better way of simulating Ctrl+Alt+Del. There are + reports that this solves the problem with greyed username and + password fields on Windows 2003 Server (bug #887617). + + - Windows Server: Bugfix for the bug #1109102: attempt to restart + the machine remotely via TightVNC led to disconnect if there was + some non-saved data, and further connections were rejected. + + - Windows Viewer: Multiple selection now works in file transfers, + thanks to developers at Novell and personally Rohit Kumar. + + - Windows Viewer: The viewer terminated silently when the server + dropped connection right after accepting it. Now we report such + errors. + + - Windows version source archive: Included project files for + compiling with Visual C++ 2005 Express Edition. Also, all required + libraries are now included within the source distribution. + + - Unix Server: Applied patches from Debian Linux that port Xvnc to + x86_64 platform (tightvnc-1.2.9-amd64support.p and + tightvnc-1.3_alpha7-x86_64.patch), thanks to Quanah Gibson-Mount. + + - Java viewer: Implemented scaling, either with a fixed scaling + factor or automatic. If Java 2D API is available (Java 1.2 and + higher), then high-quality scaling is used. From the other side, + the viewer remains compatible with Java 1.1 where it would simply + use scaling with much decreased image quality. Scaling can be + enabled with new "Scaling Factor" parameter but cannot be + controlled from the GUI yet. + + - Java viewer: Added support for ZRLE encoding. + + - Java viewer: Disabled focus traversal keys under JVMs 1.4 and + higher. This fixes the problem with not sending Tab key events to + the VNC server. + + - Java viewer: Fixed wrong pixel format interpretation at decoding + RichCursor pseudo-encoding (local cursor could be rendered in + wrong colors). + + - Other improvements and bugfixes, see ChangeLog files within the + distribution for more details. + +* TightVNC 1.3.8, release candidate version + + - Win32 server: Fixed major problem with disconnecting clients on + screen locking, user logoff and logon, in the service mode. + + - Win32 server: Added support for DFMirage driver direct screen + access mode (from DemoForge LLC). + + - Win32 server: Added support for multiple monitors (from DemoForge + LLC). + + - Win32 server: Improved layout and functionality of the Properties + dialog. + + - Win32 server: More accurate password handling - now the server + code tries to distinguish between "empty" and "unset" passwords + better. + + - Win32 server: New -shareall, -shareprimary and -sharearea + command-line options, working similarly to the -sharewindow + option. + + - Win32 server: Fixed problems with restoring desktop wallpaper. + + - Win32 viewer: Fixed bug with not enabling JPEG compression by + default. + + - Win32 viewer: Fixed bug with not setting proper size of the viewer + window. + + - Unix server: Port numbers are now calculated modulo 65536 with + vncviewer's -listen option. That makes it possible to listen on + TCP ports under 5900. + + - Java viewer: Automatic encoding selection based on measuring + current network throughput. + + - Other improvements and bugfixes, see ChangeLog files within the + distribution for more details. + +* TightVNC 1.3dev7, release candidate version + + - Win32 server: Fixed the problem with "olemainthreadwndname not + responding" in service mode under Windows NT 4.0. Under that OS, + the TightVNC service could hang on logoff. + + - Win32 server: Removed the code for "desktop optimizations" that + was rather harmful than useful. Hopefully, this should fix + problems with crashing Delphi applications. Also this should + prevent settings like font smoothing always set to true on + disconnect. + + - Win32 server: Fixed the issue with port number edit boxes that + were labeled incorrectly in the Properties dialog. + + - Win32 server: Disallowing clipboard transfers in view-only mode. + + - Win32 server: Fixed the problem with carriage return/linefeed + conversion of clipboard data. + + - Win32 server: Fixed the problem with wallpaper being removed only + after completing the initial screen transmission. + + - Win32 server: Minor improvements in the File Transfers dialog. + + - Win32 server: More context help messages in Properties and File + Transfers dialogs. + + - Unix server: Fixed a serious bug with sending cursor updates when + there was no FrameBufferUpdateRequest from that client. + + - Unix server: Fixed problems with building Xvnc on modern linux + distributions, such as Fedora Core 3. + + - Unix server: Disallowing clipboard transfers for view-only + clients. + + - Other improvements and bugfixes, see ChangeLog files within the + distribution for more details. + +* TightVNC 1.3dev6, Win32 release candidate version + + - Win32 server: Improved layout of the Properties dialog, added + context help for every option. Also, current mirror driver status + is shown in the Hooks tab. + + - Win32 server: Implemented new checkbox "Enable applet params in + URLs" corresponding to EnableURLParams registry setting. + + - Win32 server: The option "Don't use mirror display driver even if + available" is now functional. + + - Win32 server: New option "Blank screen on client connections". + When set and new client connects, the server's monitor is forced + to go to power saving mode. + + - Win32 server: Fixed bugs with saving certain settings in the + registry, and bugs with setting default values when the registry + is not writable. + + - Win32 server: Fixed a problem with one-pixel mouse offset. + + - Win32 server: Fixed problems with inter-thread locking, this + should solve "Unhandled message type received" problems. + + - Win32 server: Fixed a problem with the setting "Block remote input + on local activity", it was not working with DLL hooks disabled. + + - Win32 server: Fixed various problems with file transfer + implementation. Error handling was improved, the C: drive bug + under Win98/Me seems to be solved. + + - Win32 viewer: New "Auto" scaling mode. In this mode, the viewer + scales remote desktop to fit local window or screen size. If the + window size is changed, the scaling factor is adjusted + automatically. + + - Win32 viewer: Now the viewer checks server's capabilities and does + not ever use non-standard protocol messages not supported by the + server. This change affects file transfers only, as other features + do not use non-standard protocol messages.. + + - Java viewer: New "scale remote cursor" option has been added. It + allows to reduce or enlarge cursor image in the full-control mode. + + - Java viewer: A cursor repaint problem has been fixed. + + - Other improvements and bugfixes, see ChangeLog files within the + distribution for more details. + +* TightVNC 1.3dev5, development version + + - Win32 server: Support for the "DFMirage" mirror video driver has + been added (the driver itself will be available separately). Using + the mirror driver greatly increases the speed and reliability of + updates, and also desreases CPU utilization on the server. + + - Win32 server: New polling algorithm has been implemented. It's + similar to that found in x0rfbserver. New algorithm uses minimum + CPU time when there are no changes on the screen, and detects + major changes very quickly, resulting in greatly improved + responsiveness on the client side. + + - Win32 server: Improved methods for filtering screen changes that + actually do not change anything. New algorithm not only works + faster, but it also detects changes much more accurately, leaving + less work to encoders. + + - Win32 viewer: A special mode for Unix users has been implemented: + when ScrollLock is on, the viewer will send Meta on pressing Alt + keys. + + - Win32 server: Fixed a problem with view-only clients that were + enabled full control on just opening the Properties dialog of the + server. + + - Win32 server: It should not ever hang any more on changing ports + or the LoopbackOnly setting. + + - Win32 server: DisableTrayIcon and RemoveWallpaper settings are + working again. + + - Win32 server: The problem with not saving Query Settings has been + fixed. + + - Win32 server: The polling mode "on event received only" has been + fixed - it did not work correctly in previous version. + + - Win32 server: Fixed a number of issues with mouse handling, + including that annoying problem with pointer jumping on slow + connections. + + - Win32 server: Applied a bugfix from HorizonLive solving the + problem with crashes or incorrect operation after color depth + changes on the server's desktop. + + - Win32 viewer: It does not crash any more on entering long + passwords in the authentication window. + + - Win32 viewer: Positioning and resizing logic of the viewer window + has been improved. + + - Win32 viewer: Now the viewer chooses more reasonable file names + for saved .vnc sessions. + + - Win32 viewer: In the full-screen mode, the viewer allows other + windows to be shown above the remote desktop. This makes hotkeys + such as Shift-Ctrl-Alt-O useful in the full-screen mode. + + - Unix version: A number of bugfixes -- copying clipboard to + non-authenticated clients in Xvnc, delayed cursor shape updates in + Xvnc, and crashing on switching between KDE virtual desktops in + vncviewer. + + - Unix viewer: Support for the new -autopass option has been added, + a patch from Ki NETWORKS, Inc. + + - Other changes, see ChangeLog files within the distribution for + more details. + +* TightVNC 1.3dev4, development version + + - Featuring updated Unix version and Java viewer, supporting RFB + protocol version 3.7, with or without TightVNC protocol + extensions. Version 3.3 of the protocol is supported as well. + + - Win32 version: Built-in Java viewer was absent in the previous + development version; now it's available again. + + - Win32 version: Now the server does not crash on remote + Ctrl-Alt-Del events, and on changing display modes. + + - Win32 version: A problem with reinstalling the service has been + fixed (WinVNC -reinstall command-line option). In previous + versions, reinstalling the service could fail if a user did not + close "Service unregistered" message box within a few seconds. + + - Win32 version: Now the server does not hang on selecting equal RFB + and HTTP port numbers. A warning is shown instead. + + - Win32 version: The server does not hang on toggling loopback + connection options, and on changing port/display numbers. + + - Win32 version: WinVNC does not crash on choosing "Kill All + Clients" during file download. + + - Win32 version: CopyRect handling in the server has been fixed, the + CopyRect encoding is enabled again. + + - Win32 version: The Advanced Properties dialog of the server has + been removed. The controls of that dialog has been moved to tabs + in the Properties dialog. + + - Win32 version: Context help in the server's Properties dialog has + been implemented (although not all descriptions are ready yet). + + - Unix viewer: Fixed a bug with the viewer crashing on selecting + text in Xvnc, and then choosing F8 / Clipboard: local -> remote, + twice. + + - There was some progress on supporting pluggable encryption and + authentication methods, in both Win32 and Unix versions, and in + the Java viewer. + + - Other changes, see ChangeLog files within the distribution for + more details. + +---------------------------------------------------------------------- + +* TightVNC 1.3dev3, Win32 development (unstable) version + + - All features and fixes from 1.2.9 and 1.3dev1 versions included. + + - Improved GUI of the viewer featuring toolbar, hotkeys, pre-set + connection profiles, more configuration options, context help in + dialogs, and more. Finally, the viewer remembers all + per-connection and global settings in the registry. + + - File transfers between viewer and server machines. + + - Support for RFB protocol version 3.7, with TightVNC extensions. + + - A possibility to turn off hooking via VNCHooks.dll in WinVNC while + full screen polling is in use. + + - Other changes, see ChangeLog files within the distribution for + more details. + +---------------------------------------------------------------------- + +* TightVNC 1.2.9 + + - Win32 version: Major security-related bug in the server has been + fixed -- handling of the "QueryAllowNoPass" option was seriously + broken. Together with fixing this bug, the whole authentication + logic in the server code has been redesigned. + + - Win32 version: Now the HKEY_CURRENT_USER registry hive is being + closed properly on restoring display settings, on disconnect. This + change should solve the problem with unloading the registry on + logout, when WinVNC is running as a service. + + - Win32 version: Problems with "QuerySetting" and "QueryTimeout" + options have been fixed -- the settings could be copied from user + configuration to default settings without user's intention. + + - Win32 version: A long-standing bug has been fixed -- the logic to + handle retries after authentication failures was flawed, and used + to delete the same object twice under certain conditions. + + - Win32 version: Now it's possible to specify port numbers with the + winvnc -connect option, using the "host::port" format. Also, + providing a -connect option without arguments now brings up the + "Add New Client" dialog. + + - Unix version: New "Request refresh" button has been implemented in + the viewer's F8 popup menu. + + - Unix version: Xvnc compilation fixes for HP-UX and MacOS X have + been applied, from Ki NETWORKS, Inc. + + - Unix version: New vncpasswd -f command-line option has been + implemented. It allows providing passwords on stdin and writes + encrypted passwords to stdout. In addition, the password file name + "-" now denotes stdout. Finally, a buffer overflow has been fixed + in vncpasswd -- it could be caused by a long file name in the + command line. + + - Unix version: A patch to fix input focus problems in the X11 + viewer has been applied, from Greg Breland. + + - Unix version: A patch fixing Xvnc crashes on Sparc has been + applied, from the RealVNC distribution. + + - Unix version: A problem with incorrect port interpretation has + been fixed, in the vncviewer's -tunnel option handling. Thanks to + Clark Sessions. + + - Java viewer: A modification from Bernd Krueger-Knauber has been + accepted, to pass through X keysyms for foreign currencies. + + - Java viewer: The problem with initial keyboard focus not set to + the desktop on some JVMs has been fixed. + + - Other minor improvements and bugfixes. + +---------------------------------------------------------------------- + +* TightVNC 1.2.8 + + - Unix and Win32 versions: Support for a separate view-only password + has been implemented. Now the servers support two passwords -- one + to allow full control, another to restrict remote keyboard and + mouse input. + + - Win32 version: The password reset problem has been solved. In + versions starting from 1.2.4, the password could get changed in + the registry on opening Properties dialog and just hitting the OK + button. + + - Win32 version: New "-reload" command-line option has been + implemented in Win32 server. It forces the running instance to + reload the registry settings. + + - Win32 version: "RemoveWallpaper" and "LockSetting" options have + been made configurable in the Properties dialog; the code has been + ported from RealVNC 3.3.6. + + - Win32 version: Support for "AllowEditClients" registry setting has + been ported from RealVNC 3.3.6. + + - Unix version: New "-x11cursor" option has been implemented in + vncviewer; a patch from Peter Astrand. This option allows using a + real X11 cursor with X11-style cursor shape updates, disables the + dot cursor, and disables cursor position updates in non-fullscreen + mode. + + - Unix version: New "RunCommand" command to customize the X11 + vncviewer popup menu has been implemented; a patch from Peter + Astrand. + + - Unix version: Several patches from Debian Linux have been applied. + This should fix a number of bugs and improve building on some + platforms supported by Debian Linux. + + - Unix version: A problem with Xvnc eating all CPU time after xfs + restarts has been fixed; a patch from Martin Koegler. + + - Other minor improvements and bugfixes. + +---------------------------------------------------------------------- + +* TightVNC 1.2.7 + + - Unix and Win32 versions, Java viewer: The most significant problem + with local cursor handling has been solved -- now clients can see + remote cursor movements performed on the server or by another + client. New PointerPos encoding and cursor shape updates both + minimize bandwidth requirements and greatly improve responsiveness + of the mouse pointer, while still allow to track correct pointer + position in all situations. + + - Unix and Win32 versions: In all the places where display numbers + had to be used, now it's easy to use port numbers as well. The + viewers now allow to use new "hostname::port" syntax, in addition + to the traditional "hostname:display" format. The same new syntax + can be used in the "Add new client" dialog of Win32 server. In the + server, now it's equally easy to set display and port numbers. + Besides that, HTTP and RFB port numbers can be set individually. + + - Unix and Win32 versions: In servers, decreased JPEG quality + factors for low quality levels. This improves bandwidth usage + while the image quality remains satisfactory in most cases. In + clients, JPEG compression is now enabled by default, because + usually it's a reasonable choice. To prevent viewers from + requesting JPEG compression, new -nojpeg option can be used. + + - Unix and Win32 versions: Improved installer under Windows, better + RPMs for Linux. + + - Win32 version: Major enhancements in layout and functionality of + the dialog boxes. + + - Win32 version: New keyboard handling code has been ported from + RealVNC 3.3.6. This should solve all the issues with arrow keys + acting as numbers in console windows, and shift+arrows not working + under Win2k. + + - Win32 version: Adopted WinVNC -reinstall option from RealVNC + 3.3.5, together with a number of other changes in different + places. The viewer now accepts a port number after the -listen + command-line option, an improvement from RealVNC 3.3.6. + + - Win32 version: Eliminated high CPU usage on the server before + sending cursor shape updates. + + - Unix version: Bugfix for Xvnc's -localhost and -interface options + that were broken on many systems, thanks to Luke Mewburn for the + bugfix. Xvnc -version command-line option is now supported. + + - Tight encoding is now documented in rfbproto.h files within source + archives. + + - Java viewer: Implemented new buttons "Login again" and "Close + window" near the disconnect or error messages in the applet mode, + and introduced new "Offer Relogin" parameter to control this + improvement. Thanks to Peter Astrand for the initial version of + the "Login again" patch. + + - Java viewer: Support for connections via HTTP proxies using HTTP + CONNECT method. This will not work in the applet mode, due to Java + security restrictions. + + - Java viewer: Extra .vnc files have been removed, having just + index.vnc should be enough. Also, an example HTML page has been + prepared, to simplify installation under a standalone Web server. + + - Java viewer: Added a MANIFEST to the JAR archive, to allow easy + execution of the JAR file, using java -jar command-line option. + + - Other minor improvements and bugfixes. + +---------------------------------------------------------------------- + +* TightVNC 1.3dev1, Win32 development (unstable) version + + - Implemented partial screen sharing. Any single window or any + rectangular screen area can be shared instead of the whole screen. + The position and dimensions of the shared screen area can be + changed dynamically, and client windows will adjust their + dimensions on the fly. The user interface to choose shared screen + area is very intuitive and easy to use. + + - Screen resolution changes won't cause WinVNC to disconnect clients + any more (but changes in screen color format still result in + disconnects, this will be fixed later). + + - It's possible to make WinVNC ignore remote inputs when local mouse + or keyboard is in use. Remote events will be re-enabled after a + specified timeout (3 seconds by default). + + - There may be other changes I forgot to mention. :-) + +---------------------------------------------------------------------- + +* TightVNC 1.2.6 + + - Win32 version: In this version, when WinVNC binds to a local TCP + port, it does not try to check several times if the port is in + use. It just re-uses the port if the display number is not set to + "Auto". One visible effect of this change is that the delay + between starting up and showing the icon is greatly reduced. + + - Unix version: Fixed the bug which caused the vncserver script to + fail when the XAUTHORITY environment variable was not set. + + - Unix version: Fixed the bug which prevented the vncpasswd utility + from setting correct permissons on the passwd file. + + - Unix version: Fixed a repeated challenge replay attack + vulnerability, bugtraq id 5296. + + - Unix version: Added files to simplify building of Linux RPMs, + thanks to Peter Astrand. + + - Unix version: Improved scrolling in the full-screen mode, modified + patch from Ville Herva. + + - Minor cleanups. + +---------------------------------------------------------------------- + +* TightVNC 1.2.5 + + - Win32 version: Fixed a problem in the I/O subsystem that was + introduced in TightVNC 1.2.2 and was causing major slowdown in + communication with clients. + + - Win32 version: Enabled remote upgrade in the installation script. + Also, the installer will install a copy of the TightVNC Web site, + and will create shortcuts to most important documentation pages. + + - Win32 version: Implemented new feature to specify applet + parameters in URL requests being sent to the built-in HTTP server. + Added support for new "EnableURLParams" registry setting which can + be used to enable this feature. + + - Win32 version: Added support for the NewFBSize pseudo-encoding + allowing to change framebuffer geometry on the fly on server's + request. + + - Win32 version: Included "solution" and "project" files for MS + Visual Studio 7, from Andrew van der Stock, applied a set of minor + fixes to suppress compilation warnings under MS Visual Studio 7. + + - Win32 version: The viewer now tries to preserve the size and + position of the desktop window after applying new connection + options. + + - Unix version: Implemented new feature to specify applet parameters + in URL requests being sent to the built-in HTTP server. Added + support for new $PARAMS variable in .vnc HTML templates. + + - Unix version: Added the possibility to keep users' vnc directories + under /tmp, as suggested by Ivan Popov. This mode can be enabled + by editing the $vncUserDir variable in the vncserver script. Also, + new -t option has been implemented in the vncpasswd utility which + allows to change VNC password files under /tmp. + + - Unix version: Applied Xvnc -viewonly patch from Ehud Karni. + + - Unix version: Applied Linux/PowerPC Xvnc fix from Peter A. Castro. + + - Unix version: Bug fixed: Xvnc failed to reset compression level + and JPEG image quality on reading lists of encodings supported by + clients. + + - Unix version: Made the viewer handle XCursor encoding operating on + the framebuffer instead of setting new cursors directly in X. + + - Unix version: Applied a number of porting fixes from Ki Networks, + Inc. + + - Java viewer: Added new feature allowing to save RFB sessions in + FBS files compatible with rfbproxy. This feature works only if JVM + security manager allows access to the local filesystem, which is + usually true only when the viewer is used as a standalone + application or if the viewer applet is cryptographically signed. + New "Record" button will appear in the button panel if this + feature is enabled. + + - Java viewer: Added new "ENCPASSWORD" parameter, modified patch + from Peter Astrand. + + - Java viewer: Applied patch from Peter Astrand to fix problems with + Swedish keys and broken JVMs. + + - Other minor fixes and cleanups. + +---------------------------------------------------------------------- + +* TightVNC 1.2.4 + + - Win32 version: WinVNC crashes on reporting zero statistics were + fixed. This should eliminate crashes when using x2vnc and win2vnc + client programs. + + - Win32 version: a problem with listening viewer was fixed. + Initiating multiple non-shared connections could crash the viewer + application. + + - Win32 version: real passwords are never placed into the password + text control in the WinVNC Properties dialog any more. This should + prevent grabbing plain-text passwords from that text control. + + - Win32 version: logging on errors was improved to provide better + diagnosis for errors, especially for those causing the message + "Connection closed" right after authentication. + + - Win32 version: handling of log files was improved. Now WinVNC + should be able to save backup copies of log files under + Win95/98/Me. Also, all log files are now written in MS-DOS/Windows + text format instead of the Unix one. + + - Win32 version: a problem with reporting error messages in the + listening viewer was fixed. + + - Win32 version: reporting incorrect statistics in the Tight encoder + was fixed. + + - Win32 version: HTML pages and templates for the built-in HTTP + server were improved. + + - Unix version: applied patch from Ki Networks, Inc. solving build + problems on a number of commercial Unix systems, and fixing a + number of minor bugs and typos. + + - Unix version: added a possibility to denote standard input with + the "-" file name instead of a real password file name. + + - Unix version: fixed a bug causing vncpasswd utility work + incorrectly when a file name argument was given in the command + line. + + - Unix version: applied patch to solve keyboard focus problems in + the full-screen vncviewer, from Peter Astrand. The patch does not + seem to solve all the issues, but definitely makes things better. + New grabKeyboard resource was added to control full-screen mode + behavior. + + - Java viewer: new "Show Offline Desktop" parameter was added to + make the desktop still visible even after the remote side has + closed connection. + + - Java viewer: error messages were made much more meaningful. + + - Java viewer: keyboard focus problems were fixed. This should + prevent opening new windows (e.g. Options or Clipboard) behind the + active authenticator or desktop window. + + - Java viewer: now "R"/"r" keys can be used to request screen + updates in view-only mode. + + - Java viewer: applied patch from Peter Astrand to fix problems with + Swedish keys and broken JVMs. + + - Other minor fixes and cleanups. + +---------------------------------------------------------------------- + +* TightVNC 1.2.3 + + - Unix and Win32 versions: zlib library was updated to the most + recent version (1.1.4) where a potential security issue was fixed. + + - Unix and Win32 versions: fixed blocking I/O problems in built-in + HTTP servers. Older versions had to wait while one client finishes + his transaction, only then they served new client connections, + thus making easy denial-of-service attacks possible. + + - Unix and Win32 versions: updated built-in Java viewer, see details + below. + + - Win32 version: Added support for mouse wheel events. Wheel mouse + support is fully compatible and interoperable with Unix version + where this feature was available for a long time. + + - Win32 version (WinVNC): The -connect command-line option now + accepts a display number after a hostname. + + - Win32 version: Creating associations for .vnc files in the + installer. + + - Java viewer was GREATLY improved: the code was converted to Java + 1.1, painting techniques were re-designed completely (now the + viewer should work in MacOS), several new parameters were added, + all parameters were documented in the README file. Most important + new features include: support for 24-bit colors, JPEG support in + Tight encoding, RFB Bell message support, new "Refresh" button, a + possibility to operate in a separate scrollable window, dynamic + view-only mode. Many more changes were introduces, see the + ChangeLog for more information. Please note that new Java viewer + class names were changed, e.g. vncviewer.jar file has become + VncViewer.jar etc. + + - Unix version: a number of changes in the vncserver script, e.g. + the default color depth is now 24, extra delay after Xvnc startup + removed, font path is now configurable in the beginning of the + script, and more. + + - Unix version: zlib library was removed from the core X sources. + Instead, both vncviewer and Xvnc now can use either system zlib + and JPEG libraries, or ones packaged within TightVNC source + archive in the lib/ directory. Unix sources are distributed in two + versions: one with these libraries for those who don't have them + installed in the system, and another version without libraries, + copied directly from CVS, for those who do have zlib and/or JPEG + libraries installed. In the former case, build procedure would + include additional "make libs" step. System libraries will be + linked dynamically, libraries included in the source archive will + be linked in statically. + + - Unix version now includes comprehensive manual pages for + vncviewer, vncserver, Xvnc, vncconnect and vncpasswd programs. The + vncinstall script in the source distribution now accepts one more + parameter allowing to specify where to install manual pages. + + - Unix version (Xvnc): a number of patches from Red Hat Linux vnc + package were incorporated into the TightVNC codebase. This adds + support for more architectures including s390 and s390x, adds a + possibility to use tcp_wrappers for Xvnc access control. + + - Unix version (Xvnc): several bugfixes, e.g. applied patch to fix + crash in the code dealing with font server; fixed word alignment + problem in raw encoder experienced by Sparc users. + + - Unix version is no more distributed as patches to a standard VNC + release. This is because patches cannot handle changes in binary + files and handle file removals very inefficiently. + + - Other minor fixes and cleanups. + +---------------------------------------------------------------------- + +* TightVNC 1.2.2 + + - Win32 server: long-standing Win9x resource consumption problem has + been fixed. Now the server thread does not use blocking I/O, and + therefore is always ready to process messages from the VNCHooks + DLL. + + - Win32 server: now built-in HTTP daemon may be enabled and disabled + interactively from the Advanced Preferences dialog (this setting + is saved in new "EnableHTTPDaemon" registry key). + + - Win32 server: changes in layout and text of the Advanced + Preferences dialog. + + - Xvnc: Minor bugfix which should prevent potential dereference of a + NULL pointer. + + - Unix viewer: Now viewer window would be raised on beep (bell) + event, unless new -noraiseonbeep option is provided in the command + line or "raiseOnBeep" resource set to False. + + - One more packaging option for the Unix source: ready to build + archive with Zlib and JPEG libraries inside. + + - Other minor fixes and cleanups. + +---------------------------------------------------------------------- + +* TightVNC 1.2.1 + + - Win32 server: added support for reverse connections on ports other + than 5500, modified patch from Steve Kann. + + - Win32 viewer: added support for new command-line options: + -noshared and -encoding XXX. + + - Bugfixes in Win32 viewer: changes in exception handling eliminate + Borland C++ compilation problems causing application crashes on + repetitive connections, notably in the listen mode. Also, now + warning exceptions causing disconnects are reported to user, + except for the case when a user has closed the viewer window. + + - Better packaging in Win32 version: self-installing package is + available, vncviewer now shows correct icon image. + + - Unix vncviewer: Default tunneling command template has been + changed, to allow tunneled connections to hosts where only + loopback VNC connections are enabled. New -via + command-line option provides enhanced tunneling functionality, now + one can make vncviewer tunnel connections to a VNC host via third + machine acting as a gateway. + + - Java viewer: Addition of new parameters PASSWORD, "Show Controls", + and "View Only", modified patch from Steve Kann. + +---------------------------------------------------------------------- + +* TightVNC 1.2.0 + + - Tight encoding is now configurable and can operate at different + compression levels where low compression levels are very fast in + terms of CPU usage. New "-compresslevel N" option implemented in + vncviewer to set compression levels for Tight encoding (1 - fast, + 9 - best). + + - Enhanced techniques to split large rectangles in Tight encoder; + now it tries to find large solid-color areas and send them in + separate rectangles. + + - Lossy JPEG compression in Tight encoding has been implemented, new + "-quality N" vncviewer option should be used to enable this + feature (0 - low image quality and best compression, 9 - best + image quality). JPEG compression is used only for screen areas + that seem to be suitable for JPEG compression (although algorithms + to detect such areas are not perfect, of course). + + - New "XCursor" and "RichCursor" encodings implemented. They are + used to transmit cursor shape updates from server to clients + ("local cursor" feature requested by many users). Mouse movement + no longer causes framebuffer updates to happen, vncviewer + processes mouse locally when this feature is active. New + -nocursorshape vncviewer option turns this feature off. + + - A number of recent changes from both TridiaVNC and AT&T's releases + merged into the source, now the code is based on version 3.3.3r2 + for Unix part, and on 3.3.3r9 for Win32. + + - Unix vncviewer: When -tunnel option is specified in the command + line, special rules are now used to choose preferred encoding. Now + viewer does not think that server is running on the same machine + when tunneling is on and the preferred encoding is now "tight" + with default compression instead of raw. + + - Xvnc: Rules to set default pixel formats have been changed: now + they are RGB565 instead of BGR556 for color depth 16, and RGB888 + instead of BGR888 for depth 24. This makes Xvnc compatible with + Imlib renderer used in Gnome and also helps to avoid unnecessary + pixel format translations in many cases. + + - Xvnc: X11 modifier mapped to META key is now Mod4 instead of Mod1. + New -compatiblekbd option implemented in Xvnc to force META and + ALT keys behave the same way as they do in the original AT&T's + version. + + - A number of bugs fixed: viewer crashes after inflate() call, Xvnc + CoRRE encoding problems, Xvnc bit-order issues in XCursor and + RichCursor encodings, etc. + + - Java viewer now supports Tight encoding and cursor shape updates. + Drawing techniques were changed, settings "Raw pixel drawing: + Fast/Reliable" and "CopyRect: Fast/Reliable" removed from the + Options panel since they do not make sense in new drawing model. + + - Other new features, optimizations, fixes and cleanups, see + ChangeLog files. + +---------------------------------------------------------------------- + +* VNC Tight Encoding 1.1 + + - New ``gradient'' filter implemented in servers (it can be disabled + in Xvnc with new -lazytight option). The filter preprocess + full-color screen areas prior to compression in order to achieve + better compression ratios (with the cost of slower compression). + Vncviewers of version 1.0 had support for this filter already, but + there was small bug causing image distortions in certain cases. So + it is recommended to upgrade both servers and viewers. + + - Stupid bug fixed: extra unused color was included in palettes in + many cases; compression ratios used to be worse than they should + be. + + - The algorithm used to split large rectangles into parts has been + changed. This change can increase compression ratios in many + situations. + + - Byte-order issues in servers have been (hopefully) fixed. + + - Performance tuning, code rewrites and cleanups in various places. + +---------------------------------------------------------------------- + +* VNC Tight Encoding 1.0 + + - Initial release. + +---------------------------------------------------------------------- diff --git a/ZlibInStream.java b/ZlibInStream.java new file mode 100644 index 0000000..b6e3659 --- /dev/null +++ b/ZlibInStream.java @@ -0,0 +1,111 @@ +/* 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 +// + +public class ZlibInStream extends InStream { + + static final int defaultBufSize = 16384; + + public ZlibInStream(int bufSize_) { + bufSize = bufSize_; + b = new byte[bufSize]; + ptr = end = ptrOffset = 0; + inflater = new java.util.zip.Inflater(); + } + + public ZlibInStream() { this(defaultBufSize); } + + public void setUnderlying(InStream is, int bytesIn_) { + underlying = is; + bytesIn = bytesIn_; + ptr = end = 0; + } + + public void reset() throws Exception { + ptr = end = 0; + if (underlying == null) return; + + while (bytesIn > 0) { + decompress(); + end = 0; // throw away any data + } + underlying = null; + } + + public int pos() { return ptrOffset + ptr; } + + protected int overrun(int itemSize, int nItems) throws Exception { + 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, 0, end - ptr); + + ptrOffset += ptr; + end -= ptr; + ptr = 0; + + while (end < itemSize) { + decompress(); + } + + if (itemSize * nItems > end) + nItems = end / 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 void decompress() throws Exception { + try { + underlying.check(1); + int avail_in = underlying.getend() - underlying.getptr(); + if (avail_in > bytesIn) + avail_in = bytesIn; + + if (inflater.needsInput()) { + inflater.setInput(underlying.getbuf(), underlying.getptr(), avail_in); + } + + int n = inflater.inflate(b, end, bufSize - end); + + end += n; + if (inflater.needsInput()) { + bytesIn -= avail_in; + underlying.setptr(underlying.getptr() + avail_in); + } + } catch (java.util.zip.DataFormatException e) { + throw new Exception("ZlibInStream: inflate failed"); + } + } + + private InStream underlying; + private int bufSize; + private int ptrOffset; + private java.util.zip.Inflater inflater; + private int bytesIn; +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..1ebf0c2 --- /dev/null +++ b/index.html @@ -0,0 +1,29 @@ + + + + +TightVNC desktop + + + + +
+TightVNC site + diff --git a/index.vnc b/index.vnc new file mode 100644 index 0000000..a987bf5 --- /dev/null +++ b/index.vnc @@ -0,0 +1,25 @@ + + + + +$USER's $DESKTOP desktop ($DISPLAY) + + + +$PARAMS + +
+TightVNC site + -- 1.7.9.5