home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1998 September / PCO_0998.ISO / filesbbs / frei / vnc-java.arj / VNC-JAVA.ZIP / vncviewer.java < prev   
Encoding:
Java Source  |  1998-05-08  |  10.4 KB  |  469 lines

  1. //
  2. //  Copyright (C) 1997, 1998 Olivetti & Oracle Research Laboratory
  3. //
  4. //  This is free software; you can redistribute it and/or modify
  5. //  it under the terms of the GNU General Public License as published by
  6. //  the Free Software Foundation; either version 2 of the License, or
  7. //  (at your option) any later version.
  8. //
  9. //  This software is distributed in the hope that it will be useful,
  10. //  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. //  GNU General Public License for more details.
  13. //
  14. //  You should have received a copy of the GNU General Public License
  15. //  along with this software; if not, write to the Free Software
  16. //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  17. //  USA.
  18. //
  19.  
  20. //
  21. // vncviewer.java - the VNC viewer applet.  This class mainly just sets up the
  22. // user interface, leaving it to the vncCanvas to do the actual rendering of
  23. // a VNC desktop.
  24. //
  25.  
  26. import java.awt.*;
  27. import java.io.*;
  28.  
  29. public class vncviewer extends java.applet.Applet
  30.                implements java.lang.Runnable
  31. {
  32.   boolean inAnApplet = true;
  33.  
  34.   //
  35.   // main() is called when run as a java program from the command line.  It
  36.   // simply creates a frame and runs the applet inside it.
  37.   //
  38.  
  39.   public static void main(String[] argv) {
  40.     vncviewer v = new vncviewer();
  41.     v.mainArgs = argv;
  42.     v.inAnApplet = false;
  43.  
  44.     v.f = new Frame("VNC");
  45.     v.f.add("Center", v);
  46.  
  47.     v.init();
  48.     v.start();
  49.   }
  50.  
  51.   Frame f;
  52.   String[] mainArgs;
  53.   String host;
  54.   int port;
  55.   rfbProto rfb;
  56.   Thread rfbThread;
  57.   GridBagLayout gridbag;
  58.   Panel buttonPanel;
  59.   Button disconnectButton;
  60.   Button optionsButton;
  61.   Button clipboardButton;
  62.   Button ctrlAltDelButton;
  63.   optionsFrame options;
  64.   clipboardFrame clipboard;
  65.   authenticationPanel authenticator;
  66.  
  67.  
  68.   //
  69.   // init()
  70.   //
  71.  
  72.   public void init() {
  73.  
  74.     readParameters();
  75.  
  76.     options = new optionsFrame(this);
  77.     clipboard = new clipboardFrame(this);
  78.     authenticator = new authenticationPanel();
  79.  
  80.     rfbThread = new Thread(this);
  81.     rfbThread.start();
  82.   }
  83.  
  84.   public void update(Graphics g) {
  85.   }
  86.  
  87.   //
  88.   // run() - executed by the rfbThread to deal with the RFB socket.
  89.   //
  90.  
  91.   public void run() {
  92.  
  93.     gridbag = new GridBagLayout();
  94.     setLayout(gridbag);
  95.  
  96.     buttonPanel = new Panel();
  97.     buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
  98.     disconnectButton = new Button("Disconnect");
  99.     disconnectButton.disable();
  100.     buttonPanel.add(disconnectButton);
  101.     optionsButton = new Button("Options");
  102.     buttonPanel.add(optionsButton);
  103.     clipboardButton = new Button("Clipboard");
  104.     clipboardButton.disable();
  105.     buttonPanel.add(clipboardButton);
  106.     ctrlAltDelButton = new Button("Send Ctrl-Alt-Del");
  107.     ctrlAltDelButton.disable();
  108.     buttonPanel.add(ctrlAltDelButton);
  109.  
  110.     GridBagConstraints gbc = new GridBagConstraints();
  111.     gbc.gridwidth = GridBagConstraints.REMAINDER;
  112.     gbc.anchor = GridBagConstraints.NORTHWEST;
  113.     gridbag.setConstraints(buttonPanel,gbc);
  114.     add(buttonPanel);
  115.  
  116.     try {
  117.       connectAndAuthenticate();
  118.  
  119.       doProtocolInitialisation();
  120.  
  121.       vncCanvas vc = new vncCanvas(this);
  122.       gbc.weightx = 1.0;
  123.       gbc.weighty = 1.0;
  124.       gridbag.setConstraints(vc,gbc);
  125.       add(vc);
  126.  
  127.       if (!inAnApplet) {
  128.     f.setTitle(rfb.desktopName);
  129.     f.pack();
  130.       } else {
  131.     validate();
  132.       }
  133.  
  134.       disconnectButton.enable();
  135.       clipboardButton.enable();
  136.       ctrlAltDelButton.enable();
  137.  
  138.       vc.processNormalProtocol();
  139.  
  140.     } catch (Exception e) {
  141.       e.printStackTrace();
  142.       fatalError(e.toString());
  143.     }
  144.     
  145.   }
  146.  
  147.  
  148.   //
  149.   // Connect to the RFB server and authenticate the user.
  150.   //
  151.  
  152.   void connectAndAuthenticate() throws IOException {
  153.  
  154.     GridBagConstraints gbc = new GridBagConstraints();
  155.     gbc.gridwidth = GridBagConstraints.REMAINDER;
  156.     gbc.anchor = GridBagConstraints.NORTHWEST;
  157.     gbc.weightx = 1.0;
  158.     gbc.weighty = 1.0;
  159.     gbc.ipadx = 100;
  160.     gbc.ipady = 50;
  161.     gridbag.setConstraints(authenticator,gbc);
  162.     add(authenticator);
  163.     validate();
  164.     if (!inAnApplet) {
  165.       f.pack();
  166.       f.show();
  167.     }
  168.  
  169.     boolean authenticationDone = false;
  170.  
  171.     while (!authenticationDone) {
  172.  
  173.       synchronized(authenticator) {
  174.     try {
  175.       authenticator.wait();
  176.     } catch (InterruptedException e) {
  177.     }
  178.       }
  179.  
  180.       rfb = new rfbProto(host, port, this);
  181.  
  182.       rfb.readVersionMsg();
  183.  
  184.       System.out.println("RFB server supports protocol version " +
  185.              rfb.serverMajor + "." + rfb.serverMinor);
  186.  
  187.       rfb.writeVersionMsg();
  188.  
  189.       switch (rfb.readAuthScheme()) {
  190.  
  191.       case rfb.NoAuth:
  192.     System.out.println("No authentication needed");
  193.     authenticationDone = true;
  194.     break;
  195.  
  196.       case rfb.VncAuth:
  197.     byte[] challenge = new byte[16];
  198.     rfb.is.readFully(challenge);
  199.  
  200.     String pw = authenticator.password.getText();
  201.     if (pw.length() > 8) pw = pw.substring(0,8); // truncate to 8 chars
  202.  
  203.     if (pw.length() == 0) {
  204.       authenticator.retry();
  205.       break;
  206.     }
  207.  
  208.     byte[] key = new byte[8];
  209.     pw.getBytes(0, pw.length(), key, 0);
  210.  
  211.     for (int i = pw.length(); i < 8; i++) {
  212.       key[i] = (byte)0;
  213.     }
  214.  
  215.     DesCipher des = new DesCipher(key);
  216.  
  217.     des.encrypt(challenge,0,challenge,0);
  218.     des.encrypt(challenge,8,challenge,8);
  219.  
  220.     rfb.os.write(challenge);
  221.  
  222.     int authResult = rfb.is.readInt();
  223.  
  224.     switch (authResult) {
  225.     case rfb.VncAuthOK:
  226.       System.out.println("VNC authentication succeeded");
  227.       authenticationDone = true;
  228.       break;
  229.     case rfb.VncAuthFailed:
  230.       System.out.println("VNC authentication failed");
  231.       authenticator.retry();
  232.       break;
  233.     case rfb.VncAuthTooMany:
  234.       throw new IOException("VNC authentication failed - " +
  235.                 "too many tries");
  236.     default:
  237.       throw new IOException("Unknown VNC authentication result " +
  238.                 authResult);
  239.     }
  240.     break;
  241.       }
  242.     }
  243.  
  244.     remove(authenticator);
  245.   }
  246.  
  247.  
  248.   //
  249.   // Do the rest of the protocol initialisation.
  250.   //
  251.  
  252.   void doProtocolInitialisation() throws IOException {
  253.     System.out.println("sending client init");
  254.  
  255.     rfb.writeClientInit();
  256.  
  257.     rfb.readServerInit();
  258.  
  259.     System.out.println("Desktop name is " + rfb.desktopName);
  260.     System.out.println("Desktop size is " + rfb.framebufferWidth + " x " +
  261.                rfb.framebufferHeight);
  262.  
  263.     setEncodings();
  264.   }
  265.  
  266.  
  267.   //
  268.   // setEncodings() - send the current encodings from the options frame
  269.   // to the RFB server.
  270.   //
  271.  
  272.   void setEncodings() {
  273.     try {
  274.       if ((rfb != null) && rfb.inNormalProtocol) {
  275.     rfb.writeSetEncodings(options.encodings, options.nEncodings);
  276.       }
  277.     } catch (Exception e) {
  278.       e.printStackTrace();
  279.     }
  280.   }
  281.  
  282.  
  283.   //
  284.   // setCutText() - send the given cut text to the RFB server.
  285.   //
  286.  
  287.   void setCutText(String text) {
  288.     try {
  289.       if ((rfb != null) && rfb.inNormalProtocol) {
  290.     rfb.writeClientCutText(text);
  291.       }
  292.     } catch (Exception e) {
  293.       e.printStackTrace();
  294.     }
  295.   }
  296.  
  297.  
  298.   //
  299.   // Respond to an action i.e. button press
  300.   //
  301.  
  302.   public synchronized boolean action(Event evt, Object what) {
  303.  
  304.     if (evt.target == optionsButton) {
  305.  
  306.       if (options.isVisible()) {
  307.     options.hide();
  308.       } else {
  309.     options.show();
  310.       }
  311.  
  312.     } else if (evt.target == disconnectButton) {
  313.  
  314.       System.out.println("disconnect");
  315.       options.dispose();
  316.       clipboard.dispose();
  317.  
  318.       if (inAnApplet) {
  319.     removeAll();
  320.     rfb.close();
  321.     rfb = null;
  322.     Label l = new Label("Disconnected");
  323.     setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
  324.     add(l);
  325.     validate();
  326.     rfbThread.stop();
  327.       } else {
  328.     System.exit(1);
  329.       }
  330.  
  331.     } else if (evt.target == clipboardButton) {
  332.  
  333.       if (clipboard.isVisible()) {
  334.     clipboard.hide();
  335.       } else {
  336.     clipboard.show();
  337.       }
  338.  
  339.     } else if (evt.target == ctrlAltDelButton) {
  340.  
  341.       try {
  342.     Event ctrlAltDelEvent = new Event(null, 0, null);
  343.  
  344.     ctrlAltDelEvent.key = 127;
  345.     ctrlAltDelEvent.modifiers = Event.CTRL_MASK | Event.ALT_MASK;
  346.  
  347.     ctrlAltDelEvent.id = Event.KEY_PRESS;
  348.     rfb.writeKeyEvent(ctrlAltDelEvent);
  349.  
  350.     ctrlAltDelEvent.id = Event.KEY_RELEASE;
  351.     rfb.writeKeyEvent(ctrlAltDelEvent);
  352.       } catch (Exception e) {
  353.     e.printStackTrace();
  354.       }
  355.     }
  356.     return false;
  357.   }
  358.  
  359.  
  360.   //
  361.   // Detect when the focus goes in and out of the applet.  See
  362.   // vncCanvas.handleEvent() for details of why this is necessary.
  363.   //
  364.  
  365.   boolean gotFocus = false;
  366.  
  367.   public boolean gotFocus(Event evt, Object what) {
  368.     gotFocus = true;
  369.     return true;
  370.   }
  371.   public boolean lostFocus(Event evt, Object what) {
  372.     gotFocus = false;
  373.     return true;
  374.   }
  375.  
  376.  
  377.   //
  378.   // encryptBytes() - encrypt some bytes in memory using a password.  Note that
  379.   // the mapping from password to key must be the same as that used on the rfb
  380.   // server side.
  381.   //
  382.   // Note also that IDEA encrypts data in 8-byte blocks, so here we will ignore
  383.   // any data beyond the last 8-byte boundary leaving it to the calling
  384.   // function to pad the data appropriately.
  385.   //
  386.  
  387.   void encryptBytes(byte[] bytes, String passwd) {
  388.     byte[] key = new byte[8];
  389.     passwd.getBytes(0, passwd.length(), key, 0);
  390.  
  391.     for (int i = passwd.length(); i < 8; i++) {
  392.       key[i] = (byte)0;
  393.     }
  394.  
  395.     DesCipher des = new DesCipher(key);
  396.  
  397.     des.encrypt(bytes,0,bytes,0);
  398.     des.encrypt(bytes,8,bytes,8);
  399.   }
  400.  
  401.  
  402.   //
  403.   // readParameters() - read parameters from the html source or from the
  404.   // command line.  On the command line, the arguments are just a sequence of
  405.   // param_name/param_value pairs where the names and values correspond to
  406.   // those expected in the html applet tag source.
  407.   //
  408.  
  409.   public void readParameters() {
  410.     host = readParameter("HOST", !inAnApplet);
  411.     if (host == null) {
  412.       host = getCodeBase().getHost();
  413.       if (host.equals("")) {
  414.     fatalError("HOST parameter not specified");
  415.       }
  416.     }
  417.  
  418.     String s = readParameter("PORT", true);
  419.     port = Integer.parseInt(s);
  420.   }
  421.  
  422.   public String readParameter(String name, boolean required) {
  423.     if (inAnApplet) {
  424.       String s = getParameter(name);
  425.       if ((s == null) && required) {
  426.     fatalError(name + " parameter not specified");
  427.       }
  428.       return s;
  429.     }
  430.  
  431.     for (int i = 0; i < mainArgs.length; i += 2) {
  432.       if (mainArgs[i].equalsIgnoreCase(name)) {
  433.     try {
  434.       return mainArgs[i+1];
  435.     } catch (Exception e) {
  436.       if (required) {
  437.         fatalError(name + " parameter not specified");
  438.       }
  439.       return null;
  440.     }
  441.       }
  442.     }
  443.     if (required) {
  444.       fatalError(name + " parameter not specified");
  445.     }
  446.     return null;
  447.   }
  448.  
  449.   //
  450.   // fatalError() - print out a fatal error message.
  451.   //
  452.  
  453.   public void fatalError(String s) {
  454.     System.out.println(s);
  455.  
  456.     if (inAnApplet) {
  457.       removeAll();
  458.       Label l = new Label(s);
  459.  
  460.       setLayout(new FlowLayout(FlowLayout.LEFT, 30, 30));
  461.       add(l);
  462.       validate();
  463.       Thread.currentThread().stop();
  464.     } else {
  465.       System.exit(1);
  466.     }
  467.   }
  468. }
  469.