git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@2457 3789f03b-4d11-0410-bbf8-ca57d06f2519tags/v0.0.90
// | |||||
// 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(); | |||||
} | |||||
} |
// | |||||
// Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved. | |||||
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. | |||||
// | |||||
// This is free software; you can redistribute it and/or modify | |||||
// it under the terms of the GNU General Public License as published by | |||||
// the Free Software Foundation; either version 2 of the License, or | |||||
// (at your option) any later version. | |||||
// | |||||
// This software is distributed in the hope that it will be useful, | |||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
// GNU General Public License for more details. | |||||
// | |||||
// You should have received a copy of the GNU General Public License | |||||
// along with this software; if not, write to the Free Software | |||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |||||
// USA. | |||||
// | |||||
// | |||||
// ButtonPanel class implements panel with four buttons in the | |||||
// VNCViewer desktop window. | |||||
// | |||||
import java.awt.*; | |||||
import java.awt.event.*; | |||||
import java.io.*; | |||||
class ButtonPanel extends Panel implements ActionListener { | |||||
VncViewer viewer; | |||||
Button disconnectButton; | |||||
Button optionsButton; | |||||
Button recordButton; | |||||
Button clipboardButton; | |||||
Button ctrlAltDelButton; | |||||
Button refreshButton; | |||||
ButtonPanel(VncViewer v) { | |||||
viewer = v; | |||||
setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); | |||||
disconnectButton = new Button("Disconnect"); | |||||
disconnectButton.setEnabled(false); | |||||
add(disconnectButton); | |||||
disconnectButton.addActionListener(this); | |||||
optionsButton = new Button("Options"); | |||||
add(optionsButton); | |||||
optionsButton.addActionListener(this); | |||||
clipboardButton = new Button("Clipboard"); | |||||
clipboardButton.setEnabled(false); | |||||
add(clipboardButton); | |||||
clipboardButton.addActionListener(this); | |||||
if (viewer.rec != null) { | |||||
recordButton = new Button("Record"); | |||||
add(recordButton); | |||||
recordButton.addActionListener(this); | |||||
} | |||||
ctrlAltDelButton = new Button("Send Ctrl-Alt-Del"); | |||||
ctrlAltDelButton.setEnabled(false); | |||||
add(ctrlAltDelButton); | |||||
ctrlAltDelButton.addActionListener(this); | |||||
refreshButton = new Button("Refresh"); | |||||
refreshButton.setEnabled(false); | |||||
add(refreshButton); | |||||
refreshButton.addActionListener(this); | |||||
} | |||||
// | |||||
// Enable buttons on successful connection. | |||||
// | |||||
public void enableButtons() { | |||||
disconnectButton.setEnabled(true); | |||||
clipboardButton.setEnabled(true); | |||||
refreshButton.setEnabled(true); | |||||
} | |||||
// | |||||
// Disable all buttons on disconnect. | |||||
// | |||||
public void disableButtonsOnDisconnect() { | |||||
remove(disconnectButton); | |||||
disconnectButton = new Button("Hide desktop"); | |||||
disconnectButton.setEnabled(true); | |||||
add(disconnectButton, 0); | |||||
disconnectButton.addActionListener(this); | |||||
optionsButton.setEnabled(false); | |||||
clipboardButton.setEnabled(false); | |||||
ctrlAltDelButton.setEnabled(false); | |||||
refreshButton.setEnabled(false); | |||||
validate(); | |||||
} | |||||
// | |||||
// Enable/disable controls that should not be available in view-only | |||||
// mode. | |||||
// | |||||
public void enableRemoteAccessControls(boolean enable) { | |||||
ctrlAltDelButton.setEnabled(enable); | |||||
} | |||||
// | |||||
// Event processing. | |||||
// | |||||
public void actionPerformed(ActionEvent evt) { | |||||
viewer.moveFocusToDesktop(); | |||||
if (evt.getSource() == disconnectButton) { | |||||
viewer.disconnect(); | |||||
} else if (evt.getSource() == optionsButton) { | |||||
viewer.options.setVisible(!viewer.options.isVisible()); | |||||
} else if (evt.getSource() == recordButton) { | |||||
viewer.rec.setVisible(!viewer.rec.isVisible()); | |||||
} else if (evt.getSource() == clipboardButton) { | |||||
viewer.clipboard.setVisible(!viewer.clipboard.isVisible()); | |||||
} else if (evt.getSource() == ctrlAltDelButton) { | |||||
try { | |||||
final int modifiers = InputEvent.CTRL_MASK | InputEvent.ALT_MASK; | |||||
KeyEvent ctrlAltDelEvent = | |||||
new KeyEvent(this, KeyEvent.KEY_PRESSED, 0, modifiers, 127); | |||||
viewer.rfb.writeKeyEvent(ctrlAltDelEvent); | |||||
ctrlAltDelEvent = | |||||
new KeyEvent(this, KeyEvent.KEY_RELEASED, 0, modifiers, 127); | |||||
viewer.rfb.writeKeyEvent(ctrlAltDelEvent); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} else if (evt.getSource() == refreshButton) { | |||||
try { | |||||
RfbProto rfb = viewer.rfb; | |||||
rfb.writeFramebufferUpdateRequest(0, 0, rfb.framebufferWidth, | |||||
rfb.framebufferHeight, false); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
// | |||||
// 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; | |||||
} |
// | |||||
// 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; | |||||
} | |||||
// | |||||
// 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); | |||||
} | |||||
} | |||||
} |
// | |||||
// This DES class has been extracted from package Acme.Crypto for use in VNC. | |||||
// The bytebit[] array has been reversed so that the most significant bit | |||||
// in each byte of the key is ignored, not the least significant. Also the | |||||
// unnecessary odd parity code has been removed. | |||||
// | |||||
// These changes are: | |||||
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. | |||||
// | |||||
// This software is distributed in the hope that it will be useful, | |||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |||||
// | |||||
// DesCipher - the DES encryption method | |||||
// | |||||
// The meat of this code is by Dave Zimmerman <dzimm@widget.com>, and is: | |||||
// | |||||
// Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved. | |||||
// | |||||
// Permission to use, copy, modify, and distribute this software | |||||
// and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and | |||||
// without fee is hereby granted, provided that this copyright notice is kept | |||||
// intact. | |||||
// | |||||
// WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY | |||||
// OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | |||||
// TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | |||||
// PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE | |||||
// FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | |||||
// DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. | |||||
// | |||||
// THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE | |||||
// CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE | |||||
// PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT | |||||
// NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE | |||||
// SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE | |||||
// SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE | |||||
// PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET WORKSHOP | |||||
// SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR | |||||
// HIGH RISK ACTIVITIES. | |||||
// | |||||
// | |||||
// The rest is: | |||||
// | |||||
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved. | |||||
// | |||||
// Redistribution and use in source and binary forms, with or without | |||||
// modification, are permitted provided that the following conditions | |||||
// are met: | |||||
// 1. Redistributions of source code must retain the above copyright | |||||
// notice, this list of conditions and the following disclaimer. | |||||
// 2. Redistributions in binary form must reproduce the above copyright | |||||
// notice, this list of conditions and the following disclaimer in the | |||||
// documentation and/or other materials provided with the distribution. | |||||
// | |||||
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||||
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||||
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
// SUCH DAMAGE. | |||||
// | |||||
// Visit the ACME Labs Java page for up-to-date versions of this and other | |||||
// fine Java utilities: http://www.acme.com/java/ | |||||
import java.io.*; | |||||
/// The DES encryption method. | |||||
// <P> | |||||
// This is surprisingly fast, for pure Java. On a SPARC 20, wrapped | |||||
// in Acme.Crypto.EncryptedOutputStream or Acme.Crypto.EncryptedInputStream, | |||||
// it does around 7000 bytes/second. | |||||
// <P> | |||||
// Most of this code is by Dave Zimmerman <dzimm@widget.com>, and is | |||||
// Copyright (c) 1996 Widget Workshop, Inc. See the source file for details. | |||||
// <P> | |||||
// <A HREF="/resources/classes/Acme/Crypto/DesCipher.java">Fetch the software.</A><BR> | |||||
// <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A> | |||||
// <P> | |||||
// @see Des3Cipher | |||||
// @see EncryptedOutputStream | |||||
// @see EncryptedInputStream | |||||
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]; | |||||
} | |||||
} | |||||
} |
// | |||||
// 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); | |||||
} | |||||
} | |||||
// | |||||
// 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; | |||||
} | |||||
} | |||||
/* 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; | |||||
} |
GNU GENERAL PUBLIC LICENSE | |||||
Version 2, June 1991 | |||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc. | |||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | |||||
Everyone is permitted to copy and distribute verbatim copies | |||||
of this license document, but changing it is not allowed. | |||||
Preamble | |||||
The licenses for most software are designed to take away your | |||||
freedom to share and change it. By contrast, the GNU General Public | |||||
License is intended to guarantee your freedom to share and change free | |||||
software--to make sure the software is free for all its users. This | |||||
General Public License applies to most of the Free Software | |||||
Foundation's software and to any other program whose authors commit to | |||||
using it. (Some other Free Software Foundation software is covered by | |||||
the GNU Library General Public License instead.) You can apply it to | |||||
your programs, too. | |||||
When we speak of free software, we are referring to freedom, not | |||||
price. Our General Public Licenses are designed to make sure that you | |||||
have the freedom to distribute copies of free software (and charge for | |||||
this service if you wish), that you receive source code or can get it | |||||
if you want it, that you can change the software or use pieces of it | |||||
in new free programs; and that you know you can do these things. | |||||
To protect your rights, we need to make restrictions that forbid | |||||
anyone to deny you these rights or to ask you to surrender the rights. | |||||
These restrictions translate to certain responsibilities for you if you | |||||
distribute copies of the software, or if you modify it. | |||||
For example, if you distribute copies of such a program, whether | |||||
gratis or for a fee, you must give the recipients all the rights that | |||||
you have. You must make sure that they, too, receive or can get the | |||||
source code. And you must show them these terms so they know their | |||||
rights. | |||||
We protect your rights with two steps: (1) copyright the software, and | |||||
(2) offer you this license which gives you legal permission to copy, | |||||
distribute and/or modify the software. | |||||
Also, for each author's protection and ours, we want to make certain | |||||
that everyone understands that there is no warranty for this free | |||||
software. If the software is modified by someone else and passed on, we | |||||
want its recipients to know that what they have is not the original, so | |||||
that any problems introduced by others will not reflect on the original | |||||
authors' reputations. | |||||
Finally, any free program is threatened constantly by software | |||||
patents. We wish to avoid the danger that redistributors of a free | |||||
program will individually obtain patent licenses, in effect making the | |||||
program proprietary. To prevent this, we have made it clear that any | |||||
patent must be licensed for everyone's free use or not licensed at all. | |||||
The precise terms and conditions for copying, distribution and | |||||
modification follow. | |||||
GNU GENERAL PUBLIC LICENSE | |||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |||||
0. This License applies to any program or other work which contains | |||||
a notice placed by the copyright holder saying it may be distributed | |||||
under the terms of this General Public License. The "Program", below, | |||||
refers to any such program or work, and a "work based on the Program" | |||||
means either the Program or any derivative work under copyright law: | |||||
that is to say, a work containing the Program or a portion of it, | |||||
either verbatim or with modifications and/or translated into another | |||||
language. (Hereinafter, translation is included without limitation in | |||||
the term "modification".) Each licensee is addressed as "you". | |||||
Activities other than copying, distribution and modification are not | |||||
covered by this License; they are outside its scope. The act of | |||||
running the Program is not restricted, and the output from the Program | |||||
is covered only if its contents constitute a work based on the | |||||
Program (independent of having been made by running the Program). | |||||
Whether that is true depends on what the Program does. | |||||
1. You may copy and distribute verbatim copies of the Program's | |||||
source code as you receive it, in any medium, provided that you | |||||
conspicuously and appropriately publish on each copy an appropriate | |||||
copyright notice and disclaimer of warranty; keep intact all the | |||||
notices that refer to this License and to the absence of any warranty; | |||||
and give any other recipients of the Program a copy of this License | |||||
along with the Program. | |||||
You may charge a fee for the physical act of transferring a copy, and | |||||
you may at your option offer warranty protection in exchange for a fee. | |||||
2. You may modify your copy or copies of the Program or any portion | |||||
of it, thus forming a work based on the Program, and copy and | |||||
distribute such modifications or work under the terms of Section 1 | |||||
above, provided that you also meet all of these conditions: | |||||
a) You must cause the modified files to carry prominent notices | |||||
stating that you changed the files and the date of any change. | |||||
b) You must cause any work that you distribute or publish, that in | |||||
whole or in part contains or is derived from the Program or any | |||||
part thereof, to be licensed as a whole at no charge to all third | |||||
parties under the terms of this License. | |||||
c) If the modified program normally reads commands interactively | |||||
when run, you must cause it, when started running for such | |||||
interactive use in the most ordinary way, to print or display an | |||||
announcement including an appropriate copyright notice and a | |||||
notice that there is no warranty (or else, saying that you provide | |||||
a warranty) and that users may redistribute the program under | |||||
these conditions, and telling the user how to view a copy of this | |||||
License. (Exception: if the Program itself is interactive but | |||||
does not normally print such an announcement, your work based on | |||||
the Program is not required to print an announcement.) | |||||
These requirements apply to the modified work as a whole. If | |||||
identifiable sections of that work are not derived from the Program, | |||||
and can be reasonably considered independent and separate works in | |||||
themselves, then this License, and its terms, do not apply to those | |||||
sections when you distribute them as separate works. But when you | |||||
distribute the same sections as part of a whole which is a work based | |||||
on the Program, the distribution of the whole must be on the terms of | |||||
this License, whose permissions for other licensees extend to the | |||||
entire whole, and thus to each and every part regardless of who wrote it. | |||||
Thus, it is not the intent of this section to claim rights or contest | |||||
your rights to work written entirely by you; rather, the intent is to | |||||
exercise the right to control the distribution of derivative or | |||||
collective works based on the Program. | |||||
In addition, mere aggregation of another work not based on the Program | |||||
with the Program (or with a work based on the Program) on a volume of | |||||
a storage or distribution medium does not bring the other work under | |||||
the scope of this License. | |||||
3. You may copy and distribute the Program (or a work based on it, | |||||
under Section 2) in object code or executable form under the terms of | |||||
Sections 1 and 2 above provided that you also do one of the following: | |||||
a) Accompany it with the complete corresponding machine-readable | |||||
source code, which must be distributed under the terms of Sections | |||||
1 and 2 above on a medium customarily used for software interchange; or, | |||||
b) Accompany it with a written offer, valid for at least three | |||||
years, to give any third party, for a charge no more than your | |||||
cost of physically performing source distribution, a complete | |||||
machine-readable copy of the corresponding source code, to be | |||||
distributed under the terms of Sections 1 and 2 above on a medium | |||||
customarily used for software interchange; or, | |||||
c) Accompany it with the information you received as to the offer | |||||
to distribute corresponding source code. (This alternative is | |||||
allowed only for noncommercial distribution and only if you | |||||
received the program in object code or executable form with such | |||||
an offer, in accord with Subsection b above.) | |||||
The source code for a work means the preferred form of the work for | |||||
making modifications to it. For an executable work, complete source | |||||
code means all the source code for all modules it contains, plus any | |||||
associated interface definition files, plus the scripts used to | |||||
control compilation and installation of the executable. However, as a | |||||
special exception, the source code distributed need not include | |||||
anything that is normally distributed (in either source or binary | |||||
form) with the major components (compiler, kernel, and so on) of the | |||||
operating system on which the executable runs, unless that component | |||||
itself accompanies the executable. | |||||
If distribution of executable or object code is made by offering | |||||
access to copy from a designated place, then offering equivalent | |||||
access to copy the source code from the same place counts as | |||||
distribution of the source code, even though third parties are not | |||||
compelled to copy the source along with the object code. | |||||
4. You may not copy, modify, sublicense, or distribute the Program | |||||
except as expressly provided under this License. Any attempt | |||||
otherwise to copy, modify, sublicense or distribute the Program is | |||||
void, and will automatically terminate your rights under this License. | |||||
However, parties who have received copies, or rights, from you under | |||||
this License will not have their licenses terminated so long as such | |||||
parties remain in full compliance. | |||||
5. You are not required to accept this License, since you have not | |||||
signed it. However, nothing else grants you permission to modify or | |||||
distribute the Program or its derivative works. These actions are | |||||
prohibited by law if you do not accept this License. Therefore, by | |||||
modifying or distributing the Program (or any work based on the | |||||
Program), you indicate your acceptance of this License to do so, and | |||||
all its terms and conditions for copying, distributing or modifying | |||||
the Program or works based on it. | |||||
6. Each time you redistribute the Program (or any work based on the | |||||
Program), the recipient automatically receives a license from the | |||||
original licensor to copy, distribute or modify the Program subject to | |||||
these terms and conditions. You may not impose any further | |||||
restrictions on the recipients' exercise of the rights granted herein. | |||||
You are not responsible for enforcing compliance by third parties to | |||||
this License. | |||||
7. If, as a consequence of a court judgment or allegation of patent | |||||
infringement or for any other reason (not limited to patent issues), | |||||
conditions are imposed on you (whether by court order, agreement or | |||||
otherwise) that contradict the conditions of this License, they do not | |||||
excuse you from the conditions of this License. If you cannot | |||||
distribute so as to satisfy simultaneously your obligations under this | |||||
License and any other pertinent obligations, then as a consequence you | |||||
may not distribute the Program at all. For example, if a patent | |||||
license would not permit royalty-free redistribution of the Program by | |||||
all those who receive copies directly or indirectly through you, then | |||||
the only way you could satisfy both it and this License would be to | |||||
refrain entirely from distribution of the Program. | |||||
If any portion of this section is held invalid or unenforceable under | |||||
any particular circumstance, the balance of the section is intended to | |||||
apply and the section as a whole is intended to apply in other | |||||
circumstances. | |||||
It is not the purpose of this section to induce you to infringe any | |||||
patents or other property right claims or to contest validity of any | |||||
such claims; this section has the sole purpose of protecting the | |||||
integrity of the free software distribution system, which is | |||||
implemented by public license practices. Many people have made | |||||
generous contributions to the wide range of software distributed | |||||
through that system in reliance on consistent application of that | |||||
system; it is up to the author/donor to decide if he or she is willing | |||||
to distribute software through any other system and a licensee cannot | |||||
impose that choice. | |||||
This section is intended to make thoroughly clear what is believed to | |||||
be a consequence of the rest of this License. | |||||
8. If the distribution and/or use of the Program is restricted in | |||||
certain countries either by patents or by copyrighted interfaces, the | |||||
original copyright holder who places the Program under this License | |||||
may add an explicit geographical distribution limitation excluding | |||||
those countries, so that distribution is permitted only in or among | |||||
countries not thus excluded. In such case, this License incorporates | |||||
the limitation as if written in the body of this License. | |||||
9. The Free Software Foundation may publish revised and/or new versions | |||||
of the General Public License from time to time. Such new versions will | |||||
be similar in spirit to the present version, but may differ in detail to | |||||
address new problems or concerns. | |||||
Each version is given a distinguishing version number. If the Program | |||||
specifies a version number of this License which applies to it and "any | |||||
later version", you have the option of following the terms and conditions | |||||
either of that version or of any later version published by the Free | |||||
Software Foundation. If the Program does not specify a version number of | |||||
this License, you may choose any version ever published by the Free Software | |||||
Foundation. | |||||
10. If you wish to incorporate parts of the Program into other free | |||||
programs whose distribution conditions are different, write to the author | |||||
to ask for permission. For software which is copyrighted by the Free | |||||
Software Foundation, write to the Free Software Foundation; we sometimes | |||||
make exceptions for this. Our decision will be guided by the two goals | |||||
of preserving the free status of all derivatives of our free software and | |||||
of promoting the sharing and reuse of software generally. | |||||
NO WARRANTY | |||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | |||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS | |||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE | |||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | |||||
REPAIR OR CORRECTION. | |||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | |||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | |||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | |||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | |||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | |||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | |||||
POSSIBILITY OF SUCH DAMAGES. | |||||
END OF TERMS AND CONDITIONS | |||||
Appendix: How to Apply These Terms to Your New Programs | |||||
If you develop a new program, and you want it to be of the greatest | |||||
possible use to the public, the best way to achieve this is to make it | |||||
free software which everyone can redistribute and change under these terms. | |||||
To do so, attach the following notices to the program. It is safest | |||||
to attach them to the start of each source file to most effectively | |||||
convey the exclusion of warranty; and each file should have at least | |||||
the "copyright" line and a pointer to where the full notice is found. | |||||
<one line to give the program's name and a brief idea of what it does.> | |||||
Copyright (C) 19yy <name of author> | |||||
This program is free software; you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation; either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program; if not, write to the Free Software | |||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |||||
USA. | |||||
Also add information on how to contact you by electronic and paper mail. | |||||
If the program is interactive, make it output a short notice like this | |||||
when it starts in an interactive mode: | |||||
Gnomovision version 69, Copyright (C) 19yy name of author | |||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | |||||
This is free software, and you are welcome to redistribute it | |||||
under certain conditions; type `show c' for details. | |||||
The hypothetical commands `show w' and `show c' should show the appropriate | |||||
parts of the General Public License. Of course, the commands you use may | |||||
be called something other than `show w' and `show c'; they could even be | |||||
mouse-clicks or menu items--whatever suits your program. | |||||
You should also get your employer (if you work as a programmer) or your | |||||
school, if any, to sign a "copyright disclaimer" for the program, if | |||||
necessary. Here is a sample; alter the names: | |||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program | |||||
`Gnomovision' (which makes passes at compilers) written by James Hacker. | |||||
<signature of Ty Coon>, 1 April 1989 | |||||
Ty Coon, President of Vice | |||||
This General Public License does not permit incorporating your program into | |||||
proprietary programs. If your program is a subroutine library, you may | |||||
consider it more useful to permit linking proprietary applications with the | |||||
library. If this is what you want to do, use the GNU Library General | |||||
Public License instead of this License. |
Manifest-Version: 1.0 | |||||
Main-Class: VncViewer |
# | |||||
# Making the VNC applet. | |||||
# | |||||
CP = cp | |||||
JC = javac | |||||
JCFLAGS = -target 1.1 | |||||
JAR = jar | |||||
ARCHIVE = VncViewer.jar | |||||
MANIFEST = MANIFEST.MF | |||||
PAGES = index.vnc | |||||
INSTALL_DIR = /usr/local/vnc/classes | |||||
CLASSES = VncViewer.class RfbProto.class AuthPanel.class VncCanvas.class \ | |||||
VncCanvas2.class \ | |||||
OptionsFrame.class ClipboardFrame.class ButtonPanel.class \ | |||||
DesCipher.class CapabilityInfo.class CapsContainer.class \ | |||||
RecordingFrame.class SessionRecorder.class \ | |||||
SocketFactory.class HTTPConnectSocketFactory.class \ | |||||
HTTPConnectSocket.class ReloginPanel.class \ | |||||
InStream.class MemInStream.class ZlibInStream.class | |||||
SOURCES = VncViewer.java RfbProto.java AuthPanel.java VncCanvas.java \ | |||||
VncCanvas2.java \ | |||||
OptionsFrame.java ClipboardFrame.java ButtonPanel.java \ | |||||
DesCipher.java CapabilityInfo.java CapsContainer.java \ | |||||
RecordingFrame.java SessionRecorder.java \ | |||||
SocketFactory.java HTTPConnectSocketFactory.java \ | |||||
HTTPConnectSocket.java ReloginPanel.java \ | |||||
InStream.java MemInStream.java ZlibInStream.java | |||||
all: $(CLASSES) $(ARCHIVE) | |||||
$(CLASSES): $(SOURCES) | |||||
$(JC) $(JCFLAGS) -O $(SOURCES) | |||||
$(ARCHIVE): $(CLASSES) $(MANIFEST) | |||||
$(JAR) cfm $(ARCHIVE) $(MANIFEST) $(CLASSES) | |||||
install: $(CLASSES) $(ARCHIVE) | |||||
$(CP) $(CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR) | |||||
export:: $(CLASSES) $(ARCHIVE) $(PAGES) | |||||
@$(ExportJavaClasses) | |||||
clean:: | |||||
$(RM) *.class *.jar |
/* 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"); | |||||
} | |||||
} |
// | |||||
// 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", | |||||
"Continuous updates", | |||||
"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" }, | |||||
{ "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, | |||||
contUpdatesIndex = 5, | |||||
eightBitColorsIndex = 6, | |||||
mouseButtonIndex = 7, | |||||
viewOnlyIndex = 8, | |||||
scaleCursorIndex = 9, | |||||
shareDesktopIndex = 10; | |||||
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 continuousUpdates; | |||||
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[contUpdatesIndex].select("No"); | |||||
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(); | |||||
setContinuousUpdates(); | |||||
setOtherOptions(); | |||||
} | |||||
// | |||||
// Disable the shareDesktop option | |||||
// | |||||
void disableShareDesktop() { | |||||
labels[shareDesktopIndex].setEnabled(false); | |||||
choices[shareDesktopIndex].setEnabled(false); | |||||
} | |||||
// | |||||
// Disable the "Continuous updates" option. This method is called | |||||
// when we figure out that the server does not support corresponding | |||||
// protocol extensions. | |||||
// | |||||
void disableContUpdates() { | |||||
labels[contUpdatesIndex].setEnabled(false); | |||||
choices[contUpdatesIndex].setEnabled(false); | |||||
choices[contUpdatesIndex].select("No"); | |||||
continuousUpdates = 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); | |||||
} | |||||
// | |||||
// setContinuousUpdates sets continuousUpdates variable depending on | |||||
// the GUI setting. VncViewer monitors the state of this variable and | |||||
// send corresponding protocol messages to the server when necessary. | |||||
// | |||||
void setContinuousUpdates() { | |||||
continuousUpdates = | |||||
choices[contUpdatesIndex].getSelectedItem().equals("Yes"); | |||||
} | |||||
// | |||||
// setOtherOptions looks at the "other" choices (ones that do not | |||||
// cause sending any protocol messages) 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[contUpdatesIndex]) { | |||||
setContinuousUpdates(); | |||||
} 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) {} | |||||
} |
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 HOST parameter is required, PORT defaults to 5900 if omitted, and | |||||
there is a number of other optional parameters, 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 <PARAM> HTML tags, | |||||
within the appropriate <APPLET> section. Here is an example: | |||||
<APPLET CODE=VncViewer.class ARCHIVE=VncViewer.jar WIDTH=400 HEIGHT=300> | |||||
<PARAM NAME="PORT" VALUE=5901> | |||||
<PARAM NAME="Scaling factor" VALUE=50> | |||||
</APPLET> | |||||
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: 5900. | |||||
This parameter specifies TCP port number for outgoing VNC connection. | |||||
Note that this port is not the one used for HTTP connection from the | |||||
browser, it is the port used for VNC/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: "0". | |||||
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. | |||||
--> "DEBUG_XU" (no GUI equivalent) | |||||
Value: non-negative integer. | |||||
Default: 0. | |||||
Debugging option that causes update statistics reset after the specified | |||||
number of first framebuffer updates. This option was added to measure the | |||||
performance of a VNC server. First few updates (especially the very first | |||||
one) may be notably slower than others, and the viewer can exclude such | |||||
updates from statistics. | |||||
--> "DEBUG_CU" (no GUI equivalent) | |||||
Value: non-negative integer. | |||||
Default: 0. | |||||
Debugging option that causes the viewer disconnect after the specified | |||||
number of framebuffer updates. When used with the "DEBUG_XU" parameter, | |||||
the number of updates specified in "DEBUG_XU" is not counted as part of | |||||
this parameter's value. E.g. if "DEBUG_XU"=2 and "DEBUG_CU"=10, then the | |||||
viewer will disconnect after 12 framebuffer updates: update statistics | |||||
will be reset after first two updates, then collected for next 10 | |||||
updates, then the viewer will disconnect automatically. If the value is | |||||
0, the viewer will not disconnect automatically. This option was added to | |||||
measure the performance of a VNC server. | |||||
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 | |||||
<dzimm@widget.com> and Jef Poskanzer <jef@acme.com>. This is: | |||||
Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved. | |||||
Permission to use, copy, modify, and distribute this software and its | |||||
documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee | |||||
is hereby granted, provided that this copyright notice is kept intact. | |||||
WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE | |||||
SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT | |||||
NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | |||||
PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE | |||||
LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, | |||||
MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. | |||||
THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE | |||||
CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE | |||||
PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT | |||||
NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE | |||||
SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE | |||||
SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE | |||||
PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET | |||||
WORKSHOP SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF | |||||
FITNESS FOR HIGH RISK ACTIVITIES. | |||||
Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights | |||||
reserved. | |||||
Redistribution and use in source and binary forms, with or without | |||||
modification, are permitted provided that the following conditions | |||||
are met: | |||||
1. Redistributions of source code must retain the above copyright | |||||
notice, this list of conditions and the following disclaimer. | |||||
2. Redistributions in binary form must reproduce the above copyright | |||||
notice, this list of conditions and the following disclaimer in the | |||||
documentation and/or other materials provided with the distribution. | |||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS | |||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | |||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
Visit the ACME Labs Java page for up-to-date versions of this and other | |||||
fine Java utilities: http://www.acme.com/java/ |
// | |||||
// 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); | |||||
} | |||||
} | |||||
} |
// | |||||
// 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()); | |||||
} | |||||
} |
// | |||||
// 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); | |||||
} | |||||
} | |||||
// | |||||
// 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; | |||||
} |
// | |||||
// 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) {} | |||||
} | |||||
} | |||||
/* 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; | |||||
} |
<!-- | |||||
index.html - an example HTML page for TightVNC Java viewer applet, to be | |||||
used with a standalone Web server running on the same machine where the | |||||
TightVNC server is running. Before using this example, please MAKE SURE | |||||
to check the following: | |||||
* the value of the PORT parameter should be set correctly (normally, the | |||||
port number is 5900 + display number); | |||||
* the CODE and ARCHIVE attributes of the <APPLET> tag should point to | |||||
the correct directory (this example assumes that this page is in the | |||||
same directory with .jar and .class files); | |||||
* the WIDTH and HEIGHT attributes of the <APPLET> tag correspond to the | |||||
actual desktop size on the server (height should be increased to leave | |||||
enough space for the button panel). | |||||
--> | |||||
<HTML> | |||||
<TITLE> | |||||
TightVNC desktop | |||||
</TITLE> | |||||
<APPLET CODE="VncViewer.class" ARCHIVE="VncViewer.jar" | |||||
WIDTH="800" HEIGHT="632"> | |||||
<PARAM NAME="PORT" VALUE="5901"> | |||||
</APPLET> | |||||
<BR> | |||||
<A href="http://www.tightvnc.com/">TightVNC site</A> | |||||
</HTML> |
<!-- | |||||
index.vnc - default HTML page for TightVNC Java viewer applet, to be | |||||
used with Xvnc. On any file ending in .vnc, the HTTP server embedded in | |||||
Xvnc will substitute the following variables when preceded by a dollar: | |||||
USER, DESKTOP, DISPLAY, APPLETWIDTH, APPLETHEIGHT, WIDTH, HEIGHT, PORT, | |||||
PARAMS. Use two dollar signs ($$) to get a dollar sign in the generated | |||||
HTML page. | |||||
NOTE: the $PARAMS variable is not supported by the standard VNC, so | |||||
make sure you have TightVNC on the server side, if you're using this | |||||
variable. | |||||
--> | |||||
<HTML> | |||||
<TITLE> | |||||
$USER's $DESKTOP desktop ($DISPLAY) | |||||
</TITLE> | |||||
<APPLET CODE=VncViewer.class ARCHIVE=VncViewer.jar | |||||
WIDTH=$APPLETWIDTH HEIGHT=$APPLETHEIGHT> | |||||
<param name=PORT value=$PORT> | |||||
$PARAMS | |||||
</APPLET> | |||||
<BR> | |||||
<A href="http://www.tightvnc.com/">TightVNC site</A> | |||||
</HTML> |