Home | History | Annotate | Download | only in ssl
      1 diff -Naur JavaViewer.orig/ButtonPanel.java JavaViewer/ButtonPanel.java
      2 --- JavaViewer.orig/ButtonPanel.java	2004-12-12 20:51:02.000000000 -0500
      3 +++ JavaViewer/ButtonPanel.java	2007-05-31 15:40:45.000000000 -0400
      4 @@ -43,30 +43,36 @@
      5      viewer = v;
      6  
      7      setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
      8 -    disconnectButton = new Button("Disconnect");
      9 +	if (v.ftpOnly) {
     10 +		disconnectButton = new Button("Quit");
     11 +	} else {
     12 +		disconnectButton = new Button("Close");
     13 +	}
     14      disconnectButton.setEnabled(false);
     15      add(disconnectButton);
     16      disconnectButton.addActionListener(this);
     17 -    optionsButton = new Button("Options");
     18 -    add(optionsButton);
     19 -    optionsButton.addActionListener(this);
     20 -    clipboardButton = new Button("Clipboard");
     21 -    clipboardButton.setEnabled(false);
     22 -    add(clipboardButton);
     23 -    clipboardButton.addActionListener(this);
     24 -    if (viewer.rec != null) {
     25 -      recordButton = new Button("Record");
     26 -      add(recordButton);
     27 -      recordButton.addActionListener(this);
     28 -    }
     29 -    ctrlAltDelButton = new Button("Send Ctrl-Alt-Del");
     30 -    ctrlAltDelButton.setEnabled(false);
     31 -    add(ctrlAltDelButton);
     32 -    ctrlAltDelButton.addActionListener(this);
     33 -    refreshButton = new Button("Refresh");
     34 -    refreshButton.setEnabled(false);
     35 -    add(refreshButton);
     36 -    refreshButton.addActionListener(this);
     37 +	if (!v.ftpOnly) {
     38 +		optionsButton = new Button("Options");
     39 +		add(optionsButton);
     40 +		optionsButton.addActionListener(this);
     41 +		clipboardButton = new Button("Clipboard");
     42 +		clipboardButton.setEnabled(false);
     43 +		add(clipboardButton);
     44 +		clipboardButton.addActionListener(this);
     45 +		if (viewer.rec != null) {
     46 +			recordButton = new Button("Record");
     47 +			add(recordButton);
     48 +			recordButton.addActionListener(this);
     49 +		}
     50 +		ctrlAltDelButton = new Button("Send Ctrl-Alt-Del");
     51 +		ctrlAltDelButton.setEnabled(false);
     52 +		add(ctrlAltDelButton);
     53 +		ctrlAltDelButton.addActionListener(this);
     54 +		refreshButton = new Button("Refresh");
     55 +		refreshButton.setEnabled(false);
     56 +		add(refreshButton);
     57 +		refreshButton.addActionListener(this);
     58 +	}
     59      ftpButton = new Button("File Transfer");
     60      ftpButton.setEnabled(false);
     61      add(ftpButton);
     62 @@ -79,9 +85,10 @@
     63  
     64    public void enableButtons() {
     65      disconnectButton.setEnabled(true);
     66 +    ftpButton.setEnabled(true);
     67 +    if (viewer.ftpOnly) {return;}
     68      clipboardButton.setEnabled(true);
     69      refreshButton.setEnabled(true);
     70 -    ftpButton.setEnabled(true);
     71    }
     72  
     73    //
     74 @@ -89,6 +96,9 @@
     75    //
     76  
     77    public void disableButtonsOnDisconnect() {
     78 +    ftpButton.setEnabled(false);
     79 +    if (viewer.ftpOnly) {return;}
     80 +
     81      remove(disconnectButton);
     82      disconnectButton = new Button("Hide desktop");
     83      disconnectButton.setEnabled(true);
     84 @@ -99,7 +109,6 @@
     85      clipboardButton.setEnabled(false);
     86      ctrlAltDelButton.setEnabled(false);
     87      refreshButton.setEnabled(false);
     88 -    ftpButton.setEnabled(false);
     89  
     90      validate();
     91    }
     92 @@ -110,6 +119,7 @@
     93    //
     94  
     95    public void enableRemoteAccessControls(boolean enable) {
     96 +    if (viewer.ftpOnly) {return;}
     97      ctrlAltDelButton.setEnabled(enable);
     98    }
     99  
    100 @@ -163,9 +173,19 @@
    101      }
    102      else if (evt.getSource() == ftpButton)
    103      {
    104 -		viewer.ftp.setVisible(!viewer.ftp.isVisible());
    105 +// begin runge/x11vnc
    106 +		if (viewer.ftpOnly) {
    107 +			viewer.vncFrame.setVisible(false);
    108 +		}
    109 +		viewer.ftp.setSavedLocations();
    110 +		if (viewer.ftp.isVisible()) {
    111 +			viewer.ftp.doClose();
    112 +		} else {
    113 +			viewer.ftp.doOpen();
    114 +		}
    115 +// end runge/x11vnc
    116  		viewer.rfb.readServerDriveList();
    117 -	
    118 +
    119      }
    120    }
    121  }
    122 diff -Naur JavaViewer.orig/FTPFrame.java JavaViewer/FTPFrame.java
    123 --- JavaViewer.orig/FTPFrame.java	2005-03-15 23:53:14.000000000 -0500
    124 +++ JavaViewer/FTPFrame.java	2009-01-13 09:48:30.000000000 -0500
    125 @@ -24,8 +24,17 @@
    126  import java.io.*;
    127  import java.util.ArrayList;
    128  import java.util.Vector;
    129 +import java.util.Date;
    130  import javax.swing.*;
    131  
    132 +import java.nio.ByteBuffer;
    133 +import java.nio.CharBuffer;
    134 +import java.nio.charset.*;
    135 +
    136 +// begin runge/x11vnc
    137 +import java.util.Arrays;
    138 +// end runge/x11vnc
    139 +
    140  
    141  /*
    142   * Created on Feb 25, 2004
    143 @@ -74,12 +83,31 @@
    144  	public javax.swing.JTextField connectionStatus = null;
    145  	public boolean updateDriveList;
    146  	private Vector remoteList = null;
    147 +	private Vector remoteListInfo = null;
    148  	private Vector localList = null;
    149 +	private Vector localListInfo = null;
    150  	private File currentLocalDirectory = null;	// Holds the current local Directory
    151  	private File currentRemoteDirectory = null;	// Holds the current remote Directory
    152  	private File localSelection = null;		// Holds the currently selected local file  
    153  	private String remoteSelection = null;	// Holds the currently selected remote file
    154  	public String selectedTable = null;
    155 +
    156 +// begin runge/x11vnc
    157 +	private javax.swing.JButton viewButton = null;
    158 +	private javax.swing.JButton refreshButton = null;
    159 +	public File saveLocalDirectory = null;
    160 +	public long saveLocalDirectoryTime = 0;
    161 +	public int saveLocalDirectoryCount = 0;
    162 +	public String saveRemoteDirectory = null;
    163 +	public long saveRemoteDirectoryTime = 0;
    164 +	public int saveRemoteDirectoryCount = 0;
    165 +	private boolean localCurrentIsDir = true;
    166 +	private int lastRemoteIndex = -1;
    167 +	private int lastLocalIndex = -1;
    168 +	private boolean doingShortcutDir = false;
    169 +	private boolean gotShortcutDir = false;
    170 +	private boolean ignore_events = false;
    171 +// end   runge/x11vnc
    172  	
    173  //	 sf@2004 - Separate directories and files for better lisibility
    174  	private ArrayList DirsList;
    175 @@ -125,11 +153,61 @@
    176  	 
    177  	 void refreshRemoteLocation()
    178  	 {
    179 +
    180 +//System.out.println("refreshRemoteLocation1");
    181  		remoteList.clear();
    182 +		remoteListInfo.clear();
    183  		remoteFileTable.setListData(remoteList);	
    184 +System.out.println("refreshRemoteLocation '" + remoteLocation.getText() + "'");	// runge/x11vnc
    185  		viewer.rfb.readServerDirectory(remoteLocation.getText());
    186  	 }
    187  	 
    188 +// begin runge/x11vnc
    189 +	 public void setSavedLocations() {
    190 +		saveLocalDirectory = currentLocalDirectory;
    191 +		saveLocalDirectoryTime = System.currentTimeMillis();
    192 +		saveLocalDirectoryCount = 0;
    193 +
    194 +		if (remoteLocation != null) {
    195 +			saveRemoteDirectory = remoteLocation.getText();
    196 +System.out.println("RemoteSave '" + saveRemoteDirectory + "'");
    197 +		}
    198 +		saveRemoteDirectoryTime = System.currentTimeMillis();
    199 +		saveRemoteDirectoryCount = 0;
    200 +	 }
    201 +
    202 +	private File saveLocalHack(File dir) {
    203 +		saveLocalDirectoryCount++;
    204 +//System.out.println("L " + saveLocalDirectoryCount + " dt: " + (System.currentTimeMillis() - saveLocalDirectoryTime) + " - " + saveLocalDirectory);
    205 +		if (System.currentTimeMillis() > saveLocalDirectoryTime + 2000 || saveLocalDirectoryCount > 2) {
    206 +			saveLocalDirectory = null;
    207 +		}
    208 +		if (saveLocalDirectory != null) {
    209 +			currentLocalDirectory = saveLocalDirectory;
    210 +			localLocation.setText(saveLocalDirectory.toString());
    211 +			return saveLocalDirectory;
    212 +		} else {
    213 +			return dir;
    214 +		}
    215 +	}
    216 +
    217 +	private String saveRemoteHack(String indrive) {
    218 +		saveRemoteDirectoryCount++;
    219 +//System.out.println("R " + saveRemoteDirectoryCount + " - " + saveRemoteDirectory);
    220 +		if (saveRemoteDirectory != null && saveRemoteDirectoryCount > 1) {
    221 +			saveRemoteDirectory = null;
    222 +		}
    223 +		if (saveRemoteDirectory != null) {
    224 +			if (! saveRemoteDirectory.equals("")) {
    225 +System.out.println("saveRemoteHack setText + refreshRemoteLocation '" + saveRemoteDirectory + "'");
    226 +				return saveRemoteDirectory;
    227 +			}
    228 +		}
    229 +		return indrive;
    230 +	}
    231 +// end runge/x11vnc
    232 +
    233 +
    234  	/*
    235  	 * Prints the list of drives on the remote directory and returns a String[].  
    236  	 * str takes as string like A:fC:lD:lE:lF:lG:cH:c
    237 @@ -143,6 +221,9 @@
    238  		int size = str.length();
    239  		String driveType = null;
    240  		String[] drive = new String[str.length() / 3];
    241 +		int idx = 0, C_drive = -1, O_drive = -1;
    242 +
    243 +System.out.println("ComboBox: Str   '" + str + "'");
    244  
    245  		// Loop through the string to create a String[]
    246  		for (int i = 0; i < size; i = i + 3) {
    247 @@ -150,26 +231,68 @@
    248  			driveType = str.substring(i + 2, i + 3);
    249  			if (driveType.compareTo("f") == 0)
    250  				drive[i / 3] += "\\ Floppy";
    251 -			if (driveType.compareTo("l") == 0)
    252 +			if (driveType.compareTo("l") == 0) {
    253  				drive[i / 3] += "\\ Local Disk";
    254 +				if (drive[i/3].substring(0,1).toUpperCase().equals("C")) {
    255 +					C_drive = idx;
    256 +				} else if (O_drive < 0) {
    257 +					O_drive = idx;
    258 +				}
    259 +			}
    260  			if (driveType.compareTo("c") == 0)
    261  				drive[i / 3] += "\\ CD-ROM";
    262  			if (driveType.compareTo("n") == 0)
    263  				drive[i / 3] += "\\ Network";
    264  
    265  			remoteDrivesComboBox.addItem(drive[i / 3]);
    266 +System.out.println("ComboBox: Add " + idx + " '" + drive[i/3] + "'");
    267 +			idx++;
    268 +		}
    269 +
    270 +		// runge
    271 +		if (viewer.ftpDropDown != null) {
    272 +			String[] dd = viewer.ftpDropDown.split("\\.");
    273 +			for (int i=0; i < dd.length; i++) {
    274 +				if (!dd[i].equals("")) {
    275 +					String s = dd[i];
    276 +					if (s.startsWith("TOP_")) {
    277 +						s = s.substring(4);
    278 +						remoteDrivesComboBox.insertItemAt(" [" + s + "]", 0);
    279 +					} else {
    280 +						remoteDrivesComboBox.addItem(" [" + s + "]");
    281 +					}
    282 +				}
    283 +			}
    284 +		} else {
    285 +			remoteDrivesComboBox.addItem(" [My Documents]");
    286 +			remoteDrivesComboBox.addItem(" [Desktop]");
    287 +			remoteDrivesComboBox.addItem(" [Home]");
    288  		}
    289 +
    290  		//sf@ - Select Drive C:as default if possible
    291  		boolean bFound = false;
    292 -		for(int i = 0; i < remoteDrivesComboBox.getItemCount() ; i++)
    293 -		{
    294 -			if(remoteDrivesComboBox.getItemAt(i).toString().substring(0,1).toUpperCase().equals("C"))
    295 -			{
    296 -				remoteDrivesComboBox.setSelectedIndex(i);
    297 +
    298 +		if (false) {
    299 +			for(int i = 0; i < remoteDrivesComboBox.getItemCount() ; i++) {
    300 +				if(remoteDrivesComboBox.getItemAt(i).toString().substring(0,1).toUpperCase().equals("C")) {
    301 +					remoteDrivesComboBox.setSelectedIndex(i);
    302 +					bFound = true;
    303 +				}
    304 +			}
    305 +		} else {
    306 +			if (C_drive >= 0) {
    307 +				remoteDrivesComboBox.setSelectedIndex(C_drive);
    308 +				bFound = true;
    309 +System.out.println("ComboBox: C_drive index: " + C_drive);
    310 +			} else if (O_drive >= 0) {
    311 +				remoteDrivesComboBox.setSelectedIndex(O_drive);
    312  				bFound = true;
    313 +System.out.println("ComboBox: Other_drive index: " + O_drive);
    314  			}
    315  		}
    316 +
    317  		if (!bFound) remoteDrivesComboBox.setSelectedIndex(0);
    318 +
    319  		updateDriveList = false;
    320  		return drive;
    321  	}
    322 @@ -185,6 +308,8 @@
    323  		stopButton.setVisible(true);
    324  		stopButton.setEnabled(true);
    325  		receiveButton.setEnabled(false);
    326 +		viewButton.setEnabled(false);	// runge/x11vnc
    327 +		refreshButton.setEnabled(false);
    328  		remoteTopButton.setEnabled(false);
    329  		sendButton.setEnabled(false);
    330  		remoteFileTable.setEnabled(false);
    331 @@ -207,6 +332,8 @@
    332  		stopButton.setVisible(false);
    333  		stopButton.setEnabled(false);
    334  		receiveButton.setEnabled(true);
    335 +		viewButton.setEnabled(true);	// runge/x11vnc
    336 +		refreshButton.setEnabled(true);
    337  		remoteTopButton.setEnabled(true);
    338  		sendButton.setEnabled(true);
    339  		remoteFileTable.setEnabled(true);
    340 @@ -221,10 +348,11 @@
    341  	/*
    342  	 * Print Directory prints out all the contents of a directory
    343  	 */
    344 -	void printDirectory(ArrayList a) {
    345 +	void printDirectory(ArrayList a, ArrayList b) {
    346  
    347  		for (int i = 0; i < a.size(); i++) {
    348  			remoteList.addElement(a.get(i));
    349 +			remoteListInfo.addElement(b.get(i));
    350  		}
    351  		remoteFileTable.setListData(remoteList);
    352  	}
    353 @@ -235,10 +363,12 @@
    354  	 * @return void
    355  	 */
    356  	private void initialize() {
    357 +		ignore_events = true;
    358  		this.setSize(794, 500);
    359  		this.setContentPane(getJContentPane());
    360 +		ignore_events = false;
    361  		updateDriveList = true;
    362 -		}
    363 +	}
    364  	/**
    365  	 * This method initializes jContentPane.  This is the main content pane
    366  	 * 
    367 @@ -253,6 +383,33 @@
    368  			jContentPane.add(getRemotePanel(), java.awt.BorderLayout.EAST);
    369  			jContentPane.add(getLocalPanel(), java.awt.BorderLayout.WEST);
    370  			jContentPane.add(getButtonPanel(), java.awt.BorderLayout.CENTER);
    371 +
    372 +			KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
    373 +			AbstractAction escapeAction = new AbstractAction() {
    374 +				public void actionPerformed(ActionEvent actionEvent) {
    375 +					System.out.println("Escape Pressed");
    376 +					if (viewer.ftpOnly) {
    377 +						System.out.println("exiting...");
    378 +						System.exit(0);
    379 +					} else {
    380 +						doClose();
    381 +					}
    382 +				}
    383 +			};
    384 +			jContentPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(stroke, "escapeAction");
    385 +			jContentPane.getInputMap().put(stroke, "escapeAction");
    386 +			jContentPane.getActionMap().put("escapeAction", escapeAction);
    387 +
    388 +			stroke = KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_MASK);
    389 +			AbstractAction resetAction = new AbstractAction() {
    390 +				public void actionPerformed(ActionEvent actionEvent) {
    391 +					System.out.println("Ctrl-R Pressed");
    392 +					doReset();
    393 +				}
    394 +			};
    395 +			jContentPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(stroke, "resetAction");
    396 +			jContentPane.getInputMap().put(stroke, "resetAction");
    397 +			jContentPane.getActionMap().put("resetAction", resetAction);
    398  		}
    399  		return jContentPane;
    400  	}
    401 @@ -270,6 +427,7 @@
    402  			topPanelLocal.add(getLocalMachineLabel(), java.awt.BorderLayout.CENTER);
    403  			topPanelLocal.add(getLocalTopButton(), java.awt.BorderLayout.EAST);
    404  			topPanelLocal.setBackground(java.awt.Color.lightGray);
    405 +//System.out.println("getTopPanelLocal");
    406  		}
    407  		return topPanelLocal;
    408  	}
    409 @@ -288,6 +446,7 @@
    410  			topPanelRemote.add(getRemoteMachineLabel(), java.awt.BorderLayout.CENTER);
    411  			topPanelRemote.add(getRemoteTopButton(), java.awt.BorderLayout.EAST);
    412  			topPanelRemote.setBackground(java.awt.Color.lightGray);
    413 +//System.out.println("getTopPanelRemote");
    414  		}
    415  		return topPanelRemote;
    416  	}
    417 @@ -301,6 +460,7 @@
    418  		if (topPanelCenter == null) {
    419  			topPanelCenter = new javax.swing.JPanel();
    420  			topPanelCenter.add(getDummyButton(), null);
    421 +//System.out.println("getTopPanelCenter");
    422  		}
    423  		return topPanelCenter;
    424  	}
    425 @@ -328,6 +488,7 @@
    426  			topPanel.add(getRemoteTopButton(), null);
    427  			topPanel.setBackground(java.awt.Color.lightGray);
    428  			*/
    429 +//System.out.println("getTopPanel");
    430  		}
    431  		return topPanel;
    432  	}
    433 @@ -348,6 +509,7 @@
    434  			statusPanel.add(getJProgressBar(), null);
    435  			statusPanel.add(getConnectionStatus(), null);
    436  			statusPanel.setBackground(java.awt.Color.lightGray);
    437 +//System.out.println("getStatusPanel");
    438  			
    439  		}
    440  		return statusPanel;
    441 @@ -368,6 +530,7 @@
    442  			remotePanel.add(getRemoteScrollPane(), null);
    443  			remotePanel.add(getRemoteStatus(), null);
    444  			remotePanel.setBackground(java.awt.Color.lightGray);
    445 +//System.out.println("getRemotePanel");
    446  		}
    447  		return remotePanel;
    448  	}
    449 @@ -390,6 +553,7 @@
    450  			localPanel.setComponentOrientation(
    451  				java.awt.ComponentOrientation.UNKNOWN);
    452  			localPanel.setName("localPanel");
    453 +//System.out.println("getLocalPanel");
    454  		}
    455  		return localPanel;
    456  	}
    457 @@ -405,12 +569,15 @@
    458  			buttonPanel = new javax.swing.JPanel();
    459  			buttonPanel.setLayout(null);
    460  			buttonPanel.add(getReceiveButton(), null);
    461 +			buttonPanel.add(getRefreshButton(), null);	// runge/x11vnc
    462 +			buttonPanel.add(getViewButton(), null);	// runge/x11vnc
    463  			buttonPanel.add(getNewFolderButton(), null);
    464  			buttonPanel.add(getCloseButton(), null);
    465  			buttonPanel.add(getDeleteButton(), null);
    466  			buttonPanel.add(getSendButton(), null);
    467  			buttonPanel.add(getStopButton(), null);
    468  			buttonPanel.setBackground(java.awt.Color.lightGray);
    469 +//System.out.println("getButtonPanel");
    470  		}
    471  		return buttonPanel;
    472  	}
    473 @@ -422,10 +589,11 @@
    474  	private javax.swing.JButton getSendButton() {
    475  		if (sendButton == null) {
    476  			sendButton = new javax.swing.JButton();
    477 -			sendButton.setBounds(20, 30, 97, 25);
    478 +			sendButton.setBounds(15, 30, 107, 25);	// runge/x11vnc
    479  			sendButton.setText("Send >>");
    480  			sendButton.setName("sendButton");
    481  			sendButton.addActionListener(this);
    482 +//System.out.println("getSendButton");
    483  
    484  		}
    485  		return sendButton;
    486 @@ -438,7 +606,7 @@
    487  	private javax.swing.JButton getReceiveButton() {
    488  		if (receiveButton == null) {
    489  			receiveButton = new javax.swing.JButton();
    490 -			receiveButton.setBounds(20, 60, 97, 25);
    491 +			receiveButton.setBounds(15, 60, 107, 25);	// runge/x11vnc
    492  			receiveButton.setText("<< Receive");
    493  			receiveButton.setName("receiveButton");
    494  			receiveButton.addActionListener(this);
    495 @@ -453,7 +621,7 @@
    496  	private javax.swing.JButton getDeleteButton() {
    497  		if (deleteButton == null) {
    498  			deleteButton = new javax.swing.JButton();
    499 -			deleteButton.setBounds(20, 110, 97, 25);
    500 +			deleteButton.setBounds(15, 110, 107, 25);	// runge/x11vnc
    501  			deleteButton.setText("Delete File");
    502  			deleteButton.setName("deleteButton");
    503  			deleteButton.addActionListener(this);
    504 @@ -468,7 +636,7 @@
    505  	private javax.swing.JButton getNewFolderButton() {
    506  		if (newFolderButton == null) {
    507  			newFolderButton = new javax.swing.JButton();
    508 -			newFolderButton.setBounds(20, 140, 97, 25);
    509 +			newFolderButton.setBounds(15, 140, 107, 25);	// runge/x11vnc
    510  			newFolderButton.setText("New Folder");
    511  			newFolderButton.setName("newFolderButton");
    512  			newFolderButton.addActionListener(this);
    513 @@ -476,6 +644,39 @@
    514  		return newFolderButton;
    515  	}
    516  	
    517 +// begin runge/x11vnc
    518 +	/**
    519 +	 * This method initializes refreshButton
    520 +	 * 
    521 +	 * @return javax.swing.JButton
    522 +	 */
    523 +	private javax.swing.JButton getRefreshButton() {
    524 +		if (refreshButton == null) {
    525 +			refreshButton = new javax.swing.JButton();
    526 +			refreshButton.setBounds(15, 170, 107, 25);
    527 +			refreshButton.setText("Refresh");
    528 +			refreshButton.setName("refreshButton");
    529 +			refreshButton.addActionListener(this);
    530 +		}
    531 +		return refreshButton;
    532 +	}
    533 +	/**
    534 +	 * This method initializes viewButton
    535 +	 * 
    536 +	 * @return javax.swing.JButton
    537 +	 */
    538 +	private javax.swing.JButton getViewButton() {
    539 +		if (viewButton == null) {
    540 +			viewButton = new javax.swing.JButton();
    541 +			viewButton.setBounds(15, 200, 107, 25);
    542 +			viewButton.setText("View File");
    543 +			viewButton.setName("viewButton");
    544 +			viewButton.addActionListener(this);
    545 +		}
    546 +		return viewButton;
    547 +	}
    548 +// end   runge/x11vnc
    549 +
    550  	/**
    551  	 * This method initializes stopButton
    552  	 * 
    553 @@ -486,7 +687,7 @@
    554  		if (stopButton == null)
    555  		{
    556  			stopButton = new javax.swing.JButton();
    557 -			stopButton.setBounds(20, 200, 97, 25);
    558 +			stopButton.setBounds(15, 230, 107, 25);	// runge/x11vnc
    559  			stopButton.setText("Stop");
    560  			stopButton.setName("stopButton");
    561  			stopButton.addActionListener(this);
    562 @@ -503,8 +704,12 @@
    563  	private javax.swing.JButton getCloseButton() {
    564  		if (closeButton == null) {
    565  			closeButton = new javax.swing.JButton();
    566 -			closeButton.setBounds(20, 325, 97, 25);
    567 -			closeButton.setText("Close");
    568 +			closeButton.setBounds(15, 325, 107, 25);	// runge/x11vnc
    569 +			if (viewer.ftpOnly) {
    570 +				closeButton.setText("Quit");
    571 +			} else {
    572 +				closeButton.setText("Close");
    573 +			}
    574  			closeButton.setName("closeButton");
    575  			closeButton.addActionListener(this);
    576  		}
    577 @@ -551,6 +756,7 @@
    578  			//Select the second entry (e.g. C:\)
    579  			// localDrivesComboBox.setSelectedIndex(1);
    580  			localDrivesComboBox.addActionListener(this);
    581 +//System.out.println("getLocalDrivesComboBox");
    582  		}
    583  		updateDriveList = false;
    584  		return localDrivesComboBox;
    585 @@ -567,6 +773,7 @@
    586  			remoteDrivesComboBox.setFont(
    587  				new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10));
    588  			remoteDrivesComboBox.addActionListener(this);
    589 +//System.out.println("getRemoteDrivesComboBox");
    590  
    591  		}
    592  		return remoteDrivesComboBox;
    593 @@ -587,6 +794,7 @@
    594  			localMachineLabel.setFont(
    595  				new java.awt.Font("Dialog", java.awt.Font.BOLD, 11));
    596  			localMachineLabel.setEditable(false);
    597 +//System.out.println("getLocalMachineLabel");
    598  		}
    599  		return localMachineLabel;
    600  	}
    601 @@ -622,6 +830,7 @@
    602  			localTopButton.setFont(
    603  				new java.awt.Font("Dialog", java.awt.Font.BOLD, 10));
    604  			localTopButton.addActionListener(this);
    605 +//System.out.println("getLocalTopButton");
    606  		}
    607  		return localTopButton;
    608  	}
    609 @@ -638,6 +847,7 @@
    610  			remoteTopButton.setFont(
    611  				new java.awt.Font("Dialog", java.awt.Font.BOLD, 10));
    612  			remoteTopButton.addActionListener(this);
    613 +//System.out.println("getRemoteTopButton");
    614  		}
    615  		return remoteTopButton;
    616  	}
    617 @@ -650,9 +860,24 @@
    618  	private javax.swing.JList getLocalFileTable() {
    619  		if (localFileTable == null) {
    620  			localList = new Vector(0);
    621 +			localListInfo = new Vector(0);
    622  			localFileTable = new JList(localList);
    623 +			MouseMotionListener mlisten = new MouseMotionAdapter() {
    624 +				public void mouseMoved(MouseEvent e) {
    625 +					int index = localFileTable.locationToIndex(e.getPoint());
    626 +					if (index == lastLocalIndex) {
    627 +						return;
    628 +					} else if (index < 0) {
    629 +						return;
    630 +					}
    631 +					lastLocalIndex = index;
    632 +					connectionStatus.setText((String) localListInfo.get(index));
    633 +				}
    634 +			};
    635  			localFileTable.addMouseListener(this);
    636 +			localFileTable.addMouseMotionListener(mlisten);
    637  			localFileTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    638 +//System.out.println("getLocalFileTable");
    639  		}
    640  		return localFileTable;
    641  	}
    642 @@ -669,6 +894,7 @@
    643  			localScrollPane.setFont(
    644  				new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10));
    645  			localScrollPane.setName("localFileList");
    646 +//System.out.println("getLocalScrollPane");
    647  		}
    648  		return localScrollPane;
    649  	}
    650 @@ -680,10 +906,25 @@
    651  	private javax.swing.JList getRemoteFileTable() {
    652  		if (remoteFileTable == null) {
    653  			remoteList = new Vector(0);
    654 +			remoteListInfo = new Vector(0);
    655  			remoteFileTable = new JList(remoteList);
    656 +			MouseMotionListener mlisten = new MouseMotionAdapter() {
    657 +				public void mouseMoved(MouseEvent e) {
    658 +					int index = remoteFileTable.locationToIndex(e.getPoint());
    659 +					if (index == lastRemoteIndex) {
    660 +						return;
    661 +					} else if (index < 0) {
    662 +						return;
    663 +					}
    664 +					lastRemoteIndex = index;
    665 +					connectionStatus.setText((String) remoteListInfo.get(index));
    666 +				}
    667 +			};
    668  			remoteFileTable.addMouseListener(this);
    669 +			remoteFileTable.addMouseMotionListener(mlisten);
    670  			remoteFileTable.setSelectedValue("C:\\", false);
    671  			remoteFileTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    672 +//System.out.println("getRemoteFileTable");
    673  			
    674  		}
    675  		return remoteFileTable;
    676 @@ -698,6 +939,7 @@
    677  			remoteScrollPane = new javax.swing.JScrollPane();
    678  			remoteScrollPane.setViewportView(getRemoteFileTable());
    679  			remoteScrollPane.setPreferredSize(new java.awt.Dimension(325, 418));
    680 +//System.out.println("getRemoteScrollPane");
    681  		}
    682  		return remoteScrollPane;
    683  	}
    684 @@ -716,6 +958,7 @@
    685  			remoteLocation.setBackground(new Color(255,255,238));
    686  			remoteLocation.setFont(
    687  				new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10));
    688 +//System.out.println("getRemoteLocation");
    689  		}
    690  		return remoteLocation;
    691  	}
    692 @@ -732,6 +975,7 @@
    693  			localLocation.setBackground( new Color(255,255,238));
    694  			localLocation.setFont(
    695  				new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10));
    696 +//System.out.println("getLocalLocation");
    697  		}
    698  		return localLocation;
    699  	}
    700 @@ -748,6 +992,7 @@
    701  			localStatus.setFont(
    702  				new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10));
    703  			localStatus.setEditable(false);
    704 +//System.out.println("getLocalStatus");
    705  		}
    706  		return localStatus;
    707  	}
    708 @@ -764,6 +1009,7 @@
    709  			remoteStatus.setFont(
    710  				new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10));
    711  			remoteStatus.setEditable(false);
    712 +//System.out.println("getRemoteStatus");
    713  		}
    714  		return remoteStatus;
    715  	}
    716 @@ -777,9 +1023,10 @@
    717  			historyComboBox = new javax.swing.JComboBox();
    718  			historyComboBox.setFont(
    719  				new java.awt.Font("Dialog", java.awt.Font.BOLD, 10));
    720 -			historyComboBox.insertItemAt(new String("Pulldown to view history ..."),0);
    721 +			historyComboBox.insertItemAt(new String("Pulldown to view history;   Press Escape to Close/Quit;   Press Ctrl-R to Reset Panel."),0);
    722  			historyComboBox.setSelectedIndex(0);
    723  			historyComboBox.addActionListener(this);
    724 +//System.out.println("getHistoryComboBox");
    725  		}
    726  		return historyComboBox;
    727  	}
    728 @@ -791,6 +1038,7 @@
    729  	private javax.swing.JProgressBar getJProgressBar() {
    730  		if (jProgressBar == null) {
    731  			jProgressBar = new javax.swing.JProgressBar();
    732 +//System.out.println("getJProgressBar");
    733  		}
    734  		return jProgressBar;
    735  	}
    736 @@ -806,6 +1054,7 @@
    737  			connectionStatus.setBackground(java.awt.Color.lightGray);
    738  			connectionStatus.setFont(
    739  				new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10));
    740 +//System.out.println("getConnectionStatus");
    741  		}
    742  			connectionStatus.setEditable(false);
    743  		return connectionStatus;
    744 @@ -815,7 +1064,12 @@
    745  	 * Implements Action listener.
    746  	 */
    747  	public void actionPerformed(ActionEvent evt) {
    748 -		System.out.println(evt.getSource());
    749 +//		System.out.println(evt.getSource());
    750 +
    751 +		if (ignore_events) {
    752 +			System.out.println("ignore_events: " + evt.getSource());
    753 +			return;
    754 +		}
    755  
    756  		if (evt.getSource() == closeButton)
    757  		{ // Close Button
    758 @@ -829,15 +1083,27 @@
    759  		{
    760  			doReceive();
    761  		}
    762 +// begin runge/x11vnc
    763 +		else if (evt.getSource() == viewButton)
    764 +		{
    765 +			doView();
    766 +		}
    767 +// end   runge/x11vnc
    768  		else if (evt.getSource() == localDrivesComboBox)
    769  		{
    770  			changeLocalDrive();
    771  		}
    772  		else if (evt.getSource() == remoteDrivesComboBox)
    773  		{ 
    774 +//System.out.println("remoteDrivesComboBox");	// runge/x11vnc
    775  			changeRemoteDrive();
    776 -			remoteList.clear();
    777 -			remoteFileTable.setListData(remoteList);
    778 +
    779 +			// are these really needed? changeRemoteDrive() does them at the end.
    780 +			if (false) {
    781 +				remoteList.clear();
    782 +				remoteListInfo.clear();
    783 +				remoteFileTable.setListData(remoteList);
    784 +			}
    785  		}
    786  		else if (evt.getSource() == localTopButton)
    787  		{
    788 @@ -845,12 +1111,17 @@
    789  		}
    790  		else if (evt.getSource() == remoteTopButton)
    791  		{
    792 +//System.out.println("remoteTopButton");	// runge/x11vnc
    793  		  	changeRemoteDrive();
    794  		}
    795  		else if(evt.getSource() == deleteButton)
    796  		{
    797  			doDelete();
    798  		}
    799 +		else if(evt.getSource() == refreshButton)
    800 +		{
    801 +			doRefresh();
    802 +		}
    803  		else if(evt.getSource()==newFolderButton)
    804  		{
    805  			doNewFolder();
    806 @@ -864,7 +1135,7 @@
    807  
    808  	private void doNewFolder()
    809  	{
    810 -		String name = JOptionPane.showInputDialog(null,"Enter new directory name", "Create New Directory", JOptionPane.QUESTION_MESSAGE);
    811 +		String name = JOptionPane.showInputDialog(jContentPane,"Enter new directory name", "Create New Directory", JOptionPane.QUESTION_MESSAGE);
    812  		if(selectedTable.equals("remote"))
    813  		{
    814  			name = remoteLocation.getText()+name;
    815 @@ -880,34 +1151,106 @@
    816  			historyComboBox.setSelectedIndex(0);
    817  		}
    818  	}
    819 -	private void doClose()
    820 +	public void doClose()
    821  	{
    822 +		if (viewer.ftpOnly) {
    823 +			viewer.disconnect();
    824 +			return;
    825 +		}
    826  		try {
    827  			this.setVisible(false);
    828 -			viewer.rfb.writeFramebufferUpdateRequest(
    829 -									0,
    830 -									0,
    831 -									viewer.rfb.framebufferWidth,
    832 -									viewer.rfb.framebufferHeight,
    833 -									true);
    834 +			viewer.rfb.writeFramebufferUpdateRequest(0, 0, viewer.rfb.framebufferWidth,
    835 +			    viewer.rfb.framebufferHeight, true);
    836 +
    837 +			if (false) {
    838 +				this.dispose();
    839 +				jContentPane = null;
    840 +			}
    841  		} catch (IOException e) {
    842  			// TODO Auto-generated catch block
    843  			e.printStackTrace();
    844  		}
    845  	}
    846 +	private void unSwing() {
    847 +		jContentPane = null;
    848 +		topPanel = null;
    849 +		topPanelLocal = null;
    850 +		topPanelRemote = null;
    851 +		topPanelCenter = null;
    852 +		statusPanel = null;
    853 +		remotePanel = null;
    854 +		localPanel = null;
    855 +		buttonPanel = null;
    856 +		sendButton = null;
    857 +		receiveButton = null;
    858 +		deleteButton = null;
    859 +		newFolderButton = null;
    860 +		stopButton = null;
    861 +		closeButton = null;
    862 +		dummyButton = null;
    863 +		localDrivesComboBox = null;
    864 +		remoteDrivesComboBox = null;
    865 +		localMachineLabel = null;
    866 +		remoteMachineLabel = null;
    867 +		localTopButton = null;
    868 +		remoteTopButton = null;
    869 +		localScrollPane = null;
    870 +		localFileTable = null;
    871 +		remoteScrollPane = null;
    872 +		remoteFileTable = null;
    873 +		remoteLocation = null;
    874 +		localLocation = null;
    875 +		localStatus = null;
    876 +		remoteStatus = null;
    877 +		historyComboBox = null;
    878 +		jProgressBar = null;
    879 +		connectionStatus = null;
    880 +		viewButton = null;
    881 +		refreshButton = null;
    882 +	}
    883 +
    884 +	public void doReset()
    885 +	{
    886 +		try {
    887 +			this.setVisible(false);
    888 +			this.dispose();
    889 +			jContentPane = null;
    890 +		        try {Thread.sleep(500);} catch (InterruptedException e) {}
    891 +			viewer.ftp_init();
    892 +		} catch (Exception e) {
    893 +			// TODO Auto-generated catch block
    894 +			e.printStackTrace();
    895 +		}
    896 +	}
    897  
    898 +	public void doOpen()
    899 +	{
    900 +		try {
    901 +			this.setVisible(true);
    902 +			if (false) {
    903 +				this.initialize();
    904 +			}
    905 +		} catch (Exception e) {
    906 +			// TODO Auto-generated catch block
    907 +			e.printStackTrace();
    908 +		}
    909 +	}
    910  	private void doDelete()
    911  	{
    912 -		System.out.println("Delete Button Pressed");
    913 +//		System.out.println("Delete Button Pressed");
    914  		//Call this method to delete a file at server
    915  		if(selectedTable.equals("remote"))
    916  		{	
    917 -			String sFileName = ((String) this.remoteFileTable.getSelectedValue());
    918 +			Object selected = this.remoteFileTable.getSelectedValue();
    919 +			if (selected == null) {
    920 +				return;
    921 +			}
    922 +			String sFileName = ((String) selected);
    923  			
    924  //			 sf@2004 - Directory can't be deleted
    925  			if (sFileName.substring(0, 2).equals(" [") && sFileName.substring((sFileName.length() - 1), sFileName.length()).equals("]"))
    926  			{
    927 -				JOptionPane.showMessageDialog(null, (String)"Directory Deletion is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE);
    928 +				JOptionPane.showMessageDialog(jContentPane, (String)"Directory Deletion is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE);
    929  				return;
    930  			}			
    931  			
    932 @@ -916,7 +1259,7 @@
    933  			// sf@2004 - Delete prompt
    934  			if (remoteList.contains(sFileName))
    935  			{
    936 -				int r = JOptionPane.showConfirmDialog(null, "Are you sure you want to delete the file \n< " + sFileName + " >\n on Remote Machine ?", "File Transfer Warning", JOptionPane.YES_NO_OPTION);
    937 +				int r = JOptionPane.showConfirmDialog(jContentPane, "Are you sure you want to delete the file \n< " + sFileName + " >\n on Remote Machine ?", "File Transfer Warning", JOptionPane.YES_NO_OPTION);
    938  				if (r == JOptionPane.NO_OPTION)
    939  					return;
    940  			}
    941 @@ -926,18 +1269,22 @@
    942  		}
    943  		else
    944  		{
    945 -			String sFileName = ((String) this.localFileTable.getSelectedValue());
    946 +			Object selected = this.localFileTable.getSelectedValue();
    947 +			if (selected == null) {
    948 +				return;
    949 +			}
    950 +			String sFileName = ((String) selected);
    951  			
    952  //			 sf@2004 - Directory can't be deleted
    953  			if (sFileName.substring(0, 2).equals(" [") && sFileName.substring((sFileName.length() - 1), sFileName.length()).equals("]"))
    954  			{
    955 -				JOptionPane.showMessageDialog(null, (String)"Directory Deletion is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE);
    956 +				JOptionPane.showMessageDialog(jContentPane, (String)"Directory Deletion is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE);
    957  				return;
    958  			}			
    959  			// sf@2004 - Delete prompt
    960  			if (localList.contains(sFileName))
    961  			{
    962 -				int r = JOptionPane.showConfirmDialog(null, "Are you sure you want to delete the file \n< " + sFileName + " >\n on Local Machine ?", "File Transfer Warning", JOptionPane.YES_NO_OPTION);
    963 +				int r = JOptionPane.showConfirmDialog(jContentPane, "Are you sure you want to delete the file \n< " + sFileName + " >\n on Local Machine ?", "File Transfer Warning", JOptionPane.YES_NO_OPTION);
    964  				if (r == JOptionPane.NO_OPTION)
    965  					return;
    966  			}			
    967 @@ -952,21 +1299,25 @@
    968  
    969  	private void doReceive()
    970  	{
    971 -		System.out.println("Received Button Pressed");
    972 +//		System.out.println("Received Button Pressed");
    973  
    974 -		String sFileName = ((String) this.remoteFileTable.getSelectedValue());
    975 +		Object selected = this.remoteFileTable.getSelectedValue();
    976 +		if (selected == null) {
    977 +			return;
    978 +		}
    979 +		String sFileName = ((String) selected);
    980  		
    981  		// sf@2004 - Directory can't be transfered
    982  		if (sFileName.substring(0, 2).equals(" [") && sFileName.substring((sFileName.length() - 1), sFileName.length()).equals("]"))
    983  		{
    984 -			JOptionPane.showMessageDialog(null, (String)"Directory Transfer is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE);
    985 +			JOptionPane.showMessageDialog(jContentPane, (String)"Directory Transfer is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE);
    986  			return;
    987  		}
    988  		
    989  		// sf@2004 - Overwrite prompt
    990  		if (localList.contains(sFileName))
    991  		{
    992 -			int r = JOptionPane.showConfirmDialog(null, "The file < " + sFileName + " >\n already exists on Local Machine\n Are you sure you want to overwrite it ?", "File Transfer Warning", JOptionPane.YES_NO_OPTION);
    993 +			int r = JOptionPane.showConfirmDialog(jContentPane, "The file < " + sFileName + " >\n already exists on Local Machine\n Are you sure you want to overwrite it ?", "File Transfer Warning", JOptionPane.YES_NO_OPTION);
    994  			if (r == JOptionPane.NO_OPTION)
    995  				return;
    996  		}
    997 @@ -979,23 +1330,101 @@
    998  		viewer.rfb.requestRemoteFile(remoteFileName,localDestinationPath);
    999  	}
   1000  
   1001 +// begin runge/x11vnc
   1002 +	private void doRefresh()
   1003 +	{
   1004 +		System.out.println("Refreshing Local and Remote.");
   1005 +		refreshLocalLocation();
   1006 +		refreshRemoteLocation();
   1007 +	}
   1008 +
   1009 +	private void doView()
   1010 +	{
   1011 +//		System.out.println("View Button Pressed");
   1012 +
   1013 +		if (selectedTable == null) {
   1014 +			return;
   1015 +		}
   1016 +		if (selectedTable.equals("remote")) {
   1017 +			viewRemote();
   1018 +		} else if (selectedTable.equals("local")) {
   1019 +			viewLocal();
   1020 +		}
   1021 +	}
   1022 +
   1023 +	private File doReceiveTmp()
   1024 +	{
   1025 +
   1026 +		if (remoteFileTable == null) {
   1027 +			return null;
   1028 +		}
   1029 +		Object selected = this.remoteFileTable.getSelectedValue();
   1030 +		if (selected == null) {
   1031 +			return null;
   1032 +		}
   1033 +		String sFileName = ((String) selected);
   1034 +		
   1035 +		if (sFileName == null) {
   1036 +			return null;
   1037 +		}
   1038 +		
   1039 +		// sf@2004 - Directory can't be transfered
   1040 +		if (sFileName.substring(0, 2).equals(" [") && sFileName.substring((sFileName.length() - 1), sFileName.length()).equals("]"))
   1041 +		{
   1042 +			return null;
   1043 +		}
   1044 +		
   1045 +		File tmp = null;
   1046 +		try {
   1047 +			tmp = File.createTempFile("ULTRAFTP", ".txt");
   1048 +		} catch (Exception e) {
   1049 +			return null;
   1050 +		}
   1051 +		
   1052 +		//updateHistory("Downloaded " + localSelection.toString());
   1053 +		String remoteFileName = this.remoteLocation.getText();
   1054 +		remoteFileName+= ((String) this.remoteFileTable.getSelectedValue()).substring(1);
   1055 +		System.out.println("remoteFileName: " + remoteFileName);
   1056 +if (false) {
   1057 +		char[] b = remoteFileName.toCharArray();
   1058 +		for (int n = 0; n < b.length; n++) {
   1059 +			System.out.print(Integer.toHexString(b[n]) + " ");
   1060 +		}
   1061 +		System.out.println("");
   1062 +		for (int n = 0; n < b.length; n++) {
   1063 +			System.out.print(b[n]);
   1064 +		}
   1065 +		System.out.println("");
   1066 +}
   1067 +		
   1068 +		String localDestinationPath = tmp.getAbsolutePath();
   1069 +		viewer.rfb.requestRemoteFile(remoteFileName,localDestinationPath);
   1070 +		System.out.println("ReceiveTmp: " + localDestinationPath);
   1071 +		return tmp;
   1072 +	}
   1073 +// end   runge/x11vnc
   1074 +
   1075  	private void doSend()
   1076  	{
   1077 -		System.out.println("Send Button Pressed");
   1078 +//		System.out.println("Send Button Pressed");
   1079  
   1080 -		String sFileName = ((String) this.localFileTable.getSelectedValue());
   1081 +		Object selected = this.localFileTable.getSelectedValue();
   1082 +		if (selected == null) {
   1083 +			return;
   1084 +		}
   1085 +		String sFileName = ((String) selected);
   1086  		
   1087  		// sf@2004 - Directory can't be transfered
   1088  		if (sFileName.substring(0, 2).equals(" [") && sFileName.substring((sFileName.length() - 1), sFileName.length()).equals("]"))
   1089  		{
   1090 -			JOptionPane.showMessageDialog(null, (String)"Directory Transfer is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE);
   1091 +			JOptionPane.showMessageDialog(jContentPane, (String)"Directory Transfer is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE);
   1092  			return;
   1093  		}
   1094  		
   1095  		// sf@2004 - Overwrite prompt
   1096  		if (remoteList.contains(sFileName))
   1097  		{
   1098 -			int r = JOptionPane.showConfirmDialog(null, "The file < " + sFileName + " >\n already exists on Remote Machine\n Are you sure you want to overwrite it ?", "File Transfer Warning", JOptionPane.YES_NO_OPTION);
   1099 +			int r = JOptionPane.showConfirmDialog(jContentPane, "The file < " + sFileName + " >\n already exists on Remote Machine\n Are you sure you want to overwrite it ?", "File Transfer Warning", JOptionPane.YES_NO_OPTION);
   1100  			if (r == JOptionPane.NO_OPTION)
   1101  				return;
   1102  		}
   1103 @@ -1013,6 +1442,7 @@
   1104  	// 
   1105  	private void doStop()
   1106  	{
   1107 +		System.out.println("** Current Transfer Aborted **");
   1108  		viewer.rfb.fAbort = true;
   1109  	}
   1110  	/**
   1111 @@ -1024,6 +1454,14 @@
   1112  		System.out.println("History: " + message);
   1113  		historyComboBox.insertItemAt(new String(message), 0);
   1114  	}
   1115 +
   1116 +	public void receivedRemoteDirectoryName(String str) {
   1117 +		if (doingShortcutDir) {
   1118 +			if (str.length() > 1) {
   1119 +				remoteLocation.setText(str);
   1120 +			}
   1121 +		}
   1122 +	}
   1123  	
   1124  	/**
   1125  	 * This method updates the file table to the current selection of the remoteComboBox
   1126 @@ -1034,11 +1472,44 @@
   1127  		remoteSelection = null;
   1128  	
   1129  		if (!updateDriveList) {
   1130 -			String drive =	remoteDrivesComboBox.getSelectedItem().toString().substring(0,1)+ ":\\";
   1131 -			viewer.rfb.readServerDirectory(drive);
   1132 -			remoteLocation.setText(drive);
   1133 +//System.out.println("changeRemoteDrive-A " + drive);	// begin runge/x11vnc
   1134 +			Object selected = remoteDrivesComboBox.getSelectedItem();
   1135 +			if (selected != null)  {
   1136 +				String instr =	selected.toString();
   1137 +				if (instr != null) {
   1138 +System.out.println("changeRemoteDrive: instr='" + instr + "'");
   1139 +					String drive =	instr.substring(0,1)+ ":\\";
   1140 +					if (instr.startsWith(" [")) {
   1141 +						int idx = instr.lastIndexOf(']'); 
   1142 +						if (idx > 2) {
   1143 +							drive = instr.substring(2, idx);
   1144 +						} else {
   1145 +							drive = instr.substring(2);
   1146 +						}
   1147 +						if (drive.equals("Home")) {
   1148 +							drive = "";
   1149 +						}
   1150 +						drive += "\\";
   1151 +						doingShortcutDir = true;
   1152 +					} else {
   1153 +						doingShortcutDir = false;
   1154 +						drive = saveRemoteHack(drive);
   1155 +					}
   1156 +					gotShortcutDir = false;
   1157 +					viewer.rfb.readServerDirectory(drive);
   1158 +					if (!gotShortcutDir) {
   1159 +						remoteLocation.setText(drive);
   1160 +					}
   1161 +				} else {
   1162 +System.out.println("changeRemoteDrive: instr null");
   1163 +				}
   1164 +			} else {
   1165 +System.out.println("changeRemoteDrive: selection null");
   1166 +			}
   1167 +//System.out.println("changeRemoteDrive-B " + drive);	// end runge/x11vnc
   1168  		}
   1169  		remoteList.clear();
   1170 +		remoteListInfo.clear();
   1171  		remoteFileTable.setListData(remoteList);
   1172  	}
   1173  	/**
   1174 @@ -1048,6 +1519,7 @@
   1175  	private void changeLocalDrive()
   1176  	{
   1177  		File currentDrive = new File(localDrivesComboBox.getSelectedItem().toString());
   1178 +System.out.println("changeLocalDrive " + currentDrive.toString());	// runge/x11vnc
   1179  		if(currentDrive.canRead())
   1180  		{
   1181  			localSelection = null;
   1182 @@ -1057,9 +1529,11 @@
   1183  		else
   1184  		{
   1185  			localList.clear();
   1186 +			localListInfo.clear();
   1187  			localStatus.setText("WARNING: Drive " + localDrivesComboBox.getSelectedItem().toString());
   1188  			connectionStatus.setText(" > WARNING - Local Drive unavailable (possibly restricted access or media not present)");
   1189  		}
   1190 +
   1191  	}
   1192  	/**
   1193  	 * Determines which FileTable was double-clicked and updates the table
   1194 @@ -1098,10 +1572,18 @@
   1195  		selectedTable = "remote";
   1196  		localFileTable.setBackground(new Color(238, 238, 238));
   1197  		remoteFileTable.setBackground(new Color(255, 255, 255));
   1198 -		String name = (remoteFileTable.getSelectedValue().toString()).substring(1);
   1199 +		Object selected = remoteFileTable.getSelectedValue();
   1200 +		if (selected == null) {
   1201 +			return;
   1202 +		}
   1203 +		String selstr = selected.toString();
   1204 +		if (selstr == null) {
   1205 +			return;
   1206 +		}
   1207 +		String name = selstr.substring(1);
   1208  		if( !name.substring(0, 2).equals(" ["))	
   1209  			remoteSelection = remoteLocation.getText() + name.substring(0, name.length());
   1210 -		
   1211 +
   1212  	}
   1213  
   1214  	/*
   1215 @@ -1115,10 +1597,38 @@
   1216  		localFileTable.setBackground(new Color(255, 255, 255));
   1217  		File currentSelection = new File(currentLocalDirectory, getTrimmedSelection());
   1218  		
   1219 -		if(currentSelection.isFile()) 
   1220 +// begin runge/x11vnc
   1221 +		// localSelection = currentSelection.getAbsoluteFile();
   1222 +		if(currentSelection.isFile()) {
   1223  			localSelection = currentSelection.getAbsoluteFile();
   1224 +			localCurrentIsDir = false;
   1225 +		} else {
   1226 +			localCurrentIsDir = true;
   1227 +		}
   1228 +// end   runge/x11vnc
   1229  
   1230  	}
   1231 +
   1232 +// begin runge/x11vnc
   1233 +	private void viewRemote() {
   1234 +		File tmp = doReceiveTmp();
   1235 +		if (tmp == null) {
   1236 +			return;
   1237 +		}
   1238 +		TextViewer tv = new TextViewer("Remote: " + remoteSelection, tmp, true);
   1239 +	}
   1240 +	private void viewLocal() {
   1241 +		if (localSelection == null) {
   1242 +			return;
   1243 +		}
   1244 +		if (localCurrentIsDir) {
   1245 +			return;
   1246 +		}
   1247 +		File loc = new File(localSelection.toString());
   1248 +		TextViewer tv = new TextViewer("Local: " + localSelection.toString(), loc, false);
   1249 +	}
   1250 +// end runge/x11vnc
   1251 +
   1252  	/**
   1253  	 * Updates the Remote File Table based on selection.  Called from mouseClicked handler
   1254  	 */
   1255 @@ -1126,20 +1636,29 @@
   1256  		String name = null;
   1257  		String action = null;
   1258  		String drive = null;
   1259 -		name = (remoteFileTable.getSelectedValue().toString()).substring(1);
   1260 +		Object selected = remoteFileTable.getSelectedValue();
   1261 +		if (selected == null) {
   1262 +			return;
   1263 +		}
   1264 +		String sname = selected.toString();
   1265 +		if (sname == null) {
   1266 +			return;
   1267 +		}
   1268 +		name = sname.substring(1);
   1269  
   1270  		if (name.equals("[..]"))
   1271  		{
   1272  			action = "up";
   1273  			remoteSelection = null;
   1274  			drive = remoteLocation.getText().substring(0, remoteLocation.getText().length() - 1);
   1275 -			// JOptionPane.showMessageDialog(null, (String)drive, "FileTransfer DEBUG", JOptionPane.INFORMATION_MESSAGE);
   1276 +			// JOptionPane.showMessageDialog(jContentPane, (String)drive, "FileTransfer DEBUG", JOptionPane.INFORMATION_MESSAGE);
   1277  			int index = drive.lastIndexOf("\\");
   1278  			drive = drive.substring(0, index + 1);
   1279  
   1280  			remoteLocation.setText(drive);
   1281  			viewer.rfb.readServerDirectory(drive);
   1282  			remoteList.clear();
   1283 +			remoteListInfo.clear();
   1284  			remoteFileTable.setListData(remoteList);	
   1285  		}
   1286  		else if (!name.substring(0, 2).equals(" [") && !name.substring((name.length() - 1), name.length()).equals("]"))
   1287 @@ -1149,6 +1668,7 @@
   1288  			remoteSelection = remoteLocation.getText() + name.substring(0, name.length());
   1289  			drive = remoteLocation.getText();
   1290  			// ??
   1291 +			viewRemote();	// runge/x11vnc
   1292  		}
   1293  		else
   1294  		{ 
   1295 @@ -1159,10 +1679,12 @@
   1296  			remoteLocation.setText(drive);
   1297  			viewer.rfb.readServerDirectory(drive);
   1298  			remoteList.clear();
   1299 +			remoteListInfo.clear();
   1300  			remoteFileTable.setListData(remoteList);	
   1301  		}	
   1302  		//remoteLocation.setText(drive);	
   1303  	}
   1304 +
   1305  	/**
   1306  	 * Updates the Local File Table based on selection. Called from MouseClicked handler
   1307  	 */
   1308 @@ -1188,6 +1710,7 @@
   1309  		else if (currentSelection.isFile())
   1310  		{
   1311  			localSelection = currentSelection.getAbsoluteFile();
   1312 +			viewLocal();	// runge/x11vnc
   1313  		}
   1314  		else if (currentSelection.isDirectory())
   1315  		{
   1316 @@ -1201,13 +1724,22 @@
   1317  	 * 
   1318  	 */
   1319  	private String getTrimmedSelection(){
   1320 -		String currentSelection = (localFileTable.getSelectedValue().toString()).substring(1);
   1321 -				if(currentSelection.substring(0,1).equals("[") &&
   1322 -				currentSelection.substring(currentSelection.length()-1,currentSelection.length()).equals("]")){
   1323 -				return currentSelection.substring(1,currentSelection.length()-1);
   1324 -				} else {
   1325 -					return currentSelection;
   1326 -				}
   1327 +		String currentSelection = "";
   1328 +		Object selected = localFileTable.getSelectedValue();
   1329 +		if (selected == null) {
   1330 +			return currentSelection;
   1331 +		}
   1332 +		String selstr = selected.toString();
   1333 +		if (selstr == null) {
   1334 +			return currentSelection;
   1335 +		}
   1336 +		currentSelection = selstr.substring(1);
   1337 +		if(currentSelection.substring(0,1).equals("[") &&
   1338 +			currentSelection.substring(currentSelection.length()-1,currentSelection.length()).equals("]")){
   1339 +			return currentSelection.substring(1,currentSelection.length()-1);
   1340 +		} else {
   1341 +			return currentSelection;
   1342 +		}
   1343  	}
   1344  
   1345  	/*
   1346 @@ -1241,36 +1773,148 @@
   1347  	 	return null;
   1348  	}
   1349  	
   1350 +	String timeStr(long t) {
   1351 +		Date date = new Date(t);
   1352 +		return date.toString();
   1353 +	}
   1354 +	String dotPast(double f, int n) {
   1355 +		String fs = "" + f;
   1356 +		int i = fs.lastIndexOf(".") + n;
   1357 +		if (i >= 0) {
   1358 +			int len = fs.length();
   1359 +			if (i >= len) {
   1360 +				i = len-1;
   1361 +			}
   1362 +			fs = fs.substring(0, i);
   1363 +		}
   1364 +		return fs;
   1365 +	}
   1366 +	String sizeStr(int s) {
   1367 +		if (s < 0) {
   1368 +			return s + "? B";
   1369 +		} else if (s < 1024) {
   1370 +			return s + " B";
   1371 +		} else if (s < 1024 * 1024) {
   1372 +			double k = s / 1024.0;
   1373 +			String ks = dotPast(k, 3);
   1374 +			
   1375 +			return s + " (" + ks + " KB)";
   1376 +		} else {
   1377 +			double m = s / (1024.0*1024.0);
   1378 +			String ms = dotPast(m, 3);
   1379 +			return s + " (" + ms + " MB)";
   1380 +		}
   1381 +	}
   1382 +
   1383 +	int max_char(String text) {
   1384 +		int maxc = 0;
   1385 +		char chars[] = text.toCharArray();
   1386 +		for (int n = 0; n < chars.length; n++) {
   1387 +			if ((int) chars[n] > maxc) {
   1388 +				maxc = (int) chars[n];
   1389 +			}
   1390 +		}
   1391 +		return maxc;
   1392 +	}
   1393  
   1394  	/*
   1395  	 * Navigates the local file structure up or down one directory
   1396  	 */
   1397  	public void changeLocalDirectory(File dir)
   1398  	{
   1399 -			currentLocalDirectory = dir;	// Updates Global
   1400 +			dir = saveLocalHack(dir);	// runge/x11vnc
   1401 +
   1402 +			if (dir == null) {
   1403 +				connectionStatus.setText("Error changing local directory.");
   1404 +				historyComboBox.insertItemAt(new String("> Error changing local directory."), 0);
   1405 +				historyComboBox.setSelectedIndex(0);
   1406 +				return;
   1407 +			}
   1408 +
   1409  			File allFiles[] = dir.listFiles();	// Reads files
   1410  			String[] contents = dir.list();
   1411  
   1412 +			if (contents == null || allFiles == null) {
   1413 +				connectionStatus.setText("Error changing local directory.");
   1414 +				historyComboBox.insertItemAt(new String("> Error changing local directory."), 0);
   1415 +				historyComboBox.setSelectedIndex(0);
   1416 +				return;
   1417 +			}
   1418 +
   1419 +			currentLocalDirectory = dir;	// Updates Global
   1420 +// begin runge/x11vnc
   1421 +System.out.println("changeLocalDirectory: " + dir.toString());
   1422 +			if (contents != null) {
   1423 +				java.util.Arrays.sort(contents, String.CASE_INSENSITIVE_ORDER);
   1424 +				for (int i = 0; i < contents.length; i++) {
   1425 +					allFiles[i] = new File(dir, contents[i]);
   1426 +				}
   1427 +			} else {
   1428 +				return;
   1429 +			}
   1430 +// end runge/x11vnc
   1431 +
   1432  			localList.clear();
   1433 +			localListInfo.clear();
   1434  			localList.addElement(" [..]");
   1435 +			localListInfo.addElement(" [..]");
   1436 +
   1437 +			ArrayList DirInfo = new ArrayList();
   1438 +			ArrayList FilInfo = new ArrayList();
   1439 +
   1440 +			Charset charset = Charset.forName("ISO-8859-1");
   1441 +			CharsetDecoder decoder = charset.newDecoder();
   1442 +			CharsetEncoder encoder = charset.newEncoder();
   1443  			
   1444  			// Populate the Lists
   1445  			for (int i = 0; i < contents.length; i++)
   1446  			{
   1447 -				if (allFiles[i].isDirectory())
   1448 +				String f1 = contents[i];
   1449 +
   1450 +if (false) {
   1451 +	
   1452 +System.out.println("max_char: " + max_char(f1) + " "  + f1);
   1453 +				if (max_char(f1) > 255) {
   1454 +					try {
   1455 +System.out.println("bbuf1");
   1456 +						ByteBuffer bbuf = encoder.encode(CharBuffer.wrap(f1.toCharArray()));
   1457 +System.out.println("bbuf2");
   1458 +						CharBuffer cbuf = decoder.decode(bbuf);
   1459 +System.out.println("bbuf3");
   1460 +						f1 = cbuf.toString(); 
   1461 +System.out.println("did bbuf: " + f1);
   1462 +					} catch (Exception e) {
   1463 +						;
   1464 +					}
   1465 +				}
   1466 +}
   1467 +				
   1468 +				String f2 = f1;
   1469 +				if (f2.length() < 24) {
   1470 +					for (int ik = f2.length(); ik < 24; ik++) {
   1471 +						f2 = f2 + " ";
   1472 +					}
   1473 +				}
   1474 +				String s = f2 + "    \tLastmod: " + timeStr(allFiles[i].lastModified()) + "    \t\tSize: " + sizeStr((int) allFiles[i].length()); 
   1475 +				if (allFiles[i].isDirectory()) {
   1476  					// localList.addElement("[" + contents[i] + "]");
   1477 -					DirsList.add(" [" + contents[i] + "]"); // sf@2004
   1478 -				else
   1479 -				{
   1480 +					DirsList.add(" [" + f1 + "]"); // sf@2004
   1481 +					DirInfo.add(s);
   1482 +				} else {
   1483  					// localList.addElement(contents[i]);
   1484 -					FilesList.add(" " + contents[i]); // sf@2004
   1485 +					FilesList.add(" " + f1); // sf@2004
   1486 +					FilInfo.add(s);
   1487  				}
   1488  			}
   1489  			// sf@2004
   1490 -			for (int i = 0; i < DirsList.size(); i++) 
   1491 +			for (int i = 0; i < DirsList.size(); i++) {
   1492  				localList.addElement(DirsList.get(i));
   1493 -			for (int i = 0; i < FilesList.size(); i++) 
   1494 +				localListInfo.addElement(DirInfo.get(i));
   1495 +			}
   1496 +			for (int i = 0; i < FilesList.size(); i++) {
   1497  				localList.addElement(FilesList.get(i));
   1498 +				localListInfo.addElement(FilInfo.get(i));
   1499 +			}
   1500  			
   1501  			FilesList.clear();
   1502  			DirsList.clear();
   1503 @@ -1296,3 +1940,147 @@
   1504  	}
   1505  
   1506  } //  @jve:visual-info  decl-index=0 visual-constraint="10,10"
   1507 +
   1508 +// begin runge/x11vnc
   1509 +class TextViewer extends JFrame implements ActionListener {
   1510 +
   1511 +	JTextArea textArea = new JTextArea(35, 80);
   1512 +	File file = null;
   1513 +	JButton refreshButton;
   1514 +	JButton dismissButton;
   1515 +	Timer tim = null;
   1516 +	int rcnt = 0;
   1517 +	int tms = 250;
   1518 +	boolean delete_it = false;
   1519 +	TextViewer me;
   1520 +
   1521 +	public TextViewer(String s, File f, boolean d) {
   1522 +
   1523 +		delete_it = d;
   1524 +		file = f;
   1525 +		me = this;
   1526 +
   1527 +		JScrollPane scrollPane = new JScrollPane(textArea,
   1528 +		    JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
   1529 +		    JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
   1530 +
   1531 +		textArea.setEditable(false);
   1532 +		textArea.setFont(new Font("Monospaced", Font.PLAIN, 12));
   1533 +
   1534 +		KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, InputEvent.SHIFT_MASK);
   1535 +		AbstractAction escapeAction = new AbstractAction() {
   1536 +			public void actionPerformed(ActionEvent actionEvent) {
   1537 +				cleanse();
   1538 +				me.dispose();
   1539 +			}
   1540 +		};
   1541 +		textArea.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(stroke, "escapeAction");
   1542 +		textArea.getInputMap().put(stroke, "escapeAction");
   1543 +		textArea.getActionMap().put("escapeAction", escapeAction);
   1544 +
   1545 +		refreshButton = new JButton();
   1546 +		refreshButton.setText("Reload");
   1547 +		refreshButton.setName("refreshButton");
   1548 +		refreshButton.addActionListener(this);
   1549 +
   1550 +		dismissButton = new JButton();
   1551 +		dismissButton.setText("Dismiss");
   1552 +		dismissButton.setName("dismissButton");
   1553 +		dismissButton.addActionListener(this);
   1554 +
   1555 +		JPanel buttons = new JPanel();
   1556 +		buttons.setLayout(new BorderLayout());
   1557 +		buttons.add(refreshButton, BorderLayout.WEST);
   1558 +		buttons.add(dismissButton, BorderLayout.EAST);
   1559 +
   1560 +		JPanel content = new JPanel();
   1561 +		content.setLayout(new BorderLayout());
   1562 +		content.add(scrollPane, BorderLayout.CENTER);
   1563 +		content.add(buttons, BorderLayout.SOUTH);
   1564 +
   1565 +		ActionListener tsk = new ActionListener() {
   1566 +			public void actionPerformed(ActionEvent evt) {
   1567 +				// System.out.println("tsk");
   1568 +				refresh();
   1569 +			}
   1570 +		};
   1571 +		tim = new Timer(tms, tsk);
   1572 +		tim.start();
   1573 +
   1574 +		this.setContentPane(content);
   1575 +		this.setTitle("TextViewer - " + s);
   1576 +		this.pack();
   1577 +		this.setVisible(true);
   1578 +	}
   1579 +
   1580 +	private void refresh() {
   1581 +
   1582 +		rcnt++;
   1583 +		if (rcnt * tms > 3000 && tim != null) {
   1584 +			tim.stop();
   1585 +			tim = null;
   1586 +		}
   1587 +		BufferedReader input = null;
   1588 +		StringBuffer contents = new StringBuffer();
   1589 +		try {
   1590 +			if (input == null) {
   1591 +				input = new BufferedReader(new FileReader(file));
   1592 +			}
   1593 +			String line = null;
   1594 +			int i = 0;
   1595 +			while (( line = input.readLine()) != null) {
   1596 +				if (i == 0) {
   1597 +					// System.out.println("read");
   1598 +				}
   1599 +				i++;
   1600 +				contents.append(line);
   1601 +				contents.append(System.getProperty("line.separator"));
   1602 +			}
   1603 +		} catch (Exception e) {
   1604 +			;
   1605 +		} finally {
   1606 +			try {
   1607 +				if (input != null) {
   1608 +					input.close();
   1609 +					input = null;
   1610 +				}
   1611 +			} catch (Exception e) {
   1612 +				;
   1613 +			}
   1614 +		}
   1615 +
   1616 +		textArea.setText(contents.toString());
   1617 +		textArea.setCaretPosition(0);
   1618 +	}
   1619 +
   1620 +	public void actionPerformed(ActionEvent evt) {
   1621 +
   1622 +		if (evt.getSource() == refreshButton) {
   1623 +			refresh();
   1624 +		}
   1625 +		if (evt.getSource() == dismissButton) {
   1626 +			cleanse();
   1627 +			this.dispose();
   1628 +		}
   1629 +	}
   1630 +
   1631 +	private void cleanse() {
   1632 +		if (delete_it && file != null) {
   1633 +			try {
   1634 +				file.delete();
   1635 +				file = null;
   1636 +			} catch (Exception e) {
   1637 +				;
   1638 +			}
   1639 +		}
   1640 +	}
   1641 +
   1642 +	protected void finalize() throws Throwable {
   1643 +		try {
   1644 +			cleanse();
   1645 +		} finally {
   1646 +			super.finalize();
   1647 +		}
   1648 +	}
   1649 +}
   1650 +// end runge/x11vnc
   1651 diff -Naur JavaViewer.orig/Makefile JavaViewer/Makefile
   1652 --- JavaViewer.orig/Makefile	2006-05-29 09:06:32.000000000 -0400
   1653 +++ JavaViewer/Makefile	2010-05-18 20:53:32.000000000 -0400
   1654 @@ -4,6 +4,7 @@
   1655  
   1656  CP = cp
   1657  JC = javac
   1658 +JC_ARGS = -target 1.4 -source 1.4
   1659  JAR = jar
   1660  ARCHIVE = VncViewer.jar
   1661  PAGES = index.vnc shared.vnc noshared.vnc hextile.vnc zlib.vnc tight.vnc
   1662 @@ -20,7 +21,7 @@
   1663  all: $(CLASSES) $(ARCHIVE)
   1664  
   1665  $(CLASSES): $(SOURCES)
   1666 -	$(JC) -O $(SOURCES)
   1667 +	$(JC) $(JC_ARGS) -O $(SOURCES)
   1668  
   1669  $(ARCHIVE): $(CLASSES)
   1670  	$(JAR) cf $(ARCHIVE) $(CLASSES)
   1671 diff -Naur JavaViewer.orig/OptionsFrame.java JavaViewer/OptionsFrame.java
   1672 --- JavaViewer.orig/OptionsFrame.java	2005-11-21 18:50:16.000000000 -0500
   1673 +++ JavaViewer/OptionsFrame.java	2007-05-13 22:18:30.000000000 -0400
   1674 @@ -144,7 +144,10 @@
   1675      choices[jpegQualityIndex].select("6");
   1676      choices[cursorUpdatesIndex].select("Enable");
   1677      choices[useCopyRectIndex].select("Yes");
   1678 -    choices[eightBitColorsIndex].select("64");
   1679 +// begin runge/x11vnc
   1680 +//    choices[eightBitColorsIndex].select("64");
   1681 +    choices[eightBitColorsIndex].select("Full");
   1682 +// end runge/x11vnc
   1683      choices[mouseButtonIndex].select("Normal");
   1684      choices[viewOnlyIndex].select("No");
   1685      choices[shareDesktopIndex].select("Yes");
   1686 diff -Naur JavaViewer.orig/RfbProto.java JavaViewer/RfbProto.java
   1687 --- JavaViewer.orig/RfbProto.java	2006-05-24 15:14:40.000000000 -0400
   1688 +++ JavaViewer/RfbProto.java	2010-11-30 22:13:58.000000000 -0500
   1689 @@ -31,6 +31,7 @@
   1690  import java.net.Socket;
   1691  import java.util.*;
   1692  import java.util.zip.*;
   1693 +import java.text.DateFormat;
   1694  
   1695  
   1696  class RfbProto {
   1697 @@ -86,8 +87,11 @@
   1698  
   1699  	// sf@2004 - FileTransfer part
   1700  	ArrayList remoteDirsList;
   1701 +	ArrayList remoteDirsListInfo;
   1702  	ArrayList remoteFilesList;
   1703 +	ArrayList remoteFilesListInfo;
   1704  	ArrayList a;
   1705 +	ArrayList b;
   1706  	boolean fFTInit = true; // sf@2004
   1707  	boolean fFTAllowed = true;
   1708  	boolean fAbort = false;
   1709 @@ -199,6 +203,10 @@
   1710  	// playback.
   1711  	int numUpdatesInSession;
   1712  
   1713 +// begin runge/x11vnc
   1714 +	int readServerDriveListCnt = -1;
   1715 +	long readServerDriveListTime = 0;
   1716 +// end   runge/x11vnc
   1717  	//
   1718  	// Constructor. Make TCP connection to RFB server.
   1719  	//
   1720 @@ -207,7 +215,27 @@
   1721  		viewer = v;
   1722  		host = h;
   1723  		port = p;
   1724 -		sock = new Socket(host, port);
   1725 +// begin runge/x11vnc
   1726 +//		sock = new Socket(host, port);
   1727 +    if (! viewer.disableSSL) {
   1728 +       System.out.println("new SSLSocketToMe");
   1729 +       SSLSocketToMe ssl;
   1730 +       try {
   1731 +               ssl = new SSLSocketToMe(host, port, v);
   1732 +       } catch (Exception e) {
   1733 +               throw new IOException(e.getMessage());
   1734 +       }
   1735 +
   1736 +       try {
   1737 +               sock = ssl.connectSock();
   1738 +       } catch (Exception es) {
   1739 +               throw new IOException(es.getMessage());
   1740 +       }
   1741 +    } else {
   1742 +       sock = new Socket(host, port);
   1743 +    }
   1744 +// end runge/x11vnc
   1745 +
   1746  		is =
   1747  			new DataInputStream(
   1748  				new BufferedInputStream(sock.getInputStream(), 16384));
   1749 @@ -215,9 +243,12 @@
   1750  		osw = new OutputStreamWriter(sock.getOutputStream());
   1751  		inDirectory2 = false;
   1752  		a = new ArrayList();
   1753 +		b = new ArrayList();
   1754  		// sf@2004
   1755  		remoteDirsList = new ArrayList();
   1756 +		remoteDirsListInfo = new ArrayList();
   1757  		remoteFilesList = new ArrayList();
   1758 +		remoteFilesListInfo = new ArrayList();
   1759  	
   1760  		sendFileSource = "";
   1761  	}
   1762 @@ -420,7 +451,13 @@
   1763  	//
   1764  
   1765  	int readServerMessageType() throws IOException {
   1766 -		int msgType = is.readUnsignedByte();
   1767 +		int msgType;
   1768 +		try {
   1769 +			msgType = is.readUnsignedByte();
   1770 +		} catch (Exception e) {
   1771 +			viewer.disconnect();
   1772 +			return -1;
   1773 +		}
   1774  
   1775  		// If the session is being recorded:
   1776  		if (rec != null) {
   1777 @@ -600,6 +637,7 @@
   1778  		contentParamT = is.readUnsignedByte();
   1779  		contentParamT = contentParamT << 8;
   1780  		contentParam = contentParam | contentParamT;
   1781 +//System.out.println("FTM: contentType " + contentType + " contentParam " + contentParam);
   1782  		if (contentType == rfbRDrivesList || contentType == rfbDirPacket)
   1783  		{
   1784  			readDriveOrDirectory(contentParam);
   1785 @@ -610,7 +648,7 @@
   1786  		}
   1787  		else if (contentType == rfbFilePacket)
   1788  		{
   1789 -				receiveFileChunk();
   1790 +			receiveFileChunk();
   1791  		}
   1792  		else if (contentType == rfbEndOfFile)
   1793  		{
   1794 @@ -618,6 +656,10 @@
   1795  		}
   1796  		else if (contentType == rfbAbortFileTransfer)
   1797  		{
   1798 +			System.out.println("rfbAbortFileTransfer: fFileReceptionRunning="
   1799 +			    + fFileReceptionRunning + " fAbort="
   1800 +			    + fAbort + " fFileReceptionError="
   1801 +			    + fFileReceptionError);
   1802  			if (fFileReceptionRunning)
   1803  			{
   1804  				endOfReceiveFile(false); // Error
   1805 @@ -626,6 +668,11 @@
   1806  			{
   1807  				// sf@2004 - Todo: Add TestPermission 
   1808  				// System.out.println("File Transfer Aborted!");
   1809 +
   1810 +				// runge: seems like we must at least read the remaining
   1811 +				// 8 bytes of the header, right?
   1812 +				int size = is.readInt();
   1813 +				int length = is.readInt();
   1814  			}
   1815  			
   1816  		}
   1817 @@ -645,6 +692,7 @@
   1818  		{
   1819  			System.out.println("ContentType: " + contentType);
   1820  		}
   1821 +//System.out.println("FTM: done");
   1822  	}
   1823  
   1824  	//Refactored from readRfbFileTransferMsg()
   1825 @@ -662,6 +710,7 @@
   1826  
   1827  	//Refactored from readRfbFileTransferMsg()
   1828  	public void readDriveOrDirectory(int contentParam) throws IOException {
   1829 +//System.out.println("RDOD: " + contentParam + " " + inDirectory2);
   1830  		if (contentParam == rfbADrivesList)
   1831  		{
   1832  			readFTPMsgDriveList();
   1833 @@ -688,13 +737,21 @@
   1834  
   1835  	// Internally used. Write an Rfb message to the server
   1836  	void writeRfbFileTransferMsg(
   1837 -								int contentType,
   1838 -								int contentParam,
   1839 -								long size, // 0 : compression not supported - 1 : compression supported
   1840 -								long length,
   1841 -								String text) throws IOException
   1842 +		int contentType,
   1843 +		int contentParam,
   1844 +		long size, // 0 : compression not supported - 1 : compression supported
   1845 +		long length,
   1846 +		String text) throws IOException
   1847  	{
   1848  		byte b[] = new byte[12];
   1849 +		byte byteArray[];
   1850 +
   1851 +		if (viewer.dsmActive) {
   1852 +			// need to send the rfbFileTransfer msg type twice for the plugin...
   1853 +			byte b2[] = new byte[1];
   1854 +			b2[0] = (byte) rfbFileTransfer;
   1855 +			os.write(b2);
   1856 +		}
   1857  
   1858  		b[0] = (byte) rfbFileTransfer;
   1859  		b[1] = (byte) contentType;
   1860 @@ -702,7 +759,7 @@
   1861  
   1862  		byte by = 0;
   1863  		long c = 0;
   1864 -		length++;
   1865 +
   1866  		c = size & 0xFF000000;
   1867  		by = (byte) (c >>> 24);
   1868  		b[4] = by;
   1869 @@ -716,6 +773,32 @@
   1870  		by = (byte) c;
   1871  		b[7] = by;
   1872  
   1873 +		if (text != null) {
   1874 +			byte byteArray0[] = text.getBytes();
   1875 +			int maxc = max_char(text);
   1876 +			if (maxc > 255) {
   1877 +				System.out.println("writeRfbFileTransferMsg: using getBytes(\"UTF-8\")");
   1878 +				byteArray0 = text.getBytes("UTF-8");
   1879 +			} else if (maxc > 127) {
   1880 +				System.out.println("writeRfbFileTransferMsg: using getBytes(\"ISO-8859-1\")");
   1881 +				byteArray0 = text.getBytes("ISO-8859-1");
   1882 +			}
   1883 +			byteArray = new byte[byteArray0.length + 1];
   1884 +			for (int i = 0; i < byteArray0.length; i++) {
   1885 +				byteArray[i] = byteArray0[i];
   1886 +			}
   1887 +			byteArray[byteArray.length - 1] = 0;
   1888 +System.out.println("writeRfbFileTransferMsg: length: " + length + " -> byteArray.length: " + byteArray.length);
   1889 +
   1890 +			// will equal length for ascii, ISO-8859-1, more for UTF-8
   1891 +			length = byteArray.length;
   1892 +
   1893 +			//length++;	// used to not include null byte at end.
   1894 +		} else {
   1895 +			String moo = "moo";
   1896 +			byteArray = moo.getBytes();
   1897 +		}
   1898 +
   1899  		c = length & 0xFF000000;
   1900  		by = (byte) (c >>> 24);
   1901  		b[8] = by;
   1902 @@ -729,29 +812,91 @@
   1903  		by = (byte) c;
   1904  		b[11] = by;
   1905  		os.write(b);
   1906 +
   1907 +//System.out.println("size: " + size + " length: " + length + " text: " + text);
   1908  		
   1909  
   1910  		if (text != null)
   1911  		{
   1912 -			byte byteArray[] = text.getBytes();
   1913 -			byte byteArray2[] = new byte[byteArray.length + 1];
   1914 -			for (int i = 0; i < byteArray.length; i++) {
   1915 -				byteArray2[i] = byteArray[i];
   1916 +			os.write(byteArray);
   1917 +		}
   1918 +	}
   1919 +
   1920 +	int max_char(String text) {
   1921 +		int maxc = 0;
   1922 +		char chars[] = text.toCharArray();
   1923 +		for (int n = 0; n < chars.length; n++) {
   1924 +			if ((int) chars[n] > maxc) {
   1925 +				maxc = (int) chars[n];
   1926  			}
   1927 -			byteArray2[byteArray2.length - 1] = 0;
   1928 -			os.write(byteArray2);
   1929  		}
   1930 -		
   1931 +		return maxc;
   1932  	}
   1933  
   1934 +	String guess_encoding(char[] chars) {
   1935 +		boolean saw_high_char = false;
   1936 +
   1937 +		for (int i = 0; i < chars.length; i++) {
   1938 +			if (chars[i] == '\0') {
   1939 +				break;
   1940 +			}
   1941 +			if (chars[i] >= 128) {
   1942 +				saw_high_char = true;
   1943 +				break;
   1944 +			}
   1945 +		}
   1946 +		if (!saw_high_char) {
   1947 +			return "ASCII";
   1948 +		}
   1949 +		char prev = 1;
   1950 +		boolean valid_utf8 = true;
   1951 +		int n = 0;
   1952 +		for (int i = 0; i < chars.length; i++) {
   1953 +			if (chars[i] == '\0') {
   1954 +				break;
   1955 +			}
   1956 +			char c = chars[i];
   1957 +			if (prev < 128 && c >= 128) {
   1958 +				if (c >> 5 == 0x6) {
   1959 +					n = 1;
   1960 +				} else if (c >> 4 == 0xe) {
   1961 +					n = 2;
   1962 +				} else if (c >> 3 == 0x1e) {
   1963 +					n = 3;
   1964 +				} else if (c >> 2 == 0x3e) {
   1965 +					n = 4;
   1966 +				} else {
   1967 +					valid_utf8 = false;
   1968 +					break;
   1969 +				}
   1970 +			} else {
   1971 +				if (n > 0) {
   1972 +					if (c < 128) {
   1973 +						valid_utf8 = false;
   1974 +						break;
   1975 +					}
   1976 +					n--;
   1977 +				}
   1978 +			}
   1979 +
   1980 +			prev = c;
   1981 +		}
   1982 +		if (valid_utf8) {
   1983 +			return "UTF-8";
   1984 +		} else {
   1985 +			return "ISO-8859-1";
   1986 +		}
   1987 +	}
   1988 +
   1989 +
   1990  	//Internally used. Write an rfb message to the server for sending files ONLY 
   1991  	int writeRfbFileTransferMsgForSendFile(
   1992 -											int contentType,
   1993 -											int contentParam,
   1994 -											long size,
   1995 -											long length,
   1996 -											String source
   1997 -											) throws IOException
   1998 +		int contentType,
   1999 +		int contentParam,
   2000 +		long size,
   2001 +		long length,
   2002 +		String source
   2003 +		) throws IOException
   2004  	{
   2005  		File f = new File(source);
   2006  		fis = new FileInputStream(f);
   2007 @@ -768,50 +913,47 @@
   2008  	
   2009  		while (bytesRead!=-1)
   2010  		{
   2011 -				counter += bytesRead;
   2012 -				myDeflater.setInput(byteBuffer, 0, bytesRead);
   2013 -				myDeflater.finish();
   2014 -				compressedSize = myDeflater.deflate(CompressionBuffer);
   2015 -				myDeflater.reset();
   2016 -				// If the compressed data is larger than the original one, we're dealing with
   2017 -				// already compressed data
   2018 -				if (compressedSize > bytesRead)
   2019 -					fCompress = false;
   2020 -				this.writeRfbFileTransferMsg(
   2021 -											contentType,
   2022 -											contentParam,
   2023 -											(fCompress ? 1 : 0), 
   2024 -											(fCompress ? compressedSize-1 : bytesRead-1),
   2025 -											null
   2026 -											);
   2027 -				// Todo: Test write error !
   2028 -				os.write(
   2029 -						fCompress ? CompressionBuffer : byteBuffer,
   2030 -						0,
   2031 -						fCompress ? compressedSize : bytesRead
   2032 -						);
   2033 -				
   2034 -				// Todo: test read error !
   2035 -				bytesRead = fis.read(byteBuffer);
   2036 -				
   2037 -				// viewer.ftp.connectionStatus.setText("Sent: "+ counter + " bytes of "+ f.length() + " bytes");
   2038 -				viewer.ftp.jProgressBar.setValue((int)((counter * 100) / f.length()));
   2039 -				viewer.ftp.connectionStatus.setText(">>> Sending File: " + source + " - Size: " + f.length() + " bytes - Progress: " + ((counter * 100) / f.length()) + "%");
   2040 -				
   2041 -				if (fAbort == true)
   2042 -				{
   2043 -					fAbort = false;
   2044 -					fError = true;
   2045 -					break;
   2046 -				}
   2047 -				try
   2048 -				{
   2049 -			        Thread.sleep(5);
   2050 -			    }
   2051 -				catch(InterruptedException e)
   2052 -				{
   2053 -			        System.err.println("Interrupted");
   2054 -			    }				
   2055 +			counter += bytesRead;
   2056 +			myDeflater.setInput(byteBuffer, 0, bytesRead);
   2057 +			myDeflater.finish();
   2058 +			compressedSize = myDeflater.deflate(CompressionBuffer);
   2059 +			myDeflater.reset();
   2060 +			// If the compressed data is larger than the original one, we're dealing with
   2061 +			// already compressed data
   2062 +			if (compressedSize > bytesRead)
   2063 +				fCompress = false;
   2064 +			this.writeRfbFileTransferMsg(
   2065 +				contentType,
   2066 +				contentParam,
   2067 +				(fCompress ? 1 : 0), 
   2068 +// RUNGE				(fCompress ? compressedSize-1 : bytesRead-1),
   2069 +				(fCompress ? compressedSize : bytesRead),
   2070 +				null
   2071 +			);
   2072 +			// Todo: Test write error !
   2073 +			os.write(fCompress ? CompressionBuffer : byteBuffer, 0, fCompress ? compressedSize : bytesRead);
   2074 +			
   2075 +			// Todo: test read error !
   2076 +			bytesRead = fis.read(byteBuffer);
   2077 +			
   2078 +			// viewer.ftp.connectionStatus.setText("Sent: "+ counter + " bytes of "+ f.length() + " bytes");
   2079 +			viewer.ftp.jProgressBar.setValue((int)((counter * 100) / f.length()));
   2080 +			viewer.ftp.connectionStatus.setText(">>> Sending File: " + source + " - Size: " + f.length() + " bytes - Progress: " + ((counter * 100) / f.length()) + "%");
   2081 +			
   2082 +			if (fAbort == true)
   2083 +			{
   2084 +				fAbort = false;
   2085 +				fError = true;
   2086 +				break;
   2087 +			}
   2088 +			try
   2089 +			{
   2090 +		        Thread.sleep(5);
   2091 +		    }
   2092 +			catch(InterruptedException e)
   2093 +			{
   2094 +		        System.err.println("Interrupted");
   2095 +		    }				
   2096  		}
   2097  		
   2098  		writeRfbFileTransferMsg(fError ? rfbAbortFileTransfer : rfbEndOfFile, 0, 0, 0, null);
   2099 @@ -831,24 +973,30 @@
   2100  			{
   2101  				System.out.print((char) is.readUnsignedByte());
   2102  			}
   2103 +			System.out.println("");
   2104 +
   2105 +			if (size == rfbRErrorCmd || size == -1) {
   2106 +				viewer.ftp.enableButtons();
   2107 +				viewer.ftp.connectionStatus.setText("Remote file not available for writing.");
   2108 +				viewer.ftp.historyComboBox.insertItemAt(new String(" > Error - Remote file not available for writing."), 0);
   2109 +				viewer.ftp.historyComboBox.setSelectedIndex(0);
   2110 +				return;
   2111 +			}
   2112  			
   2113 -			int ret = writeRfbFileTransferMsgForSendFile(
   2114 -															rfbFilePacket,
   2115 -															0,
   2116 -															0,
   2117 -															0,
   2118 -															sendFileSource);
   2119 +			int ret = writeRfbFileTransferMsgForSendFile(rfbFilePacket, 0, 0, 0, sendFileSource);
   2120  	
   2121  			viewer.ftp.refreshRemoteLocation();
   2122  			if (ret != 1)
   2123  			{
   2124  				viewer.ftp.connectionStatus.setText(" > Error - File NOT sent");
   2125 -				viewer.ftp.historyComboBox.insertItemAt(new String(" > Error - File: <" + sendFileSource) + "> was not correctly sent (aborted by user or error)",0);
   2126 +				viewer.ftp.historyComboBox.insertItemAt(new String(" > Error - File: <" + sendFileSource)
   2127 +				    + "> was not correctly sent (aborted or error). Data may still be buffered/in transit. Wait for remote listing...",0);
   2128  			}
   2129  			else
   2130  			{
   2131  				viewer.ftp.connectionStatus.setText(" > File sent");
   2132 -				viewer.ftp.historyComboBox.insertItemAt(new String(" > File: <" + sendFileSource) + "> was sent to Remote Machine",0);
   2133 +				viewer.ftp.historyComboBox.insertItemAt(new String(" > File: <" + sendFileSource)
   2134 +				    + "> was sent to Remote Machine. Note: data may still be buffered/in transit. Wait for remote listing...",0);
   2135  			}
   2136  			viewer.ftp.historyComboBox.setSelectedIndex(0);
   2137  			viewer.ftp.enableButtons();
   2138 @@ -907,7 +1055,7 @@
   2139  	//Handles acknowledgement that the file has been deleted on the server
   2140  	void deleteRemoteFileFeedback() throws IOException
   2141  	{
   2142 -		is.readInt();
   2143 +		int ret = is.readInt();
   2144  		int length = is.readInt();
   2145  		String f = "";
   2146  		for (int i = 0; i < length; i++)
   2147 @@ -916,7 +1064,11 @@
   2148  		}
   2149  		
   2150  		viewer.ftp.refreshRemoteLocation();	
   2151 -		viewer.ftp.historyComboBox.insertItemAt(new String(" > Deleted File On Remote Machine: " + f.substring(0, f.length()-1)),0);
   2152 +		if (ret == -1) {
   2153 +			viewer.ftp.historyComboBox.insertItemAt(new String(" > ERROR Could not Delete File On Remote Machine: "),0);
   2154 +		} else {
   2155 +			viewer.ftp.historyComboBox.insertItemAt(new String(" > Deleted File On Remote Machine: " + f.substring(0, f.length()-1)),0);
   2156 +		}
   2157  		viewer.ftp.historyComboBox.setSelectedIndex(0);
   2158  	}
   2159  
   2160 @@ -926,12 +1078,7 @@
   2161  		try
   2162  		{
   2163  			String temp = text;
   2164 -			writeRfbFileTransferMsg(
   2165 -									rfbCommand,
   2166 -									rfbCFileDelete,
   2167 -									0,
   2168 -									temp.length(),
   2169 -									temp);
   2170 +			writeRfbFileTransferMsg(rfbCommand, rfbCFileDelete, 0, temp.length(), temp);
   2171  		}
   2172  		catch (IOException e)
   2173  		{
   2174 @@ -943,7 +1090,7 @@
   2175  	// Handles acknowledgement that the directory has been created on the server
   2176  	void createRemoteDirectoryFeedback() throws IOException
   2177  	{
   2178 -		is.readInt();
   2179 +		int ret = is.readInt();
   2180  		int length = is.readInt();
   2181  		String f="";
   2182  		for (int i = 0; i < length; i++)
   2183 @@ -951,7 +1098,11 @@
   2184  			f += (char)is.readUnsignedByte();
   2185  		}
   2186  		viewer.ftp.refreshRemoteLocation();	
   2187 -		viewer.ftp.historyComboBox.insertItemAt(new String(" > Created Directory on Remote Machine: " + f.substring(0, f.length()-1)),0);
   2188 +		if (ret == -1) {
   2189 +			viewer.ftp.historyComboBox.insertItemAt(new String(" > ERROR Could not Create Directory on Remote Machine."),0);
   2190 +		} else {
   2191 +			viewer.ftp.historyComboBox.insertItemAt(new String(" > Created Directory on Remote Machine: " + f.substring(0, f.length()-1)),0);
   2192 +		}
   2193  		viewer.ftp.historyComboBox.setSelectedIndex(0);
   2194  	}
   2195  
   2196 @@ -961,12 +1112,7 @@
   2197  		try
   2198  		{
   2199  			String temp = text;
   2200 -			writeRfbFileTransferMsg(
   2201 -				rfbCommand,
   2202 -				rfbCDirCreate,
   2203 -				0,
   2204 -				temp.length(),
   2205 -				temp);
   2206 +			writeRfbFileTransferMsg(rfbCommand, rfbCDirCreate, 0, temp.length(), temp);
   2207  		}
   2208  		catch (IOException e)
   2209  		{
   2210 @@ -979,15 +1125,13 @@
   2211  	{
   2212  		try
   2213  		{
   2214 +//System.out.println("requestRemoteFile text: " + text);
   2215 +//System.out.println("requestRemoteFile leng: " + text.length());
   2216  			String temp = text;
   2217  			receivePath = localPath;
   2218  					
   2219 -			writeRfbFileTransferMsg(
   2220 -									rfbFileTransferRequest,
   2221 -									0,
   2222 -									1, // 0 : compression not supported - 1 : compression supported
   2223 -									temp.length(),
   2224 -									temp);
   2225 +			// 0 : compression not supported - 1 : compression supported
   2226 +			writeRfbFileTransferMsg(rfbFileTransferRequest, 0, 1, temp.length(), temp);
   2227  		}
   2228  		catch (IOException e)
   2229  		{
   2230 @@ -1004,6 +1148,9 @@
   2231  		viewer.ftp.disableButtons();
   2232  		int size = is.readInt();
   2233  		int length = is.readInt();
   2234 +
   2235 +//System.out.println("receiveFileHeader size: " + size);
   2236 +//System.out.println("receiveFileHeader leng: " + length);
   2237  		
   2238  		String tempName = "";
   2239  		for (int i = 0; i < length; i++)
   2240 @@ -1011,6 +1158,15 @@
   2241  			tempName += (char) is.readUnsignedByte();
   2242  		}
   2243  
   2244 +		if (size == rfbRErrorCmd || size == -1) {
   2245 +			fFileReceptionRunning = false;
   2246 +			viewer.ftp.enableButtons();
   2247 +			viewer.ftp.connectionStatus.setText("Remote file not available for reading.");
   2248 +			viewer.ftp.historyComboBox.insertItemAt(new String(" > Error - Remote file not available for reading."), 0);
   2249 +			viewer.ftp.historyComboBox.setSelectedIndex(0);
   2250 +			return;
   2251 +		}
   2252 +
   2253  		// sf@2004 - Read the high part of file size (not yet in rfbFileTransferMsg for 
   2254  		// backward compatibility reasons...)
   2255  		int sizeH = is.readInt();
   2256 @@ -1021,7 +1177,16 @@
   2257  		fileSize=0;
   2258  		fileChunkCounter = 0;
   2259  		String fileName = receivePath;
   2260 -		fos = new FileOutputStream(fileName);
   2261 +		try {
   2262 +			fos = new FileOutputStream(fileName);
   2263 +		} catch (Exception e) {
   2264 +			fFileReceptionRunning = false;
   2265 +			writeRfbFileTransferMsg(rfbAbortFileTransfer, 0, 0, 0, null);
   2266 +			viewer.ftp.historyComboBox.insertItemAt(new String(" > ERROR opening Local File: <" + fileName ),0);
   2267 +			viewer.ftp.historyComboBox.setSelectedIndex(0);
   2268 +			viewer.ftp.enableButtons();
   2269 +			return;
   2270 +		}
   2271  		writeRfbFileTransferMsg(rfbFileHeader, 0, 0, 0, null);
   2272  	}
   2273  
   2274 @@ -1085,7 +1250,13 @@
   2275  			fAbort = false;
   2276  			fFileReceptionError = true;
   2277  			writeRfbFileTransferMsg(rfbAbortFileTransfer, 0, 0, 0, null);
   2278 -			
   2279 +
   2280 +			//runge for use with x11vnc/libvncserver, no rfbAbortFileTransfer reply sent.
   2281 +		        try {Thread.sleep(500);} catch (InterruptedException e) {}
   2282 +			viewer.ftp.enableButtons();
   2283 +			viewer.ftp.refreshLocalLocation();
   2284 +			viewer.ftp.connectionStatus.setText(" > Error - File NOT received");
   2285 +			viewer.ftp.historyComboBox.insertItemAt(new String(" > Error - File: <" + receivePath + "> not correctly received from Remote Machine (aborted by user or error)") ,0);
   2286  		}
   2287  		// sf@2004 - For old FT protocole only
   2288  		/*
   2289 @@ -1104,7 +1275,7 @@
   2290  		int length = is.readInt();
   2291  		fileSize=0;
   2292  		fos.close();
   2293 -		
   2294 +
   2295  		viewer.ftp.refreshLocalLocation();
   2296  		if (fReceptionOk && !fFileReceptionError)
   2297  		{
   2298 @@ -1132,12 +1303,7 @@
   2299  		try
   2300  		{
   2301  			String temp = text;
   2302 -			writeRfbFileTransferMsg(
   2303 -									rfbDirContentRequest,
   2304 -									rfbRDirContent,
   2305 -									0,
   2306 -									temp.length(),
   2307 -									temp);
   2308 +			writeRfbFileTransferMsg(rfbDirContentRequest, rfbRDirContent, 0, temp.length(), temp);
   2309  		}
   2310  		catch (IOException e)
   2311  		{
   2312 @@ -1197,11 +1363,80 @@
   2313  					str += temp;
   2314  				}
   2315  			}
   2316 +			// runge
   2317 +			viewer.ftp.receivedRemoteDirectoryName(str);
   2318  			// viewer.ftp.changeRemoteDirectory(str);
   2319  			
   2320  		}
   2321  	}
   2322  
   2323 +	int zogswap(int n) {
   2324 +		long l = n;
   2325 +		if (l < 0) {
   2326 +			l += 0x100000000L;
   2327 +		}
   2328 +		l = l & 0xFFFFFFFF;
   2329 +		l = (l >> 24) | ((l & 0x00ff0000) >> 8) | ((l & 0x0000ff00) << 8) | (l << 24);
   2330 +		return (int) l;
   2331 +	}
   2332 +
   2333 +	int windozeToUnix(int L, int H) {
   2334 +		long L2 = zogswap(L);
   2335 +		long H2 = zogswap(H);
   2336 +		long unix = (H2 << 32) + L2;
   2337 +		unix -= 11644473600L * 10000000L;
   2338 +		unix /= 10000000L;
   2339 +		//System.out.println("unix time: " + unix + " H2: " + H2 + " L2: " + L2);
   2340 +		return (int) unix;
   2341 +	}
   2342 +	
   2343 +	String timeStr(int t, int h) {
   2344 +		if (h == 0) {
   2345 +			// x11vnc/libvncserver unix
   2346 +			t = zogswap(t);
   2347 +		} else {
   2348 +			// ultra (except if h==0 by chance)
   2349 +			t = windozeToUnix(t, h);
   2350 +		}
   2351 +		long tl = (long) t;
   2352 +		Date date = new Date(tl * 1000);
   2353 +		if (true) {
   2354 +			return date.toString();
   2355 +		} else {
   2356 +			return DateFormat.getDateTimeInstance().format(date);
   2357 +		}
   2358 +	}
   2359 +
   2360 +	String dotPast(double f, int n) {
   2361 +		String fs = "" + f;
   2362 +		int i = fs.lastIndexOf(".") + n;
   2363 +		if (i >= 0) {
   2364 +			int len = fs.length();
   2365 +			if (i >= len) {
   2366 +				i = len-1;
   2367 +			}
   2368 +			fs = fs.substring(0, i);
   2369 +		}
   2370 +		return fs;
   2371 +	}
   2372 +	String sizeStr(int s) {
   2373 +		s = zogswap(s);
   2374 +		if (s < 0) {
   2375 +			return s + "? B";
   2376 +		} else if (s < 1024) {
   2377 +			return s + " B";
   2378 +		} else if (s < 1024 * 1024) {
   2379 +			double k = s / 1024.0;
   2380 +			String ks = dotPast(k, 3);
   2381 +			
   2382 +			return s + " (" + ks + " KB)";
   2383 +		} else {
   2384 +			double m = s / (1024.0*1024.0);
   2385 +			String ms = dotPast(m, 3);
   2386 +			return s + " (" + ms + " MB)";
   2387 +		}
   2388 +	}
   2389 +
   2390  	//Internally used to receive directory content from server
   2391  	//Here, the server sends one file/directory with it's attributes
   2392  	void readFTPMsgDirectoryListContent() throws IOException
   2393 @@ -1217,17 +1452,32 @@
   2394  			dwReserved0,
   2395  			dwReserved1;
   2396  		long ftCreationTime, ftLastAccessTime, ftLastWriteTime;
   2397 +		int ftCreationTimeL, ftLastAccessTimeL, ftLastWriteTimeL;
   2398 +		int ftCreationTimeH, ftLastAccessTimeH, ftLastWriteTimeH;
   2399  		char cFileName, cAlternateFileName;
   2400  		int length = 0;
   2401  		is.readInt();
   2402  		length = is.readInt();
   2403 +
   2404 +		char[] chars = new char[4*length];
   2405 +		int char_cnt = 0;
   2406 +		for (int i = 0; i < chars.length; i++) {
   2407 +			chars[i] = '\0';
   2408 +		}
   2409 +		
   2410  		dwFileAttributes = is.readInt();
   2411  		length -= 4;
   2412 -		ftCreationTime = is.readLong();
   2413 +		//ftCreationTime = is.readLong();
   2414 +		ftCreationTimeL = is.readInt();
   2415 +		ftCreationTimeH = is.readInt();
   2416  		length -= 8;
   2417 -		ftLastAccessTime = is.readLong();
   2418 +		//ftLastAccessTime = is.readLong();
   2419 +		ftLastAccessTimeL = is.readInt();
   2420 +		ftLastAccessTimeH = is.readInt();
   2421  		length -= 8;
   2422 -		ftLastWriteTime = is.readLong();
   2423 +		//ftLastWriteTime = is.readLong();
   2424 +		ftLastWriteTimeL = is.readInt();
   2425 +		ftLastWriteTimeH = is.readInt();
   2426  		length -= 8;
   2427  		nFileSizeHigh = is.readInt();
   2428  		length -= 4;
   2429 @@ -1239,10 +1489,12 @@
   2430  		length -= 4;
   2431  		cFileName = (char) is.readUnsignedByte();
   2432  		length--;
   2433 +		chars[char_cnt++] = cFileName;
   2434  		while (cFileName != '\0')
   2435  		{
   2436  			fileName += cFileName;
   2437  			cFileName = (char) is.readUnsignedByte();
   2438 +			chars[char_cnt++] = cFileName;
   2439  			length--;
   2440  		}
   2441  		cAlternateFileName = (char) is.readByte();
   2442 @@ -1253,7 +1505,28 @@
   2443  			cAlternateFileName = (char) is.readUnsignedByte();
   2444  			length--;
   2445  		}
   2446 -		if (dwFileAttributes == 268435456
   2447 +		String guessed = guess_encoding(chars);
   2448 +		if (!guessed.equals("ASCII")) {
   2449 +			System.out.println("guess: " + guessed + "\t" + fileName);
   2450 +		}
   2451 +		if (guessed.equals("UTF-8")) {
   2452 +			try {
   2453 +				byte[] bytes = new byte[char_cnt-1];
   2454 +				for (int i=0; i < char_cnt-1; i++) {
   2455 +					bytes[i] = (byte) chars[i];
   2456 +				}
   2457 +				String newstr = new String(bytes, "UTF-8");
   2458 +				fileName = newstr;
   2459 +			} catch (Exception e) {
   2460 +				System.out.println("failed to convert bytes to UTF-8 based string");
   2461 +			}
   2462 +		}
   2463 +		for (int i = 0; i < char_cnt; i++) {
   2464 +			//System.out.println("char[" + i + "]\t" + (int) chars[i]);
   2465 +		}
   2466 +		if (fileName.length() <= 0) {
   2467 +			;
   2468 +		} else if (dwFileAttributes == 268435456
   2469  			|| dwFileAttributes == 369098752
   2470  			|| dwFileAttributes == 285212672 
   2471  			|| dwFileAttributes == 271056896
   2472 @@ -1263,11 +1536,74 @@
   2473  			|| dwFileAttributes == 369623040)
   2474  		{
   2475  			fileName = " [" + fileName + "]";
   2476 -			remoteDirsList.add(fileName); // sf@2004
   2477 -		}
   2478 -		else
   2479 -		{
   2480 -			remoteFilesList.add(" " + fileName); // sf@2004
   2481 +// begin runge/x11vnc
   2482 +//			remoteDirsList.add(fileName); // sf@2004
   2483 +			int i = -1;
   2484 +			String t1 = fileName.toLowerCase();
   2485 +			for (int j = 0; j < remoteDirsList.size(); j++) {
   2486 +				String t = (String) remoteDirsList.get(j);
   2487 +				String t2 = t.toLowerCase();
   2488 +				if (t1.compareTo(t2) < 0) {
   2489 +					i = j;
   2490 +					break;
   2491 +				}
   2492 +			}
   2493 +			//String s = "Lastmod: " + timeStr(ftLastWriteTimeL, ftLastWriteTimeH) + "    " + fileName; 
   2494 +			String f2 = fileName;
   2495 +			if (f2.length() < 24) {
   2496 +				for (int ik = f2.length(); ik < 24; ik++) {
   2497 +					f2 = f2 + " ";
   2498 +				}
   2499 +			}
   2500 +			String s = f2 + "    \tLastmod: " + timeStr(ftLastWriteTimeL, ftLastWriteTimeH) + "    \t\tSize: " + sizeStr(nFileSizeLow); 
   2501 +			//s = fileName + " Lastmod: " + zogswap(ftLastWriteTimeL); 
   2502 +			if (i >= 0) {
   2503 +				remoteDirsList.add(i, fileName);
   2504 +				remoteDirsListInfo.add(i, s);
   2505 +			} else {
   2506 +				remoteDirsList.add(fileName);
   2507 +				remoteDirsListInfo.add(s);
   2508 +			}
   2509 +// end runge/x11vnc
   2510 +		} else {
   2511 +// begin runge/x11vnc
   2512 +//			remoteFilesList.add(" " + fileName); // sf@2004
   2513 +	
   2514 +			fileName = " " + fileName;
   2515 +			int i = -1;
   2516 +			String t1 = fileName.toLowerCase();
   2517 +			for (int j = 0; j < remoteFilesList.size(); j++) {
   2518 +				String t = (String) remoteFilesList.get(j);
   2519 +				String t2 = t.toLowerCase();
   2520 +				if (t1.compareTo(t2) < 0) {
   2521 +					i = j;
   2522 +					break;
   2523 +				}
   2524 +			}
   2525 +			String f2 = fileName;
   2526 +			if (f2.length() < 24) {
   2527 +				for (int ik = f2.length(); ik < 24; ik++) {
   2528 +					f2 = f2 + " ";
   2529 +				}
   2530 +			}
   2531 +
   2532 +if (false) {
   2533 +System.out.println("fileName:         " + f2);
   2534 +System.out.println("ftLastWriteTimeL: " + ftLastWriteTimeL);
   2535 +System.out.println("ftLastWriteTimeH: " + ftLastWriteTimeH);
   2536 +System.out.println("nFileSizeLow:     " + nFileSizeLow);
   2537 +}
   2538 +
   2539 +			String s = f2 + "    \tLastmod: " + timeStr(ftLastWriteTimeL, ftLastWriteTimeH) + "    \t\tSize: " + sizeStr(nFileSizeLow); 
   2540 +			//s = fileName + " Lastmod: " + ftLastWriteTimeL + "/" + zogswap(ftLastWriteTimeL) + "  Size: " + nFileSizeLow + "/" + zogswap(nFileSizeLow); 
   2541 +			if (i >= 0) {
   2542 +				remoteFilesList.add(i, fileName);
   2543 +				remoteFilesListInfo.add(i, s);
   2544 +			} else {
   2545 +				remoteFilesList.add(fileName);
   2546 +				remoteFilesListInfo.add(s);
   2547 +			}
   2548 +// end runge/x11vnc
   2549  		}
   2550  	
   2551  		// a.add(fileName);
   2552 @@ -1282,14 +1618,32 @@
   2553  
   2554  		// sf@2004
   2555  		a.clear();
   2556 -		for (int i = 0; i < remoteDirsList.size(); i++) 
   2557 +		b.clear();
   2558 +		for (int i = 0; i < remoteDirsList.size(); i++) {
   2559  			a.add(remoteDirsList.get(i));
   2560 -		for (int i = 0; i < remoteFilesList.size(); i++) 
   2561 +			b.add(remoteDirsListInfo.get(i));
   2562 +		}
   2563 +		for (int i = 0; i < remoteFilesList.size(); i++) {
   2564  			a.add(remoteFilesList.get(i));
   2565 +
   2566 +			b.add(remoteFilesListInfo.get(i));
   2567 +		}
   2568  		remoteDirsList.clear();
   2569 +		remoteDirsListInfo.clear();
   2570  		remoteFilesList.clear();
   2571 +		remoteFilesListInfo.clear();
   2572  		
   2573 -		viewer.ftp.printDirectory(a);
   2574 +// begin runge/x11vnc
   2575 +		// Hack for double listing at startup... probably libvncserver bug..
   2576 +		readServerDriveListCnt++;
   2577 +		if (readServerDriveListCnt == 2) {
   2578 +			if (System.currentTimeMillis() - readServerDriveListTime < 2000)  {
   2579 +//System.out.println("readServerDriveListCnt skip " + readServerDriveListCnt);
   2580 +				return;
   2581 +			}
   2582 +		}
   2583 +// end runge/x11vnc
   2584 +		viewer.ftp.printDirectory(a, b);
   2585  	}
   2586  
   2587  	//Internally used to signify the drive requested is not ready
   2588 @@ -1299,6 +1653,8 @@
   2589  		System.out.println("Remote Drive unavailable");
   2590  		viewer.ftp.connectionStatus.setText(" > WARNING - Remote Drive unavailable (possibly restricted access or media not present)");
   2591  		viewer.ftp.remoteStatus.setText("WARNING: Remote Drive unavailable");
   2592 +		viewer.ftp.historyComboBox.insertItemAt(new String(" > WARNING: Remote Drive unavailable."), 0);
   2593 +		viewer.ftp.historyComboBox.setSelectedIndex(0);
   2594  	}
   2595  
   2596  	//Call this method to request the list of drives on the server.
   2597 @@ -1306,12 +1662,11 @@
   2598  	{
   2599  		try
   2600  		{
   2601 -			viewer.rfb.writeRfbFileTransferMsg(
   2602 -												RfbProto.rfbDirContentRequest,
   2603 -												RfbProto.rfbRDrivesList,
   2604 -												0,
   2605 -												0,
   2606 -												null);
   2607 +			viewer.rfb.writeRfbFileTransferMsg(RfbProto.rfbDirContentRequest, RfbProto.rfbRDrivesList, 0, 0, null);
   2608 +// begin runge/x11vnc
   2609 +			readServerDriveListCnt = 0;
   2610 +			readServerDriveListTime = System.currentTimeMillis();
   2611 +// end   runge/x11vnc
   2612  		}
   2613  		catch (IOException e)
   2614  		{
   2615 @@ -1355,21 +1710,21 @@
   2616  		int h,
   2617  		boolean incremental)
   2618  		throws IOException {
   2619 -			if (!viewer.ftp.isVisible()) {
   2620 -		byte[] b = new byte[10];
   2621 +		if (!viewer.ftp.isVisible()) {
   2622 +			byte[] b = new byte[10];
   2623  
   2624 -		b[0] = (byte) FramebufferUpdateRequest;
   2625 -		b[1] = (byte) (incremental ? 1 : 0);
   2626 -		b[2] = (byte) ((x >> 8) & 0xff);
   2627 -		b[3] = (byte) (x & 0xff);
   2628 -		b[4] = (byte) ((y >> 8) & 0xff);
   2629 -		b[5] = (byte) (y & 0xff);
   2630 -		b[6] = (byte) ((w >> 8) & 0xff);
   2631 -		b[7] = (byte) (w & 0xff);
   2632 -		b[8] = (byte) ((h >> 8) & 0xff);
   2633 -		b[9] = (byte) (h & 0xff);
   2634 +			b[0] = (byte) FramebufferUpdateRequest;
   2635 +			b[1] = (byte) (incremental ? 1 : 0);
   2636 +			b[2] = (byte) ((x >> 8) & 0xff);
   2637 +			b[3] = (byte) (x & 0xff);
   2638 +			b[4] = (byte) ((y >> 8) & 0xff);
   2639 +			b[5] = (byte) (y & 0xff);
   2640 +			b[6] = (byte) ((w >> 8) & 0xff);
   2641 +			b[7] = (byte) (w & 0xff);
   2642 +			b[8] = (byte) ((h >> 8) & 0xff);
   2643 +			b[9] = (byte) (h & 0xff);
   2644  
   2645 -		os.write(b);
   2646 +			os.write(b);
   2647  		}
   2648  	}
   2649  
   2650 @@ -1482,7 +1837,13 @@
   2651  		b[6] = (byte) ((text.length() >> 8) & 0xff);
   2652  		b[7] = (byte) (text.length() & 0xff);
   2653  
   2654 -		System.arraycopy(text.getBytes(), 0, b, 8, text.length());
   2655 +		if (false && max_char(text) > 255) {
   2656 +			System.arraycopy(text.getBytes("UTF-8"), 0, b, 8, text.length());
   2657 +		} else if (max_char(text) > 127) {
   2658 +			System.arraycopy(text.getBytes("ISO-8859-1"), 0, b, 8, text.length());
   2659 +		} else {
   2660 +			System.arraycopy(text.getBytes(), 0, b, 8, text.length());
   2661 +		}
   2662  
   2663  		os.write(b);
   2664  	//	}
   2665 @@ -1506,6 +1867,37 @@
   2666  	final static int META_MASK = InputEvent.META_MASK;
   2667  	final static int ALT_MASK = InputEvent.ALT_MASK;
   2668  
   2669 +	void writeWheelEvent(MouseWheelEvent evt) throws IOException {
   2670 +		eventBufLen = 0;
   2671 +
   2672 +		int x = evt.getX();
   2673 +		int y = evt.getY();
   2674 +
   2675 +		if (x < 0) x = 0;
   2676 +		if (y < 0) y = 0;
   2677 +
   2678 +		int ptrmask;
   2679 +
   2680 +		int clicks = evt.getWheelRotation();
   2681 +		System.out.println("writeWheelEvent: clicks: " + clicks);
   2682 +		if (clicks > 0) {
   2683 +			ptrmask = 16;
   2684 +		} else if (clicks < 0) {
   2685 +			ptrmask = 8;
   2686 +		} else {
   2687 +			return;
   2688 +		}
   2689 +
   2690 +		eventBuf[eventBufLen++] = (byte) PointerEvent;
   2691 +		eventBuf[eventBufLen++] = (byte) ptrmask;
   2692 +		eventBuf[eventBufLen++] = (byte) ((x >> 8) & 0xff);
   2693 +		eventBuf[eventBufLen++] = (byte) (x & 0xff);
   2694 +		eventBuf[eventBufLen++] = (byte) ((y >> 8) & 0xff);
   2695 +		eventBuf[eventBufLen++] = (byte) (y & 0xff);
   2696 +
   2697 +		os.write(eventBuf, 0, eventBufLen);
   2698 +	}
   2699 +
   2700  	//
   2701  	// Write a pointer event message.  We may need to send modifier key events
   2702  	// around it to set the correct modifier state.
   2703 @@ -1610,6 +2002,21 @@
   2704  
   2705  		boolean down = (evt.getID() == KeyEvent.KEY_PRESSED);
   2706  
   2707 +		if (viewer.debugKeyboard) {
   2708 +			System.out.println("----------------------------------------");
   2709 +			System.out.println("evt.getKeyChar:      " + evt.getKeyChar());
   2710 +			System.out.println("getKeyText:          " + KeyEvent.getKeyText(evt.getKeyCode()));
   2711 +			System.out.println("evt.getKeyCode:      " + evt.getKeyCode());
   2712 +			System.out.println("evt.getID:           " + evt.getID());
   2713 +			System.out.println("evt.getKeyLocation:  " + evt.getKeyLocation());
   2714 +			System.out.println("evt.isActionKey:     " + evt.isActionKey());
   2715 +			System.out.println("evt.isControlDown:   " + evt.isControlDown());
   2716 +			System.out.println("evt.getModifiers:    " + evt.getModifiers());
   2717 +			System.out.println("getKeyModifiersText: " + KeyEvent.getKeyModifiersText(evt.getModifiers()));
   2718 +			System.out.println("evt.paramString:     " + evt.paramString());
   2719 +		}
   2720 +
   2721 +
   2722  		int key;
   2723  		if (evt.isActionKey()) {
   2724  
   2725 @@ -1685,6 +2092,9 @@
   2726  				default :
   2727  					return;
   2728  			}
   2729 +			if (key == 0xffc2 && viewer.mapF5_to_atsign) {
   2730 +				key = 0x40;
   2731 +			}
   2732  
   2733  		} else {
   2734  
   2735 @@ -1794,6 +2204,16 @@
   2736  	int oldModifiers = 0;
   2737  
   2738  	void writeModifierKeyEvents(int newModifiers) {
   2739 +		if(viewer.forbid_Ctrl_Alt) {
   2740 +			if ((newModifiers & CTRL_MASK) != 0 && (newModifiers & ALT_MASK) != 0) {
   2741 +				int orig = newModifiers;
   2742 +				newModifiers &= ~ALT_MASK;
   2743 +				newModifiers &= ~CTRL_MASK;
   2744 +				if (viewer.debugKeyboard) {
   2745 +					System.out.println("Ctrl+Alt modifiers: " + orig + " -> " + newModifiers);
   2746 +				}
   2747 +			}
   2748 +		}
   2749  		if ((newModifiers & CTRL_MASK) != (oldModifiers & CTRL_MASK))
   2750  			writeKeyEvent(0xffe3, (newModifiers & CTRL_MASK) != 0);
   2751  
   2752 diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java
   2753 --- JavaViewer.orig/SSLSocketToMe.java	1969-12-31 19:00:00.000000000 -0500
   2754 +++ JavaViewer/SSLSocketToMe.java	2010-07-10 19:18:06.000000000 -0400
   2755 @@ -0,0 +1,2067 @@
   2756 +/*
   2757 + * SSLSocketToMe.java: add SSL encryption to Java VNC Viewer.
   2758 + *
   2759 + * Copyright (c) 2006 Karl J. Runge <runge (a] karlrunge.com>
   2760 + * All rights reserved.
   2761 + *
   2762 + *  This is free software; you can redistribute it and/or modify
   2763 + *  it under the terms of the GNU General Public License as published by
   2764 + *  the Free Software Foundation; version 2 of the License, or
   2765 + *  (at your option) any later version.
   2766 + *
   2767 + *  This software is distributed in the hope that it will be useful,
   2768 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   2769 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   2770 + *  GNU General Public License for more details.
   2771 + *
   2772 + *  You should have received a copy of the GNU General Public License
   2773 + *  along with this software; if not, write to the Free Software
   2774 + *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
   2775 + *  USA.
   2776 + *
   2777 + */
   2778 +
   2779 +import java.net.*;
   2780 +import java.io.*;
   2781 +import javax.net.ssl.*;
   2782 +import java.util.*;
   2783 +
   2784 +import java.security.*;
   2785 +import java.security.cert.*;
   2786 +import java.security.spec.*;
   2787 +import java.security.cert.Certificate;
   2788 +import java.security.cert.CertificateFactory;
   2789 +
   2790 +import java.awt.*;
   2791 +import java.awt.event.*;
   2792 +
   2793 +public class SSLSocketToMe {
   2794 +
   2795 +	/* basic member data: */
   2796 +	String host;
   2797 +	int port;
   2798 +	VncViewer viewer;
   2799 +
   2800 +	boolean debug = true;
   2801 +	boolean debug_certs = false;
   2802 +
   2803 +	/* sockets */
   2804 +	SSLSocket socket = null;
   2805 +	SSLSocketFactory factory;
   2806 +
   2807 +	/* fallback for Proxy connection */
   2808 +	boolean proxy_in_use = false;
   2809 +	boolean proxy_failure = false;
   2810 +	public DataInputStream is = null;
   2811 +	public OutputStream os = null;
   2812 +
   2813 +	/* strings from user WRT proxy: */
   2814 +	String proxy_auth_string = null;
   2815 +	String proxy_dialog_host = null;
   2816 +	int proxy_dialog_port = 0;
   2817 +
   2818 +	Socket proxySock;
   2819 +	DataInputStream proxy_is;
   2820 +	OutputStream proxy_os;
   2821 +
   2822 +	/* trust contexts */
   2823 +	SSLContext trustloc_ctx;
   2824 +	SSLContext trustall_ctx;
   2825 +	SSLContext trustsrv_ctx;
   2826 +	SSLContext trusturl_ctx;
   2827 +	SSLContext trustone_ctx;
   2828 +
   2829 +	/* corresponding trust managers */
   2830 +	TrustManager[] trustAllCerts;
   2831 +	TrustManager[] trustSrvCert;
   2832 +	TrustManager[] trustUrlCert;
   2833 +	TrustManager[] trustOneCert;
   2834 +
   2835 +	/* client-side SSL auth key (oneTimeKey=...) */
   2836 +	KeyManager[] mykey = null;
   2837 +
   2838 +	boolean user_wants_to_see_cert = true;
   2839 +	String cert_fail = null;
   2840 +
   2841 +	/* cert(s) we retrieve from Web server, VNC server, or serverCert param: */
   2842 +	java.security.cert.Certificate[] trustallCerts = null;
   2843 +	java.security.cert.Certificate[] trustsrvCerts = null;
   2844 +	java.security.cert.Certificate[] trusturlCerts = null;
   2845 +
   2846 +	/* utility to decode hex oneTimeKey=... and serverCert=... */
   2847 +	byte[] hex2bytes(String s) {
   2848 +		byte[] bytes = new byte[s.length()/2];
   2849 +		for (int i=0; i<s.length()/2; i++) {
   2850 +			int j = 2*i;
   2851 +			try {
   2852 +				int val = Integer.parseInt(s.substring(j, j+2), 16);
   2853 +				if (val > 127) {
   2854 +					val -= 256;
   2855 +				}
   2856 +				Integer I = new Integer(val);
   2857 +				bytes[i] = Byte.decode(I.toString()).byteValue();
   2858 +				
   2859 +			} catch (Exception e) {
   2860 +				;
   2861 +			}
   2862 +		}
   2863 +		return bytes;
   2864 +	}
   2865 +
   2866 +	SSLSocketToMe(String h, int p, VncViewer v) throws Exception {
   2867 +		host = h;
   2868 +		port = p;
   2869 +		viewer = v;
   2870 +
   2871 +		debug_certs = v.debugCerts;
   2872 +
   2873 +		/* we will first try default factory for certification: */
   2874 +
   2875 +		factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
   2876 +
   2877 +		dbg("SSL startup: " + host + " " + port);
   2878 +
   2879 +
   2880 +		/* create trust managers to be used if initial handshake fails: */
   2881 +
   2882 +		trustAllCerts = new TrustManager[] {
   2883 +		    /*
   2884 +		     * this one accepts everything.  Only used if user
   2885 +		     * has disabled checking (trustAllVncCerts=yes)
   2886 +		     * or when we grab the cert to show it to them in
   2887 +		     * a dialog and ask them to manually verify/accept it.
   2888 +		     */
   2889 +		    new X509TrustManager() {
   2890 +			public java.security.cert.X509Certificate[]
   2891 +			    getAcceptedIssuers() {
   2892 +				return null;
   2893 +			}
   2894 +			public void checkClientTrusted(
   2895 +			    java.security.cert.X509Certificate[] certs,
   2896 +			    String authType) {
   2897 +				/* empty */
   2898 +			}
   2899 +			public void checkServerTrusted(
   2900 +			    java.security.cert.X509Certificate[] certs,
   2901 +			    String authType) {
   2902 +				/* empty */
   2903 +				dbg("ALL: an untrusted connect to grab cert.");
   2904 +			}
   2905 +		    }
   2906 +		};
   2907 +
   2908 +		trustUrlCert = new TrustManager[] {
   2909 +		    /*
   2910 +		     * this one accepts only the retrieved server
   2911 +		     * cert by SSLSocket by this applet and stored in
   2912 +		     * trusturlCerts.
   2913 +		     */
   2914 +		    new X509TrustManager() {
   2915 +			public java.security.cert.X509Certificate[]
   2916 +			    getAcceptedIssuers() {
   2917 +				return null;
   2918 +			}
   2919 +			public void checkClientTrusted(
   2920 +			    java.security.cert.X509Certificate[] certs,
   2921 +			    String authType) throws CertificateException {
   2922 +				throw new CertificateException("No Clients (URL)");
   2923 +			}
   2924 +			public void checkServerTrusted(
   2925 +			    java.security.cert.X509Certificate[] certs,
   2926 +			    String authType) throws CertificateException {
   2927 +				/* we want to check 'certs' against 'trusturlCerts' */
   2928 +				if (trusturlCerts == null) {
   2929 +					throw new CertificateException(
   2930 +					    "No Trust url Certs array.");
   2931 +				}
   2932 +				if (trusturlCerts.length < 1) {
   2933 +					throw new CertificateException(
   2934 +					    "No Trust url Certs.");
   2935 +				}
   2936 +				if (certs == null) {
   2937 +					throw new CertificateException(
   2938 +					    "No this-certs array.");
   2939 +				}
   2940 +				if (certs.length < 1) {
   2941 +					throw new CertificateException(
   2942 +					    "No this-certs Certs.");
   2943 +				}
   2944 +				if (certs.length != trusturlCerts.length) {
   2945 +					throw new CertificateException(
   2946 +					    "certs.length != trusturlCerts.length " + certs.length + " " + trusturlCerts.length);
   2947 +				}
   2948 +				boolean ok = true;
   2949 +				for (int i = 0; i < certs.length; i++)  {
   2950 +					if (! trusturlCerts[i].equals(certs[i])) {
   2951 +						ok = false;
   2952 +						dbg("URL: cert mismatch at i=" + i);
   2953 +						dbg("URL: cert mismatch cert" + certs[i]);
   2954 +						dbg("URL: cert mismatch  url" + trusturlCerts[i]);
   2955 +						if (cert_fail == null) {
   2956 +							cert_fail = "cert-mismatch";
   2957 +						}
   2958 +					}
   2959 +					if (debug_certs) {
   2960 +						dbg("\n***********************************************");
   2961 +						dbg("URL: cert info at i=" + i);
   2962 +						dbg("URL: cert info cert" + certs[i]);
   2963 +						dbg("===============================================");
   2964 +						dbg("URL: cert info  url" + trusturlCerts[i]);
   2965 +						dbg("***********************************************");
   2966 +					}
   2967 +				}
   2968 +				if (!ok) {
   2969 +					throw new CertificateException(
   2970 +					    "Server Cert Chain != URL Cert Chain.");
   2971 +				}
   2972 +				dbg("URL: trusturlCerts[i] matches certs[i] i=0:" + (certs.length-1));
   2973 +			}
   2974 +		    }
   2975 +		};
   2976 +
   2977 +		trustSrvCert = new TrustManager[] {
   2978 +		    /*
   2979 +		     * this one accepts cert given to us in the serverCert
   2980 +		     * Applet Parameter we were started with.  It is
   2981 +		     * currently a fatal error if the VNC Server's cert
   2982 +		     * doesn't match it.
   2983 +		     */
   2984 +		    new X509TrustManager() {
   2985 +			public java.security.cert.X509Certificate[]
   2986 +			    getAcceptedIssuers() {
   2987 +				return null;
   2988 +			}
   2989 +			public void checkClientTrusted(
   2990 +			    java.security.cert.X509Certificate[] certs,
   2991 +			    String authType) throws CertificateException {
   2992 +				throw new CertificateException("No Clients (SRV)");
   2993 +			}
   2994 +			public void checkServerTrusted(
   2995 +			    java.security.cert.X509Certificate[] certs,
   2996 +			    String authType) throws CertificateException {
   2997 +				/* we want to check 'certs' against 'trustsrvCerts' */
   2998 +				if (trustsrvCerts == null) {
   2999 +					throw new CertificateException(
   3000 +					    "No Trust srv Certs array.");
   3001 +				}
   3002 +				if (trustsrvCerts.length < 1) {
   3003 +					throw new CertificateException(
   3004 +					    "No Trust srv Certs.");
   3005 +				}
   3006 +				if (certs == null) {
   3007 +					throw new CertificateException(
   3008 +					    "No this-certs array.");
   3009 +				}
   3010 +				if (certs.length < 1) {
   3011 +					throw new CertificateException(
   3012 +					    "No this-certs Certs.");
   3013 +				}
   3014 +				if (certs.length != trustsrvCerts.length) {
   3015 +					throw new CertificateException(
   3016 +					    "certs.length != trustsrvCerts.length " + certs.length + " " + trustsrvCerts.length);
   3017 +				}
   3018 +				boolean ok = true;
   3019 +				for (int i = 0; i < certs.length; i++)  {
   3020 +					if (! trustsrvCerts[i].equals(certs[i])) {
   3021 +						ok = false;
   3022 +						dbg("SRV: cert mismatch at i=" + i);
   3023 +						dbg("SRV: cert mismatch cert" + certs[i]);
   3024 +						dbg("SRV: cert mismatch  srv" + trustsrvCerts[i]);
   3025 +						if (cert_fail == null) {
   3026 +							cert_fail = "server-cert-mismatch";
   3027 +						}
   3028 +					}
   3029 +					if (debug_certs) {
   3030 +						dbg("\n***********************************************");
   3031 +						dbg("SRV: cert info at i=" + i);
   3032 +						dbg("SRV: cert info cert" + certs[i]);
   3033 +						dbg("===============================================");
   3034 +						dbg("SRV: cert info  srv" + trustsrvCerts[i]);
   3035 +						dbg("***********************************************");
   3036 +					}
   3037 +				}
   3038 +				if (!ok) {
   3039 +					throw new CertificateException(
   3040 +					    "Server Cert Chain != serverCert Applet Parameter Cert Chain.");
   3041 +				}
   3042 +				dbg("SRV: trustsrvCerts[i] matches certs[i] i=0:" + (certs.length-1));
   3043 +			}
   3044 +		    }
   3045 +		};
   3046 +
   3047 +		trustOneCert = new TrustManager[] {
   3048 +		    /*
   3049 +		     * this one accepts only the retrieved server
   3050 +		     * cert by SSLSocket by this applet we stored in
   3051 +		     * trustallCerts that user has accepted or applet
   3052 +		     * parameter trustAllVncCerts=yes is set.  This is
   3053 +		     * for when we reconnect after the user has manually
   3054 +		     * accepted the trustall cert in the dialog (or set
   3055 +		     * trustAllVncCerts=yes applet param.)
   3056 +		     */
   3057 +		    new X509TrustManager() {
   3058 +			public java.security.cert.X509Certificate[]
   3059 +			    getAcceptedIssuers() {
   3060 +				return null;
   3061 +			}
   3062 +			public void checkClientTrusted(
   3063 +			    java.security.cert.X509Certificate[] certs,
   3064 +			    String authType) throws CertificateException {
   3065 +				throw new CertificateException("No Clients (ONE)");
   3066 +			}
   3067 +			public void checkServerTrusted(
   3068 +			    java.security.cert.X509Certificate[] certs,
   3069 +			    String authType) throws CertificateException {
   3070 +				/* we want to check 'certs' against 'trustallCerts' */
   3071 +				if (trustallCerts == null) {
   3072 +					throw new CertificateException(
   3073 +					    "No Trust All Server Certs array.");
   3074 +				}
   3075 +				if (trustallCerts.length < 1) {
   3076 +					throw new CertificateException(
   3077 +					    "No Trust All Server Certs.");
   3078 +				}
   3079 +				if (certs == null) {
   3080 +					throw new CertificateException(
   3081 +					    "No this-certs array.");
   3082 +				}
   3083 +				if (certs.length < 1) {
   3084 +					throw new CertificateException(
   3085 +					    "No this-certs Certs.");
   3086 +				}
   3087 +				if (certs.length != trustallCerts.length) {
   3088 +					throw new CertificateException(
   3089 +					    "certs.length != trustallCerts.length " + certs.length + " " + trustallCerts.length);
   3090 +				}
   3091 +				boolean ok = true;
   3092 +				for (int i = 0; i < certs.length; i++)  {
   3093 +					if (! trustallCerts[i].equals(certs[i])) {
   3094 +						ok = false;
   3095 +						dbg("ONE: cert mismatch at i=" + i);
   3096 +						dbg("ONE: cert mismatch cert" + certs[i]);
   3097 +						dbg("ONE: cert mismatch  all" + trustallCerts[i]);
   3098 +					}
   3099 +					if (debug_certs) {
   3100 +						dbg("\n***********************************************");
   3101 +						dbg("ONE: cert info at i=" + i);
   3102 +						dbg("ONE: cert info cert" + certs[i]);
   3103 +						dbg("===============================================");
   3104 +						dbg("ONE: cert info  all" + trustallCerts[i]);
   3105 +						dbg("***********************************************");
   3106 +					}
   3107 +				}
   3108 +				if (!ok) {
   3109 +					throw new CertificateException(
   3110 +					    "Server Cert Chain != TRUSTALL Cert Chain.");
   3111 +				}
   3112 +				dbg("ONE: trustallCerts[i] matches certs[i] i=0:" + (certs.length-1));
   3113 +			}
   3114 +		    }
   3115 +		};
   3116 +
   3117 +		/* 
   3118 +		 * The above TrustManagers are used:
   3119 +		 *
   3120 +		 * 1) to retrieve the server cert in case of failure to
   3121 +		 *    display it to the user in a dialog.
   3122 +		 * 2) to subsequently connect to the server if user agrees.
   3123 +		 */
   3124 +
   3125 +		/*
   3126 +		 * build oneTimeKey cert+key if supplied in applet parameter:
   3127 +		 */
   3128 +		if (viewer.oneTimeKey != null && viewer.oneTimeKey.equals("PROMPT")) {
   3129 +			ClientCertDialog d = new ClientCertDialog();
   3130 +			viewer.oneTimeKey = d.queryUser();
   3131 +		}
   3132 +		if (viewer.oneTimeKey != null && viewer.oneTimeKey.indexOf(",") > 0) {
   3133 +			int idx = viewer.oneTimeKey.indexOf(",");
   3134 +
   3135 +			String onetimekey = viewer.oneTimeKey.substring(0, idx);
   3136 +			byte[] key = hex2bytes(onetimekey);
   3137 +			String onetimecert = viewer.oneTimeKey.substring(idx+1);
   3138 +			byte[] cert = hex2bytes(onetimecert);
   3139 +
   3140 +			KeyFactory kf = KeyFactory.getInstance("RSA");
   3141 +			PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key );
   3142 +			PrivateKey ff = kf.generatePrivate (keysp);
   3143 +			if (debug_certs) {
   3144 +				dbg("one time key " + ff);
   3145 +			}
   3146 +
   3147 +			CertificateFactory cf = CertificateFactory.getInstance("X.509");
   3148 +			Collection c = cf.generateCertificates(new ByteArrayInputStream(cert));
   3149 +			Certificate[] certs = new Certificate[c.toArray().length];
   3150 +			if (c.size() == 1) {
   3151 +				Certificate tmpcert = cf.generateCertificate(new ByteArrayInputStream(cert));
   3152 +				if (debug_certs) {
   3153 +					dbg("one time cert" + tmpcert);
   3154 +				}
   3155 +				certs[0] = tmpcert;
   3156 +			} else {
   3157 +				certs = (Certificate[]) c.toArray();
   3158 +			}
   3159 +
   3160 +			KeyStore ks = KeyStore.getInstance("JKS");
   3161 +			ks.load(null, null);
   3162 +			ks.setKeyEntry("onetimekey", ff, "".toCharArray(), certs);
   3163 +			String da = KeyManagerFactory.getDefaultAlgorithm();
   3164 +			KeyManagerFactory kmf = KeyManagerFactory.getInstance(da);
   3165 +			kmf.init(ks, "".toCharArray());
   3166 +
   3167 +			mykey = kmf.getKeyManagers();
   3168 +		}
   3169 +
   3170 +		/*
   3171 +		 * build serverCert cert if supplied in applet parameter:
   3172 +		 */
   3173 +		if (viewer.serverCert != null) {
   3174 +			CertificateFactory cf = CertificateFactory.getInstance("X.509");
   3175 +			byte[] cert = hex2bytes(viewer.serverCert);
   3176 +			Collection c = cf.generateCertificates(new ByteArrayInputStream(cert));
   3177 +			trustsrvCerts = new Certificate[c.toArray().length];
   3178 +			if (c.size() == 1) {
   3179 +				Certificate tmpcert = cf.generateCertificate(new ByteArrayInputStream(cert));
   3180 +				trustsrvCerts[0] = tmpcert;
   3181 +			} else {
   3182 +				trustsrvCerts = (Certificate[]) c.toArray();
   3183 +			}
   3184 +		}
   3185 +
   3186 +		/* the trust loc certs context: */
   3187 +		try {
   3188 +			trustloc_ctx = SSLContext.getInstance("SSL");
   3189 +
   3190 +			/*
   3191 +			 * below is a failed attempt to get jvm's default
   3192 +			 * trust manager using null (below) makes it so
   3193 +			 * for HttpsURLConnection the server cannot be
   3194 +			 * verified (no prompting.)
   3195 +			 */
   3196 +			if (false) {
   3197 +				boolean didit = false;
   3198 +				TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());  
   3199 +				tmf.init((KeyStore) null);
   3200 +				TrustManager [] tml = tmf.getTrustManagers();
   3201 +				for (int i = 0; i < tml.length; i++) {
   3202 +					TrustManager tm = tml[i];
   3203 +					if (tm instanceof X509TrustManager) {
   3204 +						TrustManager tm1[] = new TrustManager[1];
   3205 +						tm1[0] = tm;
   3206 +						trustloc_ctx.init(mykey, tm1, null);
   3207 +						didit = true;
   3208 +						break;
   3209 +					}
   3210 +				}
   3211 +				if (!didit) {
   3212 +					trustloc_ctx.init(mykey, null, null);
   3213 +				}
   3214 +			} else {
   3215 +				/* we have to set trust manager to null */
   3216 +				trustloc_ctx.init(mykey, null, null);
   3217 +			}
   3218 +
   3219 +		} catch (Exception e) {
   3220 +			String msg = "SSL trustloc_ctx FAILED.";
   3221 +			dbg(msg);
   3222 +			throw new Exception(msg);
   3223 +		}
   3224 +
   3225 +		/* the trust all certs context: */
   3226 +		try {
   3227 +			trustall_ctx = SSLContext.getInstance("SSL");
   3228 +			trustall_ctx.init(mykey, trustAllCerts, new
   3229 +			    java.security.SecureRandom());
   3230 +
   3231 +		} catch (Exception e) {
   3232 +			String msg = "SSL trustall_ctx FAILED.";
   3233 +			dbg(msg);
   3234 +			throw new Exception(msg);
   3235 +		}
   3236 +
   3237 +		/* the trust url certs context: */
   3238 +		try {
   3239 +			trusturl_ctx = SSLContext.getInstance("SSL");
   3240 +			trusturl_ctx.init(mykey, trustUrlCert, new
   3241 +			    java.security.SecureRandom());
   3242 +
   3243 +		} catch (Exception e) {
   3244 +			String msg = "SSL trusturl_ctx FAILED.";
   3245 +			dbg(msg);
   3246 +			throw new Exception(msg);
   3247 +		}
   3248 +
   3249 +		/* the trust srv certs context: */
   3250 +		try {
   3251 +			trustsrv_ctx = SSLContext.getInstance("SSL");
   3252 +			trustsrv_ctx.init(mykey, trustSrvCert, new
   3253 +			    java.security.SecureRandom());
   3254 +
   3255 +		} catch (Exception e) {
   3256 +			String msg = "SSL trustsrv_ctx FAILED.";
   3257 +			dbg(msg);
   3258 +			throw new Exception(msg);
   3259 +		}
   3260 +
   3261 +		/* the trust the one cert from server context: */
   3262 +		try {
   3263 +			trustone_ctx = SSLContext.getInstance("SSL");
   3264 +			trustone_ctx.init(mykey, trustOneCert, new
   3265 +			    java.security.SecureRandom());
   3266 +
   3267 +		} catch (Exception e) {
   3268 +			String msg = "SSL trustone_ctx FAILED.";
   3269 +			dbg(msg);
   3270 +			throw new Exception(msg);
   3271 +		}
   3272 +	}
   3273 +
   3274 +	/*
   3275 +	 * we call this early on to 1) check for a proxy, 2) grab
   3276 +	 * Browser/JVM accepted HTTPS cert.
   3277 +	 */
   3278 +	public void check_for_proxy_and_grab_vnc_server_cert() {
   3279 +		
   3280 +		trusturlCerts = null;
   3281 +		proxy_in_use = false;
   3282 +
   3283 +		if (viewer.ignoreProxy) {
   3284 +			/* applet param says skip it. */
   3285 +			/* the downside is we do not set trusturlCerts for comparison later... */
   3286 +			/* nor do we autodetect x11vnc for GET=1. */
   3287 +			return;
   3288 +		}
   3289 +
   3290 +		dbg("------------------------------------------------");
   3291 +		dbg("Into check_for_proxy_and_grab_vnc_server_cert():");
   3292 +
   3293 +		dbg("TRYING HTTPS:");
   3294 +		String ustr = "https://" + host + ":";
   3295 +		if (viewer.httpsPort != null) {
   3296 +			ustr += viewer.httpsPort;
   3297 +		} else {
   3298 +			ustr += port;
   3299 +		}
   3300 +		ustr += viewer.urlPrefix + "/check.https.proxy.connection";
   3301 +		dbg("ustr is: " + ustr);
   3302 +
   3303 +		try {
   3304 +			/* prepare for an HTTPS URL connection to host:port */
   3305 +			URL url = new URL(ustr);
   3306 +			HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
   3307 +
   3308 +			if (mykey != null) {
   3309 +				/* with oneTimeKey (mykey) we can't use the default SSL context */
   3310 +				if (trustsrvCerts != null) {
   3311 +					dbg("passing trustsrv_ctx to HttpsURLConnection to provide client cert.");
   3312 +					https.setSSLSocketFactory(trustsrv_ctx.getSocketFactory());	
   3313 +				} else if (trustloc_ctx != null) {
   3314 +					dbg("passing trustloc_ctx to HttpsURLConnection to provide client cert.");
   3315 +					https.setSSLSocketFactory(trustloc_ctx.getSocketFactory());	
   3316 +				}
   3317 +			}
   3318 +
   3319 +			https.setUseCaches(false);
   3320 +			https.setRequestMethod("GET");
   3321 +			https.setRequestProperty("Pragma", "No-Cache");
   3322 +			https.setRequestProperty("Proxy-Connection", "Keep-Alive");
   3323 +			https.setDoInput(true);
   3324 +
   3325 +			dbg("trying https.connect()");
   3326 +			https.connect();
   3327 +
   3328 +			dbg("trying https.getServerCertificates()");
   3329 +			trusturlCerts = https.getServerCertificates();
   3330 +
   3331 +			if (trusturlCerts == null) {
   3332 +				dbg("set trusturlCerts to null!");
   3333 +			} else {
   3334 +				dbg("set trusturlCerts to non-null");
   3335 +			}
   3336 +
   3337 +			if (https.usingProxy()) {
   3338 +				proxy_in_use = true;
   3339 +				dbg("An HTTPS proxy is in use. There may be connection problems.");
   3340 +			}
   3341 +
   3342 +			dbg("trying https.getContent()");
   3343 +			Object output = https.getContent();
   3344 +			dbg("trying https.disconnect()");
   3345 +			https.disconnect();
   3346 +			if (! viewer.GET) {
   3347 +				String header = https.getHeaderField("VNC-Server");
   3348 +				if (header != null && header.startsWith("x11vnc")) {
   3349 +					dbg("detected x11vnc server (1), setting GET=1");
   3350 +					viewer.GET = true;
   3351 +				}
   3352 +			}
   3353 +
   3354 +		} catch(Exception e) {
   3355 +			dbg("HttpsURLConnection: " + e.getMessage());
   3356 +		}
   3357 +
   3358 +		if (proxy_in_use) {
   3359 +			dbg("exit check_for_proxy_and_grab_vnc_server_cert():");
   3360 +			dbg("------------------------------------------------");
   3361 +			return;
   3362 +		} else if (trusturlCerts != null && !viewer.forceProxy) {
   3363 +			/* Allow user to require HTTP check?  use forceProxy for now. */
   3364 +			dbg("SKIPPING HTTP PROXY CHECK: got trusturlCerts, assuming proxy info is correct.");
   3365 +			dbg("exit check_for_proxy_and_grab_vnc_server_cert():");
   3366 +			dbg("------------------------------------------------");
   3367 +			return;
   3368 +		}
   3369 +
   3370 +		/*
   3371 +		 * XXX need to remember scenario where this extra check
   3372 +		 * gives useful info.  User's Browser proxy settings?
   3373 +		 */
   3374 +		dbg("TRYING HTTP:");
   3375 +		ustr = "http://" + host + ":" + port;
   3376 +		ustr += viewer.urlPrefix + "/index.vnc";
   3377 +		dbg("ustr is: " + ustr);
   3378 +
   3379 +		try {
   3380 +			/* prepare for an HTTP URL connection to the same host:port (but not httpsPort) */
   3381 +			URL url = new URL(ustr);
   3382 +			HttpURLConnection http = (HttpURLConnection)
   3383 +			    url.openConnection();
   3384 +
   3385 +			http.setUseCaches(false);
   3386 +			http.setRequestMethod("GET");
   3387 +			http.setRequestProperty("Pragma", "No-Cache");
   3388 +			http.setRequestProperty("Proxy-Connection", "Keep-Alive");
   3389 +			http.setDoInput(true);
   3390 +
   3391 +			dbg("trying http.connect()");
   3392 +			http.connect();
   3393 +
   3394 +			if (http.usingProxy()) {
   3395 +				proxy_in_use = true;
   3396 +				dbg("An HTTP proxy is in use. There may be connection problems.");
   3397 +			}
   3398 +			dbg("trying http.getContent()");
   3399 +			Object output = http.getContent();
   3400 +			dbg("trying http.disconnect()");
   3401 +			http.disconnect();
   3402 +			if (! viewer.GET) {
   3403 +				String header = http.getHeaderField("VNC-Server");
   3404 +				if (header != null && header.startsWith("x11vnc")) {
   3405 +					dbg("detected x11vnc server (2), setting GET=1");
   3406 +					viewer.GET = true;
   3407 +				}
   3408 +			}
   3409 +		} catch(Exception e) {
   3410 +			dbg("HttpURLConnection:  " + e.getMessage());
   3411 +		}
   3412 +		dbg("exit check_for_proxy_and_grab_vnc_server_cert():");
   3413 +		dbg("------------------------------------------------");
   3414 +	}
   3415 +
   3416 +	public Socket connectSock() throws IOException {
   3417 +		/*
   3418 +		 * first try a https connection to detect a proxy, and
   3419 +		 * grab the VNC server cert at the same time:
   3420 +		 */
   3421 +		check_for_proxy_and_grab_vnc_server_cert();
   3422 +
   3423 +		boolean srv_cert = false;
   3424 +		
   3425 +		if (trustsrvCerts != null) {
   3426 +			/* applet parameter suppled serverCert */
   3427 +			dbg("viewer.trustSrvCert-0 using trustsrv_ctx");
   3428 +			factory = trustsrv_ctx.getSocketFactory();
   3429 +			srv_cert = true;
   3430 +		} else if (viewer.trustAllVncCerts) {
   3431 +			/* trust all certs (no checking) */
   3432 +			dbg("viewer.trustAllVncCerts-0 using trustall_ctx");
   3433 +			factory = trustall_ctx.getSocketFactory();
   3434 +		} else if (trusturlCerts != null) {
   3435 +			/* trust certs the Browser/JVM accepted in check_for_proxy... */
   3436 +			dbg("using trusturl_ctx");
   3437 +			factory = trusturl_ctx.getSocketFactory();
   3438 +		} else {
   3439 +			/* trust the local defaults */
   3440 +			dbg("using trustloc_ctx");
   3441 +			factory = trustloc_ctx.getSocketFactory();
   3442 +		}
   3443 +
   3444 +		socket = null;
   3445 +
   3446 +		try {
   3447 +			if (proxy_in_use && viewer.forceProxy) {
   3448 +				throw new Exception("forcing proxy (forceProxy)");
   3449 +			} else if (viewer.CONNECT != null) {
   3450 +				throw new Exception("forcing CONNECT");
   3451 +			}
   3452 +
   3453 +			int timeout = 6;
   3454 +			if (timeout > 0) {
   3455 +				socket = (SSLSocket) factory.createSocket();
   3456 +				InetSocketAddress inetaddr = new InetSocketAddress(host, port);
   3457 +				dbg("Using timeout of " + timeout + " secs to: " + host + ":" + port);
   3458 +				socket.connect(inetaddr, timeout * 1000);
   3459 +			} else {
   3460 +				socket = (SSLSocket) factory.createSocket(host, port);
   3461 +			}
   3462 +
   3463 +		} catch (Exception esock) {
   3464 +			dbg("socket error: " + esock.getMessage());
   3465 +			if (proxy_in_use || viewer.CONNECT != null) {
   3466 +				proxy_failure = true;
   3467 +				if (proxy_in_use) {
   3468 +					dbg("HTTPS proxy in use. Trying to go with it.");
   3469 +				} else {
   3470 +					dbg("viewer.CONNECT reverse proxy in use. Trying to go with it.");
   3471 +				}
   3472 +				try {
   3473 +					socket = proxy_socket(factory);
   3474 +				} catch (Exception e) {
   3475 +					dbg("proxy_socket error: " + e.getMessage());
   3476 +				}
   3477 +			} else {
   3478 +				/* n.b. socket is left in error state to cause ex. below. */
   3479 +			}
   3480 +		}
   3481 +
   3482 +		try {
   3483 +			socket.startHandshake();
   3484 +
   3485 +			dbg("The Server Connection Verified OK on 1st try.");
   3486 +
   3487 +			java.security.cert.Certificate[] currentTrustedCerts;
   3488 +			BrowserCertsDialog bcd;
   3489 +
   3490 +			SSLSession sess = socket.getSession();
   3491 +			currentTrustedCerts = sess.getPeerCertificates();
   3492 +
   3493 +			if (viewer.trustAllVncCerts) {
   3494 +				dbg("viewer.trustAllVncCerts-1  keeping socket.");
   3495 +			} else if (currentTrustedCerts == null || currentTrustedCerts.length < 1) {
   3496 +				try {
   3497 +					socket.close();
   3498 +				} catch (Exception e) {
   3499 +					dbg("socket is grumpy.");
   3500 +				}
   3501 +				socket = null;
   3502 +				throw new SSLHandshakeException("no current certs");
   3503 +			}
   3504 +
   3505 +			String serv = "";
   3506 +			try {
   3507 +				CertInfo ci = new CertInfo(currentTrustedCerts[0]);
   3508 +				serv = ci.get_certinfo("CN");
   3509 +			} catch (Exception e) {
   3510 +				;
   3511 +			}
   3512 +
   3513 +			if (viewer.trustAllVncCerts) {
   3514 +				dbg("viewer.trustAllVncCerts-2  skipping browser certs dialog");
   3515 +				user_wants_to_see_cert = false;
   3516 +			} else if (viewer.serverCert != null && trustsrvCerts != null) {
   3517 +				dbg("viewer.serverCert-1  skipping browser certs dialog");
   3518 +				user_wants_to_see_cert = false;
   3519 +			} else if (viewer.trustUrlVncCert) {
   3520 +				dbg("viewer.trustUrlVncCert-1  skipping browser certs dialog");
   3521 +				user_wants_to_see_cert = false;
   3522 +			} else {
   3523 +				/* have a dialog with the user: */
   3524 +				bcd = new BrowserCertsDialog(serv, host + ":" + port);
   3525 +				dbg("browser certs dialog begin.");
   3526 +				bcd.queryUser();
   3527 +				dbg("browser certs dialog finished.");
   3528 +
   3529 +				if (bcd.showCertDialog) {
   3530 +					String msg = "user wants to see cert";
   3531 +					dbg(msg);
   3532 +					user_wants_to_see_cert = true;
   3533 +					if (cert_fail == null) {
   3534 +						cert_fail = "user-view";
   3535 +					}
   3536 +					throw new SSLHandshakeException(msg);
   3537 +				} else {
   3538 +					user_wants_to_see_cert = false;
   3539 +					dbg("browser certs dialog: user said yes, accept it");
   3540 +				}
   3541 +			}
   3542 +
   3543 +		} catch (SSLHandshakeException eh)  {
   3544 +			dbg("SSLHandshakeException: could not automatically verify Server.");
   3545 +			dbg("msg: " + eh.getMessage());
   3546 +
   3547 +
   3548 +			/* send a cleanup string just in case: */
   3549 +			String getoutstr = "GET /index.vnc HTTP/1.0\r\nConnection: close\r\n\r\n";
   3550 +
   3551 +			try {
   3552 +				OutputStream os = socket.getOutputStream();
   3553 +				os.write(getoutstr.getBytes());
   3554 +				socket.close();
   3555 +			} catch (Exception e) {
   3556 +				dbg("socket is grumpy!");
   3557 +			}
   3558 +
   3559 +			/* reload */
   3560 +
   3561 +			socket = null;
   3562 +
   3563 +			String reason = null;
   3564 +
   3565 +			if (srv_cert) {
   3566 +				/* for serverCert usage we make this a fatal error. */
   3567 +				throw new IOException("Fatal: VNC Server's Cert does not match Applet Parameter 'serverCert=...'");
   3568 +				/* see below in TrustDialog were we describe this case to user anyway */
   3569 +			}
   3570 +
   3571 +			/*
   3572 +			 * Reconnect, trusting any cert, so we can grab
   3573 +			 * the cert to show it to the user in a dialog
   3574 +			 * for him to manually accept.  This connection
   3575 +			 * is not used for anything else.
   3576 +			 */
   3577 +			factory = trustall_ctx.getSocketFactory();
   3578 +			if (proxy_failure) {
   3579 +				socket = proxy_socket(factory);
   3580 +			} else {
   3581 +				socket = (SSLSocket) factory.createSocket(host, port);
   3582 +			}
   3583 +
   3584 +			if (debug_certs) {
   3585 +				dbg("trusturlCerts: " + trusturlCerts);
   3586 +				dbg("trustsrvCerts: " + trustsrvCerts);
   3587 +			}
   3588 +			if (trusturlCerts == null && cert_fail == null) {
   3589 +				cert_fail = "missing-certs";
   3590 +			}
   3591 +
   3592 +			try {
   3593 +				socket.startHandshake();
   3594 +
   3595 +				dbg("The TrustAll Server Cert-grab Connection (trivially) Verified OK.");
   3596 +
   3597 +				/* grab the cert: */
   3598 +				try {
   3599 +					SSLSession sess = socket.getSession();
   3600 +					trustallCerts = sess.getPeerCertificates();
   3601 +				} catch (Exception e) {
   3602 +					throw new Exception("Could not get " + 
   3603 +					    "Peer Certificate");	
   3604 +				}
   3605 +				if (debug_certs) {
   3606 +					dbg("trustallCerts: " + trustallCerts);
   3607 +				}
   3608 +
   3609 +				if (viewer.trustAllVncCerts) {
   3610 +					dbg("viewer.trustAllVncCerts-3.  skipping dialog, trusting everything.");
   3611 +				} else if (! browser_cert_match()) {
   3612 +					/*
   3613 +					 * close socket now, we will reopen after
   3614 +					 * dialog if user agrees to use the cert.
   3615 +					 */
   3616 +					try {
   3617 +						OutputStream os = socket.getOutputStream();
   3618 +						os.write(getoutstr.getBytes());
   3619 +						socket.close();
   3620 +					} catch (Exception e) {
   3621 +						dbg("socket is grumpy!!");
   3622 +					}
   3623 +					socket = null;
   3624 +
   3625 +					/* dialog with user to accept cert or not: */
   3626 +
   3627 +					TrustDialog td= new TrustDialog(host, port,
   3628 +					    trustallCerts);
   3629 +
   3630 +					if (cert_fail == null) {
   3631 +						;
   3632 +					} else if (cert_fail.equals("user-view")) {
   3633 +						reason = "Reason for this Dialog:\n\n"
   3634 +						       + "        You Asked to View the Certificate.";
   3635 +					} else if (cert_fail.equals("server-cert-mismatch")) {
   3636 +						/* this is now fatal error, see above. */
   3637 +						reason = "Reason for this Dialog:\n\n"
   3638 +						       + "        The VNC Server's Certificate does not match the Certificate\n"
   3639 +						       + "        specified in the supplied 'serverCert' Applet Parameter.";
   3640 +					} else if (cert_fail.equals("cert-mismatch")) {
   3641 +						reason = "Reason for this Dialog:\n\n"
   3642 +						       + "        The VNC Server's Certificate does not match the Website's\n"
   3643 +						       + "        HTTPS Certificate (that you previously accepted; either\n"
   3644 +						       + "        manually or automatically via Certificate Authority.)";
   3645 +					} else if (cert_fail.equals("missing-certs")) {
   3646 +						reason = "Reason for this Dialog:\n\n"
   3647 +						       + "        Not all Certificates could be obtained to check.";
   3648 +					}
   3649 +
   3650 +					if (! td.queryUser(reason)) {
   3651 +						String msg = "User decided against it.";
   3652 +						dbg(msg);
   3653 +						throw new IOException(msg);
   3654 +					}
   3655 +				}
   3656 +
   3657 +			} catch (Exception ehand2)  {
   3658 +				dbg("** Could not TrustAll Verify Server!");
   3659 +
   3660 +				throw new IOException(ehand2.getMessage());
   3661 +			}
   3662 +
   3663 +			/* reload again: */
   3664 +
   3665 +			if (socket != null) {
   3666 +				try {
   3667 +					socket.close();
   3668 +				} catch (Exception e) {
   3669 +					dbg("socket is grumpy!!!");
   3670 +				}
   3671 +				socket = null;
   3672 +			}
   3673 +
   3674 +			/*
   3675 +			 * Now connect a 3rd time, using the cert
   3676 +			 * retrieved during connection 2 (sadly, that
   3677 +			 * the user likely blindly agreed to...)
   3678 +			 */
   3679 +
   3680 +			factory = trustone_ctx.getSocketFactory();
   3681 +			if (proxy_failure) {
   3682 +				socket = proxy_socket(factory);
   3683 +			} else {
   3684 +				socket = (SSLSocket) factory.createSocket(host, port);
   3685 +			}
   3686 +
   3687 +			try {
   3688 +				socket.startHandshake();
   3689 +				dbg("TrustAll/TrustOne Server Connection Verified #3.");
   3690 +
   3691 +			} catch (Exception ehand3)  {
   3692 +				dbg("** Could not TrustAll/TrustOne Verify Server #3.");
   3693 +
   3694 +				throw new IOException(ehand3.getMessage());
   3695 +			}
   3696 +		}
   3697 +
   3698 +		/* we have socket (possibly null) at this point, so proceed: */
   3699 +
   3700 +		/* handle x11vnc GET=1, if applicable: */
   3701 +		if (socket != null && viewer.GET) {
   3702 +			String str = "GET ";
   3703 +			str += viewer.urlPrefix;
   3704 +			str += "/request.https.vnc.connection";
   3705 +			str += " HTTP/1.0\r\n";
   3706 +			str += "Pragma: No-Cache\r\n";
   3707 +			str += "\r\n";
   3708 +
   3709 +			System.out.println("sending: " + str);
   3710 +    			OutputStream os = socket.getOutputStream();
   3711 +			String type = "os";
   3712 +
   3713 +			if (type == "os") {
   3714 +				os.write(str.getBytes());
   3715 +				os.flush();
   3716 +				System.out.println("used OutputStream");
   3717 +			} else if (type == "bs") {
   3718 +				BufferedOutputStream bs = new BufferedOutputStream(os);
   3719 +				bs.write(str.getBytes());
   3720 +				bs.flush();
   3721 +				System.out.println("used BufferedOutputStream");
   3722 +			} else if (type == "ds") {
   3723 +				DataOutputStream ds = new DataOutputStream(os);
   3724 +				ds.write(str.getBytes());
   3725 +				ds.flush();
   3726 +				System.out.println("used DataOutputStream");
   3727 +			}
   3728 +			if (false) {
   3729 +				String rep = "";
   3730 +				DataInputStream is = new DataInputStream(
   3731 +				    new BufferedInputStream(socket.getInputStream(), 16384));
   3732 +				while (true) {
   3733 +					rep += readline(is);
   3734 +					if (rep.indexOf("\r\n\r\n") >= 0) {
   3735 +						break;
   3736 +					}
   3737 +				}
   3738 +				System.out.println("rep: " + rep);
   3739 +			}
   3740 +		}
   3741 +
   3742 +		dbg("SSL returning socket to caller.");
   3743 +		dbg("");
   3744 +
   3745 +		/* could be null, let caller handle that. */
   3746 +		return (Socket) socket;
   3747 +	}
   3748 +
   3749 +	boolean browser_cert_match() {
   3750 +		String msg = "Browser URL accept previously accepted cert";
   3751 +
   3752 +		if (user_wants_to_see_cert) {
   3753 +			return false;
   3754 +		}
   3755 +
   3756 +		if (viewer.serverCert != null || trustsrvCerts != null) {
   3757 +			if (cert_fail == null) {
   3758 +				cert_fail = "server-cert-mismatch";
   3759 +			}
   3760 +		}
   3761 +		if (trustallCerts != null && trusturlCerts != null) {
   3762 +		    if (trustallCerts.length == trusturlCerts.length) {
   3763 +			boolean ok = true;
   3764 +			/* check toath trustallCerts (socket) equals trusturlCerts (browser) */
   3765 +			for (int i = 0; i < trusturlCerts.length; i++)  {
   3766 +				if (! trustallCerts[i].equals(trusturlCerts[i])) {
   3767 +					dbg("BCM: cert mismatch at i=" + i);
   3768 +					dbg("BCM: cert mismatch  url" + trusturlCerts[i]);
   3769 +					dbg("BCM: cert mismatch  all" + trustallCerts[i]);
   3770 +					ok = false;
   3771 +				}
   3772 +			}
   3773 +			if (ok) {
   3774 +				System.out.println(msg);
   3775 +				if (cert_fail == null) {
   3776 +					cert_fail = "did-not-fail";
   3777 +				}
   3778 +				return true;
   3779 +			} else {
   3780 +				if (cert_fail == null) {
   3781 +					cert_fail = "cert-mismatch";
   3782 +				}
   3783 +				return false;
   3784 +			}
   3785 +		    }
   3786 +		}
   3787 +		if (cert_fail == null) {
   3788 +			cert_fail = "missing-certs";
   3789 +		}
   3790 +		return false;
   3791 +	}
   3792 +
   3793 +	private void dbg(String s) {
   3794 +		if (debug) {
   3795 +			System.out.println(s);
   3796 +		}
   3797 +	}
   3798 +
   3799 +	private int gint(String s) {
   3800 +		int n = -1;
   3801 +		try {
   3802 +			Integer I = new Integer(s);
   3803 +			n = I.intValue();
   3804 +		} catch (Exception ex) {
   3805 +			return -1;
   3806 +		}
   3807 +		return n;
   3808 +	}
   3809 +
   3810 +	/* this will do the proxy CONNECT negotiation and hook us up.  */
   3811 +
   3812 +	private void proxy_helper(String proxyHost, int proxyPort) {
   3813 +
   3814 +		boolean proxy_auth = false;
   3815 +		String proxy_auth_basic_realm = "";
   3816 +		String hp = host + ":" + port;
   3817 +		dbg("proxy_helper: " + proxyHost + ":" + proxyPort + " hp: " + hp);
   3818 +
   3819 +		/* we loop here a few times trying for the password case */
   3820 +		for (int k=0; k < 2; k++) {
   3821 +			dbg("proxy_in_use psocket: " + k);
   3822 +
   3823 +			if (proxySock != null) {
   3824 +				try {
   3825 +					proxySock.close();
   3826 +				} catch (Exception e) {
   3827 +					dbg("proxy socket is grumpy.");
   3828 +				}
   3829 +			}
   3830 +
   3831 +			proxySock = psocket(proxyHost, proxyPort);
   3832 +			if (proxySock == null) {
   3833 +				dbg("1-a sadly, returning a null socket");
   3834 +				return;
   3835 +			}
   3836 +
   3837 +			String req1 = "CONNECT " + hp + " HTTP/1.1\r\n"
   3838 +			    + "Host: " + hp + "\r\n";
   3839 +
   3840 +			dbg("requesting via proxy: " + req1);
   3841 +
   3842 +			if (proxy_auth) {
   3843 +				if (proxy_auth_string == null) {
   3844 +					ProxyPasswdDialog pp = new ProxyPasswdDialog(proxyHost, proxyPort, proxy_auth_basic_realm);
   3845 +					pp.queryUser();
   3846 +					proxy_auth_string = pp.getAuth();
   3847 +				}
   3848 +				//dbg("auth1: " + proxy_auth_string);
   3849 +
   3850 +				String auth2 = Base64Coder.encodeString(proxy_auth_string);
   3851 +				//dbg("auth2: " + auth2);
   3852 +
   3853 +				req1 += "Proxy-Authorization: Basic " + auth2 + "\r\n";
   3854 +				//dbg("req1: " + req1);
   3855 +
   3856 +				dbg("added Proxy-Authorization: Basic ... to request");
   3857 +			}
   3858 +			req1 += "\r\n";
   3859 +
   3860 +			try {
   3861 +				proxy_os.write(req1.getBytes());
   3862 +				String reply = readline(proxy_is);
   3863 +
   3864 +				dbg("proxy replied: " + reply.trim());
   3865 +
   3866 +				if (reply.indexOf("HTTP/1.") == 0 && reply.indexOf(" 407 ") > 0) {
   3867 +					proxy_auth = true;
   3868 +					proxySock.close();
   3869 +				} else if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) {
   3870 +					proxySock.close();
   3871 +					proxySock = psocket(proxyHost, proxyPort);
   3872 +					if (proxySock == null) {
   3873 +						dbg("2-a sadly, returning a null socket");
   3874 +						return;
   3875 +					}
   3876 +				}
   3877 +			} catch(Exception e) {
   3878 +				dbg("some proxy socket problem: " + e.getMessage());
   3879 +			}
   3880 +
   3881 +			/* read the rest of the HTTP headers */
   3882 +			while (true) {
   3883 +				String line = readline(proxy_is);
   3884 +				dbg("proxy line: " + line.trim());
   3885 +				if (proxy_auth) {
   3886 +					String uc = line.toLowerCase();
   3887 +					if (uc.indexOf("proxy-authenticate:") == 0) {
   3888 +						if (uc.indexOf(" basic ") >= 0) {
   3889 +							int idx = uc.indexOf(" realm");
   3890 +							if (idx >= 0) {
   3891 +								proxy_auth_basic_realm = uc.substring(idx+1);
   3892 +							}
   3893 +						}
   3894 +					}
   3895 +				}
   3896 +				if (line.equals("\r\n") || line.equals("\n")) {
   3897 +					break;
   3898 +				}
   3899 +			}
   3900 +			if (!proxy_auth || proxy_auth_basic_realm.equals("")) {
   3901 +				/* we only try once for the non-password case: */
   3902 +				break;
   3903 +			}
   3904 +		}
   3905 +	}
   3906 +
   3907 +	public SSLSocket proxy_socket(SSLSocketFactory factory) {
   3908 +		Properties props = null;
   3909 +		String proxyHost = null;
   3910 +		int proxyPort = 0;
   3911 +		String proxyHost_nossl = null;
   3912 +		int proxyPort_nossl = 0;
   3913 +		String str;
   3914 +
   3915 +		/* see if we can guess the proxy info from Properties: */
   3916 +		try {
   3917 +			props = System.getProperties();
   3918 +		} catch (Exception e) {
   3919 +			/* sandboxed applet might not be able to read it. */
   3920 +			dbg("props failed: " + e.getMessage());
   3921 +		}
   3922 +		if (viewer.proxyHost != null) {
   3923 +			dbg("Using supplied proxy " + viewer.proxyHost + " " + viewer.proxyPort + " applet parameters.");
   3924 +			proxyHost = viewer.proxyHost;
   3925 +			if (viewer.proxyPort != null) {
   3926 +				proxyPort = gint(viewer.proxyPort);
   3927 +			} else {
   3928 +				proxyPort = 8080;
   3929 +			}
   3930 +			
   3931 +		} else if (props != null) {
   3932 +			dbg("\n---------------\nAll props:");
   3933 +			props.list(System.out);
   3934 +			dbg("\n---------------\n\n");
   3935 +
   3936 +			/* scrape throught properties looking for proxy info: */
   3937 +
   3938 +			for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) {
   3939 +				String s = (String) e.nextElement();
   3940 +				String v = System.getProperty(s);
   3941 +				String s2 = s.toLowerCase();
   3942 +				String v2 = v.toLowerCase();
   3943 +
   3944 +				if (s2.indexOf("proxy.https.host") >= 0) {
   3945 +					proxyHost = v2;
   3946 +					continue;
   3947 +				}
   3948 +				if (s2.indexOf("proxy.https.port") >= 0) {
   3949 +					proxyPort = gint(v2);
   3950 +					continue;
   3951 +				}
   3952 +				if (s2.indexOf("proxy.http.host") >= 0) {
   3953 +					proxyHost_nossl = v2;
   3954 +					continue;
   3955 +				}
   3956 +				if (s2.indexOf("proxy.http.port") >= 0) {
   3957 +					proxyPort_nossl = gint(v2);
   3958 +					continue;
   3959 +				}
   3960 +			}
   3961 +
   3962 +			for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) {
   3963 +				String s = (String) e.nextElement();
   3964 +				String v = System.getProperty(s);
   3965 +				String s2 = s.toLowerCase();
   3966 +				String v2 = v.toLowerCase();
   3967 +
   3968 +				if (proxyHost != null && proxyPort > 0) {
   3969 +					break;
   3970 +				}
   3971 +
   3972 +				// look for something like: javaplugin.proxy.config.list = http=10.0.2.1:8082
   3973 +				if (s2.indexOf("proxy") < 0 && v2.indexOf("proxy") < 0) {
   3974 +					continue;
   3975 +				}
   3976 +				if (v2.indexOf("http") < 0) {
   3977 +					continue;
   3978 +				}
   3979 +
   3980 +				String[] pieces = v.split("[,;]");
   3981 +				for (int i = 0; i < pieces.length; i++) {
   3982 +					String p = pieces[i];
   3983 +					int j = p.indexOf("https");
   3984 +					if (j < 0) {
   3985 +						j = p.indexOf("http");
   3986 +						if (j < 0) {
   3987 +							continue;
   3988 +						}
   3989 +					}
   3990 +					j = p.indexOf("=", j);
   3991 +					if (j < 0) {
   3992 +						continue;
   3993 +					}
   3994 +					p = p.substring(j+1);
   3995 +					String [] hp = p.split(":");
   3996 +					if (hp.length != 2) {
   3997 +						continue;
   3998 +					}
   3999 +					if (hp[0].length() > 1 && hp[1].length() > 1) {
   4000 +
   4001 +						proxyPort = gint(hp[1]);
   4002 +						if (proxyPort < 0) {
   4003 +							continue;
   4004 +						}
   4005 +						proxyHost = new String(hp[0]);
   4006 +						break;
   4007 +					}
   4008 +				}
   4009 +			}
   4010 +		}
   4011 +		if (proxyHost != null) {
   4012 +			if (proxyHost_nossl != null && proxyPort_nossl > 0) {
   4013 +				dbg("Using http proxy info instead of https.");
   4014 +				proxyHost = proxyHost_nossl;
   4015 +				proxyPort = proxyPort_nossl;
   4016 +			}
   4017 +		}
   4018 +
   4019 +		if (proxy_in_use) {
   4020 +			if (proxy_dialog_host != null && proxy_dialog_port > 0) {
   4021 +				proxyHost = proxy_dialog_host;
   4022 +				proxyPort = proxy_dialog_port;
   4023 +			}
   4024 +			if (proxyHost != null) {
   4025 +				dbg("Lucky us! we figured out the Proxy parameters: " + proxyHost + " " + proxyPort);
   4026 +			} else {
   4027 +				/* ask user to help us: */
   4028 +				ProxyDialog pd = new ProxyDialog(proxyHost, proxyPort);
   4029 +				pd.queryUser();
   4030 +				proxyHost = pd.getHost(); 
   4031 +				proxyPort = pd.getPort();
   4032 +				proxy_dialog_host = new String(proxyHost);
   4033 +				proxy_dialog_port = proxyPort;
   4034 +				dbg("User said host: " + pd.getHost() + " port: " + pd.getPort());
   4035 +			}
   4036 +
   4037 +			proxy_helper(proxyHost, proxyPort);
   4038 +			if (proxySock == null) {
   4039 +				return null;
   4040 +			}
   4041 +		} else if (viewer.CONNECT != null) {
   4042 +			dbg("viewer.CONNECT psocket:");
   4043 +			proxySock = psocket(host, port);
   4044 +			if (proxySock == null) {
   4045 +				dbg("1-b sadly, returning a null socket");
   4046 +				return null;
   4047 +			}
   4048 +		}
   4049 +		
   4050 +		if (viewer.CONNECT != null) {
   4051 +			String hp = viewer.CONNECT;
   4052 +			String req2 = "CONNECT " + hp + " HTTP/1.1\r\n"
   4053 +			    + "Host: " + hp + "\r\n\r\n";
   4054 +
   4055 +			dbg("requesting2: " + req2);
   4056 +
   4057 +			try {
   4058 +				proxy_os.write(req2.getBytes());
   4059 +				String reply = readline(proxy_is);
   4060 +
   4061 +				dbg("proxy replied2: " + reply.trim());
   4062 +
   4063 +				if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) {
   4064 +					proxySock.close();
   4065 +					proxySock = psocket(proxyHost, proxyPort);
   4066 +					if (proxySock == null) {
   4067 +						dbg("2-b sadly, returning a null socket");
   4068 +						return null;
   4069 +					}
   4070 +				}
   4071 +			} catch(Exception e) {
   4072 +				dbg("proxy socket problem-2: " + e.getMessage());
   4073 +			}
   4074 +
   4075 +			while (true) {
   4076 +				String line = readline(proxy_is);
   4077 +				dbg("proxy line2: " + line.trim());
   4078 +				if (line.equals("\r\n") || line.equals("\n")) {
   4079 +					break;
   4080 +				}
   4081 +			}
   4082 +		}
   4083 +
   4084 +		Socket sslsock = null;
   4085 +		try {
   4086 +			sslsock = factory.createSocket(proxySock, host, port, true);
   4087 +		} catch(Exception e) {
   4088 +			dbg("sslsock prob: " + e.getMessage());
   4089 +			dbg("3 sadly, returning a null socket");
   4090 +		}
   4091 +
   4092 +		return (SSLSocket) sslsock;
   4093 +	}
   4094 +
   4095 +	Socket psocket(String h, int p) {
   4096 +		Socket psock = null;
   4097 +		try {
   4098 +			psock = new Socket(h, p);
   4099 +			proxy_is = new DataInputStream(new BufferedInputStream(
   4100 +			    psock.getInputStream(), 16384));
   4101 +			proxy_os = psock.getOutputStream();
   4102 +		} catch(Exception e) {
   4103 +			dbg("psocket prob: " + e.getMessage());
   4104 +			return null;
   4105 +		}
   4106 +
   4107 +		return psock;
   4108 +	}
   4109 +
   4110 +	String readline(DataInputStream i) {
   4111 +		byte[] ba = new byte[1];
   4112 +		String s = new String("");
   4113 +		ba[0] = 0;
   4114 +		try {
   4115 +			while (ba[0] != 0xa) {
   4116 +				ba[0] = (byte) i.readUnsignedByte();
   4117 +				s += new String(ba);
   4118 +			}
   4119 +		} catch (Exception e) {
   4120 +			;
   4121 +		}
   4122 +		return s;
   4123 +	}
   4124 +}
   4125 +
   4126 +class TrustDialog implements ActionListener {
   4127 +	String msg, host, text;
   4128 +	int port;
   4129 +	java.security.cert.Certificate[] trustallCerts = null;
   4130 +	boolean viewing_cert = false;
   4131 +	boolean trust_this_session = false;
   4132 +
   4133 +	/*
   4134 +	 * this is the gui to show the user the cert and info and ask
   4135 +	 * them if they want to continue using this cert.
   4136 +	 */
   4137 +
   4138 +	Button ok, cancel, viewcert;
   4139 +	TextArea textarea;
   4140 +	Checkbox accept, deny;
   4141 +	Dialog dialog;
   4142 +
   4143 +	String s1 = "Accept this certificate temporarily for this session";
   4144 +	String s2 = "Do not accept this certificate and do not connect to"
   4145 +	    + " this VNC server";
   4146 +	String ln = "\n---------------------------------------------------\n\n";
   4147 +		
   4148 +	TrustDialog (String h, int p, java.security.cert.Certificate[] s) {
   4149 +		host = h;
   4150 +		port = p;
   4151 +		trustallCerts = s;
   4152 +
   4153 +		msg = "VNC Server " + host + ":" + port + " Not Verified";
   4154 +	}
   4155 +
   4156 +	public boolean queryUser(String reason) {
   4157 +
   4158 +		/* create and display the dialog for unverified cert. */
   4159 +
   4160 +		Frame frame = new Frame(msg);
   4161 +
   4162 +		dialog = new Dialog(frame, true);
   4163 +
   4164 +		String infostr = "";
   4165 +		if (trustallCerts.length == 1) {
   4166 +			CertInfo ci = new CertInfo(trustallCerts[0]);
   4167 +			infostr = ci.get_certinfo("all");
   4168 +		}
   4169 +		if (reason != null) {
   4170 +			reason += "\n\n";
   4171 +		}
   4172 +
   4173 +		text = "\n" 
   4174 ++ "Unable to verify the identity of\n"
   4175 ++ "\n"
   4176 ++ "        " + host + ":" + port + "\n" 
   4177 ++ "\n"
   4178 ++ infostr
   4179 ++ "\n"
   4180 ++ "as a trusted VNC server.\n"
   4181 ++ "\n"
   4182 ++ reason
   4183 ++ "In General not being able to verify the VNC Server and/or your seeing this Dialog\n"
   4184 ++ "is due to one of the following:\n"
   4185 ++ "\n"
   4186 ++ " - Your requesting to View the Certificate before accepting.\n"
   4187 ++ "\n"
   4188 ++ " - The VNC server is using a Self-Signed Certificate or a Certificate\n"
   4189 ++ "   Authority not recognized by your Web Browser or Java Plugin runtime.\n"
   4190 ++ "\n"
   4191 ++ " - The use of an Apache SSL portal scheme employing CONNECT proxying AND\n"
   4192 ++ "   the Apache Web server has a certificate *different* from the VNC server's.\n"
   4193 ++ "\n"
   4194 ++ " - No previously accepted Certificate (via Web Broswer/Java Plugin) could be\n"
   4195 ++ "   obtained by this applet to compare the VNC Server Certificate against.\n"
   4196 ++ "\n"
   4197 ++ " - The VNC Server's Certificate does not match the one specified in the\n"
   4198 ++ "   supplied 'serverCert' Java Applet Parameter.\n"
   4199 ++ "\n"
   4200 ++ " - A Man-In-The-Middle attack impersonating as the VNC server that you wish\n"
   4201 ++ "   to connect to.  (Wouldn't that be exciting!!)\n"
   4202 ++ "\n"
   4203 ++ "By safely copying the VNC server's Certificate (or using a common Certificate\n"
   4204 ++ "Authority certificate) you can configure your Web Browser and Java Plugin to\n"
   4205 ++ "automatically authenticate this VNC Server.\n"
   4206 ++ "\n"
   4207 ++ "If you do so, then you will only have to click \"Yes\" when this VNC Viewer\n"
   4208 ++ "applet asks you whether to trust your Browser/Java Plugin's acceptance of the\n"
   4209 ++ "certificate (except for the Apache portal case above where they don't match.)\n"
   4210 ++ "\n"
   4211 ++ "You can also set the applet parameter 'trustUrlVncCert=yes' to automatically\n"
   4212 ++ "accept certificates already accepted/trusted by your Web Browser/Java Plugin,\n"
   4213 ++ "and thereby see no dialog from this VNC Viewer applet.\n"
   4214 +;
   4215 +
   4216 +		/* the accept / do-not-accept radio buttons: */
   4217 +		CheckboxGroup checkbox = new CheckboxGroup();
   4218 +		accept = new Checkbox(s1, true, checkbox);
   4219 +		deny   = new Checkbox(s2, false, checkbox);
   4220 +
   4221 +		/* put the checkboxes in a panel: */
   4222 +		Panel check = new Panel();
   4223 +		check.setLayout(new GridLayout(2, 1));
   4224 +
   4225 +		check.add(accept);
   4226 +		check.add(deny);
   4227 +
   4228 +		/* make the 3 buttons: */
   4229 +		ok = new Button("OK");
   4230 +		cancel = new Button("Cancel");
   4231 +		viewcert = new Button("View Certificate");
   4232 +
   4233 +		ok.addActionListener(this);
   4234 +		cancel.addActionListener(this);
   4235 +		viewcert.addActionListener(this);
   4236 +
   4237 +		/* put the buttons in their own panel: */
   4238 +		Panel buttonrow = new Panel();
   4239 +		buttonrow.setLayout(new FlowLayout(FlowLayout.LEFT));
   4240 +		buttonrow.add(viewcert);
   4241 +		buttonrow.add(ok);
   4242 +		buttonrow.add(cancel);
   4243 +
   4244 +		/* label at the top: */
   4245 +		Label label = new Label(msg, Label.CENTER);
   4246 +		label.setFont(new Font("Helvetica", Font.BOLD, 16));
   4247 +
   4248 +		/* textarea in the middle */
   4249 +		textarea = new TextArea(text, 38, 64,
   4250 +		    TextArea.SCROLLBARS_VERTICAL_ONLY);
   4251 +		textarea.setEditable(false);
   4252 +
   4253 +		/* put the two panels in their own panel at bottom: */
   4254 +		Panel bot = new Panel();
   4255 +		bot.setLayout(new GridLayout(2, 1));
   4256 +		bot.add(check);
   4257 +		bot.add(buttonrow);
   4258 +
   4259 +		/* now arrange things inside the dialog: */
   4260 +		dialog.setLayout(new BorderLayout());
   4261 +
   4262 +		dialog.add("North", label);
   4263 +		dialog.add("South", bot);
   4264 +		dialog.add("Center", textarea);
   4265 +
   4266 +		dialog.pack();
   4267 +		dialog.resize(dialog.preferredSize());
   4268 +
   4269 +		dialog.show();	/* block here til OK or Cancel pressed. */
   4270 +
   4271 +		return trust_this_session;
   4272 +	}
   4273 +
   4274 +	public synchronized void actionPerformed(ActionEvent evt) {
   4275 +
   4276 +		if (evt.getSource() == viewcert) {
   4277 +			/* View Certificate button clicked */
   4278 +			if (viewing_cert) {
   4279 +				/* show the original info text: */
   4280 +				textarea.setText(text);
   4281 +				viewcert.setLabel("View Certificate");
   4282 +				viewing_cert = false;
   4283 +			} else {
   4284 +				int i;
   4285 +				/* show all (likely just one) certs: */
   4286 +				textarea.setText("");
   4287 +				for (i=0; i < trustallCerts.length; i++) {
   4288 +					int j = i + 1;
   4289 +					textarea.append("Certificate[" +
   4290 +					    j + "]\n\n");
   4291 +					textarea.append(
   4292 +					    trustallCerts[i].toString());
   4293 +					textarea.append(ln);
   4294 +				}
   4295 +				viewcert.setLabel("View Info");
   4296 +				viewing_cert = true;
   4297 +
   4298 +				textarea.setCaretPosition(0);
   4299 +			}
   4300 +
   4301 +		} else if (evt.getSource() == ok) {
   4302 +			/* OK button clicked */
   4303 +			if (accept.getState()) {
   4304 +				trust_this_session = true;
   4305 +			} else {
   4306 +				trust_this_session = false;
   4307 +			}
   4308 +			//dialog.dispose();
   4309 +			dialog.hide();
   4310 +
   4311 +		} else if (evt.getSource() == cancel) {
   4312 +			/* Cancel button clicked */
   4313 +			trust_this_session = false;
   4314 +
   4315 +			//dialog.dispose();
   4316 +			dialog.hide();
   4317 +		}
   4318 +	}
   4319 +
   4320 +	String get_certinfo() {
   4321 +		String all = "";
   4322 +		String fields[] = {"CN", "OU", "O", "L", "C"};
   4323 +		int i;
   4324 +		if (trustallCerts.length < 1) {
   4325 +			all = "";
   4326 +			return all;
   4327 +		}
   4328 +		String cert = trustallCerts[0].toString();
   4329 +
   4330 +		/*
   4331 +		 * For now we simply scrape the cert string, there must
   4332 +		 * be an API for this... perhaps optionValue?
   4333 +		 */
   4334 +
   4335 +		for (i=0; i < fields.length; i++) {
   4336 +			int f, t, t1, t2;
   4337 +			String sub, mat = fields[i] + "=";
   4338 +			
   4339 +			f = cert.indexOf(mat, 0);
   4340 +			if (f > 0) {
   4341 +				t1 = cert.indexOf(", ", f);
   4342 +				t2 = cert.indexOf("\n", f);
   4343 +				if (t1 < 0 && t2 < 0) {
   4344 +					continue;
   4345 +				} else if (t1 < 0) {
   4346 +					t = t2;
   4347 +				} else if (t2 < 0) {
   4348 +					t = t1;
   4349 +				} else if (t1 < t2) {
   4350 +					t = t1;
   4351 +				} else {
   4352 +					t = t2;
   4353 +				}
   4354 +				if (t > f) {
   4355 +					sub = cert.substring(f, t);
   4356 +					all = all + "        " + sub + "\n";
   4357 +				}
   4358 +			}
   4359 +		}
   4360 +		return all;
   4361 +	}
   4362 +}
   4363 +
   4364 +class ProxyDialog implements ActionListener {
   4365 +	String guessedHost = null;
   4366 +	String guessedPort = null;
   4367 +	/*
   4368 +	 * this is the gui to show the user the cert and info and ask
   4369 +	 * them if they want to continue using this cert.
   4370 +	 */
   4371 +
   4372 +	Button ok;
   4373 +	Dialog dialog;
   4374 +	TextField entry;
   4375 +	String reply = "";
   4376 +
   4377 +	ProxyDialog (String h, int p) {
   4378 +		guessedHost = h;
   4379 +		try {
   4380 +			guessedPort = Integer.toString(p);
   4381 +		} catch (Exception e) {
   4382 +			guessedPort = "8080";
   4383 +		}
   4384 +	}
   4385 +
   4386 +	public void queryUser() {
   4387 +
   4388 +		/* create and display the dialog for unverified cert. */
   4389 +
   4390 +		Frame frame = new Frame("Need Proxy host:port");
   4391 +
   4392 +		dialog = new Dialog(frame, true);
   4393 +
   4394 +
   4395 +		Label label = new Label("Please Enter your https Proxy info as host:port", Label.CENTER);
   4396 +		//label.setFont(new Font("Helvetica", Font.BOLD, 16));
   4397 +		entry = new TextField(30);
   4398 +		ok = new Button("OK");
   4399 +		ok.addActionListener(this);
   4400 +
   4401 +		String guess = "";
   4402 +		if (guessedHost != null) {
   4403 +			guess = guessedHost + ":" + guessedPort;
   4404 +		}
   4405 +		entry.setText(guess);
   4406 +
   4407 +		dialog.setLayout(new BorderLayout());
   4408 +		dialog.add("North", label);
   4409 +		dialog.add("Center", entry);
   4410 +		dialog.add("South", ok);
   4411 +		dialog.pack();
   4412 +		dialog.resize(dialog.preferredSize());
   4413 +
   4414 +		dialog.show();	/* block here til OK or Cancel pressed. */
   4415 +		return;
   4416 +	}
   4417 +
   4418 +	public String getHost() {
   4419 +		int i = reply.indexOf(":");
   4420 +		if (i < 0) {
   4421 +			return "unknown";
   4422 +		}
   4423 +		String h = reply.substring(0, i);
   4424 +		return h;
   4425 +	}
   4426 +
   4427 +	public int getPort() {
   4428 +		int i = reply.indexOf(":");
   4429 +		int p = 8080;
   4430 +		if (i < 0) {
   4431 +			return p;
   4432 +		}
   4433 +		i++;
   4434 +		String ps = reply.substring(i);
   4435 +		try {
   4436 +			Integer I = new Integer(ps);
   4437 +			p = I.intValue();
   4438 +		} catch (Exception e) {
   4439 +			;
   4440 +		}
   4441 +		return p;
   4442 +	}
   4443 +
   4444 +	public synchronized void actionPerformed(ActionEvent evt) {
   4445 +		System.out.println(evt.getActionCommand());
   4446 +		if (evt.getSource() == ok) {
   4447 +			reply = entry.getText();
   4448 +			//dialog.dispose();
   4449 +			dialog.hide();
   4450 +		}
   4451 +	}
   4452 +}
   4453 +
   4454 +class ProxyPasswdDialog implements ActionListener {
   4455 +	String guessedHost = null;
   4456 +	String guessedPort = null;
   4457 +	String guessedUser = null;
   4458 +	String guessedPasswd = null;
   4459 +	String realm = null;
   4460 +	/*
   4461 +	 * this is the gui to show the user the cert and info and ask
   4462 +	 * them if they want to continue using this cert.
   4463 +	 */
   4464 +
   4465 +	Button ok;
   4466 +	Dialog dialog;
   4467 +	TextField entry1;
   4468 +	TextField entry2;
   4469 +	String reply1 = "";
   4470 +	String reply2 = "";
   4471 +
   4472 +	ProxyPasswdDialog (String h, int p, String realm) {
   4473 +		guessedHost = h;
   4474 +		try {
   4475 +			guessedPort = Integer.toString(p);
   4476 +		} catch (Exception e) {
   4477 +			guessedPort = "8080";
   4478 +		}
   4479 +		this.realm = realm;
   4480 +	}
   4481 +
   4482 +	public void queryUser() {
   4483 +
   4484 +		/* create and display the dialog for unverified cert. */
   4485 +
   4486 +		Frame frame = new Frame("Proxy Requires Username and Password");
   4487 +
   4488 +		dialog = new Dialog(frame, true);
   4489 +
   4490 +		//Label label = new Label("Please Enter your Web Proxy Username in the top Entry and Password in the bottom Entry", Label.CENTER);
   4491 +		TextArea label = new TextArea("Please Enter your Web Proxy\nUsername in the Top Entry and\nPassword in the Bottom Entry,\nand then press OK.", 4, 20, TextArea.SCROLLBARS_NONE);
   4492 +		entry1 = new TextField(30);
   4493 +		entry2 = new TextField(30);
   4494 +		entry2.setEchoChar('*');
   4495 +		ok = new Button("OK");
   4496 +		ok.addActionListener(this);
   4497 +
   4498 +		dialog.setLayout(new BorderLayout());
   4499 +		dialog.add("North", label);
   4500 +		dialog.add("Center", entry1);
   4501 +		dialog.add("South",  entry2);
   4502 +		dialog.add("East", ok);
   4503 +		dialog.pack();
   4504 +		dialog.resize(dialog.preferredSize());
   4505 +
   4506 +		dialog.show();	/* block here til OK or Cancel pressed. */
   4507 +		return;
   4508 +	}
   4509 +
   4510 +	public String getAuth() {
   4511 +		return reply1 + ":" + reply2;
   4512 +	}
   4513 +
   4514 +	public synchronized void actionPerformed(ActionEvent evt) {
   4515 +		System.out.println(evt.getActionCommand());
   4516 +		if (evt.getSource() == ok) {
   4517 +			reply1 = entry1.getText();
   4518 +			reply2 = entry2.getText();
   4519 +			//dialog.dispose();
   4520 +			dialog.hide();
   4521 +		}
   4522 +	}
   4523 +}
   4524 +
   4525 +class ClientCertDialog implements ActionListener {
   4526 +
   4527 +	Button ok;
   4528 +	Dialog dialog;
   4529 +	TextField entry;
   4530 +	String reply = "";
   4531 +
   4532 +	ClientCertDialog() {
   4533 +		;
   4534 +	}
   4535 +
   4536 +	public String queryUser() {
   4537 +
   4538 +		/* create and display the dialog for unverified cert. */
   4539 +
   4540 +		Frame frame = new Frame("Enter SSL Client Cert+Key String");
   4541 +
   4542 +		dialog = new Dialog(frame, true);
   4543 +
   4544 +
   4545 +		Label label = new Label("Please Enter the SSL Client Cert+Key String 308204c0...,...522d2d0a", Label.CENTER);
   4546 +		entry = new TextField(30);
   4547 +		ok = new Button("OK");
   4548 +		ok.addActionListener(this);
   4549 +
   4550 +		dialog.setLayout(new BorderLayout());
   4551 +		dialog.add("North", label);
   4552 +		dialog.add("Center", entry);
   4553 +		dialog.add("South", ok);
   4554 +		dialog.pack();
   4555 +		dialog.resize(dialog.preferredSize());
   4556 +
   4557 +		dialog.show();	/* block here til OK or Cancel pressed. */
   4558 +		return reply;
   4559 +	}
   4560 +
   4561 +	public synchronized void actionPerformed(ActionEvent evt) {
   4562 +		System.out.println(evt.getActionCommand());
   4563 +		if (evt.getSource() == ok) {
   4564 +			reply = entry.getText();
   4565 +			//dialog.dispose();
   4566 +			dialog.hide();
   4567 +		}
   4568 +	}
   4569 +}
   4570 +
   4571 +class BrowserCertsDialog implements ActionListener {
   4572 +	Button yes, no;
   4573 +	Dialog dialog;
   4574 +	String vncServer;
   4575 +	String hostport;
   4576 +	public boolean showCertDialog = true;
   4577 +
   4578 +	BrowserCertsDialog(String serv, String hp) {
   4579 +		vncServer = serv;
   4580 +		hostport = hp;
   4581 +	}
   4582 +
   4583 +	public void queryUser() {
   4584 +
   4585 +		/* create and display the dialog for unverified cert. */
   4586 +
   4587 +		Frame frame = new Frame("Use Browser/JVM Certs?");
   4588 +
   4589 +		dialog = new Dialog(frame, true);
   4590 +
   4591 +		String m = "";
   4592 +m += "\n";
   4593 +m += "This VNC Viewer applet does not have its own keystore to track\n";
   4594 +m += "SSL certificates, and so cannot authenticate the certificate\n";
   4595 +m += "of the VNC Server:\n";
   4596 +m += "\n";
   4597 +m += "        " + hostport + "\n\n        " + vncServer + "\n";
   4598 +m += "\n";
   4599 +m += "on its own.\n";
   4600 +m += "\n";
   4601 +m += "However, it has noticed that your Web Browser and/or Java VM Plugin\n";
   4602 +m += "has previously accepted the same certificate.  You may have set\n";
   4603 +m += "this up permanently or just for this session, or the server\n";
   4604 +m += "certificate was signed by a CA cert that your Web Browser or\n";
   4605 +m += "Java VM Plugin has.\n";
   4606 +m += "\n";
   4607 +m += "If the VNC Server connection times out while you are reading this\n";
   4608 +m += "dialog, then restart the connection and try again.\n";
   4609 +m += "\n";
   4610 +m += "Should this VNC Viewer applet now connect to the above VNC server?\n";
   4611 +m += "\n";
   4612 +
   4613 +		TextArea textarea = new TextArea(m, 22, 64,
   4614 +		    TextArea.SCROLLBARS_VERTICAL_ONLY);
   4615 +		textarea.setEditable(false);
   4616 +		yes = new Button("Yes");
   4617 +		yes.addActionListener(this);
   4618 +		no = new Button("No, Let Me See the Certificate.");
   4619 +		no.addActionListener(this);
   4620 +
   4621 +		dialog.setLayout(new BorderLayout());
   4622 +		dialog.add("North", textarea);
   4623 +		dialog.add("Center", yes);
   4624 +		dialog.add("South", no);
   4625 +		dialog.pack();
   4626 +		dialog.resize(dialog.preferredSize());
   4627 +
   4628 +		dialog.show();	/* block here til Yes or No pressed. */
   4629 +		System.out.println("done show()");
   4630 +		return;
   4631 +	}
   4632 +
   4633 +	public synchronized void actionPerformed(ActionEvent evt) {
   4634 +		System.out.println(evt.getActionCommand());
   4635 +		if (evt.getSource() == yes) {
   4636 +			showCertDialog = false;
   4637 +			//dialog.dispose();
   4638 +			dialog.hide();
   4639 +		} else if (evt.getSource() == no) {
   4640 +			showCertDialog = true;
   4641 +			//dialog.dispose();
   4642 +			dialog.hide();
   4643 +		}
   4644 +		System.out.println("done actionPerformed()");
   4645 +	}
   4646 +}
   4647 +
   4648 +class CertInfo {
   4649 +	String fields[] = {"CN", "OU", "O", "L", "C"};
   4650 +	java.security.cert.Certificate cert;
   4651 +	String certString = "";
   4652 +
   4653 +	CertInfo(java.security.cert.Certificate c) {
   4654 +		cert = c;
   4655 +		certString = cert.toString();
   4656 +	}
   4657 +	
   4658 +	String get_certinfo(String which) {
   4659 +		int i;
   4660 +		String cs = new String(certString);
   4661 +		String all = "";
   4662 +
   4663 +		/*
   4664 +		 * For now we simply scrape the cert string, there must
   4665 +		 * be an API for this... perhaps optionValue?
   4666 +		 */
   4667 +		for (i=0; i < fields.length; i++) {
   4668 +			int f, t, t1, t2;
   4669 +			String sub, mat = fields[i] + "=";
   4670 +			
   4671 +			f = cs.indexOf(mat, 0);
   4672 +			if (f > 0) {
   4673 +				t1 = cs.indexOf(", ", f);
   4674 +				t2 = cs.indexOf("\n", f);
   4675 +				if (t1 < 0 && t2 < 0) {
   4676 +					continue;
   4677 +				} else if (t1 < 0) {
   4678 +					t = t2;
   4679 +				} else if (t2 < 0) {
   4680 +					t = t1;
   4681 +				} else if (t1 < t2) {
   4682 +					t = t1;
   4683 +				} else {
   4684 +					t = t2;
   4685 +				}
   4686 +				if (t > f) {
   4687 +					sub = cs.substring(f, t);
   4688 +					all = all + "        " + sub + "\n";
   4689 +					if (which.equals(fields[i])) {
   4690 +						return sub;
   4691 +					}
   4692 +				}
   4693 +			}
   4694 +		}
   4695 +		if (which.equals("all")) {
   4696 +			return all;
   4697 +		} else {
   4698 +			return "";
   4699 +		}
   4700 +	}
   4701 +}
   4702 +
   4703 +class Base64Coder {
   4704 +
   4705 +	// Mapping table from 6-bit nibbles to Base64 characters.
   4706 +	private static char[]    map1 = new char[64];
   4707 +	   static {
   4708 +	      int i=0;
   4709 +	      for (char c='A'; c<='Z'; c++) map1[i++] = c;
   4710 +	      for (char c='a'; c<='z'; c++) map1[i++] = c;
   4711 +	      for (char c='0'; c<='9'; c++) map1[i++] = c;
   4712 +	      map1[i++] = '+'; map1[i++] = '/'; }
   4713 +
   4714 +	// Mapping table from Base64 characters to 6-bit nibbles.
   4715 +	private static byte[]    map2 = new byte[128];
   4716 +	   static {
   4717 +	      for (int i=0; i<map2.length; i++) map2[i] = -1;
   4718 +	      for (int i=0; i<64; i++) map2[map1[i]] = (byte)i; }
   4719 +
   4720 +	/**
   4721 +	* Encodes a string into Base64 format.
   4722 +	* No blanks or line breaks are inserted.
   4723 +	* @param s  a String to be encoded.
   4724 +	* @return   A String with the Base64 encoded data.
   4725 +	*/
   4726 +	public static String encodeString (String s) {
   4727 +	   return new String(encode(s.getBytes())); }
   4728 +
   4729 +	/**
   4730 +	* Encodes a byte array into Base64 format.
   4731 +	* No blanks or line breaks are inserted.
   4732 +	* @param in  an array containing the data bytes to be encoded.
   4733 +	* @return    A character array with the Base64 encoded data.
   4734 +	*/
   4735 +	public static char[] encode (byte[] in) {
   4736 +	   return encode(in,in.length); }
   4737 +
   4738 +	/**
   4739 +	* Encodes a byte array into Base64 format.
   4740 +	* No blanks or line breaks are inserted.
   4741 +	* @param in   an array containing the data bytes to be encoded.
   4742 +	* @param iLen number of bytes to process in <code>in</code>.
   4743 +	* @return     A character array with the Base64 encoded data.
   4744 +	*/
   4745 +	public static char[] encode (byte[] in, int iLen) {
   4746 +	   int oDataLen = (iLen*4+2)/3;       // output length without padding
   4747 +	   int oLen = ((iLen+2)/3)*4;         // output length including padding
   4748 +	   char[] out = new char[oLen];
   4749 +	   int ip = 0;
   4750 +	   int op = 0;
   4751 +	   while (ip < iLen) {
   4752 +	      int i0 = in[ip++] & 0xff;
   4753 +	      int i1 = ip < iLen ? in[ip++] & 0xff : 0;
   4754 +	      int i2 = ip < iLen ? in[ip++] & 0xff : 0;
   4755 +	      int o0 = i0 >>> 2;
   4756 +	      int o1 = ((i0 &   3) << 4) | (i1 >>> 4);
   4757 +	      int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
   4758 +	      int o3 = i2 & 0x3F;
   4759 +	      out[op++] = map1[o0];
   4760 +	      out[op++] = map1[o1];
   4761 +	      out[op] = op < oDataLen ? map1[o2] : '='; op++;
   4762 +	      out[op] = op < oDataLen ? map1[o3] : '='; op++; }
   4763 +	   return out; }
   4764 +
   4765 +	/**
   4766 +	* Decodes a string from Base64 format.
   4767 +	* @param s  a Base64 String to be decoded.
   4768 +	* @return   A String containing the decoded data.
   4769 +	* @throws   IllegalArgumentException if the input is not valid Base64 encoded data.
   4770 +	*/
   4771 +	public static String decodeString (String s) {
   4772 +	   return new String(decode(s)); }
   4773 +
   4774 +	/**
   4775 +	* Decodes a byte array from Base64 format.
   4776 +	* @param s  a Base64 String to be decoded.
   4777 +	* @return   An array containing the decoded data bytes.
   4778 +	* @throws   IllegalArgumentException if the input is not valid Base64 encoded data.
   4779 +	*/
   4780 +	public static byte[] decode (String s) {
   4781 +	   return decode(s.toCharArray()); }
   4782 +
   4783 +	/**
   4784 +	* Decodes a byte array from Base64 format.
   4785 +	* No blanks or line breaks are allowed within the Base64 encoded data.
   4786 +	* @param in  a character array containing the Base64 encoded data.
   4787 +	* @return    An array containing the decoded data bytes.
   4788 +	* @throws    IllegalArgumentException if the input is not valid Base64 encoded data.
   4789 +	*/
   4790 +	public static byte[] decode (char[] in) {
   4791 +	   int iLen = in.length;
   4792 +	   if (iLen%4 != 0) throw new IllegalArgumentException ("Length of Base64 encoded input string is not a multiple of 4.");
   4793 +	   while (iLen > 0 && in[iLen-1] == '=') iLen--;
   4794 +	   int oLen = (iLen*3) / 4;
   4795 +	   byte[] out = new byte[oLen];
   4796 +	   int ip = 0;
   4797 +	   int op = 0;
   4798 +	   while (ip < iLen) {
   4799 +	      int i0 = in[ip++];
   4800 +	      int i1 = in[ip++];
   4801 +	      int i2 = ip < iLen ? in[ip++] : 'A';
   4802 +	      int i3 = ip < iLen ? in[ip++] : 'A';
   4803 +	      if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
   4804 +		 throw new IllegalArgumentException ("Illegal character in Base64 encoded data.");
   4805 +	      int b0 = map2[i0];
   4806 +	      int b1 = map2[i1];
   4807 +	      int b2 = map2[i2];
   4808 +	      int b3 = map2[i3];
   4809 +	      if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
   4810 +		 throw new IllegalArgumentException ("Illegal character in Base64 encoded data.");
   4811 +	      int o0 = ( b0       <<2) | (b1>>>4);
   4812 +	      int o1 = ((b1 & 0xf)<<4) | (b2>>>2);
   4813 +	      int o2 = ((b2 &   3)<<6) |  b3;
   4814 +	      out[op++] = (byte)o0;
   4815 +	      if (op<oLen) out[op++] = (byte)o1;
   4816 +	      if (op<oLen) out[op++] = (byte)o2; }
   4817 +	   return out; }
   4818 +
   4819 +	// Dummy constructor.
   4820 +	private Base64Coder() {}
   4821 +
   4822 +}
   4823 diff -Naur JavaViewer.orig/VncCanvas.java JavaViewer/VncCanvas.java
   4824 --- JavaViewer.orig/VncCanvas.java	2005-11-21 18:50:18.000000000 -0500
   4825 +++ JavaViewer/VncCanvas.java	2010-11-30 22:57:50.000000000 -0500
   4826 @@ -27,6 +27,13 @@
   4827  import java.lang.*;
   4828  import java.util.zip.*;
   4829  
   4830 +// begin runge/x11vnc
   4831 +import java.util.Collections;
   4832 +// end runge/x11vnc
   4833 +
   4834 +// begin runge/x11vnc
   4835 +// all the MouseWheel stuff below.
   4836 +// end runge/x11vnc
   4837  
   4838  //
   4839  // VncCanvas is a subclass of Canvas which draws a VNC desktop on it.
   4840 @@ -34,7 +41,7 @@
   4841  
   4842  class VncCanvas
   4843  	extends Canvas
   4844 -	implements KeyListener, MouseListener, MouseMotionListener {
   4845 +	implements KeyListener, MouseListener, MouseMotionListener, MouseWheelListener {
   4846  
   4847  	VncViewer viewer;
   4848  	RfbProto rfb;
   4849 @@ -85,6 +92,22 @@
   4850  		
   4851  		cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
   4852  
   4853 +// begin runge/x11vnc
   4854 +// kludge to not show any Java cursor in the canvas since we are
   4855 +// showing the soft cursor (should be a user setting...)
   4856 +Cursor dot = Toolkit.getDefaultToolkit().createCustomCursor(
   4857 +    Toolkit.getDefaultToolkit().createImage(new byte[4]), new Point(0,0),
   4858 +    "dot");
   4859 +this.setCursor(dot);
   4860 +
   4861 +// while we are at it... get rid of the keyboard traversals that
   4862 +// make it so we can't type a Tab character:
   4863 +this.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
   4864 +    Collections.EMPTY_SET);
   4865 +this.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
   4866 +    Collections.EMPTY_SET);
   4867 +// end runge/x11vnc
   4868 +
   4869  		colors = new Color[256];
   4870  		// sf@2005 - Now Default
   4871  		for (int i = 0; i < 256; i++)
   4872 @@ -186,6 +209,7 @@
   4873  			inputEnabled = true;
   4874  			addMouseListener(this);
   4875  			addMouseMotionListener(this);
   4876 +			addMouseWheelListener(this);
   4877  			if (viewer.showControls) {
   4878  				viewer.buttonPanel.enableRemoteAccessControls(true);
   4879  			}
   4880 @@ -193,6 +217,7 @@
   4881  			inputEnabled = false;
   4882  			removeMouseListener(this);
   4883  			removeMouseMotionListener(this);
   4884 +			removeMouseWheelListener(this);
   4885  			if (viewer.showControls) {
   4886  				viewer.buttonPanel.enableRemoteAccessControls(false);
   4887  			}
   4888 @@ -202,6 +227,9 @@
   4889  	
   4890  	public void setPixelFormat() throws IOException {
   4891  		// sf@2005 - Adding more color modes
   4892 +		if (viewer.graftFtp) {
   4893 +			return;
   4894 +		}
   4895  		if (viewer.options.eightBitColors > 0)
   4896  		{
   4897  			viewer.options.oldEightBitColors = viewer.options.eightBitColors;
   4898 @@ -237,6 +265,9 @@
   4899  		}
   4900  		else 
   4901  		{
   4902 +// begin runge/x11vnc
   4903 +			viewer.options.oldEightBitColors = viewer.options.eightBitColors;
   4904 +// end runge/x11vnc
   4905  			rfb.writeSetPixelFormat(
   4906  				32,
   4907  				24,
   4908 @@ -376,12 +407,14 @@
   4909  		// Start/stop session recording if necessary.
   4910  		viewer.checkRecordingStatus();
   4911  
   4912 -		rfb.writeFramebufferUpdateRequest(
   4913 -			0,
   4914 -			0,
   4915 -			rfb.framebufferWidth,
   4916 -			rfb.framebufferHeight,
   4917 -			false);
   4918 +		if (!viewer.graftFtp) {
   4919 +			rfb.writeFramebufferUpdateRequest(
   4920 +				0,
   4921 +				0,
   4922 +				rfb.framebufferWidth,
   4923 +				rfb.framebufferHeight,
   4924 +				false);
   4925 +		}
   4926  
   4927  		//
   4928  		// main dispatch loop
   4929 @@ -390,6 +423,9 @@
   4930  		while (true) {
   4931  			// Read message type from the server.
   4932  			int msgType = rfb.readServerMessageType();
   4933 +			if (viewer.ftpOnly && msgType != RfbProto.rfbFileTransfer) {
   4934 +				System.out.println("msgType:" + msgType);
   4935 +			}
   4936  
   4937  			// Process the message depending on its type.
   4938  			switch (msgType) {
   4939 @@ -1332,6 +1368,9 @@
   4940  	public void mouseDragged(MouseEvent evt) {
   4941  		processLocalMouseEvent(evt, true);
   4942  	}
   4943 +	public void mouseWheelMoved(MouseWheelEvent evt) {
   4944 +		processLocalMouseWheelEvent(evt);
   4945 +	}
   4946  
   4947  	public void processLocalKeyEvent(KeyEvent evt) {
   4948  		if (viewer.rfb != null && rfb.inNormalProtocol) {
   4949 @@ -1367,6 +1406,19 @@
   4950  		evt.consume();
   4951  	}
   4952  
   4953 +	public void processLocalMouseWheelEvent(MouseWheelEvent evt) {
   4954 +		if (viewer.rfb != null && rfb.inNormalProtocol) {
   4955 +			synchronized(rfb) {
   4956 +			try {
   4957 +				rfb.writeWheelEvent(evt);
   4958 +			} catch (Exception e) {
   4959 +				e.printStackTrace();
   4960 +			}
   4961 +				rfb.notify();
   4962 +			}
   4963 +		}
   4964 +	}
   4965 +
   4966  	public void processLocalMouseEvent(MouseEvent evt, boolean moved) {
   4967  		if (viewer.rfb != null && rfb.inNormalProtocol) {
   4968  			if (moved) {
   4969 @@ -1532,9 +1584,14 @@
   4970  							else
   4971  							{
   4972  								result =
   4973 -									0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF)
   4974 -										<< 16 | (pixBuf[i * 4 + 2] & 0xFF)
   4975 -										<< 8 | (pixBuf[i * 4 + 3] & 0xFF);
   4976 +// begin runge/x11vnc
   4977 +//									0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF)
   4978 +//										<< 16 | (pixBuf[i * 4 + 2] & 0xFF)
   4979 +//										<< 8 | (pixBuf[i * 4 + 3] & 0xFF);
   4980 +									0xFF000000 | (pixBuf[i * 4 + 2] & 0xFF)
   4981 +										<< 16 | (pixBuf[i * 4 + 1] & 0xFF)
   4982 +										<< 8 | (pixBuf[i * 4 + 0] & 0xFF);
   4983 +// end runge/x11vnc
   4984  							}
   4985  						} else {
   4986  							result = 0; // Transparent pixel
   4987 @@ -1565,9 +1622,14 @@
   4988  						else
   4989  						{
   4990  							result =
   4991 -								0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF)
   4992 -									<< 16 | (pixBuf[i * 4 + 2] & 0xFF)
   4993 -									<< 8 | (pixBuf[i * 4 + 3] & 0xFF);
   4994 +// begin runge/x11vnc
   4995 +//								0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF)
   4996 +//									<< 16 | (pixBuf[i * 4 + 2] & 0xFF)
   4997 +//									<< 8 | (pixBuf[i * 4 + 3] & 0xFF);
   4998 +								0xFF000000 | (pixBuf[i * 4 + 2] & 0xFF)
   4999 +									<< 16 | (pixBuf[i * 4 + 1] & 0xFF)
   5000 +									<< 8 | (pixBuf[i * 4 + 0] & 0xFF);
   5001 +// end runge/x11vnc
   5002  						}
   5003  					} else {
   5004  						result = 0; // Transparent pixel
   5005 diff -Naur JavaViewer.orig/VncViewer.java JavaViewer/VncViewer.java
   5006 --- JavaViewer.orig/VncViewer.java	2006-05-24 15:14:40.000000000 -0400
   5007 +++ JavaViewer/VncViewer.java	2010-03-27 18:00:28.000000000 -0400
   5008 @@ -41,6 +41,7 @@
   5009  import java.io.*;
   5010  import java.net.*;
   5011  import javax.swing.*;
   5012 +import java.util.Date;
   5013  
   5014  public class VncViewer extends java.applet.Applet
   5015    implements java.lang.Runnable, WindowListener {
   5016 @@ -80,11 +81,11 @@
   5017    GridBagLayout gridbag;
   5018    ButtonPanel buttonPanel;
   5019    AuthPanel authenticator;
   5020 -  VncCanvas vc;
   5021 +  VncCanvas vc = null;
   5022    OptionsFrame options;
   5023    ClipboardFrame clipboard;
   5024    RecordingFrame rec;
   5025 -  FTPFrame ftp; // KMC: FTP Frame declaration
   5026 +  FTPFrame ftp = null; // KMC: FTP Frame declaration
   5027  
   5028    // Control session recording.
   5029    Object recordingSync;
   5030 @@ -96,7 +97,7 @@
   5031  
   5032    // Variables read from parameter values.
   5033    String host;
   5034 -  int port;
   5035 +  int port, vncserverport;
   5036    String passwordParam;
   5037    String encPasswordParam;
   5038    boolean showControls;
   5039 @@ -115,28 +116,75 @@
   5040    int i;
   5041    // mslogon support 2 end
   5042  
   5043 +// begin runge/x11vnc
   5044 +boolean disableSSL;
   5045 +boolean GET;
   5046 +String CONNECT;
   5047 +String urlPrefix;
   5048 +String httpsPort;
   5049 +String oneTimeKey;
   5050 +String serverCert;
   5051 +String ftpDropDown;
   5052 +String proxyHost;
   5053 +String proxyPort;
   5054 +boolean forceProxy;
   5055 +boolean ignoreProxy;
   5056 +boolean trustAllVncCerts;
   5057 +boolean trustUrlVncCert;
   5058 +boolean debugCerts;
   5059 +boolean debugKeyboard;
   5060 +boolean mapF5_to_atsign;
   5061 +boolean forbid_Ctrl_Alt;
   5062 +
   5063 +boolean ignoreMSLogonCheck;
   5064 +boolean delayAuthPanel;
   5065 +boolean ftpOnly;
   5066 +boolean graftFtp;
   5067 +boolean dsmActive;
   5068 +
   5069 +boolean gotAuth;
   5070 +int authGot;
   5071 +// end runge/x11vnc
   5072 +
   5073 +
   5074    //
   5075    // init()
   5076    //
   5077  
   5078 +public void ftp_init() {
   5079 +	boolean show = false;
   5080 +	if (ftp != null) {
   5081 +		show = true;
   5082 +	}
   5083 +	ftp = null;
   5084 +
   5085 +	ftp = new FTPFrame(this); // KMC: FTPFrame creation
   5086 +
   5087 +	if (show) {
   5088 +		ftp.doOpen();
   5089 +		rfb.readServerDriveList();
   5090 +	}
   5091 +}
   5092 +
   5093    public void init() {
   5094  
   5095      readParameters();
   5096  
   5097      if (inSeparateFrame) {
   5098 -      vncFrame = new Frame("Ultr@VNC");
   5099 -      if (!inAnApplet) {
   5100 -	vncFrame.add("Center", this);
   5101 -      }
   5102 -      vncContainer = vncFrame;
   5103 +	vncFrame = new Frame("Ultr@VNC");
   5104 +	if (!inAnApplet) {
   5105 +		vncFrame.add("Center", this);
   5106 +	}
   5107 +	vncContainer = vncFrame;
   5108      } else {
   5109 -      vncContainer = this;
   5110 +	vncContainer = this;
   5111      }
   5112  
   5113      recordingSync = new Object();
   5114  
   5115      options = new OptionsFrame(this);
   5116      clipboard = new ClipboardFrame(this);
   5117 +
   5118      // authenticator = new AuthPanel(false);   // mslogon support : go to connectAndAuthenticate()
   5119      if (RecordingFrame.checkSecurity())
   5120        rec = new RecordingFrame(this);
   5121 @@ -147,10 +195,11 @@
   5122      cursorUpdatesDef = null;
   5123      eightBitColorsDef = null;
   5124  
   5125 -    if (inSeparateFrame)
   5126 +    if (inSeparateFrame && vncFrame != null)
   5127        vncFrame.addWindowListener(this);
   5128  
   5129 -    ftp = new FTPFrame(this); // KMC: FTPFrame creation
   5130 +    ftp_init();
   5131 +
   5132      rfbThread = new Thread(this);
   5133      rfbThread.start();
   5134    }
   5135 @@ -186,6 +235,30 @@
   5136        gbc.weightx = 1.0;
   5137        gbc.weighty = 1.0;
   5138  
   5139 +	if (ftpOnly) {
   5140 +		if (showControls) {
   5141 +			buttonPanel.enableButtons();
   5142 +		}
   5143 +		ActionListener taskPerformer = new ActionListener() {
   5144 +			public void actionPerformed(ActionEvent evt) {
   5145 +				vncFrame.setVisible(false);
   5146 +				ftp.setSavedLocations();
   5147 +				if (ftp.isVisible()) {
   5148 +					ftp.doClose();
   5149 +				} else {
   5150 +					ftp.doOpen();
   5151 +				}
   5152 +				rfb.readServerDriveList();
   5153 +			}
   5154 +		};
   5155 +		Timer t = new Timer(300, taskPerformer);
   5156 +		t.setRepeats(false);
   5157 +		t.start();
   5158 +		
   5159 +		vc.processNormalProtocol();
   5160 +		return;
   5161 +	}
   5162 +
   5163  	// Add ScrollPanel to applet mode
   5164  
   5165  	// Create a panel which itself is resizeable and can hold
   5166 @@ -286,6 +359,24 @@
   5167  
   5168    void connectAndAuthenticate() throws Exception {
   5169  
   5170 +	if (graftFtp) {
   5171 +		rfb = new RfbProto(host, port, this);
   5172 +		rfb.desktopName = "ftponly";
   5173 +		rfb.framebufferWidth  = 12;
   5174 +		rfb.framebufferHeight = 12;
   5175 +		rfb.bitsPerPixel = 32;
   5176 +		rfb.depth = 24;
   5177 +		rfb.trueColour = true;
   5178 +		rfb.redMax   = 255;
   5179 +		rfb.greenMax = 255;
   5180 +		rfb.blueMax  = 255;
   5181 +		rfb.redShift   = 16;
   5182 +		rfb.greenShift = 8;
   5183 +		rfb.blueShift  = 0;
   5184 +		rfb.inNormalProtocol = true;
   5185 +		return;
   5186 +	}
   5187 +
   5188      // If "ENCPASSWORD" parameter is set, decrypt the password into
   5189      // the passwordParam string.
   5190  
   5191 @@ -336,7 +427,22 @@
   5192      //
   5193  
   5194      
   5195 -    prologueDetectAuthProtocol() ;
   5196 +// begin runge/x11vnc
   5197 +	gotAuth = false;
   5198 +	if (delayAuthPanel) {
   5199 +      		if (tryAuthenticate(null, null)) {
   5200 +			if (inSeparateFrame) {
   5201 +				vncFrame.pack();
   5202 +				vncFrame.show();
   5203 +			}
   5204 +      			return;
   5205 +      		}
   5206 +	}
   5207 +//  prologueDetectAuthProtocol() ;
   5208 +    if (ignoreMSLogonCheck == false) {
   5209 +        prologueDetectAuthProtocol() ;
   5210 +    }
   5211 +// end runge/x11vnc
   5212  
   5213      authenticator = new AuthPanel(mslogon);
   5214      
   5215 @@ -371,6 +477,7 @@
   5216       //mslogon support end
   5217      }
   5218  
   5219 +    int tries = 0;
   5220      while (true) {
   5221        // Wait for user entering a password, or a username and a password
   5222        synchronized(authenticator) {
   5223 @@ -390,6 +497,13 @@
   5224  	break;
   5225        //mslogon support end
   5226  
   5227 +// begin runge/x11vnc
   5228 +      gotAuth = false;
   5229 +      if (++tries > 2) {
   5230 +         throw new Exception("Incorrect password entered " + tries + " times.");
   5231 +      }
   5232 +// end runge/x11vnc
   5233 +
   5234        // Retry on authentication failure.
   5235        authenticator.retry();
   5236      }
   5237 @@ -405,9 +519,11 @@
   5238  
   5239    void prologueDetectAuthProtocol() throws Exception {
   5240  
   5241 -    rfb = new RfbProto(host, port, this);
   5242 +	if (!gotAuth) {
   5243 +		rfb = new RfbProto(host, port, this);
   5244  
   5245 -    rfb.readVersionMsg();
   5246 +		rfb.readVersionMsg();
   5247 +	}
   5248  
   5249      System.out.println("RFB server supports protocol version " +
   5250  		       rfb.serverMajor + "." + rfb.serverMinor);
   5251 @@ -431,16 +547,36 @@
   5252  
   5253    boolean tryAuthenticate(String us, String pw) throws Exception {
   5254      
   5255 -    rfb = new RfbProto(host, port, this);
   5256 +	int authScheme;
   5257  
   5258 -    rfb.readVersionMsg();
   5259 +	if (!gotAuth) {
   5260 +		rfb = new RfbProto(host, port, this);
   5261  
   5262 -    System.out.println("RFB server supports protocol version " +
   5263 -		       rfb.serverMajor + "." + rfb.serverMinor);
   5264 +		rfb.readVersionMsg();
   5265  
   5266 -    rfb.writeVersionMsg();
   5267 +		System.out.println("RFB server supports protocol version: " +
   5268 +			       rfb.serverMajor + "." + rfb.serverMinor);
   5269  
   5270 -    int authScheme = rfb.readAuthScheme();
   5271 +		rfb.writeVersionMsg();
   5272 +
   5273 +		authScheme = rfb.readAuthScheme();
   5274 +
   5275 +		gotAuth = true;
   5276 +		authGot = authScheme;
   5277 +	} else {
   5278 +		authScheme = authGot;
   5279 +	}
   5280 +// begin runge/x11vnc
   5281 +	if (delayAuthPanel && pw == null) {
   5282 +		if (authScheme == RfbProto.NoAuth) {
   5283 +			System.out.println("No authentication needed");
   5284 +			return true;
   5285 +		} else {
   5286 +			return false;
   5287 +		}
   5288 +	}
   5289 +System.out.println("as: " + authScheme);
   5290 +// end runge/x11vnc
   5291  
   5292      switch (authScheme) {
   5293  
   5294 @@ -629,6 +765,10 @@
   5295  
   5296    void doProtocolInitialisation() throws IOException {
   5297  
   5298 +	if (graftFtp) {
   5299 +		return;
   5300 +	}
   5301 +
   5302      rfb.writeClientInit();
   5303  
   5304      rfb.readServerInit();
   5305 @@ -774,9 +914,28 @@
   5306  	fatalError("HOST parameter not specified");
   5307        }
   5308      }
   5309 +    Date d = new Date();
   5310 +    System.out.println("-\nSSL VNC Java Applet starting.  " + d);
   5311  
   5312 -    String str = readParameter("PORT", true);
   5313 -    port = Integer.parseInt(str);
   5314 +    port = 0;
   5315 +    String str = readParameter("PORT", false);
   5316 +    if (str != null) {
   5317 +	port = Integer.parseInt(str);
   5318 +    }
   5319 +    // When there is a proxy VNCSERVERPORT may be inaccessible (inside firewall).
   5320 +    vncserverport = 0;
   5321 +    str = readParameter("VNCSERVERPORT", false);
   5322 +    if (str != null) {
   5323 +	vncserverport = Integer.parseInt(str);
   5324 +    }
   5325 +    if (port == 0 && vncserverport == 0) {
   5326 +	fatalError("Neither PORT nor VNCSERVERPORT parameters specified");
   5327 +    }
   5328 +    if (port == 0) {
   5329 +	// Nevertheless, fall back to vncserverport if we have to.
   5330 +	System.out.println("using vncserverport: '" + vncserverport + "' for PORT.");
   5331 +	port = vncserverport;
   5332 +    }
   5333  
   5334      if (inAnApplet) {
   5335        str = readParameter("Open New Window", false);
   5336 @@ -804,6 +963,158 @@
   5337      deferScreenUpdates = readIntParameter("Defer screen updates", 20);
   5338      deferCursorUpdates = readIntParameter("Defer cursor updates", 10);
   5339      deferUpdateRequests = readIntParameter("Defer update requests", 50);
   5340 +
   5341 +// begin runge/x11vnc
   5342 +    // SSL
   5343 +    disableSSL = false;
   5344 +    str = readParameter("DisableSSL", false);
   5345 +    if (str != null && str.equalsIgnoreCase("Yes"))
   5346 +      disableSSL = true;
   5347 +
   5348 +    httpsPort = readParameter("httpsPort", false);
   5349 +
   5350 +    // Extra GET, CONNECT string:
   5351 +    CONNECT = readParameter("CONNECT", false);
   5352 +    if (CONNECT != null) {
   5353 +	CONNECT = CONNECT.replaceAll(" ", ":");
   5354 +    }
   5355 +
   5356 +    GET = false;
   5357 +    str = readParameter("GET", false);
   5358 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   5359 +      GET = true;
   5360 +    }
   5361 +    if (str != null && str.equalsIgnoreCase("1")) {
   5362 +      GET = true;
   5363 +    }
   5364 +
   5365 +    urlPrefix = readParameter("urlPrefix", false);
   5366 +    if (urlPrefix != null) {
   5367 +	urlPrefix = urlPrefix.replaceAll("%2F", "/");
   5368 +	urlPrefix = urlPrefix.replaceAll("%2f", "/");
   5369 +	urlPrefix = urlPrefix.replaceAll("_2F_", "/");
   5370 +	if (urlPrefix.indexOf("/") != 0) {
   5371 +		urlPrefix = "/" + urlPrefix;
   5372 +	}
   5373 +    } else {
   5374 +    	urlPrefix = "";
   5375 +    }
   5376 +    System.out.println("urlPrefix: '" + urlPrefix + "'");
   5377 +
   5378 +    ftpDropDown = readParameter("ftpDropDown", false);
   5379 +    if (ftpDropDown != null) {
   5380 +	ftpDropDown = ftpDropDown.replaceAll("%2F", "/");
   5381 +	ftpDropDown = ftpDropDown.replaceAll("%2f", "/");
   5382 +	ftpDropDown = ftpDropDown.replaceAll("_2F_", "/");
   5383 +	ftpDropDown = ftpDropDown.replaceAll("%20", " ");
   5384 +	System.out.println("ftpDropDown: '" + ftpDropDown + "'");
   5385 +    }
   5386 +
   5387 +
   5388 +    oneTimeKey = readParameter("oneTimeKey", false);
   5389 +    if (oneTimeKey != null) {
   5390 +    	System.out.println("oneTimeKey is set.");
   5391 +    }
   5392 +
   5393 +    serverCert = readParameter("serverCert", false);
   5394 +    if (serverCert != null) {
   5395 +    	System.out.println("serverCert is set.");
   5396 +    }
   5397 +
   5398 +    forceProxy = false;
   5399 +    proxyHost = null;
   5400 +    proxyPort = null;
   5401 +    str = readParameter("forceProxy", false);
   5402 +    if (str != null) {
   5403 +	    if (str.equalsIgnoreCase("Yes")) {
   5404 +		forceProxy = true;
   5405 +	    } else if (str.equalsIgnoreCase("No")) {
   5406 +		forceProxy = false;
   5407 +	    } else {
   5408 +		forceProxy = true;
   5409 +		String[] pieces = str.split(" ");
   5410 +		proxyHost = new String(pieces[0]);
   5411 +		if (pieces.length >= 2) {
   5412 +			proxyPort = new String(pieces[1]);
   5413 +		} else {
   5414 +			proxyPort = new String("8080");
   5415 +		}
   5416 +	    }
   5417 +    }
   5418 +    str = readParameter("proxyHost", false);
   5419 +    if (str != null) {
   5420 +	proxyHost = new String(str);
   5421 +    }
   5422 +    str = readParameter("proxyPort", false);
   5423 +    if (str != null) {
   5424 +	proxyPort = new String(str);
   5425 +    }
   5426 +    if (proxyHost != null && proxyPort == null) {
   5427 +    	proxyPort = new String("8080");
   5428 +    }
   5429 +
   5430 +    ignoreProxy = false;
   5431 +    str = readParameter("ignoreProxy", false);
   5432 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   5433 +	ignoreProxy = true;
   5434 +    }
   5435 +
   5436 +    trustAllVncCerts = false;
   5437 +    str = readParameter("trustAllVncCerts", false);
   5438 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   5439 +	trustAllVncCerts = true;
   5440 +    }
   5441 +    trustUrlVncCert = false;
   5442 +    str = readParameter("trustUrlVncCert", false);
   5443 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   5444 +	trustUrlVncCert = true;
   5445 +    }
   5446 +    debugCerts = false;
   5447 +    str = readParameter("debugCerts", false);
   5448 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   5449 +	debugCerts = true;
   5450 +    }
   5451 +    debugKeyboard = false;
   5452 +    str = readParameter("debugKeyboard", false);
   5453 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   5454 +	debugKeyboard = true;
   5455 +    }
   5456 +    mapF5_to_atsign = false;
   5457 +    str = readParameter("mapF5_to_atsign", false);
   5458 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   5459 +	mapF5_to_atsign = true;
   5460 +    }
   5461 +    forbid_Ctrl_Alt = false;
   5462 +    str = readParameter("forbid_Ctrl_Alt", false);
   5463 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   5464 +	forbid_Ctrl_Alt = true;
   5465 +    }
   5466 +    ignoreMSLogonCheck = false;
   5467 +    str = readParameter("ignoreMSLogonCheck", false);
   5468 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   5469 +	ignoreMSLogonCheck = true;
   5470 +    }
   5471 +    ftpOnly = false;
   5472 +    str = readParameter("ftpOnly", false);
   5473 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   5474 +	ftpOnly = true;
   5475 +    }
   5476 +    graftFtp = false;
   5477 +    str = readParameter("graftFtp", false);
   5478 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   5479 +	graftFtp = true;
   5480 +    }
   5481 +    dsmActive = false;
   5482 +    str = readParameter("dsmActive", false);
   5483 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   5484 +	dsmActive = true;
   5485 +    }
   5486 +    delayAuthPanel = false;
   5487 +    str = readParameter("delayAuthPanel", false);
   5488 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   5489 +	delayAuthPanel = true;
   5490 +    }
   5491 +// end runge/x11vnc
   5492    }
   5493  
   5494    public String readParameter(String name, boolean required) {
   5495