From bbde67668cf78a02a121330eb40e3d4142527e8f Mon Sep 17 00:00:00 2001 From: Evan Broder Date: Fri, 28 Mar 2008 23:18:23 -0400 Subject: [PATCH] If I'm lucky, I might have a sipb-xen-vnc-client package, too svn path=/trunk/packages/sipb-xen-vnc-client/; revision=305 --- code/AuthPanel.java | 116 ++ code/ButtonPanel.java | 175 ++++ code/CapabilityInfo.java | 87 ++ code/CapsContainer.java | 103 ++ code/ChangeLog | 1708 ++++++++++++++++++++++++++++++ code/ClipboardFrame.java | 133 +++ code/DesCipher.java | 496 +++++++++ code/HTTPConnectSocket.java | 59 ++ code/HTTPConnectSocketFactory.java | 86 ++ code/InStream.java | 177 ++++ code/LICENCE.TXT | 340 ++++++ code/MANIFEST.MF | 2 + code/Makefile | 53 + code/MemInStream.java | 32 + code/OptionsFrame.java | 411 ++++++++ code/README | 493 +++++++++ code/RecordingFrame.java | 311 ++++++ code/ReloginPanel.java | 65 ++ code/RfbProto.java | 1314 +++++++++++++++++++++++ code/SIPBTrustManager.java | 122 +++ code/SessionRecorder.java | 193 ++++ code/SocketFactory.java | 36 + code/SocketWrapper.java | 262 +++++ code/VNCProxyConnectSocket.java | 61 ++ code/VNCProxyConnectSocketFactory.java | 98 ++ code/VNCProxyConnectSocketWrapper.java | 60 ++ code/VncCanvas.java | 1807 ++++++++++++++++++++++++++++++++ code/VncCanvas2.java | 63 ++ code/VncViewer.java | 972 +++++++++++++++++ code/WhatsNew | 930 ++++++++++++++++ code/ZlibInStream.java | 111 ++ code/index.html | 29 + code/index.vnc | 25 + code/trust.store | Bin 0 -> 1069 bytes debian/changelog | 5 + debian/compat | 1 + debian/control | 11 + debian/copyright | 3 + debian/rules | 9 + debian/sipb-xen-vnc-client.install | 2 + 40 files changed, 10961 insertions(+) create mode 100644 code/AuthPanel.java create mode 100644 code/ButtonPanel.java create mode 100644 code/CapabilityInfo.java create mode 100644 code/CapsContainer.java create mode 100644 code/ChangeLog create mode 100644 code/ClipboardFrame.java create mode 100644 code/DesCipher.java create mode 100644 code/HTTPConnectSocket.java create mode 100644 code/HTTPConnectSocketFactory.java create mode 100644 code/InStream.java create mode 100644 code/LICENCE.TXT create mode 100644 code/MANIFEST.MF create mode 100644 code/Makefile create mode 100644 code/MemInStream.java create mode 100644 code/OptionsFrame.java create mode 100644 code/README create mode 100644 code/RecordingFrame.java create mode 100644 code/ReloginPanel.java create mode 100644 code/RfbProto.java create mode 100644 code/SIPBTrustManager.java create mode 100644 code/SessionRecorder.java create mode 100644 code/SocketFactory.java create mode 100644 code/SocketWrapper.java create mode 100644 code/VNCProxyConnectSocket.java create mode 100644 code/VNCProxyConnectSocketFactory.java create mode 100644 code/VNCProxyConnectSocketWrapper.java create mode 100644 code/VncCanvas.java create mode 100644 code/VncCanvas2.java create mode 100644 code/VncViewer.java create mode 100644 code/WhatsNew create mode 100644 code/ZlibInStream.java create mode 100644 code/index.html create mode 100644 code/index.vnc create mode 100644 code/trust.store create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100755 debian/rules create mode 100644 debian/sipb-xen-vnc-client.install diff --git a/code/AuthPanel.java b/code/AuthPanel.java new file mode 100644 index 0000000..0043090 --- /dev/null +++ b/code/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/code/ButtonPanel.java b/code/ButtonPanel.java new file mode 100644 index 0000000..73f2446 --- /dev/null +++ b/code/ButtonPanel.java @@ -0,0 +1,175 @@ +// +// 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, ItemListener { + + VncViewer viewer; + Button disconnectButton; + Button optionsButton; + Button recordButton; + Button clipboardButton; + Button ctrlAltDelButton; + Button refreshButton; + Checkbox altCheckbox; + Checkbox ctrlCheckbox; + + 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); + + altCheckbox = new Checkbox("Alt"); + altCheckbox.setEnabled(false); + add(altCheckbox); + altCheckbox.addItemListener(this); + ctrlCheckbox = new Checkbox("Control"); + ctrlCheckbox.setEnabled(false); + add(ctrlCheckbox); + ctrlCheckbox.addItemListener(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); + ctrlCheckbox.setEnabled(enable); + altCheckbox.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(); + } + } + } + public void itemStateChanged(ItemEvent evt) { + viewer.moveFocusToDesktop(); + int state = evt.getStateChange(); + int extraModifiers = 0; + if (altCheckbox.getState()) { extraModifiers |= InputEvent.ALT_MASK; } + if (ctrlCheckbox.getState()) { extraModifiers |= InputEvent.CTRL_MASK; } + viewer.vc.extraModifiers = extraModifiers; + } +} + diff --git a/code/CapabilityInfo.java b/code/CapabilityInfo.java new file mode 100644 index 0000000..fcf27db --- /dev/null +++ b/code/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/code/CapsContainer.java b/code/CapsContainer.java new file mode 100644 index 0000000..e88cc38 --- /dev/null +++ b/code/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/code/ChangeLog b/code/ChangeLog new file mode 100644 index 0000000..05ce4d2 --- /dev/null +++ b/code/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/code/ClipboardFrame.java b/code/ClipboardFrame.java new file mode 100644 index 0000000..f0a5b8d --- /dev/null +++ b/code/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/code/DesCipher.java b/code/DesCipher.java new file mode 100644 index 0000000..2b7b5f2 --- /dev/null +++ b/code/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/code/HTTPConnectSocket.java b/code/HTTPConnectSocket.java new file mode 100644 index 0000000..390571b --- /dev/null +++ b/code/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/code/HTTPConnectSocketFactory.java b/code/HTTPConnectSocketFactory.java new file mode 100644 index 0000000..a9dbb76 --- /dev/null +++ b/code/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/code/InStream.java b/code/InStream.java new file mode 100644 index 0000000..16f7090 --- /dev/null +++ b/code/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/code/LICENCE.TXT b/code/LICENCE.TXT new file mode 100644 index 0000000..ae3b531 --- /dev/null +++ b/code/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/code/MANIFEST.MF b/code/MANIFEST.MF new file mode 100644 index 0000000..9ddbfbc --- /dev/null +++ b/code/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 +Main-Class: VncViewer diff --git a/code/Makefile b/code/Makefile new file mode 100644 index 0000000..7948898 --- /dev/null +++ b/code/Makefile @@ -0,0 +1,53 @@ +# +# Making the VNC applet. +# + +CP = cp +JC = javac +JCFLAGS = -target 1.1 -source 1.2 +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 \ + VNCProxyConnectSocketWrapper.class SocketWrapper.class SocketWrapper\$$WrappingSocketImpl.class SIPBTrustManager.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 \ + VNCProxyConnectSocketWrapper.java SocketWrapper.java SIPBTrustManager.java + +EXTRAJAR = trust.store + +all: $(CLASSES) $(ARCHIVE) + +$(CLASSES): $(SOURCES) + $(JC) $(JCFLAGS) -O $(SOURCES) + +$(ARCHIVE): $(CLASSES) $(MANIFEST) + $(JAR) cfm $(ARCHIVE) $(MANIFEST) $(CLASSES) $(EXTRAJAR) + +install: $(CLASSES) $(ARCHIVE) + $(CP) $(CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR) + +export:: $(CLASSES) $(ARCHIVE) $(PAGES) + @$(ExportJavaClasses) + +clean:: + $(RM) *.class *.jar diff --git a/code/MemInStream.java b/code/MemInStream.java new file mode 100644 index 0000000..9be98e1 --- /dev/null +++ b/code/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/code/OptionsFrame.java b/code/OptionsFrame.java new file mode 100644 index 0000000..701026a --- /dev/null +++ b/code/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/code/README b/code/README new file mode 100644 index 0000000..43ada68 --- /dev/null +++ b/code/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/code/RecordingFrame.java b/code/RecordingFrame.java new file mode 100644 index 0000000..ba53a84 --- /dev/null +++ b/code/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/code/ReloginPanel.java b/code/ReloginPanel.java new file mode 100644 index 0000000..c70fc3f --- /dev/null +++ b/code/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/code/RfbProto.java b/code/RfbProto.java new file mode 100644 index 0000000..c0f500a --- /dev/null +++ b/code/RfbProto.java @@ -0,0 +1,1314 @@ +// +// 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) { + System.out.println("Null socketFactory"); + sock = new Socket(host, port); + } else { + try { + Class factoryClass = Class.forName(viewer.socketFactory); + SocketFactory factory = (SocketFactory)factoryClass.newInstance(); + System.out.println("Using socketFactory " + factory); + 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 " + sock); + 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/code/SIPBTrustManager.java b/code/SIPBTrustManager.java new file mode 100644 index 0000000..891ef95 --- /dev/null +++ b/code/SIPBTrustManager.java @@ -0,0 +1,122 @@ +/* + * Copyright 2006 Perry Nguyen + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +public class SIPBTrustManager implements X509TrustManager { + private X509TrustManager trustManager; + private final static char[] KEY_STORE_PASSWORD = + { 'f', 'o', 'o', 'b', 'a', 'r' }; + private final static String KEY_STORE_RESOURCE = + "trust.store"; + + private KeyStore loadKeyStore() throws Exception { + InputStream in = getClass().getClassLoader().getResourceAsStream( + KEY_STORE_RESOURCE); + KeyStore ks = null; + try { + if (in == null) { + //log.severe("Unable to open KeyStore"); + throw new NullPointerException(); + } + ks = KeyStore.getInstance(KeyStore.getDefaultType()); + ks.load(in, KEY_STORE_PASSWORD); + /*if (log.isLoggable(Level.FINEST)) { + for (Enumeration aliases = ks.aliases(); + aliases.hasMoreElements();) { + String alias = aliases.nextElement(); + log.finest("ALIAS: " + alias); + } + }*/ + } catch (NoSuchAlgorithmException e) { + throwError(e); + } catch (CertificateException e) { + throwError(e); + } catch (IOException e) { + throwError(e); + } catch (KeyStoreException e) { + throwError(e); + } finally { + try { + if (in != null) + in.close(); + } + catch (IOException e) { } // ignore + } + return ks; + } + private void createTrustManager() { + try { + try { + KeyStore keystore = loadKeyStore(); + TrustManagerFactory factory = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm()); + factory.init(keystore); + TrustManager[] trustManagers = factory.getTrustManagers(); + if (trustManagers.length == 0) + throw new IllegalStateException("No trust manager found"); + setTrustManager((X509TrustManager) trustManagers[0]); + } catch (NoSuchAlgorithmException e) { + throwError(e); + } catch (KeyStoreException e) { + throwError(e); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + private void throwError(Exception e) throws Exception { + //HttpClientError error = new HttpClientError(e.getMessage()); + //error.initCause(e); + throw e; + } + public X509TrustManager getTrustManager() { + if (trustManager == null) + createTrustManager(); + return trustManager; + } + + public void setTrustManager(X509TrustManager trustManager) { + this.trustManager = trustManager; + } + + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + getTrustManager().checkClientTrusted(chain, authType); + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + getTrustManager().checkServerTrusted(chain, authType); + + } + + public X509Certificate[] getAcceptedIssuers() { + return getTrustManager().getAcceptedIssuers(); + } + +} \ No newline at end of file diff --git a/code/SessionRecorder.java b/code/SessionRecorder.java new file mode 100644 index 0000000..a02ce98 --- /dev/null +++ b/code/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/code/SocketFactory.java b/code/SocketFactory.java new file mode 100644 index 0000000..8d4b88f --- /dev/null +++ b/code/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/code/SocketWrapper.java b/code/SocketWrapper.java new file mode 100644 index 0000000..e488b28 --- /dev/null +++ b/code/SocketWrapper.java @@ -0,0 +1,262 @@ +/* + * Written by Dawid Kurzyniec and released to the public domain, as explained + * at http://creativecommons.org/licenses/publicdomain + */ + +//package edu.emory.mathcs.util.net; + +import java.io.*; +import java.net.*; +import java.nio.channels.*; + +/** + * Wrapper for sockets which enables to add functionality in subclasses + * on top of existing, connected sockets. It is useful when direct subclassing + * of delegate socket class is not possible, e.g. if the delegate socket is + * created by a library. Possible usage example is socket factory chaining. + * This class delegates all socket-related requests to the wrapped delegate, + * as of JDK 1.4. + * + * @author Dawid Kurzyniec + * @version 1.4 + */ +public abstract class SocketWrapper extends Socket { + + /** + * the wrapped delegate socket. + */ + protected final Socket delegate; + + /** + * Creates new socket wrapper for a given socket. The delegate + * must be connected and bound and it must not be closed. + * @param delegate the delegate socket to wrap + * @throws SocketException if the delegate socket is closed, not bound, + * or not connected + */ + protected SocketWrapper(Socket delegate) throws SocketException { + super(new WrappingSocketImpl(delegate)); + this.delegate = delegate; + System.out.println("Creating SocketWrapper $Rev$"); + } + + public SocketChannel getChannel() { + return delegate.getChannel(); + } + + /** + * Returns true, indicating that the socket is bound. + * + * @return true + */ + public boolean isBound() { + return true; + } + + public boolean isClosed() { + return super.isClosed() || delegate.isClosed(); + } + + /** + * Returns true, indicating that the socket is connected. + * + * @return true + */ + public boolean isConnected() { + return true; + } + + public boolean isInputShutdown() { + return super.isInputShutdown() || delegate.isInputShutdown(); + } + + public boolean isOutputShutdown() { + return super.isInputShutdown() || delegate.isOutputShutdown(); + } + + private static class WrappingSocketImpl extends SocketImpl { + private final Socket delegate; + WrappingSocketImpl(Socket delegate) throws SocketException { + if (delegate == null) { + throw new NullPointerException(); + } + if (delegate.isClosed()) { + throw new SocketException("Delegate server socket is closed"); + } + if (!(delegate.isBound())) { + throw new SocketException("Delegate server socket is not bound"); + } + if (!(delegate.isConnected())) { + throw new SocketException("Delegate server socket is not connected"); + } + this.delegate = delegate; + } + + protected void create(boolean stream) {} + + protected void connect(String host, int port) { + // delegate is always connected, thus this method is never called + throw new UnsupportedOperationException(); + } + + protected void connect(InetAddress address, int port) { + // delegate is always connected, thus this method is never called + throw new UnsupportedOperationException(); + } + + protected void connect(SocketAddress address, int timeout) { + // delegate is always connected, thus this method is never called + throw new UnsupportedOperationException(); + } + + protected void bind(InetAddress host, int port) { + // delegate is always bound, thus this method is never called + throw new UnsupportedOperationException(); + } + + protected void listen(int backlog) { + // this wrapper is never used by a ServerSocket + throw new UnsupportedOperationException(); + } + + protected void accept(SocketImpl s) { + // this wrapper is never used by a ServerSocket + throw new UnsupportedOperationException(); + } + + protected InputStream getInputStream() throws IOException { + return delegate.getInputStream(); + } + + protected OutputStream getOutputStream() throws IOException { + return delegate.getOutputStream(); + } + + protected int available() throws IOException { + return getInputStream().available(); + } + + protected void close() throws IOException { + System.out.println("Calling delegate.close"); + delegate.close(); + } + + protected void shutdownInput() throws IOException { + delegate.shutdownInput(); + } + + protected void shutdownOutput() throws IOException { + delegate.shutdownOutput(); + } + + protected FileDescriptor getFileDescriptor() { + // this wrapper is never used by a ServerSocket + throw new UnsupportedOperationException(); + } + + protected InetAddress getInetAddress() { + return delegate.getInetAddress(); + } + + protected int getPort() { + return delegate.getPort(); + } + + protected boolean supportsUrgentData() { + return false; // must be overridden in sub-class + } + + protected void sendUrgentData (int data) throws IOException { + delegate.sendUrgentData(data); + } + + protected int getLocalPort() { + return delegate.getLocalPort(); + } + + public Object getOption(int optID) throws SocketException { + switch (optID) { + case SocketOptions.IP_TOS: + return new Integer(delegate.getTrafficClass()); + case SocketOptions.SO_BINDADDR: + return delegate.getLocalAddress(); + case SocketOptions.SO_KEEPALIVE: + return Boolean.valueOf(delegate.getKeepAlive()); + case SocketOptions.SO_LINGER: + return new Integer(delegate.getSoLinger()); + case SocketOptions.SO_OOBINLINE: + return Boolean.valueOf(delegate.getOOBInline()); + case SocketOptions.SO_RCVBUF: + return new Integer(delegate.getReceiveBufferSize()); + case SocketOptions.SO_REUSEADDR: + return Boolean.valueOf(delegate.getReuseAddress()); + case SocketOptions.SO_SNDBUF: + return new Integer(delegate.getSendBufferSize()); + case SocketOptions.SO_TIMEOUT: + return new Integer(delegate.getSoTimeout()); + case SocketOptions.TCP_NODELAY: + return Boolean.valueOf(delegate.getTcpNoDelay()); + case SocketOptions.SO_BROADCAST: + default: + throw new IllegalArgumentException("Unsupported option type"); + } + } + + public void setOption(int optID, Object value) throws SocketException { + switch (optID) { + case SocketOptions.SO_BINDADDR: + throw new IllegalArgumentException("Socket is bound"); + case SocketOptions.SO_KEEPALIVE: + delegate.setKeepAlive(((Boolean)value).booleanValue()); + break; + case SocketOptions.SO_LINGER: + if (value instanceof Boolean) { + delegate.setSoLinger(((Boolean)value).booleanValue(), 0); + } + else { + delegate.setSoLinger(true, ((Integer)value).intValue()); + } + break; + case SocketOptions.SO_OOBINLINE: + delegate.setOOBInline(((Boolean)value).booleanValue()); + break; + case SocketOptions.SO_RCVBUF: + delegate.setReceiveBufferSize(((Integer)value).intValue()); + break; + case SocketOptions.SO_REUSEADDR: + delegate.setReuseAddress(((Boolean)value).booleanValue()); + break; + case SocketOptions.SO_SNDBUF: + delegate.setSendBufferSize(((Integer)value).intValue()); + break; + case SocketOptions.SO_TIMEOUT: + delegate.setSoTimeout(((Integer)value).intValue()); + break; + case SocketOptions.TCP_NODELAY: + delegate.setTcpNoDelay(((Boolean)value).booleanValue()); + break; + case SocketOptions.SO_BROADCAST: + default: + throw new IllegalArgumentException("Unsupported option type"); + } + } + } + + public void close() throws IOException { + System.out.println("Calling SocketWrapper.delegate.close"); + delegate.close(); + } + + public boolean equals(Object obj) { + if (!(obj instanceof SocketWrapper)) return false; + SocketWrapper that = (SocketWrapper)obj; + return this.delegate.equals(that.delegate); + } + + public int hashCode() { + return delegate.hashCode() ^ 0x01010101; + } + public String toString() { + return ""; + } +} \ No newline at end of file diff --git a/code/VNCProxyConnectSocket.java b/code/VNCProxyConnectSocket.java new file mode 100644 index 0000000..595acd5 --- /dev/null +++ b/code/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/code/VNCProxyConnectSocketFactory.java b/code/VNCProxyConnectSocketFactory.java new file mode 100644 index 0000000..d05fcf6 --- /dev/null +++ b/code/VNCProxyConnectSocketFactory.java @@ -0,0 +1,98 @@ +// +// 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 javax.net.ssl.*; +import java.io.*; + +class VNCProxyConnectSocketFactory implements SocketFactory { + + SSLSocketFactory factory; + + public VNCProxyConnectSocketFactory() { + try { + SSLContext c = SSLContext.getInstance("SSL"); + c.init(null, + new TrustManager[] { new SIPBTrustManager() }, + null); + factory = + (SSLSocketFactory)c.getSocketFactory(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + 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); + SSLSocket ssls = (SSLSocket)factory.createSocket(host, port); + ssls.startHandshake(); + VNCProxyConnectSocketWrapper s = + new VNCProxyConnectSocketWrapper(ssls, 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/code/VNCProxyConnectSocketWrapper.java b/code/VNCProxyConnectSocketWrapper.java new file mode 100644 index 0000000..69a0fa8 --- /dev/null +++ b/code/VNCProxyConnectSocketWrapper.java @@ -0,0 +1,60 @@ +// +// 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 VNCProxyConnectSocketWrapper extends SocketWrapper { + + public VNCProxyConnectSocketWrapper(Socket sock, + String vmname, String authtoken) + throws IOException { + + super(sock); + + // 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/code/VncCanvas.java b/code/VncCanvas.java new file mode 100644 index 0000000..4cb7d63 --- /dev/null +++ b/code/VncCanvas.java @@ -0,0 +1,1807 @@ +// +// 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; + int extraModifiers = 0; + + // + // 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 { + if (extraModifiers != 0) { + evt.setModifiers(evt.getModifiers() | extraModifiers); + } + 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/code/VncCanvas2.java b/code/VncCanvas2.java new file mode 100644 index 0000000..34c57f7 --- /dev/null +++ b/code/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/code/VncViewer.java b/code/VncViewer.java new file mode 100644 index 0000000..824f7eb --- /dev/null +++ b/code/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/code/WhatsNew b/code/WhatsNew new file mode 100644 index 0000000..c658c62 --- /dev/null +++ b/code/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/code/ZlibInStream.java b/code/ZlibInStream.java new file mode 100644 index 0000000..b6e3659 --- /dev/null +++ b/code/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/code/index.html b/code/index.html new file mode 100644 index 0000000..1ebf0c2 --- /dev/null +++ b/code/index.html @@ -0,0 +1,29 @@ + + + + +TightVNC desktop + + + + +
+TightVNC site + diff --git a/code/index.vnc b/code/index.vnc new file mode 100644 index 0000000..a987bf5 --- /dev/null +++ b/code/index.vnc @@ -0,0 +1,25 @@ + + + + +$USER's $DESKTOP desktop ($DISPLAY) + + + +$PARAMS + +
+TightVNC site + diff --git a/code/trust.store b/code/trust.store new file mode 100644 index 0000000000000000000000000000000000000000..83e925795dee02dc4dd76c596cac2579ebaf919a GIT binary patch literal 1069 zcmezO_TO6u1_mY|W(3o$xs}T9JU5weqouP)i zJhy&yUcM$>`)^R4&?@a99c$nBe|Pj43UICL;=Xn|z1N)Sh&~JZrCKlh=A+*1EJYFr zwi@4@%f!scz__@H(aE5R(GD2;%%QS;EMhDop-G14tDSG%IuM+EZPzBN=G_+T96%+! zAO*@SO^hr+4nqT0WeXecENQ$sY@?zHDckXYfC#VSKR>IySl_VF jbk)OG$-bxhw3#QbIZ<-!&&o&7_T4;p>(MmsNLCvFSFuZ! literal 0 HcmV?d00001 diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..bb2cd96 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +sipb-xen-vnc-client (1) unstable; urgency=low + + * Initial Release. + -- SIPB Xen Project Fri, 28 Mar 2008 23:02:26 -0500 + diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +4 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..6cf3964 --- /dev/null +++ b/debian/control @@ -0,0 +1,11 @@ +Source: sipb-xen-vnc-client +Section: base +Priority: extra +Maintainer: SIPB Xen Project +Build-Depends: cdbs (>= 0.4.23-1.1), debhelper (>= 4.1.0), subversion, sun-java5-jdk +Standards-Version: 3.7.2 + +Package: sipb-xen-vnc-client +Architecture: all +Depends: ${misc:Depends} +Description: Install the custom sipb-xen VNC client diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..7789434 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,3 @@ +This package was created for internal use of the SIPB Xen Project of +the MIT Student Information Processing Board. Ask sipb-xen@mit.edu if +you have questions about redistribution. diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..b783892 --- /dev/null +++ b/debian/rules @@ -0,0 +1,9 @@ +#!/usr/bin/make -f + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/makefile.mk + +DEB_SRCDIR=code + +binary-fixup/sipb-xen-vnc-client:: + svn co https://sipb-xen-dev.mit.edu:1111/trunk/packages/sipb-xen-vnc-client/code/ $(DEB_DESTDIR)/usr/local/lib/sipb-xen-vnc-client diff --git a/debian/sipb-xen-vnc-client.install b/debian/sipb-xen-vnc-client.install new file mode 100644 index 0000000..de446c1 --- /dev/null +++ b/debian/sipb-xen-vnc-client.install @@ -0,0 +1,2 @@ +files/* . +code/VncViewer.jar usr/local/lib/sipb-xen-vnc-client/ \ No newline at end of file -- 1.7.9.5