Preliminary version of RFB Session Player converted from TightVNC Java
viewer sources.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@2500 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/java/src/com/tightvnc/rfbplayer/RfbPlayer.java b/java/src/com/tightvnc/rfbplayer/RfbPlayer.java
index 2524a50..4a9bc2f 100644
--- a/java/src/com/tightvnc/rfbplayer/RfbPlayer.java
+++ b/java/src/com/tightvnc/rfbplayer/RfbPlayer.java
@@ -18,17 +18,11 @@
 //  USA.
 //
 
-//
-// VncViewer.java - the VNC viewer applet.  This class mainly just sets up the
-// user interface, leaving it to the VncCanvas to do the actual rendering of
-// a VNC desktop.
-//
-
 import java.awt.*;
 import java.awt.event.*;
 import java.io.*;
 
-public class VncViewer extends java.applet.Applet
+public class RfbPlayer extends java.applet.Applet
   implements java.lang.Runnable, WindowListener {
 
   boolean inAnApplet = true;
@@ -40,13 +34,13 @@
   //
 
   public static void main(String[] argv) {
-    VncViewer v = new VncViewer();
-    v.mainArgs = argv;
-    v.inAnApplet = false;
-    v.inSeparateFrame = true;
+    RfbPlayer p = new RfbPlayer();
+    p.mainArgs = argv;
+    p.inAnApplet = false;
+    p.inSeparateFrame = true;
 
-    v.init();
-    v.start();
+    p.init();
+    p.start();
   }
 
   String[] mainArgs;
@@ -54,24 +48,23 @@
   RfbProto rfb;
   Thread rfbThread;
 
+  public static final int MODE_STOPPED  = 0;
+  public static final int MODE_PLAYBACK = 1;
+  public static final int MODE_PAUSED   = 2;
+  protected int mode;
+
+  FbsInputStream fbsStream;
+
   Frame vncFrame;
   Container vncContainer;
   ScrollPane desktopScrollPane;
   GridBagLayout gridbag;
   ButtonPanel buttonPanel;
-  AuthPanel authenticator;
   VncCanvas vc;
-  OptionsFrame options;
-  ClipboardFrame clipboard;
 
-  // Variables read from parameter values.
-  String host;
-  int port;
-  String passwordParam;
+  String sessionFileName;
+  boolean showControls;
   int deferScreenUpdates;
-  int deferCursorUpdates;
-  int deferUpdateRequests;
-
 
   //
   // init()
@@ -82,7 +75,7 @@
     readParameters();
 
     if (inSeparateFrame) {
-      vncFrame = new Frame("TightVNC");
+      vncFrame = new Frame("RFB Session Player");
       if (!inAnApplet) {
 	vncFrame.add("Center", this);
       }
@@ -91,10 +84,6 @@
       vncContainer = this;
     }
 
-    options = new OptionsFrame(this);
-    clipboard = new ClipboardFrame(this);
-    authenticator = new AuthPanel();
-
     if (inSeparateFrame)
       vncFrame.addWindowListener(this);
 
@@ -106,7 +95,7 @@
   }
 
   //
-  // run() - executed by the rfbThread to deal with the RFB socket.
+  // run() - executed by the rfbThread to read RFB data.
   //
 
   public void run() {
@@ -118,17 +107,24 @@
     gbc.gridwidth = GridBagConstraints.REMAINDER;
     gbc.anchor = GridBagConstraints.NORTHWEST;
 
-    if (options.showControls) {
+    if (showControls) {
       buttonPanel = new ButtonPanel(this);
       buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
       gridbag.setConstraints(buttonPanel, gbc);
       vncContainer.add(buttonPanel);
     }
 
-    try {
-      connectAndAuthenticate();
+    if (inSeparateFrame) {
+      vncFrame.pack();
+      vncFrame.show();
+    } else {
+      validate();
+    }
 
-      doProtocolInitialisation();
+    try {
+      FileInputStream file = new FileInputStream(sessionFileName);
+      fbsStream = new FbsInputStream(file);
+      rfb = new RfbProto(fbsStream);
 
       vc = new VncCanvas(this);
       gbc.weightx = 1.0;
@@ -164,12 +160,20 @@
 
       }
 
-      if (options.showControls)
-        buttonPanel.enableButtons();
+      while (true) {
+	try {
+	  buttonPanel.setMode(MODE_STOPPED);
+	  vc.processNormalProtocol();
+	} catch (EOFException e) {
+	  file.close();
+	  file = new FileInputStream(sessionFileName);
+	  fbsStream = new FbsInputStream(file);
+	  rfb.newInputStream(fbsStream);
+	}
+      }
 
-      moveFocusToDesktop();
-      vc.processNormalProtocol();
-
+    } catch (FileNotFoundException e) {
+      fatalError(e.toString());
     } catch (Exception e) {
       e.printStackTrace();
       fatalError(e.toString());
@@ -177,196 +181,19 @@
     
   }
 
-
-  //
-  // Connect to the RFB server and authenticate the user.
-  //
-
-  void connectAndAuthenticate() throws IOException {
-
-    // The simplest case -- don't ask user a password, get it from the
-    // "PASSWORD" parameter instead. Authentication failures would be
-    // fatal.
-
-    if (passwordParam != null) {
-      if (inSeparateFrame) {
-	vncFrame.pack();
-	vncFrame.show();
-      } else {
-	validate();
-      }
-      if (!tryAuthenticate(passwordParam)) {
-	throw new IOException("VNC authentication failed");
-      }
-      return;
-    }
-
-    // There is no "PASSWORD" parameter -- ask user for a password,
-    // try to authenticate, retry on authentication failures.
-
-    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(authenticator, gbc);
-    vncContainer.add(authenticator);
-
-    if (inSeparateFrame) {
-      vncFrame.pack();
-      vncFrame.show();
-    } else {
-      validate();
-      // FIXME: here moveFocusToPasswordField() does not always work
-      // under Netscape 4.7x/Java 1.1.5/Linux. It seems like this call
-      // is being executed before the password field of the
-      // authenticator is fully drawn and activated, therefore
-      // requestFocus() does not work. Currently, I don't know how to
-      // solve this problem.
-      //   -- const
-      authenticator.moveFocusToPasswordField();
-    }
-
-    while (true) {
-      // Wait for user entering a password.
-      synchronized(authenticator) {
-	try {
-	  authenticator.wait();
-	} catch (InterruptedException e) {
-	}
-      }
-
-      // Try to authenticate with a given password.
-      if (tryAuthenticate(authenticator.password.getText()))
-	break;
-
-      // Retry on authentication failure.
-      authenticator.retry();
-    }
-
-    vncContainer.remove(authenticator);
+  public int getMode() {
+    return mode;
   }
 
-
-  //
-  // Try to authenticate with a given password.
-  //
-
-  boolean tryAuthenticate(String pw) throws IOException {
-
-    rfb = new RfbProto(host, port, this);
-
-    rfb.readVersionMsg();
-
-    System.out.println("RFB server supports protocol version " +
-		       rfb.serverMajor + "." + rfb.serverMinor);
-
-    rfb.writeVersionMsg();
-
-    int authScheme = rfb.readAuthScheme();
-
-    switch (authScheme) {
-
-    case RfbProto.NoAuth:
-      System.out.println("No authentication needed");
-      return true;
-
-    case RfbProto.VncAuth:
-      byte[] challenge = new byte[16];
-      rfb.is.readFully(challenge);
-
-      if (pw.length() > 8)
-	pw = pw.substring(0, 8); // Truncate to 8 chars
-
-      byte[] key = {0, 0, 0, 0, 0, 0, 0, 0};
-      System.arraycopy(pw.getBytes(), 0, key, 0, pw.length());
-
-      DesCipher des = new DesCipher(key);
-
-      des.encrypt(challenge, 0, challenge, 0);
-      des.encrypt(challenge, 8, challenge, 8);
-
-      rfb.os.write(challenge);
-
-      int authResult = rfb.is.readInt();
-
-      switch (authResult) {
-      case RfbProto.VncAuthOK:
-	System.out.println("VNC authentication succeeded");
-	return true;
-      case RfbProto.VncAuthFailed:
-	System.out.println("VNC authentication failed");
-	break;
-      case RfbProto.VncAuthTooMany:
-	throw new IOException("VNC authentication failed - " +
-			      "too many tries");
-      default:
-	throw new IOException("Unknown VNC authentication result " +
-			      authResult);
+  public void setMode(int mode) {
+    this.mode = mode;
+    if (vc != null) {
+      synchronized(vc) {
+	vc.notify();
       }
-      break;
-
-    default:
-      throw new IOException("Unknown VNC authentication scheme " +
-			    authScheme);
-    }
-    return false;
-  }
-
-
-  //
-  // Do the rest of the protocol initialisation.
-  //
-
-  void doProtocolInitialisation() throws IOException {
-
-    rfb.writeClientInit();
-
-    rfb.readServerInit();
-
-    System.out.println("Desktop name is " + rfb.desktopName);
-    System.out.println("Desktop size is " + rfb.framebufferWidth + " x " +
-		       rfb.framebufferHeight);
-
-    setEncodings();
-  }
-
-
-  //
-  // Send current encoding list to the RFB server.
-  //
-
-  void setEncodings() {
-    try {
-      if (rfb != null && rfb.inNormalProtocol) {
-	rfb.writeSetEncodings(options.encodings, options.nEncodings);
-	if (vc != null) {
-	  vc.softCursorFree();
-	}
-      }
-    } catch (Exception e) {
-      e.printStackTrace();
     }
   }
 
-
-  //
-  // setCutText() - send the given cut text to the RFB server.
-  //
-
-  void setCutText(String text) {
-    try {
-      if ((rfb != null) && rfb.inNormalProtocol) {
-	rfb.writeClientCutText(text);
-      }
-    } catch (Exception e) {
-      e.printStackTrace();
-    }
-  }
-
-
   //
   // readParameters() - read parameters from the html source or from the
   // command line.  On the command line, the arguments are just a sequence of
@@ -375,16 +202,13 @@
   //
 
   public void readParameters() {
-    host = readParameter("HOST", !inAnApplet);
-    if (host == null) {
-      host = getCodeBase().getHost();
-      if (host.equals("")) {
-	fatalError("HOST parameter not specified");
-      }
-    }
 
-    String str = readParameter("PORT", true);
-    port = Integer.parseInt(str);
+    sessionFileName = readParameter("FILE", true);
+
+    showControls = true;
+    String str = readParameter("Show Controls", false);
+    if (str != null && str.equalsIgnoreCase("No"))
+      showControls = false;
 
     if (inAnApplet) {
       str = readParameter("Open New Window", false);
@@ -392,12 +216,8 @@
 	inSeparateFrame = true;
     }
 
-    passwordParam = readParameter("PASSWORD", false);
-
     // Fine tuning options.
     deferScreenUpdates = readIntParameter("Defer screen updates", 20);
-    deferCursorUpdates = readIntParameter("Defer cursor updates", 10);
-    deferUpdateRequests = readIntParameter("Defer update requests", 50);
   }
 
   public String readParameter(String name, boolean required) {
@@ -439,51 +259,6 @@
   }
 
   //
-  // moveFocusToDesktop() - move keyboard focus either to the
-  // VncCanvas or to the AuthPanel.
-  //
-
-  void moveFocusToDesktop() {
-    if (vncContainer != null) {
-      if (vc != null && vncContainer.isAncestorOf(vc)) {
-	vc.requestFocus();
-      } else if (vncContainer.isAncestorOf(authenticator)) {
-	authenticator.moveFocusToPasswordField();
-      }
-    }
-  }
-
-  //
-  // disconnect() - close connection to server.
-  //
-
-  public void disconnect() {
-    System.out.println("Disconnect");
-    options.dispose();
-    clipboard.dispose();
-
-    if (inAnApplet) {
-      vncContainer.removeAll();
-      if (rfb != null) {
-	rfb.close();
-	rfb = null;
-      }
-      Label errLabel = new Label("Disconnected");
-      errLabel.setFont(new Font("Helvetica", Font.PLAIN, 12));
-      vncContainer.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
-      vncContainer.add(errLabel);
-      if (inSeparateFrame) {
-	vncFrame.pack();
-      } else {
-	validate();
-      }
-      rfbThread.stop();
-    } else {
-      System.exit(0);
-    }
-  }
-
-  //
   // fatalError() - print out a fatal error message.
   //
 
@@ -493,7 +268,6 @@
     if (inAnApplet) {
       vncContainer.removeAll();
       if (rfb != null) {
-	rfb.close();
 	rfb = null;
       }
       Label errLabel = new Label(str);
@@ -518,10 +292,8 @@
 
   public void destroy() {
     vncContainer.removeAll();
-    options.dispose();
-    clipboard.dispose();
     if (rfb != null) {
-      rfb.close();
+      rfb = null;
     }
     if (inSeparateFrame) {
       vncFrame.dispose();
@@ -534,8 +306,9 @@
   //
 
   public void windowClosing(WindowEvent evt) {
+    vncContainer.removeAll();
     if (rfb != null)
-      disconnect();
+      rfb = null;
 
     vncFrame.dispose();
     if (!inAnApplet) {
@@ -544,18 +317,10 @@
   }
 
   //
-  // Move the keyboard focus to the password field on window activation.
-  //
-
-  public void windowActivated(WindowEvent evt) {
-    if (vncFrame.isAncestorOf(authenticator))
-      authenticator.moveFocusToPasswordField();
-  }
-
-  //
   // 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) {}