cloudstack/thirdparty/console/ConsoleViewer.java
2011-01-28 16:07:46 -08:00

1022 lines
27 KiB
Java

//
// Copyright (C) 2001-2004 HorizonLive.com, Inc. All Rights Reserved.
// Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved.
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
//
// This is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this software; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//
//
// VncViewer.java - the VNC viewer applet. This class mainly just sets up the
// user interface, leaving it to the VncCanvas to do the actual rendering of
// a VNC desktop.
//
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.io.*;
import java.net.*;
import java.util.Date;
public class ConsoleViewer implements java.lang.Runnable {
int id = getNextId();
boolean compressServerMessage = false;
long createTime = System.currentTimeMillis();
long lastUsedTime = System.currentTimeMillis();
boolean dropMe = false;
OutputStream clientStream;
String clientStreamInfo;
int status;
public final static int STATUS_ERROR = -1;
public final static int STATUS_UNINITIALIZED = 0;
public final static int STATUS_CONNECTING = 1;
public final static int STATUS_INITIALIZING = 2;
public final static int STATUS_NORMAL_OPERATION = 3;
public final static int STATUS_AUTHENTICATION_FAILURE = 100;
boolean inAnApplet = true;
boolean inSeparateFrame = false;
boolean inProxyMode = false;
String[] mainArgs;
RfbProto rfb;
Thread rfbThread;
ConsoleApplet applet;
Frame vncFrame;
Container vncContainer;
ScrollPane desktopScrollPane;
GridBagLayout gridbag;
ButtonPanel buttonPanel;
Label connStatusLabel;
ConsoleCanvas vc;
OptionsFrame options;
ClipboardFrame clipboard;
private RecordingFrame rec;
// Control session recording.
Object recordingSync;
String sessionFileName;
boolean recordingActive;
boolean recordingStatusChanged;
String cursorUpdatesDef;
String eightBitColorsDef;
// Variables read from parameter values.
String socketFactory;
String host;
int port;
String proxyHost;
int proxyPort;
String passwordParam;
boolean showControls;
boolean offerRelogin;
boolean showOfflineDesktop;
int deferScreenUpdates;
int deferCursorUpdates;
int deferUpdateRequests;
static int id_count = 1;
synchronized static int getNextId() {
return id_count++;
}
//
// init()
//
public void init() {
if (inProxyMode) {
initProxy();
return;
}
readParameters();
if (inSeparateFrame) {
vncFrame = new Frame("VMOps ConsoleViewer");
if (!inAnApplet) {
// vncFrame.add("Center", this);
}
vncContainer = vncFrame;
} else {
vncContainer = applet;
}
recordingSync = new Object();
options = new OptionsFrame(this);
// clipboard = new ClipboardFrame(this);
// if (RecordingFrame.checkSecurity())
// rec = new RecordingFrame(this);
sessionFileName = null;
recordingActive = false;
recordingStatusChanged = false;
cursorUpdatesDef = null;
eightBitColorsDef = null;
if (inSeparateFrame)
vncFrame.addWindowListener(applet);
rfbThread = new Thread(this);
rfbThread.start();
}
private void initProxy() {
recordingSync = new Object();
options = new OptionsFrame(this);
options.viewOnly = true;
sessionFileName = null;
recordingActive = false;
recordingStatusChanged = false;
cursorUpdatesDef = null;
eightBitColorsDef = null;
rfbThread = new Thread(this);
rfbThread.setName("RFB Thread " + rfbThread.getId() + " >" + host + ":"
+ port);
rfbThread.start();
}
public void update(Graphics g) {
}
//
// run() - executed by the rfbThread to deal with the RFB socket.
//
public void run() {
if (inProxyMode) {
runProxy();
return;
}
int[] pixels = new int[16 * 16];
Image image = Toolkit.getDefaultToolkit().createImage(
new MemoryImageSource(16, 16, pixels, 0, 16));
Cursor transparentCursor =
Toolkit.getDefaultToolkit().createCustomCursor
(image, new Point(0, 0), "invisibleCursor");
vncContainer.setCursor(transparentCursor);
gridbag = new GridBagLayout();
vncContainer.setLayout(gridbag);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.NORTHWEST;
//gbc.anchor = GridBagConstraints.CENTER;
if (showControls) {
buttonPanel = new ButtonPanel(this);
gridbag.setConstraints(buttonPanel, gbc);
vncContainer.add(buttonPanel);
}
// FIXME: Use auto-scaling not only in a separate frame.
if (options.autoScale && inSeparateFrame) {
Dimension screenSize;
try {
screenSize = vncContainer.getToolkit().getScreenSize();
} catch (Exception e) {
screenSize = new Dimension(0, 0);
}
createCanvas(screenSize.width - 32, screenSize.height - 32);
} else {
createCanvas(0, 0);
}
gbc.weightx = 1.0;
gbc.weighty = 1.0;
if (inSeparateFrame) {
// Create a panel which itself is resizeable and can hold
// non-resizeable VncCanvas component at the top left corner.
Panel canvasPanel = new Panel();
canvasPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
canvasPanel.add(vc);
// Create a ScrollPane which will hold a panel with VncCanvas
// inside.
desktopScrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
gbc.fill = GridBagConstraints.BOTH;
gridbag.setConstraints(desktopScrollPane, gbc);
desktopScrollPane.add(canvasPanel);
// Finally, add our ScrollPane to the Frame window.
vncFrame.add(desktopScrollPane);
// vncFrame.setTitle(rfb.desktopName);
vncFrame.pack();
vc.resizeDesktopFrame();
} else {
gridbag.setConstraints(vc, gbc);
applet.add(vc);
applet.validate();
}
if (showControls)
buttonPanel.enableButtons();
moveFocusToDesktop();
try {
connectAndAuthenticate();
doProtocolInitialisation();
vc.rfb = rfb;
vc.setPixelFormat();
vc.rfb.writeFramebufferUpdateRequest(0, 0, vc.rfb.framebufferWidth,
vc.rfb.framebufferHeight, false);
vc.processNormalProtocol();
// We should never get here, but just in case
showMessage("Disconnected from server");
} catch (NoRouteToHostException e) {
fatalError("Network error: no route to server: " + host, e);
} catch (UnknownHostException e) {
fatalError("Network error: server name unknown: " + host, e);
} catch (ConnectException e) {
fatalError("Network error: could not connect to server: " + host
+ ":" + port, e);
} catch (EOFException e) {
fatalError("Network error: remote side closed connection", e);
} catch (IOException e) {
fatalError(e.getMessage(), e);
} catch (Exception e) {
fatalError(e.getMessage(), e);
} finally {
encodingsSaved = null;
nEncodingsSaved = 0;
synchronized (this) {
if (rfb != null) {
rfb.close();
}
}
}
}
public void runProxy() {
createCanvas(0, 0);
int delay = 0;
while (!dropMe) {
try {
status = STATUS_CONNECTING;
connectAndAuthenticate();
delay = 0; // reset the delay interval
status = STATUS_INITIALIZING;
doProtocolInitialisation();
vc.rfb = rfb;
vc.setPixelFormat();
vc.rfb.writeFramebufferUpdateRequest(0, 0,
vc.rfb.framebufferWidth, vc.rfb.framebufferHeight,
false);
status = STATUS_NORMAL_OPERATION;
vc.processNormalProtocol();
} catch (AuthenticationException e) {
status = STATUS_AUTHENTICATION_FAILURE;
String msg = e.getMessage();
Logger.log(Logger.INFO, msg);
} catch (Exception e) {
status = STATUS_ERROR;
Logger.log(Logger.INFO, e.toString());
} finally {
String oldName = Thread.currentThread().getName();
encodingsSaved = null;
nEncodingsSaved = 0;
synchronized (this) {
if (rfb != null) {
rfb.close();
}
}
}
if (dropMe) {
break;
}
if (status == STATUS_AUTHENTICATION_FAILURE) {
break;
} else {
Logger.log(Logger.INFO, "Exception caught, retrying in "
+ delay + "ms");
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
// ignored
}
delay = (int) ((float) (delay + 700) * 1.5);
if (delay > 3000) {
Logger.log(Logger.INFO, "Delay value gets too large " + delay + ", stop retrying");
break;
}
}
}
Logger.log(Logger.INFO, "RFB thread terminating");
}
//
// Create a VncCanvas instance.
//
void createCanvas(int maxWidth, int maxHeight) {
/*
* // Determine if Java 2D API is available and use a special // version
* of VncCanvas if it is present. vc = null; try { // This throws
* ClassNotFoundException if there is no Java 2D API. Class cl =
* Class.forName("java.awt.Graphics2D"); // If we could load Graphics2D
* class, then we can use VncCanvas2D. cl = Class.forName("VncCanvas2");
* Class[] argClasses = { this.getClass(), Integer.TYPE, Integer.TYPE };
* java.lang.reflect.Constructor cstr = cl.getConstructor(argClasses);
* Object[] argObjects = { this, new Integer(maxWidth), new
* Integer(maxHeight) }; vc = (VncCanvas)cstr.newInstance(argObjects); }
* catch (Exception e) { Logger.log(Logger.INFO,
* "Warning: Java 2D API is not available"); }
*
* // If we failed to create VncCanvas2D, use old VncCanvas. if (vc ==
* null)
*/
vc = new ConsoleCanvas2(this, maxWidth, maxHeight);
}
/*
* // // Process RFB socket messages. // If the rfbThread is being stopped,
* ignore any exceptions, // otherwise rethrow the exception so it can be
* handled. //
*
* void processNormalProtocol() throws Exception { try {
* vc.processNormalProtocol(); } catch (Exception e) { if (rfbThread ==
* null) { Logger.log(Logger.INFO, "Ignoring RFB socket exceptions" +
* " because applet is stopping"); } else { throw e; } } }
*/
//
// Connect to the RFB server and authenticate the user.
//
void connectAndAuthenticate() throws Exception {
showConnectionStatus("Initializing...");
if (!inProxyMode) {
if (inSeparateFrame) {
vncFrame.pack();
vncFrame.show();
} else {
applet.validate();
}
}
if (proxyHost != null) {
showConnectionStatus("Connecting to " + proxyHost + ", port "
+ proxyPort + "...");
rfb = new RfbProto(proxyHost, proxyPort, this);
rfb.readProxyVersion();
rfb.writeProxyString(host, port,
(passwordParam != null) ? passwordParam : "");
} else {
showConnectionStatus("Connecting to " + host + ", port " + port
+ "...");
rfb = new RfbProto(host, port, this);
}
showConnectionStatus("Connected to server");
rfb.readVersionMsg();
showConnectionStatus("RFB server supports protocol version "
+ rfb.serverMajor + "." + rfb.serverMinor);
rfb.writeVersionMsg();
showConnectionStatus("Using RFB protocol version " + rfb.clientMajor
+ "." + rfb.clientMinor);
int secType = rfb.negotiateSecurity();
int authType;
if (secType == RfbProto.SecTypeTight) {
showConnectionStatus("Enabling TightVNC protocol extensions");
rfb.initCapabilities();
rfb.setupTunneling();
authType = rfb.negotiateAuthenticationTight();
} else {
authType = secType;
}
switch (authType) {
case RfbProto.AuthNone:
showConnectionStatus("No authentication needed");
rfb.authenticateNone();
break;
case RfbProto.AuthVNC:
showConnectionStatus("Performing standard VNC authentication");
if (passwordParam != null) {
rfb.authenticateVNC(passwordParam);
} else {
throw new AuthenticationException("Bad password");
/*
* String pw = askPassword(); rfb.authenticateVNC(pw);
*/
}
break;
default:
throw new Exception("Unknown authentication scheme " + authType);
}
}
//
// Show a message describing the connection status.
// To hide the connection status label, use (msg == null).
//
void showConnectionStatus(String msg) {
if (inProxyMode) {
if (msg != null) {
Logger.log(Logger.INFO, msg);
}
return;
}
/*
* if (msg == null) { if (vncContainer.isAncestorOf(connStatusLabel)) {
* vncContainer.remove(connStatusLabel); } return; }
*
* Logger.log(Logger.INFO, msg);
*
* if (connStatusLabel == null) { connStatusLabel = new Label("Status: "
* + msg); connStatusLabel.setFont(new Font("Helvetica", Font.PLAIN,
* 12)); } else { connStatusLabel.setText("Status: " + msg); }
*
* if (!vncContainer.isAncestorOf(connStatusLabel)) { GridBagConstraints
* gbc = new GridBagConstraints(); gbc.gridwidth =
* GridBagConstraints.REMAINDER; gbc.fill =
* GridBagConstraints.HORIZONTAL; gbc.anchor =
* GridBagConstraints.NORTHWEST; gbc.weightx = 1.0; gbc.weighty = 1.0;
* gbc.insets = new Insets(20, 30, 20, 30);
* gridbag.setConstraints(connStatusLabel, gbc);
* vncContainer.add(connStatusLabel); }
*
* if (inSeparateFrame) { vncFrame.pack(); } else { validate(); }
*/
}
//
// Show an authentication panel.
//
/*
String askPassword() throws Exception {
showConnectionStatus(null);
AuthPanel authPanel = new AuthPanel(this);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.ipadx = 100;
gbc.ipady = 50;
gridbag.setConstraints(authPanel, gbc);
vncContainer.add(authPanel);
if (inSeparateFrame) {
vncFrame.pack();
} else {
applet.validate();
}
authPanel.moveFocusToDefaultField();
String pw = authPanel.getPassword();
vncContainer.remove(authPanel);
return pw;
}
*/
//
// Do the rest of the protocol initialisation.
//
void doProtocolInitialisation() throws IOException {
rfb.writeClientInit();
rfb.readServerInit();
/*
* Logger.log(Logger.INFO, "Desktop name is " + rfb.desktopName);
* Logger.log(Logger.INFO, "Desktop size is " + rfb.framebufferWidth +
* " x " + rfb.framebufferHeight);
*/
setEncodings();
showConnectionStatus(null);
}
//
// Send current encoding list to the RFB server.
//
int[] encodingsSaved;
int nEncodingsSaved;
void setEncodings() {
setEncodings(false);
}
void autoSelectEncodings() {
setEncodings(true);
}
void setEncodings(boolean autoSelectOnly) {
if (options == null || rfb == null || !rfb.inNormalProtocol)
return;
int preferredEncoding = options.preferredEncoding;
if (preferredEncoding == -1) {
long kbitsPerSecond = rfb.kbitsPerSecond();
if (nEncodingsSaved < 1) {
// Choose Tight or ZRLE encoding for the very first update.
// Logger.log(Logger.INFO, "Using Tight/ZRLE encodings");
preferredEncoding = RfbProto.EncodingTight;
} else if (kbitsPerSecond > 2000
&& encodingsSaved[0] != RfbProto.EncodingHextile) {
// Switch to Hextile if the connection speed is above 2Mbps.
Logger.log(Logger.INFO, "Throughput " + kbitsPerSecond
+ " kbit/s - changing to Hextile encoding");
preferredEncoding = RfbProto.EncodingHextile;
} else if (kbitsPerSecond < 1000
&& encodingsSaved[0] != RfbProto.EncodingTight) {
// Switch to Tight/ZRLE if the connection speed is below 1Mbps.
Logger.log(Logger.INFO, "Throughput " + kbitsPerSecond
+ " kbit/s - changing to Tight/ZRLE encodings");
preferredEncoding = RfbProto.EncodingTight;
} else {
// Don't change the encoder.
if (autoSelectOnly)
return;
preferredEncoding = encodingsSaved[0];
}
} else {
// Auto encoder selection is not enabled.
if (autoSelectOnly)
return;
}
int[] encodings = new int[20];
int nEncodings = 0;
encodings[nEncodings++] = preferredEncoding;
if (options.useCopyRect) {
encodings[nEncodings++] = RfbProto.EncodingCopyRect;
}
if (preferredEncoding != RfbProto.EncodingTight) {
encodings[nEncodings++] = RfbProto.EncodingTight;
}
if (preferredEncoding != RfbProto.EncodingZRLE) {
encodings[nEncodings++] = RfbProto.EncodingZRLE;
}
if (preferredEncoding != RfbProto.EncodingHextile) {
encodings[nEncodings++] = RfbProto.EncodingHextile;
}
if (preferredEncoding != RfbProto.EncodingZlib) {
encodings[nEncodings++] = RfbProto.EncodingZlib;
}
if (preferredEncoding != RfbProto.EncodingCoRRE) {
encodings[nEncodings++] = RfbProto.EncodingCoRRE;
}
if (preferredEncoding != RfbProto.EncodingRRE) {
encodings[nEncodings++] = RfbProto.EncodingRRE;
}
if (options.compressLevel >= 0 && options.compressLevel <= 9) {
encodings[nEncodings++] = RfbProto.EncodingCompressLevel0
+ options.compressLevel;
}
if (options.jpegQuality >= 0 && options.jpegQuality <= 9) {
encodings[nEncodings++] = RfbProto.EncodingQualityLevel0
+ options.jpegQuality;
}
if (options.requestCursorUpdates) {
encodings[nEncodings++] = RfbProto.EncodingXCursor;
encodings[nEncodings++] = RfbProto.EncodingRichCursor;
if (!options.ignoreCursorUpdates)
encodings[nEncodings++] = RfbProto.EncodingPointerPos;
}
encodings[nEncodings++] = RfbProto.EncodingLastRect;
encodings[nEncodings++] = RfbProto.EncodingNewFBSize;
boolean encodingsWereChanged = false;
if (nEncodings != nEncodingsSaved) {
encodingsWereChanged = true;
} else {
for (int i = 0; i < nEncodings; i++) {
if (encodings[i] != encodingsSaved[i]) {
encodingsWereChanged = true;
break;
}
}
}
if (encodingsWereChanged) {
try {
rfb.writeSetEncodings(encodings, nEncodings);
if (vc != null) {
vc.softCursorFree();
}
} catch (Exception e) {
Logger.log(Logger.ERROR, e.toString(), e);
}
encodingsSaved = encodings;
nEncodingsSaved = nEncodings;
}
}
//
// setCutText() - send the given cut text to the RFB server.
//
void setCutText(String text) {
try {
if (rfb != null && rfb.inNormalProtocol) {
rfb.writeClientCutText(text);
}
} catch (Exception e) {
Logger.log(Logger.ERROR, e.toString(), e);
}
}
//
// Order change in session recording status. To stop recording, pass
// null in place of the fname argument.
//
void setRecordingStatus(String fname) {
synchronized (recordingSync) {
sessionFileName = fname;
recordingStatusChanged = true;
}
}
//
// Start or stop session recording. Returns true if this method call
// causes recording of a new session.
//
boolean checkRecordingStatus() throws IOException {
synchronized (recordingSync) {
if (recordingStatusChanged) {
recordingStatusChanged = false;
if (sessionFileName != null) {
startRecording();
return true;
} else {
stopRecording();
}
}
}
return false;
}
//
// Start session recording.
//
protected void startRecording() throws IOException {
/*
* synchronized(recordingSync) {
*
* if (!recordingActive) { // Save settings to restore them after
* recording the session. cursorUpdatesDef =
* options.choices[options.cursorUpdatesIndex].getSelectedItem();
* eightBitColorsDef =
* options.choices[options.eightBitColorsIndex].getSelectedItem(); //
* Set options to values suitable for recording.
* options.choices[options.cursorUpdatesIndex].select("Disable");
* options.choices[options.cursorUpdatesIndex].setEnabled(false);
* options.setEncodings();
* options.choices[options.eightBitColorsIndex].select("No");
* options.choices[options.eightBitColorsIndex].setEnabled(false);
* options.setColorFormat(); } else { rfb.closeSession(); }
*
* Logger.log(Logger.INFO, "Recording the session in " +
* sessionFileName); rfb.startSession(sessionFileName); recordingActive
* = true; }
*/
}
//
// Stop session recording.
//
protected void stopRecording() throws IOException {
/*
* synchronized(recordingSync) { if (recordingActive) { // Restore
* options.
* options.choices[options.cursorUpdatesIndex].select(cursorUpdatesDef);
* options.choices[options.cursorUpdatesIndex].setEnabled(true);
* options.setEncodings();
* options.choices[options.eightBitColorsIndex].select
* (eightBitColorsDef);
* options.choices[options.eightBitColorsIndex].setEnabled(true);
* options.setColorFormat();
*
* rfb.closeSession(); Logger.log(Logger.INFO,
* "Session recording stopped."); } sessionFileName = null;
* recordingActive = false; }
*/
}
//
// readParameters() - read parameters from the html source or from the
// command line. On the command line, the arguments are just a sequence of
// param_name/param_value pairs where the names and values correspond to
// those expected in the html applet tag source.
//
void readParameters() {
String str;
host = readParameter("HOST", true);
str = readParameter("PORT", true);
port = Integer.parseInt(str);
proxyHost = readParameter("PROXYHOST", false);
if (proxyHost != null) {
str = readParameter("PROXYPORT", true);
proxyPort = Integer.parseInt(str);
}
// Read "ENCPASSWORD" or "PASSWORD" parameter if specified.
readPasswordParameters();
if (inAnApplet) {
str = readParameter("Open New Window", false);
if (str != null && str.equalsIgnoreCase("Yes"))
inSeparateFrame = true;
}
// "Show Controls" set to "No" disables button panel.
showControls = false;
str = readParameter("Show Controls", false);
if (str != null && str.equalsIgnoreCase("No"))
showControls = false;
// "Offer Relogin" set to "No" disables "Login again" and "Close
// window" buttons under error messages in applet mode.
offerRelogin = false;
str = readParameter("Offer Relogin", false);
if (str != null && str.equalsIgnoreCase("No"))
offerRelogin = false;
// Do we continue showing desktop on remote disconnect?
showOfflineDesktop = false;
str = readParameter("Show Offline Desktop", false);
if (str != null && str.equalsIgnoreCase("Yes"))
showOfflineDesktop = true;
// Fine tuning options.
deferScreenUpdates = readIntParameter("Defer screen updates", 20);
deferCursorUpdates = readIntParameter("Defer cursor updates", 10);
deferUpdateRequests = readIntParameter("Defer update requests", 50);
// SocketFactory.
socketFactory = readParameter("SocketFactory", false);
}
//
// Read password parameters.
//
private void readPasswordParameters() {
String str = readParameter("SID", false);
if (str != null)
passwordParam = str;
}
public String readParameter(String name, boolean required) {
if (inAnApplet) {
String s = applet.getParameter(name);
// Logger.log(Logger.INFO, "getParameter " + name + " = " + s);
if ((s == null) && required) {
fatalError(name + " parameter not specified");
}
return s;
}
for (int i = 0; i < mainArgs.length; i += 2) {
if (mainArgs[i].equalsIgnoreCase(name)) {
try {
return mainArgs[i + 1];
} catch (Exception e) {
if (required) {
fatalError(name + " parameter not specified");
}
return null;
}
}
}
if (required) {
fatalError(name + " parameter not specified");
}
return null;
}
int readIntParameter(String name, int defaultValue) {
String str = readParameter(name, false);
int result = defaultValue;
if (str != null) {
try {
result = Integer.parseInt(str);
} catch (NumberFormatException e) {
}
}
return result;
}
//
// moveFocusToDesktop() - move keyboard focus either to VncCanvas.
//
void moveFocusToDesktop() {
if (vncContainer != null) {
if (vc != null && vncContainer.isAncestorOf(vc))
vc.requestFocus();
}
}
//
// disconnect() - close connection to server.
//
synchronized public void disconnect() {
Logger.log(Logger.INFO, "Disconnect");
synchronized (this) {
if (rfb != null)
rfb.close();
}
// options.dispose();
// clipboard.dispose();
if (rec != null)
rec.dispose();
if (inAnApplet) {
showMessage("Disconnected");
} else {
System.exit(0);
}
}
//
// fatalError() - print out a fatal error message.
// FIXME: Do we really need two versions of the fatalError() method?
//
synchronized public void fatalError(String str) {
Logger.log(Logger.INFO, str);
if (inAnApplet) {
// vncContainer null, applet not inited,
// can not present the error to the user.
Thread.currentThread().stop();
} else {
System.exit(1);
}
}
synchronized public void fatalError(String str, Exception e) {
/*
* if (rfb != null && rfb.closed()) { // Not necessary to show error
* message if the error was caused // by I/O problems after the
* rfb.close() method call. Logger.log(Logger.INFO,
* "RFB thread finished"); return; }
*/
if (str == null) {
str = "";
}
Logger.log(Logger.INFO, str, e);
showMessage(str);
}
//
// Show message text and optionally "Relogin" and "Close" buttons.
//
void showMessage(String msg) {
if (vc != null) {
vc.paintErrorString(msg);
return;
}
Logger.log(Logger.INFO, msg);
/*
* vncContainer.removeAll();
*
* Logger.log(Logger.INFO, "showMessage " + msg);
*
* Label errLabel = new Label(msg, Label.CENTER); errLabel.setFont(new
* Font("Helvetica", Font.PLAIN, 12));
*
* if (offerRelogin) {
*
* Panel gridPanel = new Panel(new GridLayout(0, 1)); Panel outerPanel =
* new Panel(new FlowLayout(FlowLayout.LEFT));
* outerPanel.add(gridPanel); vncContainer.setLayout(new
* FlowLayout(FlowLayout.LEFT, 30, 16)); vncContainer.add(outerPanel);
* Panel textPanel = new Panel(new FlowLayout(FlowLayout.CENTER));
* textPanel.add(errLabel); gridPanel.add(textPanel); gridPanel.add(new
* ReloginPanel(this));
*
* } else {
*
* vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
* vncContainer.add(errLabel);
*
* }
*
* if (inSeparateFrame) { vncFrame.pack(); } else { validate(); }
*/
}
//
// Stop the applet.
// Main applet thread will terminate on first exception
// after seeing that rfb has been closed.
//
public void stop() {
Logger.log(Logger.INFO, "Stopping applet");
synchronized (this) {
if (rfb != null) {
rfb.close();
}
}
}
//
// This method is called before the applet is destroyed.
//
public void destroy() {
Logger.log(Logger.INFO, "Destroying applet");
vncContainer.removeAll();
// options.dispose();
// clipboard.dispose();
if (rec != null)
rec.dispose();
synchronized (this) {
if (rfb != null)
rfb.close();
}
if (inSeparateFrame)
vncFrame.dispose();
}
//
// Start/stop receiving mouse events.
//
public void enableInput(boolean enable) {
vc.enableInput(enable);
}
//
// Close application properly on window close event.
//
public void windowClosing(WindowEvent evt) {
Logger.log(Logger.INFO, "Closing window");
if (rfb != null)
disconnect();
vncContainer.hide();
if (!inAnApplet) {
System.exit(0);
}
}
public String toString() {
return ("{ConsoleViewer-"
+ host
+ ":"
+ port
+ (" created=\"" + new Date(createTime)) + "\""
+ (" lastused=\"" + new Date(lastUsedTime)) + "\""
+ (clientStream != null ? (" client=" + clientStreamInfo) : "") + "}");
}
}