diff options
Diffstat (limited to 'webclients/java-applet/ssl/ultravnc-102-JavaViewer-ssl-etc.patch')
-rw-r--r-- | webclients/java-applet/ssl/ultravnc-102-JavaViewer-ssl-etc.patch | 5494 |
1 files changed, 5494 insertions, 0 deletions
diff --git a/webclients/java-applet/ssl/ultravnc-102-JavaViewer-ssl-etc.patch b/webclients/java-applet/ssl/ultravnc-102-JavaViewer-ssl-etc.patch new file mode 100644 index 0000000..3309860 --- /dev/null +++ b/webclients/java-applet/ssl/ultravnc-102-JavaViewer-ssl-etc.patch @@ -0,0 +1,5494 @@ +diff -Naur JavaViewer.orig/ButtonPanel.java JavaViewer/ButtonPanel.java +--- JavaViewer.orig/ButtonPanel.java 2004-12-12 20:51:02.000000000 -0500 ++++ JavaViewer/ButtonPanel.java 2007-05-31 15:40:45.000000000 -0400 +@@ -43,30 +43,36 @@ + viewer = v; + + setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); +- disconnectButton = new Button("Disconnect"); ++ if (v.ftpOnly) { ++ disconnectButton = new Button("Quit"); ++ } else { ++ disconnectButton = new Button("Close"); ++ } + disconnectButton.setEnabled(false); + add(disconnectButton); + disconnectButton.addActionListener(this); +- optionsButton = new Button("Options"); +- add(optionsButton); +- optionsButton.addActionListener(this); +- clipboardButton = new Button("Clipboard"); +- clipboardButton.setEnabled(false); +- add(clipboardButton); +- clipboardButton.addActionListener(this); +- if (viewer.rec != null) { +- recordButton = new Button("Record"); +- add(recordButton); +- recordButton.addActionListener(this); +- } +- ctrlAltDelButton = new Button("Send Ctrl-Alt-Del"); +- ctrlAltDelButton.setEnabled(false); +- add(ctrlAltDelButton); +- ctrlAltDelButton.addActionListener(this); +- refreshButton = new Button("Refresh"); +- refreshButton.setEnabled(false); +- add(refreshButton); +- refreshButton.addActionListener(this); ++ if (!v.ftpOnly) { ++ optionsButton = new Button("Options"); ++ add(optionsButton); ++ optionsButton.addActionListener(this); ++ clipboardButton = new Button("Clipboard"); ++ clipboardButton.setEnabled(false); ++ add(clipboardButton); ++ clipboardButton.addActionListener(this); ++ if (viewer.rec != null) { ++ recordButton = new Button("Record"); ++ add(recordButton); ++ recordButton.addActionListener(this); ++ } ++ ctrlAltDelButton = new Button("Send Ctrl-Alt-Del"); ++ ctrlAltDelButton.setEnabled(false); ++ add(ctrlAltDelButton); ++ ctrlAltDelButton.addActionListener(this); ++ refreshButton = new Button("Refresh"); ++ refreshButton.setEnabled(false); ++ add(refreshButton); ++ refreshButton.addActionListener(this); ++ } + ftpButton = new Button("File Transfer"); + ftpButton.setEnabled(false); + add(ftpButton); +@@ -79,9 +85,10 @@ + + public void enableButtons() { + disconnectButton.setEnabled(true); ++ ftpButton.setEnabled(true); ++ if (viewer.ftpOnly) {return;} + clipboardButton.setEnabled(true); + refreshButton.setEnabled(true); +- ftpButton.setEnabled(true); + } + + // +@@ -89,6 +96,9 @@ + // + + public void disableButtonsOnDisconnect() { ++ ftpButton.setEnabled(false); ++ if (viewer.ftpOnly) {return;} ++ + remove(disconnectButton); + disconnectButton = new Button("Hide desktop"); + disconnectButton.setEnabled(true); +@@ -99,7 +109,6 @@ + clipboardButton.setEnabled(false); + ctrlAltDelButton.setEnabled(false); + refreshButton.setEnabled(false); +- ftpButton.setEnabled(false); + + validate(); + } +@@ -110,6 +119,7 @@ + // + + public void enableRemoteAccessControls(boolean enable) { ++ if (viewer.ftpOnly) {return;} + ctrlAltDelButton.setEnabled(enable); + } + +@@ -163,9 +173,19 @@ + } + else if (evt.getSource() == ftpButton) + { +- viewer.ftp.setVisible(!viewer.ftp.isVisible()); ++// begin runge/x11vnc ++ if (viewer.ftpOnly) { ++ viewer.vncFrame.setVisible(false); ++ } ++ viewer.ftp.setSavedLocations(); ++ if (viewer.ftp.isVisible()) { ++ viewer.ftp.doClose(); ++ } else { ++ viewer.ftp.doOpen(); ++ } ++// end runge/x11vnc + viewer.rfb.readServerDriveList(); +- ++ + } + } + } +diff -Naur JavaViewer.orig/FTPFrame.java JavaViewer/FTPFrame.java +--- JavaViewer.orig/FTPFrame.java 2005-03-15 23:53:14.000000000 -0500 ++++ JavaViewer/FTPFrame.java 2009-01-13 09:48:30.000000000 -0500 +@@ -24,8 +24,17 @@ + import java.io.*; + import java.util.ArrayList; + import java.util.Vector; ++import java.util.Date; + import javax.swing.*; + ++import java.nio.ByteBuffer; ++import java.nio.CharBuffer; ++import java.nio.charset.*; ++ ++// begin runge/x11vnc ++import java.util.Arrays; ++// end runge/x11vnc ++ + + /* + * Created on Feb 25, 2004 +@@ -74,12 +83,31 @@ + public javax.swing.JTextField connectionStatus = null; + public boolean updateDriveList; + private Vector remoteList = null; ++ private Vector remoteListInfo = null; + private Vector localList = null; ++ private Vector localListInfo = null; + private File currentLocalDirectory = null; // Holds the current local Directory + private File currentRemoteDirectory = null; // Holds the current remote Directory + private File localSelection = null; // Holds the currently selected local file + private String remoteSelection = null; // Holds the currently selected remote file + public String selectedTable = null; ++ ++// begin runge/x11vnc ++ private javax.swing.JButton viewButton = null; ++ private javax.swing.JButton refreshButton = null; ++ public File saveLocalDirectory = null; ++ public long saveLocalDirectoryTime = 0; ++ public int saveLocalDirectoryCount = 0; ++ public String saveRemoteDirectory = null; ++ public long saveRemoteDirectoryTime = 0; ++ public int saveRemoteDirectoryCount = 0; ++ private boolean localCurrentIsDir = true; ++ private int lastRemoteIndex = -1; ++ private int lastLocalIndex = -1; ++ private boolean doingShortcutDir = false; ++ private boolean gotShortcutDir = false; ++ private boolean ignore_events = false; ++// end runge/x11vnc + + // sf@2004 - Separate directories and files for better lisibility + private ArrayList DirsList; +@@ -125,11 +153,61 @@ + + void refreshRemoteLocation() + { ++ ++//System.out.println("refreshRemoteLocation1"); + remoteList.clear(); ++ remoteListInfo.clear(); + remoteFileTable.setListData(remoteList); ++System.out.println("refreshRemoteLocation '" + remoteLocation.getText() + "'"); // runge/x11vnc + viewer.rfb.readServerDirectory(remoteLocation.getText()); + } + ++// begin runge/x11vnc ++ public void setSavedLocations() { ++ saveLocalDirectory = currentLocalDirectory; ++ saveLocalDirectoryTime = System.currentTimeMillis(); ++ saveLocalDirectoryCount = 0; ++ ++ if (remoteLocation != null) { ++ saveRemoteDirectory = remoteLocation.getText(); ++System.out.println("RemoteSave '" + saveRemoteDirectory + "'"); ++ } ++ saveRemoteDirectoryTime = System.currentTimeMillis(); ++ saveRemoteDirectoryCount = 0; ++ } ++ ++ private File saveLocalHack(File dir) { ++ saveLocalDirectoryCount++; ++//System.out.println("L " + saveLocalDirectoryCount + " dt: " + (System.currentTimeMillis() - saveLocalDirectoryTime) + " - " + saveLocalDirectory); ++ if (System.currentTimeMillis() > saveLocalDirectoryTime + 2000 || saveLocalDirectoryCount > 2) { ++ saveLocalDirectory = null; ++ } ++ if (saveLocalDirectory != null) { ++ currentLocalDirectory = saveLocalDirectory; ++ localLocation.setText(saveLocalDirectory.toString()); ++ return saveLocalDirectory; ++ } else { ++ return dir; ++ } ++ } ++ ++ private String saveRemoteHack(String indrive) { ++ saveRemoteDirectoryCount++; ++//System.out.println("R " + saveRemoteDirectoryCount + " - " + saveRemoteDirectory); ++ if (saveRemoteDirectory != null && saveRemoteDirectoryCount > 1) { ++ saveRemoteDirectory = null; ++ } ++ if (saveRemoteDirectory != null) { ++ if (! saveRemoteDirectory.equals("")) { ++System.out.println("saveRemoteHack setText + refreshRemoteLocation '" + saveRemoteDirectory + "'"); ++ return saveRemoteDirectory; ++ } ++ } ++ return indrive; ++ } ++// end runge/x11vnc ++ ++ + /* + * Prints the list of drives on the remote directory and returns a String[]. + * str takes as string like A:fC:lD:lE:lF:lG:cH:c +@@ -143,6 +221,9 @@ + int size = str.length(); + String driveType = null; + String[] drive = new String[str.length() / 3]; ++ int idx = 0, C_drive = -1, O_drive = -1; ++ ++System.out.println("ComboBox: Str '" + str + "'"); + + // Loop through the string to create a String[] + for (int i = 0; i < size; i = i + 3) { +@@ -150,26 +231,68 @@ + driveType = str.substring(i + 2, i + 3); + if (driveType.compareTo("f") == 0) + drive[i / 3] += "\\ Floppy"; +- if (driveType.compareTo("l") == 0) ++ if (driveType.compareTo("l") == 0) { + drive[i / 3] += "\\ Local Disk"; ++ if (drive[i/3].substring(0,1).toUpperCase().equals("C")) { ++ C_drive = idx; ++ } else if (O_drive < 0) { ++ O_drive = idx; ++ } ++ } + if (driveType.compareTo("c") == 0) + drive[i / 3] += "\\ CD-ROM"; + if (driveType.compareTo("n") == 0) + drive[i / 3] += "\\ Network"; + + remoteDrivesComboBox.addItem(drive[i / 3]); ++System.out.println("ComboBox: Add " + idx + " '" + drive[i/3] + "'"); ++ idx++; ++ } ++ ++ // runge ++ if (viewer.ftpDropDown != null) { ++ String[] dd = viewer.ftpDropDown.split("\\."); ++ for (int i=0; i < dd.length; i++) { ++ if (!dd[i].equals("")) { ++ String s = dd[i]; ++ if (s.startsWith("TOP_")) { ++ s = s.substring(4); ++ remoteDrivesComboBox.insertItemAt(" [" + s + "]", 0); ++ } else { ++ remoteDrivesComboBox.addItem(" [" + s + "]"); ++ } ++ } ++ } ++ } else { ++ remoteDrivesComboBox.addItem(" [My Documents]"); ++ remoteDrivesComboBox.addItem(" [Desktop]"); ++ remoteDrivesComboBox.addItem(" [Home]"); + } ++ + //sf@ - Select Drive C:as default if possible + boolean bFound = false; +- for(int i = 0; i < remoteDrivesComboBox.getItemCount() ; i++) +- { +- if(remoteDrivesComboBox.getItemAt(i).toString().substring(0,1).toUpperCase().equals("C")) +- { +- remoteDrivesComboBox.setSelectedIndex(i); ++ ++ if (false) { ++ for(int i = 0; i < remoteDrivesComboBox.getItemCount() ; i++) { ++ if(remoteDrivesComboBox.getItemAt(i).toString().substring(0,1).toUpperCase().equals("C")) { ++ remoteDrivesComboBox.setSelectedIndex(i); ++ bFound = true; ++ } ++ } ++ } else { ++ if (C_drive >= 0) { ++ remoteDrivesComboBox.setSelectedIndex(C_drive); ++ bFound = true; ++System.out.println("ComboBox: C_drive index: " + C_drive); ++ } else if (O_drive >= 0) { ++ remoteDrivesComboBox.setSelectedIndex(O_drive); + bFound = true; ++System.out.println("ComboBox: Other_drive index: " + O_drive); + } + } ++ + if (!bFound) remoteDrivesComboBox.setSelectedIndex(0); ++ + updateDriveList = false; + return drive; + } +@@ -185,6 +308,8 @@ + stopButton.setVisible(true); + stopButton.setEnabled(true); + receiveButton.setEnabled(false); ++ viewButton.setEnabled(false); // runge/x11vnc ++ refreshButton.setEnabled(false); + remoteTopButton.setEnabled(false); + sendButton.setEnabled(false); + remoteFileTable.setEnabled(false); +@@ -207,6 +332,8 @@ + stopButton.setVisible(false); + stopButton.setEnabled(false); + receiveButton.setEnabled(true); ++ viewButton.setEnabled(true); // runge/x11vnc ++ refreshButton.setEnabled(true); + remoteTopButton.setEnabled(true); + sendButton.setEnabled(true); + remoteFileTable.setEnabled(true); +@@ -221,10 +348,11 @@ + /* + * Print Directory prints out all the contents of a directory + */ +- void printDirectory(ArrayList a) { ++ void printDirectory(ArrayList a, ArrayList b) { + + for (int i = 0; i < a.size(); i++) { + remoteList.addElement(a.get(i)); ++ remoteListInfo.addElement(b.get(i)); + } + remoteFileTable.setListData(remoteList); + } +@@ -235,10 +363,12 @@ + * @return void + */ + private void initialize() { ++ ignore_events = true; + this.setSize(794, 500); + this.setContentPane(getJContentPane()); ++ ignore_events = false; + updateDriveList = true; +- } ++ } + /** + * This method initializes jContentPane. This is the main content pane + * +@@ -253,6 +383,33 @@ + jContentPane.add(getRemotePanel(), java.awt.BorderLayout.EAST); + jContentPane.add(getLocalPanel(), java.awt.BorderLayout.WEST); + jContentPane.add(getButtonPanel(), java.awt.BorderLayout.CENTER); ++ ++ KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); ++ AbstractAction escapeAction = new AbstractAction() { ++ public void actionPerformed(ActionEvent actionEvent) { ++ System.out.println("Escape Pressed"); ++ if (viewer.ftpOnly) { ++ System.out.println("exiting..."); ++ System.exit(0); ++ } else { ++ doClose(); ++ } ++ } ++ }; ++ jContentPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(stroke, "escapeAction"); ++ jContentPane.getInputMap().put(stroke, "escapeAction"); ++ jContentPane.getActionMap().put("escapeAction", escapeAction); ++ ++ stroke = KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_MASK); ++ AbstractAction resetAction = new AbstractAction() { ++ public void actionPerformed(ActionEvent actionEvent) { ++ System.out.println("Ctrl-R Pressed"); ++ doReset(); ++ } ++ }; ++ jContentPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(stroke, "resetAction"); ++ jContentPane.getInputMap().put(stroke, "resetAction"); ++ jContentPane.getActionMap().put("resetAction", resetAction); + } + return jContentPane; + } +@@ -270,6 +427,7 @@ + topPanelLocal.add(getLocalMachineLabel(), java.awt.BorderLayout.CENTER); + topPanelLocal.add(getLocalTopButton(), java.awt.BorderLayout.EAST); + topPanelLocal.setBackground(java.awt.Color.lightGray); ++//System.out.println("getTopPanelLocal"); + } + return topPanelLocal; + } +@@ -288,6 +446,7 @@ + topPanelRemote.add(getRemoteMachineLabel(), java.awt.BorderLayout.CENTER); + topPanelRemote.add(getRemoteTopButton(), java.awt.BorderLayout.EAST); + topPanelRemote.setBackground(java.awt.Color.lightGray); ++//System.out.println("getTopPanelRemote"); + } + return topPanelRemote; + } +@@ -301,6 +460,7 @@ + if (topPanelCenter == null) { + topPanelCenter = new javax.swing.JPanel(); + topPanelCenter.add(getDummyButton(), null); ++//System.out.println("getTopPanelCenter"); + } + return topPanelCenter; + } +@@ -328,6 +488,7 @@ + topPanel.add(getRemoteTopButton(), null); + topPanel.setBackground(java.awt.Color.lightGray); + */ ++//System.out.println("getTopPanel"); + } + return topPanel; + } +@@ -348,6 +509,7 @@ + statusPanel.add(getJProgressBar(), null); + statusPanel.add(getConnectionStatus(), null); + statusPanel.setBackground(java.awt.Color.lightGray); ++//System.out.println("getStatusPanel"); + + } + return statusPanel; +@@ -368,6 +530,7 @@ + remotePanel.add(getRemoteScrollPane(), null); + remotePanel.add(getRemoteStatus(), null); + remotePanel.setBackground(java.awt.Color.lightGray); ++//System.out.println("getRemotePanel"); + } + return remotePanel; + } +@@ -390,6 +553,7 @@ + localPanel.setComponentOrientation( + java.awt.ComponentOrientation.UNKNOWN); + localPanel.setName("localPanel"); ++//System.out.println("getLocalPanel"); + } + return localPanel; + } +@@ -405,12 +569,15 @@ + buttonPanel = new javax.swing.JPanel(); + buttonPanel.setLayout(null); + buttonPanel.add(getReceiveButton(), null); ++ buttonPanel.add(getRefreshButton(), null); // runge/x11vnc ++ buttonPanel.add(getViewButton(), null); // runge/x11vnc + buttonPanel.add(getNewFolderButton(), null); + buttonPanel.add(getCloseButton(), null); + buttonPanel.add(getDeleteButton(), null); + buttonPanel.add(getSendButton(), null); + buttonPanel.add(getStopButton(), null); + buttonPanel.setBackground(java.awt.Color.lightGray); ++//System.out.println("getButtonPanel"); + } + return buttonPanel; + } +@@ -422,10 +589,11 @@ + private javax.swing.JButton getSendButton() { + if (sendButton == null) { + sendButton = new javax.swing.JButton(); +- sendButton.setBounds(20, 30, 97, 25); ++ sendButton.setBounds(15, 30, 107, 25); // runge/x11vnc + sendButton.setText("Send >>"); + sendButton.setName("sendButton"); + sendButton.addActionListener(this); ++//System.out.println("getSendButton"); + + } + return sendButton; +@@ -438,7 +606,7 @@ + private javax.swing.JButton getReceiveButton() { + if (receiveButton == null) { + receiveButton = new javax.swing.JButton(); +- receiveButton.setBounds(20, 60, 97, 25); ++ receiveButton.setBounds(15, 60, 107, 25); // runge/x11vnc + receiveButton.setText("<< Receive"); + receiveButton.setName("receiveButton"); + receiveButton.addActionListener(this); +@@ -453,7 +621,7 @@ + private javax.swing.JButton getDeleteButton() { + if (deleteButton == null) { + deleteButton = new javax.swing.JButton(); +- deleteButton.setBounds(20, 110, 97, 25); ++ deleteButton.setBounds(15, 110, 107, 25); // runge/x11vnc + deleteButton.setText("Delete File"); + deleteButton.setName("deleteButton"); + deleteButton.addActionListener(this); +@@ -468,7 +636,7 @@ + private javax.swing.JButton getNewFolderButton() { + if (newFolderButton == null) { + newFolderButton = new javax.swing.JButton(); +- newFolderButton.setBounds(20, 140, 97, 25); ++ newFolderButton.setBounds(15, 140, 107, 25); // runge/x11vnc + newFolderButton.setText("New Folder"); + newFolderButton.setName("newFolderButton"); + newFolderButton.addActionListener(this); +@@ -476,6 +644,39 @@ + return newFolderButton; + } + ++// begin runge/x11vnc ++ /** ++ * This method initializes refreshButton ++ * ++ * @return javax.swing.JButton ++ */ ++ private javax.swing.JButton getRefreshButton() { ++ if (refreshButton == null) { ++ refreshButton = new javax.swing.JButton(); ++ refreshButton.setBounds(15, 170, 107, 25); ++ refreshButton.setText("Refresh"); ++ refreshButton.setName("refreshButton"); ++ refreshButton.addActionListener(this); ++ } ++ return refreshButton; ++ } ++ /** ++ * This method initializes viewButton ++ * ++ * @return javax.swing.JButton ++ */ ++ private javax.swing.JButton getViewButton() { ++ if (viewButton == null) { ++ viewButton = new javax.swing.JButton(); ++ viewButton.setBounds(15, 200, 107, 25); ++ viewButton.setText("View File"); ++ viewButton.setName("viewButton"); ++ viewButton.addActionListener(this); ++ } ++ return viewButton; ++ } ++// end runge/x11vnc ++ + /** + * This method initializes stopButton + * +@@ -486,7 +687,7 @@ + if (stopButton == null) + { + stopButton = new javax.swing.JButton(); +- stopButton.setBounds(20, 200, 97, 25); ++ stopButton.setBounds(15, 230, 107, 25); // runge/x11vnc + stopButton.setText("Stop"); + stopButton.setName("stopButton"); + stopButton.addActionListener(this); +@@ -503,8 +704,12 @@ + private javax.swing.JButton getCloseButton() { + if (closeButton == null) { + closeButton = new javax.swing.JButton(); +- closeButton.setBounds(20, 325, 97, 25); +- closeButton.setText("Close"); ++ closeButton.setBounds(15, 325, 107, 25); // runge/x11vnc ++ if (viewer.ftpOnly) { ++ closeButton.setText("Quit"); ++ } else { ++ closeButton.setText("Close"); ++ } + closeButton.setName("closeButton"); + closeButton.addActionListener(this); + } +@@ -551,6 +756,7 @@ + //Select the second entry (e.g. C:\) + // localDrivesComboBox.setSelectedIndex(1); + localDrivesComboBox.addActionListener(this); ++//System.out.println("getLocalDrivesComboBox"); + } + updateDriveList = false; + return localDrivesComboBox; +@@ -567,6 +773,7 @@ + remoteDrivesComboBox.setFont( + new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10)); + remoteDrivesComboBox.addActionListener(this); ++//System.out.println("getRemoteDrivesComboBox"); + + } + return remoteDrivesComboBox; +@@ -587,6 +794,7 @@ + localMachineLabel.setFont( + new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); + localMachineLabel.setEditable(false); ++//System.out.println("getLocalMachineLabel"); + } + return localMachineLabel; + } +@@ -622,6 +830,7 @@ + localTopButton.setFont( + new java.awt.Font("Dialog", java.awt.Font.BOLD, 10)); + localTopButton.addActionListener(this); ++//System.out.println("getLocalTopButton"); + } + return localTopButton; + } +@@ -638,6 +847,7 @@ + remoteTopButton.setFont( + new java.awt.Font("Dialog", java.awt.Font.BOLD, 10)); + remoteTopButton.addActionListener(this); ++//System.out.println("getRemoteTopButton"); + } + return remoteTopButton; + } +@@ -650,9 +860,24 @@ + private javax.swing.JList getLocalFileTable() { + if (localFileTable == null) { + localList = new Vector(0); ++ localListInfo = new Vector(0); + localFileTable = new JList(localList); ++ MouseMotionListener mlisten = new MouseMotionAdapter() { ++ public void mouseMoved(MouseEvent e) { ++ int index = localFileTable.locationToIndex(e.getPoint()); ++ if (index == lastLocalIndex) { ++ return; ++ } else if (index < 0) { ++ return; ++ } ++ lastLocalIndex = index; ++ connectionStatus.setText((String) localListInfo.get(index)); ++ } ++ }; + localFileTable.addMouseListener(this); ++ localFileTable.addMouseMotionListener(mlisten); + localFileTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); ++//System.out.println("getLocalFileTable"); + } + return localFileTable; + } +@@ -669,6 +894,7 @@ + localScrollPane.setFont( + new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10)); + localScrollPane.setName("localFileList"); ++//System.out.println("getLocalScrollPane"); + } + return localScrollPane; + } +@@ -680,10 +906,25 @@ + private javax.swing.JList getRemoteFileTable() { + if (remoteFileTable == null) { + remoteList = new Vector(0); ++ remoteListInfo = new Vector(0); + remoteFileTable = new JList(remoteList); ++ MouseMotionListener mlisten = new MouseMotionAdapter() { ++ public void mouseMoved(MouseEvent e) { ++ int index = remoteFileTable.locationToIndex(e.getPoint()); ++ if (index == lastRemoteIndex) { ++ return; ++ } else if (index < 0) { ++ return; ++ } ++ lastRemoteIndex = index; ++ connectionStatus.setText((String) remoteListInfo.get(index)); ++ } ++ }; + remoteFileTable.addMouseListener(this); ++ remoteFileTable.addMouseMotionListener(mlisten); + remoteFileTable.setSelectedValue("C:\\", false); + remoteFileTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); ++//System.out.println("getRemoteFileTable"); + + } + return remoteFileTable; +@@ -698,6 +939,7 @@ + remoteScrollPane = new javax.swing.JScrollPane(); + remoteScrollPane.setViewportView(getRemoteFileTable()); + remoteScrollPane.setPreferredSize(new java.awt.Dimension(325, 418)); ++//System.out.println("getRemoteScrollPane"); + } + return remoteScrollPane; + } +@@ -716,6 +958,7 @@ + remoteLocation.setBackground(new Color(255,255,238)); + remoteLocation.setFont( + new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10)); ++//System.out.println("getRemoteLocation"); + } + return remoteLocation; + } +@@ -732,6 +975,7 @@ + localLocation.setBackground( new Color(255,255,238)); + localLocation.setFont( + new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10)); ++//System.out.println("getLocalLocation"); + } + return localLocation; + } +@@ -748,6 +992,7 @@ + localStatus.setFont( + new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10)); + localStatus.setEditable(false); ++//System.out.println("getLocalStatus"); + } + return localStatus; + } +@@ -764,6 +1009,7 @@ + remoteStatus.setFont( + new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10)); + remoteStatus.setEditable(false); ++//System.out.println("getRemoteStatus"); + } + return remoteStatus; + } +@@ -777,9 +1023,10 @@ + historyComboBox = new javax.swing.JComboBox(); + historyComboBox.setFont( + new java.awt.Font("Dialog", java.awt.Font.BOLD, 10)); +- historyComboBox.insertItemAt(new String("Pulldown to view history ..."),0); ++ historyComboBox.insertItemAt(new String("Pulldown to view history; Press Escape to Close/Quit; Press Ctrl-R to Reset Panel."),0); + historyComboBox.setSelectedIndex(0); + historyComboBox.addActionListener(this); ++//System.out.println("getHistoryComboBox"); + } + return historyComboBox; + } +@@ -791,6 +1038,7 @@ + private javax.swing.JProgressBar getJProgressBar() { + if (jProgressBar == null) { + jProgressBar = new javax.swing.JProgressBar(); ++//System.out.println("getJProgressBar"); + } + return jProgressBar; + } +@@ -806,6 +1054,7 @@ + connectionStatus.setBackground(java.awt.Color.lightGray); + connectionStatus.setFont( + new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10)); ++//System.out.println("getConnectionStatus"); + } + connectionStatus.setEditable(false); + return connectionStatus; +@@ -815,7 +1064,12 @@ + * Implements Action listener. + */ + public void actionPerformed(ActionEvent evt) { +- System.out.println(evt.getSource()); ++// System.out.println(evt.getSource()); ++ ++ if (ignore_events) { ++ System.out.println("ignore_events: " + evt.getSource()); ++ return; ++ } + + if (evt.getSource() == closeButton) + { // Close Button +@@ -829,15 +1083,27 @@ + { + doReceive(); + } ++// begin runge/x11vnc ++ else if (evt.getSource() == viewButton) ++ { ++ doView(); ++ } ++// end runge/x11vnc + else if (evt.getSource() == localDrivesComboBox) + { + changeLocalDrive(); + } + else if (evt.getSource() == remoteDrivesComboBox) + { ++//System.out.println("remoteDrivesComboBox"); // runge/x11vnc + changeRemoteDrive(); +- remoteList.clear(); +- remoteFileTable.setListData(remoteList); ++ ++ // are these really needed? changeRemoteDrive() does them at the end. ++ if (false) { ++ remoteList.clear(); ++ remoteListInfo.clear(); ++ remoteFileTable.setListData(remoteList); ++ } + } + else if (evt.getSource() == localTopButton) + { +@@ -845,12 +1111,17 @@ + } + else if (evt.getSource() == remoteTopButton) + { ++//System.out.println("remoteTopButton"); // runge/x11vnc + changeRemoteDrive(); + } + else if(evt.getSource() == deleteButton) + { + doDelete(); + } ++ else if(evt.getSource() == refreshButton) ++ { ++ doRefresh(); ++ } + else if(evt.getSource()==newFolderButton) + { + doNewFolder(); +@@ -864,7 +1135,7 @@ + + private void doNewFolder() + { +- String name = JOptionPane.showInputDialog(null,"Enter new directory name", "Create New Directory", JOptionPane.QUESTION_MESSAGE); ++ String name = JOptionPane.showInputDialog(jContentPane,"Enter new directory name", "Create New Directory", JOptionPane.QUESTION_MESSAGE); + if(selectedTable.equals("remote")) + { + name = remoteLocation.getText()+name; +@@ -880,34 +1151,106 @@ + historyComboBox.setSelectedIndex(0); + } + } +- private void doClose() ++ public void doClose() + { ++ if (viewer.ftpOnly) { ++ viewer.disconnect(); ++ return; ++ } + try { + this.setVisible(false); +- viewer.rfb.writeFramebufferUpdateRequest( +- 0, +- 0, +- viewer.rfb.framebufferWidth, +- viewer.rfb.framebufferHeight, +- true); ++ viewer.rfb.writeFramebufferUpdateRequest(0, 0, viewer.rfb.framebufferWidth, ++ viewer.rfb.framebufferHeight, true); ++ ++ if (false) { ++ this.dispose(); ++ jContentPane = null; ++ } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } ++ private void unSwing() { ++ jContentPane = null; ++ topPanel = null; ++ topPanelLocal = null; ++ topPanelRemote = null; ++ topPanelCenter = null; ++ statusPanel = null; ++ remotePanel = null; ++ localPanel = null; ++ buttonPanel = null; ++ sendButton = null; ++ receiveButton = null; ++ deleteButton = null; ++ newFolderButton = null; ++ stopButton = null; ++ closeButton = null; ++ dummyButton = null; ++ localDrivesComboBox = null; ++ remoteDrivesComboBox = null; ++ localMachineLabel = null; ++ remoteMachineLabel = null; ++ localTopButton = null; ++ remoteTopButton = null; ++ localScrollPane = null; ++ localFileTable = null; ++ remoteScrollPane = null; ++ remoteFileTable = null; ++ remoteLocation = null; ++ localLocation = null; ++ localStatus = null; ++ remoteStatus = null; ++ historyComboBox = null; ++ jProgressBar = null; ++ connectionStatus = null; ++ viewButton = null; ++ refreshButton = null; ++ } ++ ++ public void doReset() ++ { ++ try { ++ this.setVisible(false); ++ this.dispose(); ++ jContentPane = null; ++ try {Thread.sleep(500);} catch (InterruptedException e) {} ++ viewer.ftp_init(); ++ } catch (Exception e) { ++ // TODO Auto-generated catch block ++ e.printStackTrace(); ++ } ++ } + ++ public void doOpen() ++ { ++ try { ++ this.setVisible(true); ++ if (false) { ++ this.initialize(); ++ } ++ } catch (Exception e) { ++ // TODO Auto-generated catch block ++ e.printStackTrace(); ++ } ++ } + private void doDelete() + { +- System.out.println("Delete Button Pressed"); ++// System.out.println("Delete Button Pressed"); + //Call this method to delete a file at server + if(selectedTable.equals("remote")) + { +- String sFileName = ((String) this.remoteFileTable.getSelectedValue()); ++ Object selected = this.remoteFileTable.getSelectedValue(); ++ if (selected == null) { ++ return; ++ } ++ String sFileName = ((String) selected); + + // sf@2004 - Directory can't be deleted + if (sFileName.substring(0, 2).equals(" [") && sFileName.substring((sFileName.length() - 1), sFileName.length()).equals("]")) + { +- JOptionPane.showMessageDialog(null, (String)"Directory Deletion is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE); ++ JOptionPane.showMessageDialog(jContentPane, (String)"Directory Deletion is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE); + return; + } + +@@ -916,7 +1259,7 @@ + // sf@2004 - Delete prompt + if (remoteList.contains(sFileName)) + { +- 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); ++ 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); + if (r == JOptionPane.NO_OPTION) + return; + } +@@ -926,18 +1269,22 @@ + } + else + { +- String sFileName = ((String) this.localFileTable.getSelectedValue()); ++ Object selected = this.localFileTable.getSelectedValue(); ++ if (selected == null) { ++ return; ++ } ++ String sFileName = ((String) selected); + + // sf@2004 - Directory can't be deleted + if (sFileName.substring(0, 2).equals(" [") && sFileName.substring((sFileName.length() - 1), sFileName.length()).equals("]")) + { +- JOptionPane.showMessageDialog(null, (String)"Directory Deletion is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE); ++ JOptionPane.showMessageDialog(jContentPane, (String)"Directory Deletion is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE); + return; + } + // sf@2004 - Delete prompt + if (localList.contains(sFileName)) + { +- 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); ++ 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); + if (r == JOptionPane.NO_OPTION) + return; + } +@@ -952,21 +1299,25 @@ + + private void doReceive() + { +- System.out.println("Received Button Pressed"); ++// System.out.println("Received Button Pressed"); + +- String sFileName = ((String) this.remoteFileTable.getSelectedValue()); ++ Object selected = this.remoteFileTable.getSelectedValue(); ++ if (selected == null) { ++ return; ++ } ++ String sFileName = ((String) selected); + + // sf@2004 - Directory can't be transfered + if (sFileName.substring(0, 2).equals(" [") && sFileName.substring((sFileName.length() - 1), sFileName.length()).equals("]")) + { +- JOptionPane.showMessageDialog(null, (String)"Directory Transfer is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE); ++ JOptionPane.showMessageDialog(jContentPane, (String)"Directory Transfer is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE); + return; + } + + // sf@2004 - Overwrite prompt + if (localList.contains(sFileName)) + { +- 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); ++ 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); + if (r == JOptionPane.NO_OPTION) + return; + } +@@ -979,23 +1330,101 @@ + viewer.rfb.requestRemoteFile(remoteFileName,localDestinationPath); + } + ++// begin runge/x11vnc ++ private void doRefresh() ++ { ++ System.out.println("Refreshing Local and Remote."); ++ refreshLocalLocation(); ++ refreshRemoteLocation(); ++ } ++ ++ private void doView() ++ { ++// System.out.println("View Button Pressed"); ++ ++ if (selectedTable == null) { ++ return; ++ } ++ if (selectedTable.equals("remote")) { ++ viewRemote(); ++ } else if (selectedTable.equals("local")) { ++ viewLocal(); ++ } ++ } ++ ++ private File doReceiveTmp() ++ { ++ ++ if (remoteFileTable == null) { ++ return null; ++ } ++ Object selected = this.remoteFileTable.getSelectedValue(); ++ if (selected == null) { ++ return null; ++ } ++ String sFileName = ((String) selected); ++ ++ if (sFileName == null) { ++ return null; ++ } ++ ++ // sf@2004 - Directory can't be transfered ++ if (sFileName.substring(0, 2).equals(" [") && sFileName.substring((sFileName.length() - 1), sFileName.length()).equals("]")) ++ { ++ return null; ++ } ++ ++ File tmp = null; ++ try { ++ tmp = File.createTempFile("ULTRAFTP", ".txt"); ++ } catch (Exception e) { ++ return null; ++ } ++ ++ //updateHistory("Downloaded " + localSelection.toString()); ++ String remoteFileName = this.remoteLocation.getText(); ++ remoteFileName+= ((String) this.remoteFileTable.getSelectedValue()).substring(1); ++ System.out.println("remoteFileName: " + remoteFileName); ++if (false) { ++ char[] b = remoteFileName.toCharArray(); ++ for (int n = 0; n < b.length; n++) { ++ System.out.print(Integer.toHexString(b[n]) + " "); ++ } ++ System.out.println(""); ++ for (int n = 0; n < b.length; n++) { ++ System.out.print(b[n]); ++ } ++ System.out.println(""); ++} ++ ++ String localDestinationPath = tmp.getAbsolutePath(); ++ viewer.rfb.requestRemoteFile(remoteFileName,localDestinationPath); ++ System.out.println("ReceiveTmp: " + localDestinationPath); ++ return tmp; ++ } ++// end runge/x11vnc ++ + private void doSend() + { +- System.out.println("Send Button Pressed"); ++// System.out.println("Send Button Pressed"); + +- String sFileName = ((String) this.localFileTable.getSelectedValue()); ++ Object selected = this.localFileTable.getSelectedValue(); ++ if (selected == null) { ++ return; ++ } ++ String sFileName = ((String) selected); + + // sf@2004 - Directory can't be transfered + if (sFileName.substring(0, 2).equals(" [") && sFileName.substring((sFileName.length() - 1), sFileName.length()).equals("]")) + { +- JOptionPane.showMessageDialog(null, (String)"Directory Transfer is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE); ++ JOptionPane.showMessageDialog(jContentPane, (String)"Directory Transfer is not yet available in this version...", "FileTransfer Info", JOptionPane.INFORMATION_MESSAGE); + return; + } + + // sf@2004 - Overwrite prompt + if (remoteList.contains(sFileName)) + { +- 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); ++ 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); + if (r == JOptionPane.NO_OPTION) + return; + } +@@ -1013,6 +1442,7 @@ + // + private void doStop() + { ++ System.out.println("** Current Transfer Aborted **"); + viewer.rfb.fAbort = true; + } + /** +@@ -1024,6 +1454,14 @@ + System.out.println("History: " + message); + historyComboBox.insertItemAt(new String(message), 0); + } ++ ++ public void receivedRemoteDirectoryName(String str) { ++ if (doingShortcutDir) { ++ if (str.length() > 1) { ++ remoteLocation.setText(str); ++ } ++ } ++ } + + /** + * This method updates the file table to the current selection of the remoteComboBox +@@ -1034,11 +1472,44 @@ + remoteSelection = null; + + if (!updateDriveList) { +- String drive = remoteDrivesComboBox.getSelectedItem().toString().substring(0,1)+ ":\\"; +- viewer.rfb.readServerDirectory(drive); +- remoteLocation.setText(drive); ++//System.out.println("changeRemoteDrive-A " + drive); // begin runge/x11vnc ++ Object selected = remoteDrivesComboBox.getSelectedItem(); ++ if (selected != null) { ++ String instr = selected.toString(); ++ if (instr != null) { ++System.out.println("changeRemoteDrive: instr='" + instr + "'"); ++ String drive = instr.substring(0,1)+ ":\\"; ++ if (instr.startsWith(" [")) { ++ int idx = instr.lastIndexOf(']'); ++ if (idx > 2) { ++ drive = instr.substring(2, idx); ++ } else { ++ drive = instr.substring(2); ++ } ++ if (drive.equals("Home")) { ++ drive = ""; ++ } ++ drive += "\\"; ++ doingShortcutDir = true; ++ } else { ++ doingShortcutDir = false; ++ drive = saveRemoteHack(drive); ++ } ++ gotShortcutDir = false; ++ viewer.rfb.readServerDirectory(drive); ++ if (!gotShortcutDir) { ++ remoteLocation.setText(drive); ++ } ++ } else { ++System.out.println("changeRemoteDrive: instr null"); ++ } ++ } else { ++System.out.println("changeRemoteDrive: selection null"); ++ } ++//System.out.println("changeRemoteDrive-B " + drive); // end runge/x11vnc + } + remoteList.clear(); ++ remoteListInfo.clear(); + remoteFileTable.setListData(remoteList); + } + /** +@@ -1048,6 +1519,7 @@ + private void changeLocalDrive() + { + File currentDrive = new File(localDrivesComboBox.getSelectedItem().toString()); ++System.out.println("changeLocalDrive " + currentDrive.toString()); // runge/x11vnc + if(currentDrive.canRead()) + { + localSelection = null; +@@ -1057,9 +1529,11 @@ + else + { + localList.clear(); ++ localListInfo.clear(); + localStatus.setText("WARNING: Drive " + localDrivesComboBox.getSelectedItem().toString()); + connectionStatus.setText(" > WARNING - Local Drive unavailable (possibly restricted access or media not present)"); + } ++ + } + /** + * Determines which FileTable was double-clicked and updates the table +@@ -1098,10 +1572,18 @@ + selectedTable = "remote"; + localFileTable.setBackground(new Color(238, 238, 238)); + remoteFileTable.setBackground(new Color(255, 255, 255)); +- String name = (remoteFileTable.getSelectedValue().toString()).substring(1); ++ Object selected = remoteFileTable.getSelectedValue(); ++ if (selected == null) { ++ return; ++ } ++ String selstr = selected.toString(); ++ if (selstr == null) { ++ return; ++ } ++ String name = selstr.substring(1); + if( !name.substring(0, 2).equals(" [")) + remoteSelection = remoteLocation.getText() + name.substring(0, name.length()); +- ++ + } + + /* +@@ -1115,10 +1597,38 @@ + localFileTable.setBackground(new Color(255, 255, 255)); + File currentSelection = new File(currentLocalDirectory, getTrimmedSelection()); + +- if(currentSelection.isFile()) ++// begin runge/x11vnc ++ // localSelection = currentSelection.getAbsoluteFile(); ++ if(currentSelection.isFile()) { + localSelection = currentSelection.getAbsoluteFile(); ++ localCurrentIsDir = false; ++ } else { ++ localCurrentIsDir = true; ++ } ++// end runge/x11vnc + + } ++ ++// begin runge/x11vnc ++ private void viewRemote() { ++ File tmp = doReceiveTmp(); ++ if (tmp == null) { ++ return; ++ } ++ TextViewer tv = new TextViewer("Remote: " + remoteSelection, tmp, true); ++ } ++ private void viewLocal() { ++ if (localSelection == null) { ++ return; ++ } ++ if (localCurrentIsDir) { ++ return; ++ } ++ File loc = new File(localSelection.toString()); ++ TextViewer tv = new TextViewer("Local: " + localSelection.toString(), loc, false); ++ } ++// end runge/x11vnc ++ + /** + * Updates the Remote File Table based on selection. Called from mouseClicked handler + */ +@@ -1126,20 +1636,29 @@ + String name = null; + String action = null; + String drive = null; +- name = (remoteFileTable.getSelectedValue().toString()).substring(1); ++ Object selected = remoteFileTable.getSelectedValue(); ++ if (selected == null) { ++ return; ++ } ++ String sname = selected.toString(); ++ if (sname == null) { ++ return; ++ } ++ name = sname.substring(1); + + if (name.equals("[..]")) + { + action = "up"; + remoteSelection = null; + drive = remoteLocation.getText().substring(0, remoteLocation.getText().length() - 1); +- // JOptionPane.showMessageDialog(null, (String)drive, "FileTransfer DEBUG", JOptionPane.INFORMATION_MESSAGE); ++ // JOptionPane.showMessageDialog(jContentPane, (String)drive, "FileTransfer DEBUG", JOptionPane.INFORMATION_MESSAGE); + int index = drive.lastIndexOf("\\"); + drive = drive.substring(0, index + 1); + + remoteLocation.setText(drive); + viewer.rfb.readServerDirectory(drive); + remoteList.clear(); ++ remoteListInfo.clear(); + remoteFileTable.setListData(remoteList); + } + else if (!name.substring(0, 2).equals(" [") && !name.substring((name.length() - 1), name.length()).equals("]")) +@@ -1149,6 +1668,7 @@ + remoteSelection = remoteLocation.getText() + name.substring(0, name.length()); + drive = remoteLocation.getText(); + // ?? ++ viewRemote(); // runge/x11vnc + } + else + { +@@ -1159,10 +1679,12 @@ + remoteLocation.setText(drive); + viewer.rfb.readServerDirectory(drive); + remoteList.clear(); ++ remoteListInfo.clear(); + remoteFileTable.setListData(remoteList); + } + //remoteLocation.setText(drive); + } ++ + /** + * Updates the Local File Table based on selection. Called from MouseClicked handler + */ +@@ -1188,6 +1710,7 @@ + else if (currentSelection.isFile()) + { + localSelection = currentSelection.getAbsoluteFile(); ++ viewLocal(); // runge/x11vnc + } + else if (currentSelection.isDirectory()) + { +@@ -1201,13 +1724,22 @@ + * + */ + private String getTrimmedSelection(){ +- String currentSelection = (localFileTable.getSelectedValue().toString()).substring(1); +- if(currentSelection.substring(0,1).equals("[") && +- currentSelection.substring(currentSelection.length()-1,currentSelection.length()).equals("]")){ +- return currentSelection.substring(1,currentSelection.length()-1); +- } else { +- return currentSelection; +- } ++ String currentSelection = ""; ++ Object selected = localFileTable.getSelectedValue(); ++ if (selected == null) { ++ return currentSelection; ++ } ++ String selstr = selected.toString(); ++ if (selstr == null) { ++ return currentSelection; ++ } ++ currentSelection = selstr.substring(1); ++ if(currentSelection.substring(0,1).equals("[") && ++ currentSelection.substring(currentSelection.length()-1,currentSelection.length()).equals("]")){ ++ return currentSelection.substring(1,currentSelection.length()-1); ++ } else { ++ return currentSelection; ++ } + } + + /* +@@ -1241,36 +1773,148 @@ + return null; + } + ++ String timeStr(long t) { ++ Date date = new Date(t); ++ return date.toString(); ++ } ++ String dotPast(double f, int n) { ++ String fs = "" + f; ++ int i = fs.lastIndexOf(".") + n; ++ if (i >= 0) { ++ int len = fs.length(); ++ if (i >= len) { ++ i = len-1; ++ } ++ fs = fs.substring(0, i); ++ } ++ return fs; ++ } ++ String sizeStr(int s) { ++ if (s < 0) { ++ return s + "? B"; ++ } else if (s < 1024) { ++ return s + " B"; ++ } else if (s < 1024 * 1024) { ++ double k = s / 1024.0; ++ String ks = dotPast(k, 3); ++ ++ return s + " (" + ks + " KB)"; ++ } else { ++ double m = s / (1024.0*1024.0); ++ String ms = dotPast(m, 3); ++ return s + " (" + ms + " MB)"; ++ } ++ } ++ ++ int max_char(String text) { ++ int maxc = 0; ++ char chars[] = text.toCharArray(); ++ for (int n = 0; n < chars.length; n++) { ++ if ((int) chars[n] > maxc) { ++ maxc = (int) chars[n]; ++ } ++ } ++ return maxc; ++ } + + /* + * Navigates the local file structure up or down one directory + */ + public void changeLocalDirectory(File dir) + { +- currentLocalDirectory = dir; // Updates Global ++ dir = saveLocalHack(dir); // runge/x11vnc ++ ++ if (dir == null) { ++ connectionStatus.setText("Error changing local directory."); ++ historyComboBox.insertItemAt(new String("> Error changing local directory."), 0); ++ historyComboBox.setSelectedIndex(0); ++ return; ++ } ++ + File allFiles[] = dir.listFiles(); // Reads files + String[] contents = dir.list(); + ++ if (contents == null || allFiles == null) { ++ connectionStatus.setText("Error changing local directory."); ++ historyComboBox.insertItemAt(new String("> Error changing local directory."), 0); ++ historyComboBox.setSelectedIndex(0); ++ return; ++ } ++ ++ currentLocalDirectory = dir; // Updates Global ++// begin runge/x11vnc ++System.out.println("changeLocalDirectory: " + dir.toString()); ++ if (contents != null) { ++ java.util.Arrays.sort(contents, String.CASE_INSENSITIVE_ORDER); ++ for (int i = 0; i < contents.length; i++) { ++ allFiles[i] = new File(dir, contents[i]); ++ } ++ } else { ++ return; ++ } ++// end runge/x11vnc ++ + localList.clear(); ++ localListInfo.clear(); + localList.addElement(" [..]"); ++ localListInfo.addElement(" [..]"); ++ ++ ArrayList DirInfo = new ArrayList(); ++ ArrayList FilInfo = new ArrayList(); ++ ++ Charset charset = Charset.forName("ISO-8859-1"); ++ CharsetDecoder decoder = charset.newDecoder(); ++ CharsetEncoder encoder = charset.newEncoder(); + + // Populate the Lists + for (int i = 0; i < contents.length; i++) + { +- if (allFiles[i].isDirectory()) ++ String f1 = contents[i]; ++ ++if (false) { ++ ++System.out.println("max_char: " + max_char(f1) + " " + f1); ++ if (max_char(f1) > 255) { ++ try { ++System.out.println("bbuf1"); ++ ByteBuffer bbuf = encoder.encode(CharBuffer.wrap(f1.toCharArray())); ++System.out.println("bbuf2"); ++ CharBuffer cbuf = decoder.decode(bbuf); ++System.out.println("bbuf3"); ++ f1 = cbuf.toString(); ++System.out.println("did bbuf: " + f1); ++ } catch (Exception e) { ++ ; ++ } ++ } ++} ++ ++ String f2 = f1; ++ if (f2.length() < 24) { ++ for (int ik = f2.length(); ik < 24; ik++) { ++ f2 = f2 + " "; ++ } ++ } ++ String s = f2 + " \tLastmod: " + timeStr(allFiles[i].lastModified()) + " \t\tSize: " + sizeStr((int) allFiles[i].length()); ++ if (allFiles[i].isDirectory()) { + // localList.addElement("[" + contents[i] + "]"); +- DirsList.add(" [" + contents[i] + "]"); // sf@2004 +- else +- { ++ DirsList.add(" [" + f1 + "]"); // sf@2004 ++ DirInfo.add(s); ++ } else { + // localList.addElement(contents[i]); +- FilesList.add(" " + contents[i]); // sf@2004 ++ FilesList.add(" " + f1); // sf@2004 ++ FilInfo.add(s); + } + } + // sf@2004 +- for (int i = 0; i < DirsList.size(); i++) ++ for (int i = 0; i < DirsList.size(); i++) { + localList.addElement(DirsList.get(i)); +- for (int i = 0; i < FilesList.size(); i++) ++ localListInfo.addElement(DirInfo.get(i)); ++ } ++ for (int i = 0; i < FilesList.size(); i++) { + localList.addElement(FilesList.get(i)); ++ localListInfo.addElement(FilInfo.get(i)); ++ } + + FilesList.clear(); + DirsList.clear(); +@@ -1296,3 +1940,147 @@ + } + + } // @jve:visual-info decl-index=0 visual-constraint="10,10" ++ ++// begin runge/x11vnc ++class TextViewer extends JFrame implements ActionListener { ++ ++ JTextArea textArea = new JTextArea(35, 80); ++ File file = null; ++ JButton refreshButton; ++ JButton dismissButton; ++ Timer tim = null; ++ int rcnt = 0; ++ int tms = 250; ++ boolean delete_it = false; ++ TextViewer me; ++ ++ public TextViewer(String s, File f, boolean d) { ++ ++ delete_it = d; ++ file = f; ++ me = this; ++ ++ JScrollPane scrollPane = new JScrollPane(textArea, ++ JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, ++ JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); ++ ++ textArea.setEditable(false); ++ textArea.setFont(new Font("Monospaced", Font.PLAIN, 12)); ++ ++ KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, InputEvent.SHIFT_MASK); ++ AbstractAction escapeAction = new AbstractAction() { ++ public void actionPerformed(ActionEvent actionEvent) { ++ cleanse(); ++ me.dispose(); ++ } ++ }; ++ textArea.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(stroke, "escapeAction"); ++ textArea.getInputMap().put(stroke, "escapeAction"); ++ textArea.getActionMap().put("escapeAction", escapeAction); ++ ++ refreshButton = new JButton(); ++ refreshButton.setText("Reload"); ++ refreshButton.setName("refreshButton"); ++ refreshButton.addActionListener(this); ++ ++ dismissButton = new JButton(); ++ dismissButton.setText("Dismiss"); ++ dismissButton.setName("dismissButton"); ++ dismissButton.addActionListener(this); ++ ++ JPanel buttons = new JPanel(); ++ buttons.setLayout(new BorderLayout()); ++ buttons.add(refreshButton, BorderLayout.WEST); ++ buttons.add(dismissButton, BorderLayout.EAST); ++ ++ JPanel content = new JPanel(); ++ content.setLayout(new BorderLayout()); ++ content.add(scrollPane, BorderLayout.CENTER); ++ content.add(buttons, BorderLayout.SOUTH); ++ ++ ActionListener tsk = new ActionListener() { ++ public void actionPerformed(ActionEvent evt) { ++ // System.out.println("tsk"); ++ refresh(); ++ } ++ }; ++ tim = new Timer(tms, tsk); ++ tim.start(); ++ ++ this.setContentPane(content); ++ this.setTitle("TextViewer - " + s); ++ this.pack(); ++ this.setVisible(true); ++ } ++ ++ private void refresh() { ++ ++ rcnt++; ++ if (rcnt * tms > 3000 && tim != null) { ++ tim.stop(); ++ tim = null; ++ } ++ BufferedReader input = null; ++ StringBuffer contents = new StringBuffer(); ++ try { ++ if (input == null) { ++ input = new BufferedReader(new FileReader(file)); ++ } ++ String line = null; ++ int i = 0; ++ while (( line = input.readLine()) != null) { ++ if (i == 0) { ++ // System.out.println("read"); ++ } ++ i++; ++ contents.append(line); ++ contents.append(System.getProperty("line.separator")); ++ } ++ } catch (Exception e) { ++ ; ++ } finally { ++ try { ++ if (input != null) { ++ input.close(); ++ input = null; ++ } ++ } catch (Exception e) { ++ ; ++ } ++ } ++ ++ textArea.setText(contents.toString()); ++ textArea.setCaretPosition(0); ++ } ++ ++ public void actionPerformed(ActionEvent evt) { ++ ++ if (evt.getSource() == refreshButton) { ++ refresh(); ++ } ++ if (evt.getSource() == dismissButton) { ++ cleanse(); ++ this.dispose(); ++ } ++ } ++ ++ private void cleanse() { ++ if (delete_it && file != null) { ++ try { ++ file.delete(); ++ file = null; ++ } catch (Exception e) { ++ ; ++ } ++ } ++ } ++ ++ protected void finalize() throws Throwable { ++ try { ++ cleanse(); ++ } finally { ++ super.finalize(); ++ } ++ } ++} ++// end runge/x11vnc +diff -Naur JavaViewer.orig/Makefile JavaViewer/Makefile +--- JavaViewer.orig/Makefile 2006-05-29 09:06:32.000000000 -0400 ++++ JavaViewer/Makefile 2010-05-18 20:53:32.000000000 -0400 +@@ -4,6 +4,7 @@ + + CP = cp + JC = javac ++JC_ARGS = -target 1.4 -source 1.4 + JAR = jar + ARCHIVE = VncViewer.jar + PAGES = index.vnc shared.vnc noshared.vnc hextile.vnc zlib.vnc tight.vnc +@@ -20,7 +21,7 @@ + all: $(CLASSES) $(ARCHIVE) + + $(CLASSES): $(SOURCES) +- $(JC) -O $(SOURCES) ++ $(JC) $(JC_ARGS) -O $(SOURCES) + + $(ARCHIVE): $(CLASSES) + $(JAR) cf $(ARCHIVE) $(CLASSES) +diff -Naur JavaViewer.orig/OptionsFrame.java JavaViewer/OptionsFrame.java +--- JavaViewer.orig/OptionsFrame.java 2005-11-21 18:50:16.000000000 -0500 ++++ JavaViewer/OptionsFrame.java 2007-05-13 22:18:30.000000000 -0400 +@@ -144,7 +144,10 @@ + choices[jpegQualityIndex].select("6"); + choices[cursorUpdatesIndex].select("Enable"); + choices[useCopyRectIndex].select("Yes"); +- choices[eightBitColorsIndex].select("64"); ++// begin runge/x11vnc ++// choices[eightBitColorsIndex].select("64"); ++ choices[eightBitColorsIndex].select("Full"); ++// end runge/x11vnc + choices[mouseButtonIndex].select("Normal"); + choices[viewOnlyIndex].select("No"); + choices[shareDesktopIndex].select("Yes"); +diff -Naur JavaViewer.orig/RfbProto.java JavaViewer/RfbProto.java +--- JavaViewer.orig/RfbProto.java 2006-05-24 15:14:40.000000000 -0400 ++++ JavaViewer/RfbProto.java 2010-11-30 22:13:58.000000000 -0500 +@@ -31,6 +31,7 @@ + import java.net.Socket; + import java.util.*; + import java.util.zip.*; ++import java.text.DateFormat; + + + class RfbProto { +@@ -86,8 +87,11 @@ + + // sf@2004 - FileTransfer part + ArrayList remoteDirsList; ++ ArrayList remoteDirsListInfo; + ArrayList remoteFilesList; ++ ArrayList remoteFilesListInfo; + ArrayList a; ++ ArrayList b; + boolean fFTInit = true; // sf@2004 + boolean fFTAllowed = true; + boolean fAbort = false; +@@ -199,6 +203,10 @@ + // playback. + int numUpdatesInSession; + ++// begin runge/x11vnc ++ int readServerDriveListCnt = -1; ++ long readServerDriveListTime = 0; ++// end runge/x11vnc + // + // Constructor. Make TCP connection to RFB server. + // +@@ -207,7 +215,27 @@ + viewer = v; + host = h; + port = p; +- sock = new Socket(host, port); ++// begin runge/x11vnc ++// sock = new Socket(host, port); ++ if (! viewer.disableSSL) { ++ System.out.println("new SSLSocketToMe"); ++ SSLSocketToMe ssl; ++ try { ++ ssl = new SSLSocketToMe(host, port, v); ++ } catch (Exception e) { ++ throw new IOException(e.getMessage()); ++ } ++ ++ try { ++ sock = ssl.connectSock(); ++ } catch (Exception es) { ++ throw new IOException(es.getMessage()); ++ } ++ } else { ++ sock = new Socket(host, port); ++ } ++// end runge/x11vnc ++ + is = + new DataInputStream( + new BufferedInputStream(sock.getInputStream(), 16384)); +@@ -215,9 +243,12 @@ + osw = new OutputStreamWriter(sock.getOutputStream()); + inDirectory2 = false; + a = new ArrayList(); ++ b = new ArrayList(); + // sf@2004 + remoteDirsList = new ArrayList(); ++ remoteDirsListInfo = new ArrayList(); + remoteFilesList = new ArrayList(); ++ remoteFilesListInfo = new ArrayList(); + + sendFileSource = ""; + } +@@ -420,7 +451,13 @@ + // + + int readServerMessageType() throws IOException { +- int msgType = is.readUnsignedByte(); ++ int msgType; ++ try { ++ msgType = is.readUnsignedByte(); ++ } catch (Exception e) { ++ viewer.disconnect(); ++ return -1; ++ } + + // If the session is being recorded: + if (rec != null) { +@@ -600,6 +637,7 @@ + contentParamT = is.readUnsignedByte(); + contentParamT = contentParamT << 8; + contentParam = contentParam | contentParamT; ++//System.out.println("FTM: contentType " + contentType + " contentParam " + contentParam); + if (contentType == rfbRDrivesList || contentType == rfbDirPacket) + { + readDriveOrDirectory(contentParam); +@@ -610,7 +648,7 @@ + } + else if (contentType == rfbFilePacket) + { +- receiveFileChunk(); ++ receiveFileChunk(); + } + else if (contentType == rfbEndOfFile) + { +@@ -618,6 +656,10 @@ + } + else if (contentType == rfbAbortFileTransfer) + { ++ System.out.println("rfbAbortFileTransfer: fFileReceptionRunning=" ++ + fFileReceptionRunning + " fAbort=" ++ + fAbort + " fFileReceptionError=" ++ + fFileReceptionError); + if (fFileReceptionRunning) + { + endOfReceiveFile(false); // Error +@@ -626,6 +668,11 @@ + { + // sf@2004 - Todo: Add TestPermission + // System.out.println("File Transfer Aborted!"); ++ ++ // runge: seems like we must at least read the remaining ++ // 8 bytes of the header, right? ++ int size = is.readInt(); ++ int length = is.readInt(); + } + + } +@@ -645,6 +692,7 @@ + { + System.out.println("ContentType: " + contentType); + } ++//System.out.println("FTM: done"); + } + + //Refactored from readRfbFileTransferMsg() +@@ -662,6 +710,7 @@ + + //Refactored from readRfbFileTransferMsg() + public void readDriveOrDirectory(int contentParam) throws IOException { ++//System.out.println("RDOD: " + contentParam + " " + inDirectory2); + if (contentParam == rfbADrivesList) + { + readFTPMsgDriveList(); +@@ -688,13 +737,21 @@ + + // Internally used. Write an Rfb message to the server + void writeRfbFileTransferMsg( +- int contentType, +- int contentParam, +- long size, // 0 : compression not supported - 1 : compression supported +- long length, +- String text) throws IOException ++ int contentType, ++ int contentParam, ++ long size, // 0 : compression not supported - 1 : compression supported ++ long length, ++ String text) throws IOException + { + byte b[] = new byte[12]; ++ byte byteArray[]; ++ ++ if (viewer.dsmActive) { ++ // need to send the rfbFileTransfer msg type twice for the plugin... ++ byte b2[] = new byte[1]; ++ b2[0] = (byte) rfbFileTransfer; ++ os.write(b2); ++ } + + b[0] = (byte) rfbFileTransfer; + b[1] = (byte) contentType; +@@ -702,7 +759,7 @@ + + byte by = 0; + long c = 0; +- length++; ++ + c = size & 0xFF000000; + by = (byte) (c >>> 24); + b[4] = by; +@@ -716,6 +773,32 @@ + by = (byte) c; + b[7] = by; + ++ if (text != null) { ++ byte byteArray0[] = text.getBytes(); ++ int maxc = max_char(text); ++ if (maxc > 255) { ++ System.out.println("writeRfbFileTransferMsg: using getBytes(\"UTF-8\")"); ++ byteArray0 = text.getBytes("UTF-8"); ++ } else if (maxc > 127) { ++ System.out.println("writeRfbFileTransferMsg: using getBytes(\"ISO-8859-1\")"); ++ byteArray0 = text.getBytes("ISO-8859-1"); ++ } ++ byteArray = new byte[byteArray0.length + 1]; ++ for (int i = 0; i < byteArray0.length; i++) { ++ byteArray[i] = byteArray0[i]; ++ } ++ byteArray[byteArray.length - 1] = 0; ++System.out.println("writeRfbFileTransferMsg: length: " + length + " -> byteArray.length: " + byteArray.length); ++ ++ // will equal length for ascii, ISO-8859-1, more for UTF-8 ++ length = byteArray.length; ++ ++ //length++; // used to not include null byte at end. ++ } else { ++ String moo = "moo"; ++ byteArray = moo.getBytes(); ++ } ++ + c = length & 0xFF000000; + by = (byte) (c >>> 24); + b[8] = by; +@@ -729,29 +812,91 @@ + by = (byte) c; + b[11] = by; + os.write(b); ++ ++//System.out.println("size: " + size + " length: " + length + " text: " + text); + + + if (text != null) + { +- byte byteArray[] = text.getBytes(); +- byte byteArray2[] = new byte[byteArray.length + 1]; +- for (int i = 0; i < byteArray.length; i++) { +- byteArray2[i] = byteArray[i]; ++ os.write(byteArray); ++ } ++ } ++ ++ int max_char(String text) { ++ int maxc = 0; ++ char chars[] = text.toCharArray(); ++ for (int n = 0; n < chars.length; n++) { ++ if ((int) chars[n] > maxc) { ++ maxc = (int) chars[n]; + } +- byteArray2[byteArray2.length - 1] = 0; +- os.write(byteArray2); + } +- ++ return maxc; + } + ++ String guess_encoding(char[] chars) { ++ boolean saw_high_char = false; ++ ++ for (int i = 0; i < chars.length; i++) { ++ if (chars[i] == '\0') { ++ break; ++ } ++ if (chars[i] >= 128) { ++ saw_high_char = true; ++ break; ++ } ++ } ++ if (!saw_high_char) { ++ return "ASCII"; ++ } ++ char prev = 1; ++ boolean valid_utf8 = true; ++ int n = 0; ++ for (int i = 0; i < chars.length; i++) { ++ if (chars[i] == '\0') { ++ break; ++ } ++ char c = chars[i]; ++ if (prev < 128 && c >= 128) { ++ if (c >> 5 == 0x6) { ++ n = 1; ++ } else if (c >> 4 == 0xe) { ++ n = 2; ++ } else if (c >> 3 == 0x1e) { ++ n = 3; ++ } else if (c >> 2 == 0x3e) { ++ n = 4; ++ } else { ++ valid_utf8 = false; ++ break; ++ } ++ } else { ++ if (n > 0) { ++ if (c < 128) { ++ valid_utf8 = false; ++ break; ++ } ++ n--; ++ } ++ } ++ ++ prev = c; ++ } ++ if (valid_utf8) { ++ return "UTF-8"; ++ } else { ++ return "ISO-8859-1"; ++ } ++ } ++ ++ + //Internally used. Write an rfb message to the server for sending files ONLY + int writeRfbFileTransferMsgForSendFile( +- int contentType, +- int contentParam, +- long size, +- long length, +- String source +- ) throws IOException ++ int contentType, ++ int contentParam, ++ long size, ++ long length, ++ String source ++ ) throws IOException + { + File f = new File(source); + fis = new FileInputStream(f); +@@ -768,50 +913,47 @@ + + while (bytesRead!=-1) + { +- counter += bytesRead; +- myDeflater.setInput(byteBuffer, 0, bytesRead); +- myDeflater.finish(); +- compressedSize = myDeflater.deflate(CompressionBuffer); +- myDeflater.reset(); +- // If the compressed data is larger than the original one, we're dealing with +- // already compressed data +- if (compressedSize > bytesRead) +- fCompress = false; +- this.writeRfbFileTransferMsg( +- contentType, +- contentParam, +- (fCompress ? 1 : 0), +- (fCompress ? compressedSize-1 : bytesRead-1), +- null +- ); +- // Todo: Test write error ! +- os.write( +- fCompress ? CompressionBuffer : byteBuffer, +- 0, +- fCompress ? compressedSize : bytesRead +- ); +- +- // Todo: test read error ! +- bytesRead = fis.read(byteBuffer); +- +- // viewer.ftp.connectionStatus.setText("Sent: "+ counter + " bytes of "+ f.length() + " bytes"); +- viewer.ftp.jProgressBar.setValue((int)((counter * 100) / f.length())); +- viewer.ftp.connectionStatus.setText(">>> Sending File: " + source + " - Size: " + f.length() + " bytes - Progress: " + ((counter * 100) / f.length()) + "%"); +- +- if (fAbort == true) +- { +- fAbort = false; +- fError = true; +- break; +- } +- try +- { +- Thread.sleep(5); +- } +- catch(InterruptedException e) +- { +- System.err.println("Interrupted"); +- } ++ counter += bytesRead; ++ myDeflater.setInput(byteBuffer, 0, bytesRead); ++ myDeflater.finish(); ++ compressedSize = myDeflater.deflate(CompressionBuffer); ++ myDeflater.reset(); ++ // If the compressed data is larger than the original one, we're dealing with ++ // already compressed data ++ if (compressedSize > bytesRead) ++ fCompress = false; ++ this.writeRfbFileTransferMsg( ++ contentType, ++ contentParam, ++ (fCompress ? 1 : 0), ++// RUNGE (fCompress ? compressedSize-1 : bytesRead-1), ++ (fCompress ? compressedSize : bytesRead), ++ null ++ ); ++ // Todo: Test write error ! ++ os.write(fCompress ? CompressionBuffer : byteBuffer, 0, fCompress ? compressedSize : bytesRead); ++ ++ // Todo: test read error ! ++ bytesRead = fis.read(byteBuffer); ++ ++ // viewer.ftp.connectionStatus.setText("Sent: "+ counter + " bytes of "+ f.length() + " bytes"); ++ viewer.ftp.jProgressBar.setValue((int)((counter * 100) / f.length())); ++ viewer.ftp.connectionStatus.setText(">>> Sending File: " + source + " - Size: " + f.length() + " bytes - Progress: " + ((counter * 100) / f.length()) + "%"); ++ ++ if (fAbort == true) ++ { ++ fAbort = false; ++ fError = true; ++ break; ++ } ++ try ++ { ++ Thread.sleep(5); ++ } ++ catch(InterruptedException e) ++ { ++ System.err.println("Interrupted"); ++ } + } + + writeRfbFileTransferMsg(fError ? rfbAbortFileTransfer : rfbEndOfFile, 0, 0, 0, null); +@@ -831,24 +973,30 @@ + { + System.out.print((char) is.readUnsignedByte()); + } ++ System.out.println(""); ++ ++ if (size == rfbRErrorCmd || size == -1) { ++ viewer.ftp.enableButtons(); ++ viewer.ftp.connectionStatus.setText("Remote file not available for writing."); ++ viewer.ftp.historyComboBox.insertItemAt(new String(" > Error - Remote file not available for writing."), 0); ++ viewer.ftp.historyComboBox.setSelectedIndex(0); ++ return; ++ } + +- int ret = writeRfbFileTransferMsgForSendFile( +- rfbFilePacket, +- 0, +- 0, +- 0, +- sendFileSource); ++ int ret = writeRfbFileTransferMsgForSendFile(rfbFilePacket, 0, 0, 0, sendFileSource); + + viewer.ftp.refreshRemoteLocation(); + if (ret != 1) + { + viewer.ftp.connectionStatus.setText(" > Error - File NOT sent"); +- viewer.ftp.historyComboBox.insertItemAt(new String(" > Error - File: <" + sendFileSource) + "> was not correctly sent (aborted by user or error)",0); ++ viewer.ftp.historyComboBox.insertItemAt(new String(" > Error - File: <" + sendFileSource) ++ + "> was not correctly sent (aborted or error). Data may still be buffered/in transit. Wait for remote listing...",0); + } + else + { + viewer.ftp.connectionStatus.setText(" > File sent"); +- viewer.ftp.historyComboBox.insertItemAt(new String(" > File: <" + sendFileSource) + "> was sent to Remote Machine",0); ++ viewer.ftp.historyComboBox.insertItemAt(new String(" > File: <" + sendFileSource) ++ + "> was sent to Remote Machine. Note: data may still be buffered/in transit. Wait for remote listing...",0); + } + viewer.ftp.historyComboBox.setSelectedIndex(0); + viewer.ftp.enableButtons(); +@@ -907,7 +1055,7 @@ + //Handles acknowledgement that the file has been deleted on the server + void deleteRemoteFileFeedback() throws IOException + { +- is.readInt(); ++ int ret = is.readInt(); + int length = is.readInt(); + String f = ""; + for (int i = 0; i < length; i++) +@@ -916,7 +1064,11 @@ + } + + viewer.ftp.refreshRemoteLocation(); +- viewer.ftp.historyComboBox.insertItemAt(new String(" > Deleted File On Remote Machine: " + f.substring(0, f.length()-1)),0); ++ if (ret == -1) { ++ viewer.ftp.historyComboBox.insertItemAt(new String(" > ERROR Could not Delete File On Remote Machine: "),0); ++ } else { ++ viewer.ftp.historyComboBox.insertItemAt(new String(" > Deleted File On Remote Machine: " + f.substring(0, f.length()-1)),0); ++ } + viewer.ftp.historyComboBox.setSelectedIndex(0); + } + +@@ -926,12 +1078,7 @@ + try + { + String temp = text; +- writeRfbFileTransferMsg( +- rfbCommand, +- rfbCFileDelete, +- 0, +- temp.length(), +- temp); ++ writeRfbFileTransferMsg(rfbCommand, rfbCFileDelete, 0, temp.length(), temp); + } + catch (IOException e) + { +@@ -943,7 +1090,7 @@ + // Handles acknowledgement that the directory has been created on the server + void createRemoteDirectoryFeedback() throws IOException + { +- is.readInt(); ++ int ret = is.readInt(); + int length = is.readInt(); + String f=""; + for (int i = 0; i < length; i++) +@@ -951,7 +1098,11 @@ + f += (char)is.readUnsignedByte(); + } + viewer.ftp.refreshRemoteLocation(); +- viewer.ftp.historyComboBox.insertItemAt(new String(" > Created Directory on Remote Machine: " + f.substring(0, f.length()-1)),0); ++ if (ret == -1) { ++ viewer.ftp.historyComboBox.insertItemAt(new String(" > ERROR Could not Create Directory on Remote Machine."),0); ++ } else { ++ viewer.ftp.historyComboBox.insertItemAt(new String(" > Created Directory on Remote Machine: " + f.substring(0, f.length()-1)),0); ++ } + viewer.ftp.historyComboBox.setSelectedIndex(0); + } + +@@ -961,12 +1112,7 @@ + try + { + String temp = text; +- writeRfbFileTransferMsg( +- rfbCommand, +- rfbCDirCreate, +- 0, +- temp.length(), +- temp); ++ writeRfbFileTransferMsg(rfbCommand, rfbCDirCreate, 0, temp.length(), temp); + } + catch (IOException e) + { +@@ -979,15 +1125,13 @@ + { + try + { ++//System.out.println("requestRemoteFile text: " + text); ++//System.out.println("requestRemoteFile leng: " + text.length()); + String temp = text; + receivePath = localPath; + +- writeRfbFileTransferMsg( +- rfbFileTransferRequest, +- 0, +- 1, // 0 : compression not supported - 1 : compression supported +- temp.length(), +- temp); ++ // 0 : compression not supported - 1 : compression supported ++ writeRfbFileTransferMsg(rfbFileTransferRequest, 0, 1, temp.length(), temp); + } + catch (IOException e) + { +@@ -1004,6 +1148,9 @@ + viewer.ftp.disableButtons(); + int size = is.readInt(); + int length = is.readInt(); ++ ++//System.out.println("receiveFileHeader size: " + size); ++//System.out.println("receiveFileHeader leng: " + length); + + String tempName = ""; + for (int i = 0; i < length; i++) +@@ -1011,6 +1158,15 @@ + tempName += (char) is.readUnsignedByte(); + } + ++ if (size == rfbRErrorCmd || size == -1) { ++ fFileReceptionRunning = false; ++ viewer.ftp.enableButtons(); ++ viewer.ftp.connectionStatus.setText("Remote file not available for reading."); ++ viewer.ftp.historyComboBox.insertItemAt(new String(" > Error - Remote file not available for reading."), 0); ++ viewer.ftp.historyComboBox.setSelectedIndex(0); ++ return; ++ } ++ + // sf@2004 - Read the high part of file size (not yet in rfbFileTransferMsg for + // backward compatibility reasons...) + int sizeH = is.readInt(); +@@ -1021,7 +1177,16 @@ + fileSize=0; + fileChunkCounter = 0; + String fileName = receivePath; +- fos = new FileOutputStream(fileName); ++ try { ++ fos = new FileOutputStream(fileName); ++ } catch (Exception e) { ++ fFileReceptionRunning = false; ++ writeRfbFileTransferMsg(rfbAbortFileTransfer, 0, 0, 0, null); ++ viewer.ftp.historyComboBox.insertItemAt(new String(" > ERROR opening Local File: <" + fileName ),0); ++ viewer.ftp.historyComboBox.setSelectedIndex(0); ++ viewer.ftp.enableButtons(); ++ return; ++ } + writeRfbFileTransferMsg(rfbFileHeader, 0, 0, 0, null); + } + +@@ -1085,7 +1250,13 @@ + fAbort = false; + fFileReceptionError = true; + writeRfbFileTransferMsg(rfbAbortFileTransfer, 0, 0, 0, null); +- ++ ++ //runge for use with x11vnc/libvncserver, no rfbAbortFileTransfer reply sent. ++ try {Thread.sleep(500);} catch (InterruptedException e) {} ++ viewer.ftp.enableButtons(); ++ viewer.ftp.refreshLocalLocation(); ++ viewer.ftp.connectionStatus.setText(" > Error - File NOT received"); ++ viewer.ftp.historyComboBox.insertItemAt(new String(" > Error - File: <" + receivePath + "> not correctly received from Remote Machine (aborted by user or error)") ,0); + } + // sf@2004 - For old FT protocole only + /* +@@ -1104,7 +1275,7 @@ + int length = is.readInt(); + fileSize=0; + fos.close(); +- ++ + viewer.ftp.refreshLocalLocation(); + if (fReceptionOk && !fFileReceptionError) + { +@@ -1132,12 +1303,7 @@ + try + { + String temp = text; +- writeRfbFileTransferMsg( +- rfbDirContentRequest, +- rfbRDirContent, +- 0, +- temp.length(), +- temp); ++ writeRfbFileTransferMsg(rfbDirContentRequest, rfbRDirContent, 0, temp.length(), temp); + } + catch (IOException e) + { +@@ -1197,11 +1363,80 @@ + str += temp; + } + } ++ // runge ++ viewer.ftp.receivedRemoteDirectoryName(str); + // viewer.ftp.changeRemoteDirectory(str); + + } + } + ++ int zogswap(int n) { ++ long l = n; ++ if (l < 0) { ++ l += 0x100000000L; ++ } ++ l = l & 0xFFFFFFFF; ++ l = (l >> 24) | ((l & 0x00ff0000) >> 8) | ((l & 0x0000ff00) << 8) | (l << 24); ++ return (int) l; ++ } ++ ++ int windozeToUnix(int L, int H) { ++ long L2 = zogswap(L); ++ long H2 = zogswap(H); ++ long unix = (H2 << 32) + L2; ++ unix -= 11644473600L * 10000000L; ++ unix /= 10000000L; ++ //System.out.println("unix time: " + unix + " H2: " + H2 + " L2: " + L2); ++ return (int) unix; ++ } ++ ++ String timeStr(int t, int h) { ++ if (h == 0) { ++ // x11vnc/libvncserver unix ++ t = zogswap(t); ++ } else { ++ // ultra (except if h==0 by chance) ++ t = windozeToUnix(t, h); ++ } ++ long tl = (long) t; ++ Date date = new Date(tl * 1000); ++ if (true) { ++ return date.toString(); ++ } else { ++ return DateFormat.getDateTimeInstance().format(date); ++ } ++ } ++ ++ String dotPast(double f, int n) { ++ String fs = "" + f; ++ int i = fs.lastIndexOf(".") + n; ++ if (i >= 0) { ++ int len = fs.length(); ++ if (i >= len) { ++ i = len-1; ++ } ++ fs = fs.substring(0, i); ++ } ++ return fs; ++ } ++ String sizeStr(int s) { ++ s = zogswap(s); ++ if (s < 0) { ++ return s + "? B"; ++ } else if (s < 1024) { ++ return s + " B"; ++ } else if (s < 1024 * 1024) { ++ double k = s / 1024.0; ++ String ks = dotPast(k, 3); ++ ++ return s + " (" + ks + " KB)"; ++ } else { ++ double m = s / (1024.0*1024.0); ++ String ms = dotPast(m, 3); ++ return s + " (" + ms + " MB)"; ++ } ++ } ++ + //Internally used to receive directory content from server + //Here, the server sends one file/directory with it's attributes + void readFTPMsgDirectoryListContent() throws IOException +@@ -1217,17 +1452,32 @@ + dwReserved0, + dwReserved1; + long ftCreationTime, ftLastAccessTime, ftLastWriteTime; ++ int ftCreationTimeL, ftLastAccessTimeL, ftLastWriteTimeL; ++ int ftCreationTimeH, ftLastAccessTimeH, ftLastWriteTimeH; + char cFileName, cAlternateFileName; + int length = 0; + is.readInt(); + length = is.readInt(); ++ ++ char[] chars = new char[4*length]; ++ int char_cnt = 0; ++ for (int i = 0; i < chars.length; i++) { ++ chars[i] = '\0'; ++ } ++ + dwFileAttributes = is.readInt(); + length -= 4; +- ftCreationTime = is.readLong(); ++ //ftCreationTime = is.readLong(); ++ ftCreationTimeL = is.readInt(); ++ ftCreationTimeH = is.readInt(); + length -= 8; +- ftLastAccessTime = is.readLong(); ++ //ftLastAccessTime = is.readLong(); ++ ftLastAccessTimeL = is.readInt(); ++ ftLastAccessTimeH = is.readInt(); + length -= 8; +- ftLastWriteTime = is.readLong(); ++ //ftLastWriteTime = is.readLong(); ++ ftLastWriteTimeL = is.readInt(); ++ ftLastWriteTimeH = is.readInt(); + length -= 8; + nFileSizeHigh = is.readInt(); + length -= 4; +@@ -1239,10 +1489,12 @@ + length -= 4; + cFileName = (char) is.readUnsignedByte(); + length--; ++ chars[char_cnt++] = cFileName; + while (cFileName != '\0') + { + fileName += cFileName; + cFileName = (char) is.readUnsignedByte(); ++ chars[char_cnt++] = cFileName; + length--; + } + cAlternateFileName = (char) is.readByte(); +@@ -1253,7 +1505,28 @@ + cAlternateFileName = (char) is.readUnsignedByte(); + length--; + } +- if (dwFileAttributes == 268435456 ++ String guessed = guess_encoding(chars); ++ if (!guessed.equals("ASCII")) { ++ System.out.println("guess: " + guessed + "\t" + fileName); ++ } ++ if (guessed.equals("UTF-8")) { ++ try { ++ byte[] bytes = new byte[char_cnt-1]; ++ for (int i=0; i < char_cnt-1; i++) { ++ bytes[i] = (byte) chars[i]; ++ } ++ String newstr = new String(bytes, "UTF-8"); ++ fileName = newstr; ++ } catch (Exception e) { ++ System.out.println("failed to convert bytes to UTF-8 based string"); ++ } ++ } ++ for (int i = 0; i < char_cnt; i++) { ++ //System.out.println("char[" + i + "]\t" + (int) chars[i]); ++ } ++ if (fileName.length() <= 0) { ++ ; ++ } else if (dwFileAttributes == 268435456 + || dwFileAttributes == 369098752 + || dwFileAttributes == 285212672 + || dwFileAttributes == 271056896 +@@ -1263,11 +1536,74 @@ + || dwFileAttributes == 369623040) + { + fileName = " [" + fileName + "]"; +- remoteDirsList.add(fileName); // sf@2004 +- } +- else +- { +- remoteFilesList.add(" " + fileName); // sf@2004 ++// begin runge/x11vnc ++// remoteDirsList.add(fileName); // sf@2004 ++ int i = -1; ++ String t1 = fileName.toLowerCase(); ++ for (int j = 0; j < remoteDirsList.size(); j++) { ++ String t = (String) remoteDirsList.get(j); ++ String t2 = t.toLowerCase(); ++ if (t1.compareTo(t2) < 0) { ++ i = j; ++ break; ++ } ++ } ++ //String s = "Lastmod: " + timeStr(ftLastWriteTimeL, ftLastWriteTimeH) + " " + fileName; ++ String f2 = fileName; ++ if (f2.length() < 24) { ++ for (int ik = f2.length(); ik < 24; ik++) { ++ f2 = f2 + " "; ++ } ++ } ++ String s = f2 + " \tLastmod: " + timeStr(ftLastWriteTimeL, ftLastWriteTimeH) + " \t\tSize: " + sizeStr(nFileSizeLow); ++ //s = fileName + " Lastmod: " + zogswap(ftLastWriteTimeL); ++ if (i >= 0) { ++ remoteDirsList.add(i, fileName); ++ remoteDirsListInfo.add(i, s); ++ } else { ++ remoteDirsList.add(fileName); ++ remoteDirsListInfo.add(s); ++ } ++// end runge/x11vnc ++ } else { ++// begin runge/x11vnc ++// remoteFilesList.add(" " + fileName); // sf@2004 ++ ++ fileName = " " + fileName; ++ int i = -1; ++ String t1 = fileName.toLowerCase(); ++ for (int j = 0; j < remoteFilesList.size(); j++) { ++ String t = (String) remoteFilesList.get(j); ++ String t2 = t.toLowerCase(); ++ if (t1.compareTo(t2) < 0) { ++ i = j; ++ break; ++ } ++ } ++ String f2 = fileName; ++ if (f2.length() < 24) { ++ for (int ik = f2.length(); ik < 24; ik++) { ++ f2 = f2 + " "; ++ } ++ } ++ ++if (false) { ++System.out.println("fileName: " + f2); ++System.out.println("ftLastWriteTimeL: " + ftLastWriteTimeL); ++System.out.println("ftLastWriteTimeH: " + ftLastWriteTimeH); ++System.out.println("nFileSizeLow: " + nFileSizeLow); ++} ++ ++ String s = f2 + " \tLastmod: " + timeStr(ftLastWriteTimeL, ftLastWriteTimeH) + " \t\tSize: " + sizeStr(nFileSizeLow); ++ //s = fileName + " Lastmod: " + ftLastWriteTimeL + "/" + zogswap(ftLastWriteTimeL) + " Size: " + nFileSizeLow + "/" + zogswap(nFileSizeLow); ++ if (i >= 0) { ++ remoteFilesList.add(i, fileName); ++ remoteFilesListInfo.add(i, s); ++ } else { ++ remoteFilesList.add(fileName); ++ remoteFilesListInfo.add(s); ++ } ++// end runge/x11vnc + } + + // a.add(fileName); +@@ -1282,14 +1618,32 @@ + + // sf@2004 + a.clear(); +- for (int i = 0; i < remoteDirsList.size(); i++) ++ b.clear(); ++ for (int i = 0; i < remoteDirsList.size(); i++) { + a.add(remoteDirsList.get(i)); +- for (int i = 0; i < remoteFilesList.size(); i++) ++ b.add(remoteDirsListInfo.get(i)); ++ } ++ for (int i = 0; i < remoteFilesList.size(); i++) { + a.add(remoteFilesList.get(i)); ++ ++ b.add(remoteFilesListInfo.get(i)); ++ } + remoteDirsList.clear(); ++ remoteDirsListInfo.clear(); + remoteFilesList.clear(); ++ remoteFilesListInfo.clear(); + +- viewer.ftp.printDirectory(a); ++// begin runge/x11vnc ++ // Hack for double listing at startup... probably libvncserver bug.. ++ readServerDriveListCnt++; ++ if (readServerDriveListCnt == 2) { ++ if (System.currentTimeMillis() - readServerDriveListTime < 2000) { ++//System.out.println("readServerDriveListCnt skip " + readServerDriveListCnt); ++ return; ++ } ++ } ++// end runge/x11vnc ++ viewer.ftp.printDirectory(a, b); + } + + //Internally used to signify the drive requested is not ready +@@ -1299,6 +1653,8 @@ + System.out.println("Remote Drive unavailable"); + viewer.ftp.connectionStatus.setText(" > WARNING - Remote Drive unavailable (possibly restricted access or media not present)"); + viewer.ftp.remoteStatus.setText("WARNING: Remote Drive unavailable"); ++ viewer.ftp.historyComboBox.insertItemAt(new String(" > WARNING: Remote Drive unavailable."), 0); ++ viewer.ftp.historyComboBox.setSelectedIndex(0); + } + + //Call this method to request the list of drives on the server. +@@ -1306,12 +1662,11 @@ + { + try + { +- viewer.rfb.writeRfbFileTransferMsg( +- RfbProto.rfbDirContentRequest, +- RfbProto.rfbRDrivesList, +- 0, +- 0, +- null); ++ viewer.rfb.writeRfbFileTransferMsg(RfbProto.rfbDirContentRequest, RfbProto.rfbRDrivesList, 0, 0, null); ++// begin runge/x11vnc ++ readServerDriveListCnt = 0; ++ readServerDriveListTime = System.currentTimeMillis(); ++// end runge/x11vnc + } + catch (IOException e) + { +@@ -1355,21 +1710,21 @@ + int h, + boolean incremental) + throws IOException { +- if (!viewer.ftp.isVisible()) { +- byte[] b = new byte[10]; ++ if (!viewer.ftp.isVisible()) { ++ byte[] b = new byte[10]; + +- b[0] = (byte) FramebufferUpdateRequest; +- b[1] = (byte) (incremental ? 1 : 0); +- b[2] = (byte) ((x >> 8) & 0xff); +- b[3] = (byte) (x & 0xff); +- b[4] = (byte) ((y >> 8) & 0xff); +- b[5] = (byte) (y & 0xff); +- b[6] = (byte) ((w >> 8) & 0xff); +- b[7] = (byte) (w & 0xff); +- b[8] = (byte) ((h >> 8) & 0xff); +- b[9] = (byte) (h & 0xff); ++ b[0] = (byte) FramebufferUpdateRequest; ++ b[1] = (byte) (incremental ? 1 : 0); ++ b[2] = (byte) ((x >> 8) & 0xff); ++ b[3] = (byte) (x & 0xff); ++ b[4] = (byte) ((y >> 8) & 0xff); ++ b[5] = (byte) (y & 0xff); ++ b[6] = (byte) ((w >> 8) & 0xff); ++ b[7] = (byte) (w & 0xff); ++ b[8] = (byte) ((h >> 8) & 0xff); ++ b[9] = (byte) (h & 0xff); + +- os.write(b); ++ os.write(b); + } + } + +@@ -1482,7 +1837,13 @@ + b[6] = (byte) ((text.length() >> 8) & 0xff); + b[7] = (byte) (text.length() & 0xff); + +- System.arraycopy(text.getBytes(), 0, b, 8, text.length()); ++ if (false && max_char(text) > 255) { ++ System.arraycopy(text.getBytes("UTF-8"), 0, b, 8, text.length()); ++ } else if (max_char(text) > 127) { ++ System.arraycopy(text.getBytes("ISO-8859-1"), 0, b, 8, text.length()); ++ } else { ++ System.arraycopy(text.getBytes(), 0, b, 8, text.length()); ++ } + + os.write(b); + // } +@@ -1506,6 +1867,37 @@ + final static int META_MASK = InputEvent.META_MASK; + final static int ALT_MASK = InputEvent.ALT_MASK; + ++ void writeWheelEvent(MouseWheelEvent evt) throws IOException { ++ eventBufLen = 0; ++ ++ int x = evt.getX(); ++ int y = evt.getY(); ++ ++ if (x < 0) x = 0; ++ if (y < 0) y = 0; ++ ++ int ptrmask; ++ ++ int clicks = evt.getWheelRotation(); ++ System.out.println("writeWheelEvent: clicks: " + clicks); ++ if (clicks > 0) { ++ ptrmask = 16; ++ } else if (clicks < 0) { ++ ptrmask = 8; ++ } else { ++ return; ++ } ++ ++ eventBuf[eventBufLen++] = (byte) PointerEvent; ++ eventBuf[eventBufLen++] = (byte) ptrmask; ++ eventBuf[eventBufLen++] = (byte) ((x >> 8) & 0xff); ++ eventBuf[eventBufLen++] = (byte) (x & 0xff); ++ eventBuf[eventBufLen++] = (byte) ((y >> 8) & 0xff); ++ eventBuf[eventBufLen++] = (byte) (y & 0xff); ++ ++ os.write(eventBuf, 0, eventBufLen); ++ } ++ + // + // Write a pointer event message. We may need to send modifier key events + // around it to set the correct modifier state. +@@ -1610,6 +2002,21 @@ + + boolean down = (evt.getID() == KeyEvent.KEY_PRESSED); + ++ if (viewer.debugKeyboard) { ++ System.out.println("----------------------------------------"); ++ System.out.println("evt.getKeyChar: " + evt.getKeyChar()); ++ System.out.println("getKeyText: " + KeyEvent.getKeyText(evt.getKeyCode())); ++ System.out.println("evt.getKeyCode: " + evt.getKeyCode()); ++ System.out.println("evt.getID: " + evt.getID()); ++ System.out.println("evt.getKeyLocation: " + evt.getKeyLocation()); ++ System.out.println("evt.isActionKey: " + evt.isActionKey()); ++ System.out.println("evt.isControlDown: " + evt.isControlDown()); ++ System.out.println("evt.getModifiers: " + evt.getModifiers()); ++ System.out.println("getKeyModifiersText: " + KeyEvent.getKeyModifiersText(evt.getModifiers())); ++ System.out.println("evt.paramString: " + evt.paramString()); ++ } ++ ++ + int key; + if (evt.isActionKey()) { + +@@ -1685,6 +2092,9 @@ + default : + return; + } ++ if (key == 0xffc2 && viewer.mapF5_to_atsign) { ++ key = 0x40; ++ } + + } else { + +@@ -1794,6 +2204,16 @@ + int oldModifiers = 0; + + void writeModifierKeyEvents(int newModifiers) { ++ if(viewer.forbid_Ctrl_Alt) { ++ if ((newModifiers & CTRL_MASK) != 0 && (newModifiers & ALT_MASK) != 0) { ++ int orig = newModifiers; ++ newModifiers &= ~ALT_MASK; ++ newModifiers &= ~CTRL_MASK; ++ if (viewer.debugKeyboard) { ++ System.out.println("Ctrl+Alt modifiers: " + orig + " -> " + newModifiers); ++ } ++ } ++ } + if ((newModifiers & CTRL_MASK) != (oldModifiers & CTRL_MASK)) + writeKeyEvent(0xffe3, (newModifiers & CTRL_MASK) != 0); + +diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java +--- JavaViewer.orig/SSLSocketToMe.java 1969-12-31 19:00:00.000000000 -0500 ++++ JavaViewer/SSLSocketToMe.java 2010-07-10 19:18:06.000000000 -0400 +@@ -0,0 +1,2067 @@ ++/* ++ * SSLSocketToMe.java: add SSL encryption to Java VNC Viewer. ++ * ++ * Copyright (c) 2006 Karl J. Runge <runge@karlrunge.com> ++ * All rights reserved. ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ * ++ */ ++ ++import java.net.*; ++import java.io.*; ++import javax.net.ssl.*; ++import java.util.*; ++ ++import java.security.*; ++import java.security.cert.*; ++import java.security.spec.*; ++import java.security.cert.Certificate; ++import java.security.cert.CertificateFactory; ++ ++import java.awt.*; ++import java.awt.event.*; ++ ++public class SSLSocketToMe { ++ ++ /* basic member data: */ ++ String host; ++ int port; ++ VncViewer viewer; ++ ++ boolean debug = true; ++ boolean debug_certs = false; ++ ++ /* sockets */ ++ SSLSocket socket = null; ++ SSLSocketFactory factory; ++ ++ /* fallback for Proxy connection */ ++ boolean proxy_in_use = false; ++ boolean proxy_failure = false; ++ public DataInputStream is = null; ++ public OutputStream os = null; ++ ++ /* strings from user WRT proxy: */ ++ String proxy_auth_string = null; ++ String proxy_dialog_host = null; ++ int proxy_dialog_port = 0; ++ ++ Socket proxySock; ++ DataInputStream proxy_is; ++ OutputStream proxy_os; ++ ++ /* trust contexts */ ++ SSLContext trustloc_ctx; ++ SSLContext trustall_ctx; ++ SSLContext trustsrv_ctx; ++ SSLContext trusturl_ctx; ++ SSLContext trustone_ctx; ++ ++ /* corresponding trust managers */ ++ TrustManager[] trustAllCerts; ++ TrustManager[] trustSrvCert; ++ TrustManager[] trustUrlCert; ++ TrustManager[] trustOneCert; ++ ++ /* client-side SSL auth key (oneTimeKey=...) */ ++ KeyManager[] mykey = null; ++ ++ boolean user_wants_to_see_cert = true; ++ String cert_fail = null; ++ ++ /* cert(s) we retrieve from Web server, VNC server, or serverCert param: */ ++ java.security.cert.Certificate[] trustallCerts = null; ++ java.security.cert.Certificate[] trustsrvCerts = null; ++ java.security.cert.Certificate[] trusturlCerts = null; ++ ++ /* utility to decode hex oneTimeKey=... and serverCert=... */ ++ byte[] hex2bytes(String s) { ++ byte[] bytes = new byte[s.length()/2]; ++ for (int i=0; i<s.length()/2; i++) { ++ int j = 2*i; ++ try { ++ int val = Integer.parseInt(s.substring(j, j+2), 16); ++ if (val > 127) { ++ val -= 256; ++ } ++ Integer I = new Integer(val); ++ bytes[i] = Byte.decode(I.toString()).byteValue(); ++ ++ } catch (Exception e) { ++ ; ++ } ++ } ++ return bytes; ++ } ++ ++ SSLSocketToMe(String h, int p, VncViewer v) throws Exception { ++ host = h; ++ port = p; ++ viewer = v; ++ ++ debug_certs = v.debugCerts; ++ ++ /* we will first try default factory for certification: */ ++ ++ factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); ++ ++ dbg("SSL startup: " + host + " " + port); ++ ++ ++ /* create trust managers to be used if initial handshake fails: */ ++ ++ trustAllCerts = new TrustManager[] { ++ /* ++ * this one accepts everything. Only used if user ++ * has disabled checking (trustAllVncCerts=yes) ++ * or when we grab the cert to show it to them in ++ * a dialog and ask them to manually verify/accept it. ++ */ ++ new X509TrustManager() { ++ public java.security.cert.X509Certificate[] ++ getAcceptedIssuers() { ++ return null; ++ } ++ public void checkClientTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) { ++ /* empty */ ++ } ++ public void checkServerTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) { ++ /* empty */ ++ dbg("ALL: an untrusted connect to grab cert."); ++ } ++ } ++ }; ++ ++ trustUrlCert = new TrustManager[] { ++ /* ++ * this one accepts only the retrieved server ++ * cert by SSLSocket by this applet and stored in ++ * trusturlCerts. ++ */ ++ new X509TrustManager() { ++ public java.security.cert.X509Certificate[] ++ getAcceptedIssuers() { ++ return null; ++ } ++ public void checkClientTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ throw new CertificateException("No Clients (URL)"); ++ } ++ public void checkServerTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ /* we want to check 'certs' against 'trusturlCerts' */ ++ if (trusturlCerts == null) { ++ throw new CertificateException( ++ "No Trust url Certs array."); ++ } ++ if (trusturlCerts.length < 1) { ++ throw new CertificateException( ++ "No Trust url Certs."); ++ } ++ if (certs == null) { ++ throw new CertificateException( ++ "No this-certs array."); ++ } ++ if (certs.length < 1) { ++ throw new CertificateException( ++ "No this-certs Certs."); ++ } ++ if (certs.length != trusturlCerts.length) { ++ throw new CertificateException( ++ "certs.length != trusturlCerts.length " + certs.length + " " + trusturlCerts.length); ++ } ++ boolean ok = true; ++ for (int i = 0; i < certs.length; i++) { ++ if (! trusturlCerts[i].equals(certs[i])) { ++ ok = false; ++ dbg("URL: cert mismatch at i=" + i); ++ dbg("URL: cert mismatch cert" + certs[i]); ++ dbg("URL: cert mismatch url" + trusturlCerts[i]); ++ if (cert_fail == null) { ++ cert_fail = "cert-mismatch"; ++ } ++ } ++ if (debug_certs) { ++ dbg("\n***********************************************"); ++ dbg("URL: cert info at i=" + i); ++ dbg("URL: cert info cert" + certs[i]); ++ dbg("==============================================="); ++ dbg("URL: cert info url" + trusturlCerts[i]); ++ dbg("***********************************************"); ++ } ++ } ++ if (!ok) { ++ throw new CertificateException( ++ "Server Cert Chain != URL Cert Chain."); ++ } ++ dbg("URL: trusturlCerts[i] matches certs[i] i=0:" + (certs.length-1)); ++ } ++ } ++ }; ++ ++ trustSrvCert = new TrustManager[] { ++ /* ++ * this one accepts cert given to us in the serverCert ++ * Applet Parameter we were started with. It is ++ * currently a fatal error if the VNC Server's cert ++ * doesn't match it. ++ */ ++ new X509TrustManager() { ++ public java.security.cert.X509Certificate[] ++ getAcceptedIssuers() { ++ return null; ++ } ++ public void checkClientTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ throw new CertificateException("No Clients (SRV)"); ++ } ++ public void checkServerTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ /* we want to check 'certs' against 'trustsrvCerts' */ ++ if (trustsrvCerts == null) { ++ throw new CertificateException( ++ "No Trust srv Certs array."); ++ } ++ if (trustsrvCerts.length < 1) { ++ throw new CertificateException( ++ "No Trust srv Certs."); ++ } ++ if (certs == null) { ++ throw new CertificateException( ++ "No this-certs array."); ++ } ++ if (certs.length < 1) { ++ throw new CertificateException( ++ "No this-certs Certs."); ++ } ++ if (certs.length != trustsrvCerts.length) { ++ throw new CertificateException( ++ "certs.length != trustsrvCerts.length " + certs.length + " " + trustsrvCerts.length); ++ } ++ boolean ok = true; ++ for (int i = 0; i < certs.length; i++) { ++ if (! trustsrvCerts[i].equals(certs[i])) { ++ ok = false; ++ dbg("SRV: cert mismatch at i=" + i); ++ dbg("SRV: cert mismatch cert" + certs[i]); ++ dbg("SRV: cert mismatch srv" + trustsrvCerts[i]); ++ if (cert_fail == null) { ++ cert_fail = "server-cert-mismatch"; ++ } ++ } ++ if (debug_certs) { ++ dbg("\n***********************************************"); ++ dbg("SRV: cert info at i=" + i); ++ dbg("SRV: cert info cert" + certs[i]); ++ dbg("==============================================="); ++ dbg("SRV: cert info srv" + trustsrvCerts[i]); ++ dbg("***********************************************"); ++ } ++ } ++ if (!ok) { ++ throw new CertificateException( ++ "Server Cert Chain != serverCert Applet Parameter Cert Chain."); ++ } ++ dbg("SRV: trustsrvCerts[i] matches certs[i] i=0:" + (certs.length-1)); ++ } ++ } ++ }; ++ ++ trustOneCert = new TrustManager[] { ++ /* ++ * this one accepts only the retrieved server ++ * cert by SSLSocket by this applet we stored in ++ * trustallCerts that user has accepted or applet ++ * parameter trustAllVncCerts=yes is set. This is ++ * for when we reconnect after the user has manually ++ * accepted the trustall cert in the dialog (or set ++ * trustAllVncCerts=yes applet param.) ++ */ ++ new X509TrustManager() { ++ public java.security.cert.X509Certificate[] ++ getAcceptedIssuers() { ++ return null; ++ } ++ public void checkClientTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ throw new CertificateException("No Clients (ONE)"); ++ } ++ public void checkServerTrusted( ++ java.security.cert.X509Certificate[] certs, ++ String authType) throws CertificateException { ++ /* we want to check 'certs' against 'trustallCerts' */ ++ if (trustallCerts == null) { ++ throw new CertificateException( ++ "No Trust All Server Certs array."); ++ } ++ if (trustallCerts.length < 1) { ++ throw new CertificateException( ++ "No Trust All Server Certs."); ++ } ++ if (certs == null) { ++ throw new CertificateException( ++ "No this-certs array."); ++ } ++ if (certs.length < 1) { ++ throw new CertificateException( ++ "No this-certs Certs."); ++ } ++ if (certs.length != trustallCerts.length) { ++ throw new CertificateException( ++ "certs.length != trustallCerts.length " + certs.length + " " + trustallCerts.length); ++ } ++ boolean ok = true; ++ for (int i = 0; i < certs.length; i++) { ++ if (! trustallCerts[i].equals(certs[i])) { ++ ok = false; ++ dbg("ONE: cert mismatch at i=" + i); ++ dbg("ONE: cert mismatch cert" + certs[i]); ++ dbg("ONE: cert mismatch all" + trustallCerts[i]); ++ } ++ if (debug_certs) { ++ dbg("\n***********************************************"); ++ dbg("ONE: cert info at i=" + i); ++ dbg("ONE: cert info cert" + certs[i]); ++ dbg("==============================================="); ++ dbg("ONE: cert info all" + trustallCerts[i]); ++ dbg("***********************************************"); ++ } ++ } ++ if (!ok) { ++ throw new CertificateException( ++ "Server Cert Chain != TRUSTALL Cert Chain."); ++ } ++ dbg("ONE: trustallCerts[i] matches certs[i] i=0:" + (certs.length-1)); ++ } ++ } ++ }; ++ ++ /* ++ * The above TrustManagers are used: ++ * ++ * 1) to retrieve the server cert in case of failure to ++ * display it to the user in a dialog. ++ * 2) to subsequently connect to the server if user agrees. ++ */ ++ ++ /* ++ * build oneTimeKey cert+key if supplied in applet parameter: ++ */ ++ if (viewer.oneTimeKey != null && viewer.oneTimeKey.equals("PROMPT")) { ++ ClientCertDialog d = new ClientCertDialog(); ++ viewer.oneTimeKey = d.queryUser(); ++ } ++ if (viewer.oneTimeKey != null && viewer.oneTimeKey.indexOf(",") > 0) { ++ int idx = viewer.oneTimeKey.indexOf(","); ++ ++ String onetimekey = viewer.oneTimeKey.substring(0, idx); ++ byte[] key = hex2bytes(onetimekey); ++ String onetimecert = viewer.oneTimeKey.substring(idx+1); ++ byte[] cert = hex2bytes(onetimecert); ++ ++ KeyFactory kf = KeyFactory.getInstance("RSA"); ++ PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key ); ++ PrivateKey ff = kf.generatePrivate (keysp); ++ if (debug_certs) { ++ dbg("one time key " + ff); ++ } ++ ++ CertificateFactory cf = CertificateFactory.getInstance("X.509"); ++ Collection c = cf.generateCertificates(new ByteArrayInputStream(cert)); ++ Certificate[] certs = new Certificate[c.toArray().length]; ++ if (c.size() == 1) { ++ Certificate tmpcert = cf.generateCertificate(new ByteArrayInputStream(cert)); ++ if (debug_certs) { ++ dbg("one time cert" + tmpcert); ++ } ++ certs[0] = tmpcert; ++ } else { ++ certs = (Certificate[]) c.toArray(); ++ } ++ ++ KeyStore ks = KeyStore.getInstance("JKS"); ++ ks.load(null, null); ++ ks.setKeyEntry("onetimekey", ff, "".toCharArray(), certs); ++ String da = KeyManagerFactory.getDefaultAlgorithm(); ++ KeyManagerFactory kmf = KeyManagerFactory.getInstance(da); ++ kmf.init(ks, "".toCharArray()); ++ ++ mykey = kmf.getKeyManagers(); ++ } ++ ++ /* ++ * build serverCert cert if supplied in applet parameter: ++ */ ++ if (viewer.serverCert != null) { ++ CertificateFactory cf = CertificateFactory.getInstance("X.509"); ++ byte[] cert = hex2bytes(viewer.serverCert); ++ Collection c = cf.generateCertificates(new ByteArrayInputStream(cert)); ++ trustsrvCerts = new Certificate[c.toArray().length]; ++ if (c.size() == 1) { ++ Certificate tmpcert = cf.generateCertificate(new ByteArrayInputStream(cert)); ++ trustsrvCerts[0] = tmpcert; ++ } else { ++ trustsrvCerts = (Certificate[]) c.toArray(); ++ } ++ } ++ ++ /* the trust loc certs context: */ ++ try { ++ trustloc_ctx = SSLContext.getInstance("SSL"); ++ ++ /* ++ * below is a failed attempt to get jvm's default ++ * trust manager using null (below) makes it so ++ * for HttpsURLConnection the server cannot be ++ * verified (no prompting.) ++ */ ++ if (false) { ++ boolean didit = false; ++ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); ++ tmf.init((KeyStore) null); ++ TrustManager [] tml = tmf.getTrustManagers(); ++ for (int i = 0; i < tml.length; i++) { ++ TrustManager tm = tml[i]; ++ if (tm instanceof X509TrustManager) { ++ TrustManager tm1[] = new TrustManager[1]; ++ tm1[0] = tm; ++ trustloc_ctx.init(mykey, tm1, null); ++ didit = true; ++ break; ++ } ++ } ++ if (!didit) { ++ trustloc_ctx.init(mykey, null, null); ++ } ++ } else { ++ /* we have to set trust manager to null */ ++ trustloc_ctx.init(mykey, null, null); ++ } ++ ++ } catch (Exception e) { ++ String msg = "SSL trustloc_ctx FAILED."; ++ dbg(msg); ++ throw new Exception(msg); ++ } ++ ++ /* the trust all certs context: */ ++ try { ++ trustall_ctx = SSLContext.getInstance("SSL"); ++ trustall_ctx.init(mykey, trustAllCerts, new ++ java.security.SecureRandom()); ++ ++ } catch (Exception e) { ++ String msg = "SSL trustall_ctx FAILED."; ++ dbg(msg); ++ throw new Exception(msg); ++ } ++ ++ /* the trust url certs context: */ ++ try { ++ trusturl_ctx = SSLContext.getInstance("SSL"); ++ trusturl_ctx.init(mykey, trustUrlCert, new ++ java.security.SecureRandom()); ++ ++ } catch (Exception e) { ++ String msg = "SSL trusturl_ctx FAILED."; ++ dbg(msg); ++ throw new Exception(msg); ++ } ++ ++ /* the trust srv certs context: */ ++ try { ++ trustsrv_ctx = SSLContext.getInstance("SSL"); ++ trustsrv_ctx.init(mykey, trustSrvCert, new ++ java.security.SecureRandom()); ++ ++ } catch (Exception e) { ++ String msg = "SSL trustsrv_ctx FAILED."; ++ dbg(msg); ++ throw new Exception(msg); ++ } ++ ++ /* the trust the one cert from server context: */ ++ try { ++ trustone_ctx = SSLContext.getInstance("SSL"); ++ trustone_ctx.init(mykey, trustOneCert, new ++ java.security.SecureRandom()); ++ ++ } catch (Exception e) { ++ String msg = "SSL trustone_ctx FAILED."; ++ dbg(msg); ++ throw new Exception(msg); ++ } ++ } ++ ++ /* ++ * we call this early on to 1) check for a proxy, 2) grab ++ * Browser/JVM accepted HTTPS cert. ++ */ ++ public void check_for_proxy_and_grab_vnc_server_cert() { ++ ++ trusturlCerts = null; ++ proxy_in_use = false; ++ ++ if (viewer.ignoreProxy) { ++ /* applet param says skip it. */ ++ /* the downside is we do not set trusturlCerts for comparison later... */ ++ /* nor do we autodetect x11vnc for GET=1. */ ++ return; ++ } ++ ++ dbg("------------------------------------------------"); ++ dbg("Into check_for_proxy_and_grab_vnc_server_cert():"); ++ ++ dbg("TRYING HTTPS:"); ++ String ustr = "https://" + host + ":"; ++ if (viewer.httpsPort != null) { ++ ustr += viewer.httpsPort; ++ } else { ++ ustr += port; ++ } ++ ustr += viewer.urlPrefix + "/check.https.proxy.connection"; ++ dbg("ustr is: " + ustr); ++ ++ try { ++ /* prepare for an HTTPS URL connection to host:port */ ++ URL url = new URL(ustr); ++ HttpsURLConnection https = (HttpsURLConnection) url.openConnection(); ++ ++ if (mykey != null) { ++ /* with oneTimeKey (mykey) we can't use the default SSL context */ ++ if (trustsrvCerts != null) { ++ dbg("passing trustsrv_ctx to HttpsURLConnection to provide client cert."); ++ https.setSSLSocketFactory(trustsrv_ctx.getSocketFactory()); ++ } else if (trustloc_ctx != null) { ++ dbg("passing trustloc_ctx to HttpsURLConnection to provide client cert."); ++ https.setSSLSocketFactory(trustloc_ctx.getSocketFactory()); ++ } ++ } ++ ++ https.setUseCaches(false); ++ https.setRequestMethod("GET"); ++ https.setRequestProperty("Pragma", "No-Cache"); ++ https.setRequestProperty("Proxy-Connection", "Keep-Alive"); ++ https.setDoInput(true); ++ ++ dbg("trying https.connect()"); ++ https.connect(); ++ ++ dbg("trying https.getServerCertificates()"); ++ trusturlCerts = https.getServerCertificates(); ++ ++ if (trusturlCerts == null) { ++ dbg("set trusturlCerts to null!"); ++ } else { ++ dbg("set trusturlCerts to non-null"); ++ } ++ ++ if (https.usingProxy()) { ++ proxy_in_use = true; ++ dbg("An HTTPS proxy is in use. There may be connection problems."); ++ } ++ ++ dbg("trying https.getContent()"); ++ Object output = https.getContent(); ++ dbg("trying https.disconnect()"); ++ https.disconnect(); ++ if (! viewer.GET) { ++ String header = https.getHeaderField("VNC-Server"); ++ if (header != null && header.startsWith("x11vnc")) { ++ dbg("detected x11vnc server (1), setting GET=1"); ++ viewer.GET = true; ++ } ++ } ++ ++ } catch(Exception e) { ++ dbg("HttpsURLConnection: " + e.getMessage()); ++ } ++ ++ if (proxy_in_use) { ++ dbg("exit check_for_proxy_and_grab_vnc_server_cert():"); ++ dbg("------------------------------------------------"); ++ return; ++ } else if (trusturlCerts != null && !viewer.forceProxy) { ++ /* Allow user to require HTTP check? use forceProxy for now. */ ++ dbg("SKIPPING HTTP PROXY CHECK: got trusturlCerts, assuming proxy info is correct."); ++ dbg("exit check_for_proxy_and_grab_vnc_server_cert():"); ++ dbg("------------------------------------------------"); ++ return; ++ } ++ ++ /* ++ * XXX need to remember scenario where this extra check ++ * gives useful info. User's Browser proxy settings? ++ */ ++ dbg("TRYING HTTP:"); ++ ustr = "http://" + host + ":" + port; ++ ustr += viewer.urlPrefix + "/index.vnc"; ++ dbg("ustr is: " + ustr); ++ ++ try { ++ /* prepare for an HTTP URL connection to the same host:port (but not httpsPort) */ ++ URL url = new URL(ustr); ++ HttpURLConnection http = (HttpURLConnection) ++ url.openConnection(); ++ ++ http.setUseCaches(false); ++ http.setRequestMethod("GET"); ++ http.setRequestProperty("Pragma", "No-Cache"); ++ http.setRequestProperty("Proxy-Connection", "Keep-Alive"); ++ http.setDoInput(true); ++ ++ dbg("trying http.connect()"); ++ http.connect(); ++ ++ if (http.usingProxy()) { ++ proxy_in_use = true; ++ dbg("An HTTP proxy is in use. There may be connection problems."); ++ } ++ dbg("trying http.getContent()"); ++ Object output = http.getContent(); ++ dbg("trying http.disconnect()"); ++ http.disconnect(); ++ if (! viewer.GET) { ++ String header = http.getHeaderField("VNC-Server"); ++ if (header != null && header.startsWith("x11vnc")) { ++ dbg("detected x11vnc server (2), setting GET=1"); ++ viewer.GET = true; ++ } ++ } ++ } catch(Exception e) { ++ dbg("HttpURLConnection: " + e.getMessage()); ++ } ++ dbg("exit check_for_proxy_and_grab_vnc_server_cert():"); ++ dbg("------------------------------------------------"); ++ } ++ ++ public Socket connectSock() throws IOException { ++ /* ++ * first try a https connection to detect a proxy, and ++ * grab the VNC server cert at the same time: ++ */ ++ check_for_proxy_and_grab_vnc_server_cert(); ++ ++ boolean srv_cert = false; ++ ++ if (trustsrvCerts != null) { ++ /* applet parameter suppled serverCert */ ++ dbg("viewer.trustSrvCert-0 using trustsrv_ctx"); ++ factory = trustsrv_ctx.getSocketFactory(); ++ srv_cert = true; ++ } else if (viewer.trustAllVncCerts) { ++ /* trust all certs (no checking) */ ++ dbg("viewer.trustAllVncCerts-0 using trustall_ctx"); ++ factory = trustall_ctx.getSocketFactory(); ++ } else if (trusturlCerts != null) { ++ /* trust certs the Browser/JVM accepted in check_for_proxy... */ ++ dbg("using trusturl_ctx"); ++ factory = trusturl_ctx.getSocketFactory(); ++ } else { ++ /* trust the local defaults */ ++ dbg("using trustloc_ctx"); ++ factory = trustloc_ctx.getSocketFactory(); ++ } ++ ++ socket = null; ++ ++ try { ++ if (proxy_in_use && viewer.forceProxy) { ++ throw new Exception("forcing proxy (forceProxy)"); ++ } else if (viewer.CONNECT != null) { ++ throw new Exception("forcing CONNECT"); ++ } ++ ++ int timeout = 6; ++ if (timeout > 0) { ++ socket = (SSLSocket) factory.createSocket(); ++ InetSocketAddress inetaddr = new InetSocketAddress(host, port); ++ dbg("Using timeout of " + timeout + " secs to: " + host + ":" + port); ++ socket.connect(inetaddr, timeout * 1000); ++ } else { ++ socket = (SSLSocket) factory.createSocket(host, port); ++ } ++ ++ } catch (Exception esock) { ++ dbg("socket error: " + esock.getMessage()); ++ if (proxy_in_use || viewer.CONNECT != null) { ++ proxy_failure = true; ++ if (proxy_in_use) { ++ dbg("HTTPS proxy in use. Trying to go with it."); ++ } else { ++ dbg("viewer.CONNECT reverse proxy in use. Trying to go with it."); ++ } ++ try { ++ socket = proxy_socket(factory); ++ } catch (Exception e) { ++ dbg("proxy_socket error: " + e.getMessage()); ++ } ++ } else { ++ /* n.b. socket is left in error state to cause ex. below. */ ++ } ++ } ++ ++ try { ++ socket.startHandshake(); ++ ++ dbg("The Server Connection Verified OK on 1st try."); ++ ++ java.security.cert.Certificate[] currentTrustedCerts; ++ BrowserCertsDialog bcd; ++ ++ SSLSession sess = socket.getSession(); ++ currentTrustedCerts = sess.getPeerCertificates(); ++ ++ if (viewer.trustAllVncCerts) { ++ dbg("viewer.trustAllVncCerts-1 keeping socket."); ++ } else if (currentTrustedCerts == null || currentTrustedCerts.length < 1) { ++ try { ++ socket.close(); ++ } catch (Exception e) { ++ dbg("socket is grumpy."); ++ } ++ socket = null; ++ throw new SSLHandshakeException("no current certs"); ++ } ++ ++ String serv = ""; ++ try { ++ CertInfo ci = new CertInfo(currentTrustedCerts[0]); ++ serv = ci.get_certinfo("CN"); ++ } catch (Exception e) { ++ ; ++ } ++ ++ if (viewer.trustAllVncCerts) { ++ dbg("viewer.trustAllVncCerts-2 skipping browser certs dialog"); ++ user_wants_to_see_cert = false; ++ } else if (viewer.serverCert != null && trustsrvCerts != null) { ++ dbg("viewer.serverCert-1 skipping browser certs dialog"); ++ user_wants_to_see_cert = false; ++ } else if (viewer.trustUrlVncCert) { ++ dbg("viewer.trustUrlVncCert-1 skipping browser certs dialog"); ++ user_wants_to_see_cert = false; ++ } else { ++ /* have a dialog with the user: */ ++ bcd = new BrowserCertsDialog(serv, host + ":" + port); ++ dbg("browser certs dialog begin."); ++ bcd.queryUser(); ++ dbg("browser certs dialog finished."); ++ ++ if (bcd.showCertDialog) { ++ String msg = "user wants to see cert"; ++ dbg(msg); ++ user_wants_to_see_cert = true; ++ if (cert_fail == null) { ++ cert_fail = "user-view"; ++ } ++ throw new SSLHandshakeException(msg); ++ } else { ++ user_wants_to_see_cert = false; ++ dbg("browser certs dialog: user said yes, accept it"); ++ } ++ } ++ ++ } catch (SSLHandshakeException eh) { ++ dbg("SSLHandshakeException: could not automatically verify Server."); ++ dbg("msg: " + eh.getMessage()); ++ ++ ++ /* send a cleanup string just in case: */ ++ String getoutstr = "GET /index.vnc HTTP/1.0\r\nConnection: close\r\n\r\n"; ++ ++ try { ++ OutputStream os = socket.getOutputStream(); ++ os.write(getoutstr.getBytes()); ++ socket.close(); ++ } catch (Exception e) { ++ dbg("socket is grumpy!"); ++ } ++ ++ /* reload */ ++ ++ socket = null; ++ ++ String reason = null; ++ ++ if (srv_cert) { ++ /* for serverCert usage we make this a fatal error. */ ++ throw new IOException("Fatal: VNC Server's Cert does not match Applet Parameter 'serverCert=...'"); ++ /* see below in TrustDialog were we describe this case to user anyway */ ++ } ++ ++ /* ++ * Reconnect, trusting any cert, so we can grab ++ * the cert to show it to the user in a dialog ++ * for him to manually accept. This connection ++ * is not used for anything else. ++ */ ++ factory = trustall_ctx.getSocketFactory(); ++ if (proxy_failure) { ++ socket = proxy_socket(factory); ++ } else { ++ socket = (SSLSocket) factory.createSocket(host, port); ++ } ++ ++ if (debug_certs) { ++ dbg("trusturlCerts: " + trusturlCerts); ++ dbg("trustsrvCerts: " + trustsrvCerts); ++ } ++ if (trusturlCerts == null && cert_fail == null) { ++ cert_fail = "missing-certs"; ++ } ++ ++ try { ++ socket.startHandshake(); ++ ++ dbg("The TrustAll Server Cert-grab Connection (trivially) Verified OK."); ++ ++ /* grab the cert: */ ++ try { ++ SSLSession sess = socket.getSession(); ++ trustallCerts = sess.getPeerCertificates(); ++ } catch (Exception e) { ++ throw new Exception("Could not get " + ++ "Peer Certificate"); ++ } ++ if (debug_certs) { ++ dbg("trustallCerts: " + trustallCerts); ++ } ++ ++ if (viewer.trustAllVncCerts) { ++ dbg("viewer.trustAllVncCerts-3. skipping dialog, trusting everything."); ++ } else if (! browser_cert_match()) { ++ /* ++ * close socket now, we will reopen after ++ * dialog if user agrees to use the cert. ++ */ ++ try { ++ OutputStream os = socket.getOutputStream(); ++ os.write(getoutstr.getBytes()); ++ socket.close(); ++ } catch (Exception e) { ++ dbg("socket is grumpy!!"); ++ } ++ socket = null; ++ ++ /* dialog with user to accept cert or not: */ ++ ++ TrustDialog td= new TrustDialog(host, port, ++ trustallCerts); ++ ++ if (cert_fail == null) { ++ ; ++ } else if (cert_fail.equals("user-view")) { ++ reason = "Reason for this Dialog:\n\n" ++ + " You Asked to View the Certificate."; ++ } else if (cert_fail.equals("server-cert-mismatch")) { ++ /* this is now fatal error, see above. */ ++ reason = "Reason for this Dialog:\n\n" ++ + " The VNC Server's Certificate does not match the Certificate\n" ++ + " specified in the supplied 'serverCert' Applet Parameter."; ++ } else if (cert_fail.equals("cert-mismatch")) { ++ reason = "Reason for this Dialog:\n\n" ++ + " The VNC Server's Certificate does not match the Website's\n" ++ + " HTTPS Certificate (that you previously accepted; either\n" ++ + " manually or automatically via Certificate Authority.)"; ++ } else if (cert_fail.equals("missing-certs")) { ++ reason = "Reason for this Dialog:\n\n" ++ + " Not all Certificates could be obtained to check."; ++ } ++ ++ if (! td.queryUser(reason)) { ++ String msg = "User decided against it."; ++ dbg(msg); ++ throw new IOException(msg); ++ } ++ } ++ ++ } catch (Exception ehand2) { ++ dbg("** Could not TrustAll Verify Server!"); ++ ++ throw new IOException(ehand2.getMessage()); ++ } ++ ++ /* reload again: */ ++ ++ if (socket != null) { ++ try { ++ socket.close(); ++ } catch (Exception e) { ++ dbg("socket is grumpy!!!"); ++ } ++ socket = null; ++ } ++ ++ /* ++ * Now connect a 3rd time, using the cert ++ * retrieved during connection 2 (sadly, that ++ * the user likely blindly agreed to...) ++ */ ++ ++ factory = trustone_ctx.getSocketFactory(); ++ if (proxy_failure) { ++ socket = proxy_socket(factory); ++ } else { ++ socket = (SSLSocket) factory.createSocket(host, port); ++ } ++ ++ try { ++ socket.startHandshake(); ++ dbg("TrustAll/TrustOne Server Connection Verified #3."); ++ ++ } catch (Exception ehand3) { ++ dbg("** Could not TrustAll/TrustOne Verify Server #3."); ++ ++ throw new IOException(ehand3.getMessage()); ++ } ++ } ++ ++ /* we have socket (possibly null) at this point, so proceed: */ ++ ++ /* handle x11vnc GET=1, if applicable: */ ++ if (socket != null && viewer.GET) { ++ String str = "GET "; ++ str += viewer.urlPrefix; ++ str += "/request.https.vnc.connection"; ++ str += " HTTP/1.0\r\n"; ++ str += "Pragma: No-Cache\r\n"; ++ str += "\r\n"; ++ ++ System.out.println("sending: " + str); ++ OutputStream os = socket.getOutputStream(); ++ String type = "os"; ++ ++ if (type == "os") { ++ os.write(str.getBytes()); ++ os.flush(); ++ System.out.println("used OutputStream"); ++ } else if (type == "bs") { ++ BufferedOutputStream bs = new BufferedOutputStream(os); ++ bs.write(str.getBytes()); ++ bs.flush(); ++ System.out.println("used BufferedOutputStream"); ++ } else if (type == "ds") { ++ DataOutputStream ds = new DataOutputStream(os); ++ ds.write(str.getBytes()); ++ ds.flush(); ++ System.out.println("used DataOutputStream"); ++ } ++ if (false) { ++ String rep = ""; ++ DataInputStream is = new DataInputStream( ++ new BufferedInputStream(socket.getInputStream(), 16384)); ++ while (true) { ++ rep += readline(is); ++ if (rep.indexOf("\r\n\r\n") >= 0) { ++ break; ++ } ++ } ++ System.out.println("rep: " + rep); ++ } ++ } ++ ++ dbg("SSL returning socket to caller."); ++ dbg(""); ++ ++ /* could be null, let caller handle that. */ ++ return (Socket) socket; ++ } ++ ++ boolean browser_cert_match() { ++ String msg = "Browser URL accept previously accepted cert"; ++ ++ if (user_wants_to_see_cert) { ++ return false; ++ } ++ ++ if (viewer.serverCert != null || trustsrvCerts != null) { ++ if (cert_fail == null) { ++ cert_fail = "server-cert-mismatch"; ++ } ++ } ++ if (trustallCerts != null && trusturlCerts != null) { ++ if (trustallCerts.length == trusturlCerts.length) { ++ boolean ok = true; ++ /* check toath trustallCerts (socket) equals trusturlCerts (browser) */ ++ for (int i = 0; i < trusturlCerts.length; i++) { ++ if (! trustallCerts[i].equals(trusturlCerts[i])) { ++ dbg("BCM: cert mismatch at i=" + i); ++ dbg("BCM: cert mismatch url" + trusturlCerts[i]); ++ dbg("BCM: cert mismatch all" + trustallCerts[i]); ++ ok = false; ++ } ++ } ++ if (ok) { ++ System.out.println(msg); ++ if (cert_fail == null) { ++ cert_fail = "did-not-fail"; ++ } ++ return true; ++ } else { ++ if (cert_fail == null) { ++ cert_fail = "cert-mismatch"; ++ } ++ return false; ++ } ++ } ++ } ++ if (cert_fail == null) { ++ cert_fail = "missing-certs"; ++ } ++ return false; ++ } ++ ++ private void dbg(String s) { ++ if (debug) { ++ System.out.println(s); ++ } ++ } ++ ++ private int gint(String s) { ++ int n = -1; ++ try { ++ Integer I = new Integer(s); ++ n = I.intValue(); ++ } catch (Exception ex) { ++ return -1; ++ } ++ return n; ++ } ++ ++ /* this will do the proxy CONNECT negotiation and hook us up. */ ++ ++ private void proxy_helper(String proxyHost, int proxyPort) { ++ ++ boolean proxy_auth = false; ++ String proxy_auth_basic_realm = ""; ++ String hp = host + ":" + port; ++ dbg("proxy_helper: " + proxyHost + ":" + proxyPort + " hp: " + hp); ++ ++ /* we loop here a few times trying for the password case */ ++ for (int k=0; k < 2; k++) { ++ dbg("proxy_in_use psocket: " + k); ++ ++ if (proxySock != null) { ++ try { ++ proxySock.close(); ++ } catch (Exception e) { ++ dbg("proxy socket is grumpy."); ++ } ++ } ++ ++ proxySock = psocket(proxyHost, proxyPort); ++ if (proxySock == null) { ++ dbg("1-a sadly, returning a null socket"); ++ return; ++ } ++ ++ String req1 = "CONNECT " + hp + " HTTP/1.1\r\n" ++ + "Host: " + hp + "\r\n"; ++ ++ dbg("requesting via proxy: " + req1); ++ ++ if (proxy_auth) { ++ if (proxy_auth_string == null) { ++ ProxyPasswdDialog pp = new ProxyPasswdDialog(proxyHost, proxyPort, proxy_auth_basic_realm); ++ pp.queryUser(); ++ proxy_auth_string = pp.getAuth(); ++ } ++ //dbg("auth1: " + proxy_auth_string); ++ ++ String auth2 = Base64Coder.encodeString(proxy_auth_string); ++ //dbg("auth2: " + auth2); ++ ++ req1 += "Proxy-Authorization: Basic " + auth2 + "\r\n"; ++ //dbg("req1: " + req1); ++ ++ dbg("added Proxy-Authorization: Basic ... to request"); ++ } ++ req1 += "\r\n"; ++ ++ try { ++ proxy_os.write(req1.getBytes()); ++ String reply = readline(proxy_is); ++ ++ dbg("proxy replied: " + reply.trim()); ++ ++ if (reply.indexOf("HTTP/1.") == 0 && reply.indexOf(" 407 ") > 0) { ++ proxy_auth = true; ++ proxySock.close(); ++ } else if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) { ++ proxySock.close(); ++ proxySock = psocket(proxyHost, proxyPort); ++ if (proxySock == null) { ++ dbg("2-a sadly, returning a null socket"); ++ return; ++ } ++ } ++ } catch(Exception e) { ++ dbg("some proxy socket problem: " + e.getMessage()); ++ } ++ ++ /* read the rest of the HTTP headers */ ++ while (true) { ++ String line = readline(proxy_is); ++ dbg("proxy line: " + line.trim()); ++ if (proxy_auth) { ++ String uc = line.toLowerCase(); ++ if (uc.indexOf("proxy-authenticate:") == 0) { ++ if (uc.indexOf(" basic ") >= 0) { ++ int idx = uc.indexOf(" realm"); ++ if (idx >= 0) { ++ proxy_auth_basic_realm = uc.substring(idx+1); ++ } ++ } ++ } ++ } ++ if (line.equals("\r\n") || line.equals("\n")) { ++ break; ++ } ++ } ++ if (!proxy_auth || proxy_auth_basic_realm.equals("")) { ++ /* we only try once for the non-password case: */ ++ break; ++ } ++ } ++ } ++ ++ public SSLSocket proxy_socket(SSLSocketFactory factory) { ++ Properties props = null; ++ String proxyHost = null; ++ int proxyPort = 0; ++ String proxyHost_nossl = null; ++ int proxyPort_nossl = 0; ++ String str; ++ ++ /* see if we can guess the proxy info from Properties: */ ++ try { ++ props = System.getProperties(); ++ } catch (Exception e) { ++ /* sandboxed applet might not be able to read it. */ ++ dbg("props failed: " + e.getMessage()); ++ } ++ if (viewer.proxyHost != null) { ++ dbg("Using supplied proxy " + viewer.proxyHost + " " + viewer.proxyPort + " applet parameters."); ++ proxyHost = viewer.proxyHost; ++ if (viewer.proxyPort != null) { ++ proxyPort = gint(viewer.proxyPort); ++ } else { ++ proxyPort = 8080; ++ } ++ ++ } else if (props != null) { ++ dbg("\n---------------\nAll props:"); ++ props.list(System.out); ++ dbg("\n---------------\n\n"); ++ ++ /* scrape throught properties looking for proxy info: */ ++ ++ for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) { ++ String s = (String) e.nextElement(); ++ String v = System.getProperty(s); ++ String s2 = s.toLowerCase(); ++ String v2 = v.toLowerCase(); ++ ++ if (s2.indexOf("proxy.https.host") >= 0) { ++ proxyHost = v2; ++ continue; ++ } ++ if (s2.indexOf("proxy.https.port") >= 0) { ++ proxyPort = gint(v2); ++ continue; ++ } ++ if (s2.indexOf("proxy.http.host") >= 0) { ++ proxyHost_nossl = v2; ++ continue; ++ } ++ if (s2.indexOf("proxy.http.port") >= 0) { ++ proxyPort_nossl = gint(v2); ++ continue; ++ } ++ } ++ ++ for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) { ++ String s = (String) e.nextElement(); ++ String v = System.getProperty(s); ++ String s2 = s.toLowerCase(); ++ String v2 = v.toLowerCase(); ++ ++ if (proxyHost != null && proxyPort > 0) { ++ break; ++ } ++ ++ // look for something like: javaplugin.proxy.config.list = http=10.0.2.1:8082 ++ if (s2.indexOf("proxy") < 0 && v2.indexOf("proxy") < 0) { ++ continue; ++ } ++ if (v2.indexOf("http") < 0) { ++ continue; ++ } ++ ++ String[] pieces = v.split("[,;]"); ++ for (int i = 0; i < pieces.length; i++) { ++ String p = pieces[i]; ++ int j = p.indexOf("https"); ++ if (j < 0) { ++ j = p.indexOf("http"); ++ if (j < 0) { ++ continue; ++ } ++ } ++ j = p.indexOf("=", j); ++ if (j < 0) { ++ continue; ++ } ++ p = p.substring(j+1); ++ String [] hp = p.split(":"); ++ if (hp.length != 2) { ++ continue; ++ } ++ if (hp[0].length() > 1 && hp[1].length() > 1) { ++ ++ proxyPort = gint(hp[1]); ++ if (proxyPort < 0) { ++ continue; ++ } ++ proxyHost = new String(hp[0]); ++ break; ++ } ++ } ++ } ++ } ++ if (proxyHost != null) { ++ if (proxyHost_nossl != null && proxyPort_nossl > 0) { ++ dbg("Using http proxy info instead of https."); ++ proxyHost = proxyHost_nossl; ++ proxyPort = proxyPort_nossl; ++ } ++ } ++ ++ if (proxy_in_use) { ++ if (proxy_dialog_host != null && proxy_dialog_port > 0) { ++ proxyHost = proxy_dialog_host; ++ proxyPort = proxy_dialog_port; ++ } ++ if (proxyHost != null) { ++ dbg("Lucky us! we figured out the Proxy parameters: " + proxyHost + " " + proxyPort); ++ } else { ++ /* ask user to help us: */ ++ ProxyDialog pd = new ProxyDialog(proxyHost, proxyPort); ++ pd.queryUser(); ++ proxyHost = pd.getHost(); ++ proxyPort = pd.getPort(); ++ proxy_dialog_host = new String(proxyHost); ++ proxy_dialog_port = proxyPort; ++ dbg("User said host: " + pd.getHost() + " port: " + pd.getPort()); ++ } ++ ++ proxy_helper(proxyHost, proxyPort); ++ if (proxySock == null) { ++ return null; ++ } ++ } else if (viewer.CONNECT != null) { ++ dbg("viewer.CONNECT psocket:"); ++ proxySock = psocket(host, port); ++ if (proxySock == null) { ++ dbg("1-b sadly, returning a null socket"); ++ return null; ++ } ++ } ++ ++ if (viewer.CONNECT != null) { ++ String hp = viewer.CONNECT; ++ String req2 = "CONNECT " + hp + " HTTP/1.1\r\n" ++ + "Host: " + hp + "\r\n\r\n"; ++ ++ dbg("requesting2: " + req2); ++ ++ try { ++ proxy_os.write(req2.getBytes()); ++ String reply = readline(proxy_is); ++ ++ dbg("proxy replied2: " + reply.trim()); ++ ++ if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) { ++ proxySock.close(); ++ proxySock = psocket(proxyHost, proxyPort); ++ if (proxySock == null) { ++ dbg("2-b sadly, returning a null socket"); ++ return null; ++ } ++ } ++ } catch(Exception e) { ++ dbg("proxy socket problem-2: " + e.getMessage()); ++ } ++ ++ while (true) { ++ String line = readline(proxy_is); ++ dbg("proxy line2: " + line.trim()); ++ if (line.equals("\r\n") || line.equals("\n")) { ++ break; ++ } ++ } ++ } ++ ++ Socket sslsock = null; ++ try { ++ sslsock = factory.createSocket(proxySock, host, port, true); ++ } catch(Exception e) { ++ dbg("sslsock prob: " + e.getMessage()); ++ dbg("3 sadly, returning a null socket"); ++ } ++ ++ return (SSLSocket) sslsock; ++ } ++ ++ Socket psocket(String h, int p) { ++ Socket psock = null; ++ try { ++ psock = new Socket(h, p); ++ proxy_is = new DataInputStream(new BufferedInputStream( ++ psock.getInputStream(), 16384)); ++ proxy_os = psock.getOutputStream(); ++ } catch(Exception e) { ++ dbg("psocket prob: " + e.getMessage()); ++ return null; ++ } ++ ++ return psock; ++ } ++ ++ String readline(DataInputStream i) { ++ byte[] ba = new byte[1]; ++ String s = new String(""); ++ ba[0] = 0; ++ try { ++ while (ba[0] != 0xa) { ++ ba[0] = (byte) i.readUnsignedByte(); ++ s += new String(ba); ++ } ++ } catch (Exception e) { ++ ; ++ } ++ return s; ++ } ++} ++ ++class TrustDialog implements ActionListener { ++ String msg, host, text; ++ int port; ++ java.security.cert.Certificate[] trustallCerts = null; ++ boolean viewing_cert = false; ++ boolean trust_this_session = false; ++ ++ /* ++ * this is the gui to show the user the cert and info and ask ++ * them if they want to continue using this cert. ++ */ ++ ++ Button ok, cancel, viewcert; ++ TextArea textarea; ++ Checkbox accept, deny; ++ Dialog dialog; ++ ++ String s1 = "Accept this certificate temporarily for this session"; ++ String s2 = "Do not accept this certificate and do not connect to" ++ + " this VNC server"; ++ String ln = "\n---------------------------------------------------\n\n"; ++ ++ TrustDialog (String h, int p, java.security.cert.Certificate[] s) { ++ host = h; ++ port = p; ++ trustallCerts = s; ++ ++ msg = "VNC Server " + host + ":" + port + " Not Verified"; ++ } ++ ++ public boolean queryUser(String reason) { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame(msg); ++ ++ dialog = new Dialog(frame, true); ++ ++ String infostr = ""; ++ if (trustallCerts.length == 1) { ++ CertInfo ci = new CertInfo(trustallCerts[0]); ++ infostr = ci.get_certinfo("all"); ++ } ++ if (reason != null) { ++ reason += "\n\n"; ++ } ++ ++ text = "\n" +++ "Unable to verify the identity of\n" +++ "\n" +++ " " + host + ":" + port + "\n" +++ "\n" +++ infostr +++ "\n" +++ "as a trusted VNC server.\n" +++ "\n" +++ reason +++ "In General not being able to verify the VNC Server and/or your seeing this Dialog\n" +++ "is due to one of the following:\n" +++ "\n" +++ " - Your requesting to View the Certificate before accepting.\n" +++ "\n" +++ " - The VNC server is using a Self-Signed Certificate or a Certificate\n" +++ " Authority not recognized by your Web Browser or Java Plugin runtime.\n" +++ "\n" +++ " - The use of an Apache SSL portal scheme employing CONNECT proxying AND\n" +++ " the Apache Web server has a certificate *different* from the VNC server's.\n" +++ "\n" +++ " - No previously accepted Certificate (via Web Broswer/Java Plugin) could be\n" +++ " obtained by this applet to compare the VNC Server Certificate against.\n" +++ "\n" +++ " - The VNC Server's Certificate does not match the one specified in the\n" +++ " supplied 'serverCert' Java Applet Parameter.\n" +++ "\n" +++ " - A Man-In-The-Middle attack impersonating as the VNC server that you wish\n" +++ " to connect to. (Wouldn't that be exciting!!)\n" +++ "\n" +++ "By safely copying the VNC server's Certificate (or using a common Certificate\n" +++ "Authority certificate) you can configure your Web Browser and Java Plugin to\n" +++ "automatically authenticate this VNC Server.\n" +++ "\n" +++ "If you do so, then you will only have to click \"Yes\" when this VNC Viewer\n" +++ "applet asks you whether to trust your Browser/Java Plugin's acceptance of the\n" +++ "certificate (except for the Apache portal case above where they don't match.)\n" +++ "\n" +++ "You can also set the applet parameter 'trustUrlVncCert=yes' to automatically\n" +++ "accept certificates already accepted/trusted by your Web Browser/Java Plugin,\n" +++ "and thereby see no dialog from this VNC Viewer applet.\n" ++; ++ ++ /* the accept / do-not-accept radio buttons: */ ++ CheckboxGroup checkbox = new CheckboxGroup(); ++ accept = new Checkbox(s1, true, checkbox); ++ deny = new Checkbox(s2, false, checkbox); ++ ++ /* put the checkboxes in a panel: */ ++ Panel check = new Panel(); ++ check.setLayout(new GridLayout(2, 1)); ++ ++ check.add(accept); ++ check.add(deny); ++ ++ /* make the 3 buttons: */ ++ ok = new Button("OK"); ++ cancel = new Button("Cancel"); ++ viewcert = new Button("View Certificate"); ++ ++ ok.addActionListener(this); ++ cancel.addActionListener(this); ++ viewcert.addActionListener(this); ++ ++ /* put the buttons in their own panel: */ ++ Panel buttonrow = new Panel(); ++ buttonrow.setLayout(new FlowLayout(FlowLayout.LEFT)); ++ buttonrow.add(viewcert); ++ buttonrow.add(ok); ++ buttonrow.add(cancel); ++ ++ /* label at the top: */ ++ Label label = new Label(msg, Label.CENTER); ++ label.setFont(new Font("Helvetica", Font.BOLD, 16)); ++ ++ /* textarea in the middle */ ++ textarea = new TextArea(text, 38, 64, ++ TextArea.SCROLLBARS_VERTICAL_ONLY); ++ textarea.setEditable(false); ++ ++ /* put the two panels in their own panel at bottom: */ ++ Panel bot = new Panel(); ++ bot.setLayout(new GridLayout(2, 1)); ++ bot.add(check); ++ bot.add(buttonrow); ++ ++ /* now arrange things inside the dialog: */ ++ dialog.setLayout(new BorderLayout()); ++ ++ dialog.add("North", label); ++ dialog.add("South", bot); ++ dialog.add("Center", textarea); ++ ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til OK or Cancel pressed. */ ++ ++ return trust_this_session; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ ++ if (evt.getSource() == viewcert) { ++ /* View Certificate button clicked */ ++ if (viewing_cert) { ++ /* show the original info text: */ ++ textarea.setText(text); ++ viewcert.setLabel("View Certificate"); ++ viewing_cert = false; ++ } else { ++ int i; ++ /* show all (likely just one) certs: */ ++ textarea.setText(""); ++ for (i=0; i < trustallCerts.length; i++) { ++ int j = i + 1; ++ textarea.append("Certificate[" + ++ j + "]\n\n"); ++ textarea.append( ++ trustallCerts[i].toString()); ++ textarea.append(ln); ++ } ++ viewcert.setLabel("View Info"); ++ viewing_cert = true; ++ ++ textarea.setCaretPosition(0); ++ } ++ ++ } else if (evt.getSource() == ok) { ++ /* OK button clicked */ ++ if (accept.getState()) { ++ trust_this_session = true; ++ } else { ++ trust_this_session = false; ++ } ++ //dialog.dispose(); ++ dialog.hide(); ++ ++ } else if (evt.getSource() == cancel) { ++ /* Cancel button clicked */ ++ trust_this_session = false; ++ ++ //dialog.dispose(); ++ dialog.hide(); ++ } ++ } ++ ++ String get_certinfo() { ++ String all = ""; ++ String fields[] = {"CN", "OU", "O", "L", "C"}; ++ int i; ++ if (trustallCerts.length < 1) { ++ all = ""; ++ return all; ++ } ++ String cert = trustallCerts[0].toString(); ++ ++ /* ++ * For now we simply scrape the cert string, there must ++ * be an API for this... perhaps optionValue? ++ */ ++ ++ for (i=0; i < fields.length; i++) { ++ int f, t, t1, t2; ++ String sub, mat = fields[i] + "="; ++ ++ f = cert.indexOf(mat, 0); ++ if (f > 0) { ++ t1 = cert.indexOf(", ", f); ++ t2 = cert.indexOf("\n", f); ++ if (t1 < 0 && t2 < 0) { ++ continue; ++ } else if (t1 < 0) { ++ t = t2; ++ } else if (t2 < 0) { ++ t = t1; ++ } else if (t1 < t2) { ++ t = t1; ++ } else { ++ t = t2; ++ } ++ if (t > f) { ++ sub = cert.substring(f, t); ++ all = all + " " + sub + "\n"; ++ } ++ } ++ } ++ return all; ++ } ++} ++ ++class ProxyDialog implements ActionListener { ++ String guessedHost = null; ++ String guessedPort = null; ++ /* ++ * this is the gui to show the user the cert and info and ask ++ * them if they want to continue using this cert. ++ */ ++ ++ Button ok; ++ Dialog dialog; ++ TextField entry; ++ String reply = ""; ++ ++ ProxyDialog (String h, int p) { ++ guessedHost = h; ++ try { ++ guessedPort = Integer.toString(p); ++ } catch (Exception e) { ++ guessedPort = "8080"; ++ } ++ } ++ ++ public void queryUser() { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame("Need Proxy host:port"); ++ ++ dialog = new Dialog(frame, true); ++ ++ ++ Label label = new Label("Please Enter your https Proxy info as host:port", Label.CENTER); ++ //label.setFont(new Font("Helvetica", Font.BOLD, 16)); ++ entry = new TextField(30); ++ ok = new Button("OK"); ++ ok.addActionListener(this); ++ ++ String guess = ""; ++ if (guessedHost != null) { ++ guess = guessedHost + ":" + guessedPort; ++ } ++ entry.setText(guess); ++ ++ dialog.setLayout(new BorderLayout()); ++ dialog.add("North", label); ++ dialog.add("Center", entry); ++ dialog.add("South", ok); ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til OK or Cancel pressed. */ ++ return; ++ } ++ ++ public String getHost() { ++ int i = reply.indexOf(":"); ++ if (i < 0) { ++ return "unknown"; ++ } ++ String h = reply.substring(0, i); ++ return h; ++ } ++ ++ public int getPort() { ++ int i = reply.indexOf(":"); ++ int p = 8080; ++ if (i < 0) { ++ return p; ++ } ++ i++; ++ String ps = reply.substring(i); ++ try { ++ Integer I = new Integer(ps); ++ p = I.intValue(); ++ } catch (Exception e) { ++ ; ++ } ++ return p; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ System.out.println(evt.getActionCommand()); ++ if (evt.getSource() == ok) { ++ reply = entry.getText(); ++ //dialog.dispose(); ++ dialog.hide(); ++ } ++ } ++} ++ ++class ProxyPasswdDialog implements ActionListener { ++ String guessedHost = null; ++ String guessedPort = null; ++ String guessedUser = null; ++ String guessedPasswd = null; ++ String realm = null; ++ /* ++ * this is the gui to show the user the cert and info and ask ++ * them if they want to continue using this cert. ++ */ ++ ++ Button ok; ++ Dialog dialog; ++ TextField entry1; ++ TextField entry2; ++ String reply1 = ""; ++ String reply2 = ""; ++ ++ ProxyPasswdDialog (String h, int p, String realm) { ++ guessedHost = h; ++ try { ++ guessedPort = Integer.toString(p); ++ } catch (Exception e) { ++ guessedPort = "8080"; ++ } ++ this.realm = realm; ++ } ++ ++ public void queryUser() { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame("Proxy Requires Username and Password"); ++ ++ dialog = new Dialog(frame, true); ++ ++ //Label label = new Label("Please Enter your Web Proxy Username in the top Entry and Password in the bottom Entry", Label.CENTER); ++ 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); ++ entry1 = new TextField(30); ++ entry2 = new TextField(30); ++ entry2.setEchoChar('*'); ++ ok = new Button("OK"); ++ ok.addActionListener(this); ++ ++ dialog.setLayout(new BorderLayout()); ++ dialog.add("North", label); ++ dialog.add("Center", entry1); ++ dialog.add("South", entry2); ++ dialog.add("East", ok); ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til OK or Cancel pressed. */ ++ return; ++ } ++ ++ public String getAuth() { ++ return reply1 + ":" + reply2; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ System.out.println(evt.getActionCommand()); ++ if (evt.getSource() == ok) { ++ reply1 = entry1.getText(); ++ reply2 = entry2.getText(); ++ //dialog.dispose(); ++ dialog.hide(); ++ } ++ } ++} ++ ++class ClientCertDialog implements ActionListener { ++ ++ Button ok; ++ Dialog dialog; ++ TextField entry; ++ String reply = ""; ++ ++ ClientCertDialog() { ++ ; ++ } ++ ++ public String queryUser() { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame("Enter SSL Client Cert+Key String"); ++ ++ dialog = new Dialog(frame, true); ++ ++ ++ Label label = new Label("Please Enter the SSL Client Cert+Key String 308204c0...,...522d2d0a", Label.CENTER); ++ entry = new TextField(30); ++ ok = new Button("OK"); ++ ok.addActionListener(this); ++ ++ dialog.setLayout(new BorderLayout()); ++ dialog.add("North", label); ++ dialog.add("Center", entry); ++ dialog.add("South", ok); ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til OK or Cancel pressed. */ ++ return reply; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ System.out.println(evt.getActionCommand()); ++ if (evt.getSource() == ok) { ++ reply = entry.getText(); ++ //dialog.dispose(); ++ dialog.hide(); ++ } ++ } ++} ++ ++class BrowserCertsDialog implements ActionListener { ++ Button yes, no; ++ Dialog dialog; ++ String vncServer; ++ String hostport; ++ public boolean showCertDialog = true; ++ ++ BrowserCertsDialog(String serv, String hp) { ++ vncServer = serv; ++ hostport = hp; ++ } ++ ++ public void queryUser() { ++ ++ /* create and display the dialog for unverified cert. */ ++ ++ Frame frame = new Frame("Use Browser/JVM Certs?"); ++ ++ dialog = new Dialog(frame, true); ++ ++ String m = ""; ++m += "\n"; ++m += "This VNC Viewer applet does not have its own keystore to track\n"; ++m += "SSL certificates, and so cannot authenticate the certificate\n"; ++m += "of the VNC Server:\n"; ++m += "\n"; ++m += " " + hostport + "\n\n " + vncServer + "\n"; ++m += "\n"; ++m += "on its own.\n"; ++m += "\n"; ++m += "However, it has noticed that your Web Browser and/or Java VM Plugin\n"; ++m += "has previously accepted the same certificate. You may have set\n"; ++m += "this up permanently or just for this session, or the server\n"; ++m += "certificate was signed by a CA cert that your Web Browser or\n"; ++m += "Java VM Plugin has.\n"; ++m += "\n"; ++m += "If the VNC Server connection times out while you are reading this\n"; ++m += "dialog, then restart the connection and try again.\n"; ++m += "\n"; ++m += "Should this VNC Viewer applet now connect to the above VNC server?\n"; ++m += "\n"; ++ ++ TextArea textarea = new TextArea(m, 22, 64, ++ TextArea.SCROLLBARS_VERTICAL_ONLY); ++ textarea.setEditable(false); ++ yes = new Button("Yes"); ++ yes.addActionListener(this); ++ no = new Button("No, Let Me See the Certificate."); ++ no.addActionListener(this); ++ ++ dialog.setLayout(new BorderLayout()); ++ dialog.add("North", textarea); ++ dialog.add("Center", yes); ++ dialog.add("South", no); ++ dialog.pack(); ++ dialog.resize(dialog.preferredSize()); ++ ++ dialog.show(); /* block here til Yes or No pressed. */ ++ System.out.println("done show()"); ++ return; ++ } ++ ++ public synchronized void actionPerformed(ActionEvent evt) { ++ System.out.println(evt.getActionCommand()); ++ if (evt.getSource() == yes) { ++ showCertDialog = false; ++ //dialog.dispose(); ++ dialog.hide(); ++ } else if (evt.getSource() == no) { ++ showCertDialog = true; ++ //dialog.dispose(); ++ dialog.hide(); ++ } ++ System.out.println("done actionPerformed()"); ++ } ++} ++ ++class CertInfo { ++ String fields[] = {"CN", "OU", "O", "L", "C"}; ++ java.security.cert.Certificate cert; ++ String certString = ""; ++ ++ CertInfo(java.security.cert.Certificate c) { ++ cert = c; ++ certString = cert.toString(); ++ } ++ ++ String get_certinfo(String which) { ++ int i; ++ String cs = new String(certString); ++ String all = ""; ++ ++ /* ++ * For now we simply scrape the cert string, there must ++ * be an API for this... perhaps optionValue? ++ */ ++ for (i=0; i < fields.length; i++) { ++ int f, t, t1, t2; ++ String sub, mat = fields[i] + "="; ++ ++ f = cs.indexOf(mat, 0); ++ if (f > 0) { ++ t1 = cs.indexOf(", ", f); ++ t2 = cs.indexOf("\n", f); ++ if (t1 < 0 && t2 < 0) { ++ continue; ++ } else if (t1 < 0) { ++ t = t2; ++ } else if (t2 < 0) { ++ t = t1; ++ } else if (t1 < t2) { ++ t = t1; ++ } else { ++ t = t2; ++ } ++ if (t > f) { ++ sub = cs.substring(f, t); ++ all = all + " " + sub + "\n"; ++ if (which.equals(fields[i])) { ++ return sub; ++ } ++ } ++ } ++ } ++ if (which.equals("all")) { ++ return all; ++ } else { ++ return ""; ++ } ++ } ++} ++ ++class Base64Coder { ++ ++ // Mapping table from 6-bit nibbles to Base64 characters. ++ private static char[] map1 = new char[64]; ++ static { ++ int i=0; ++ for (char c='A'; c<='Z'; c++) map1[i++] = c; ++ for (char c='a'; c<='z'; c++) map1[i++] = c; ++ for (char c='0'; c<='9'; c++) map1[i++] = c; ++ map1[i++] = '+'; map1[i++] = '/'; } ++ ++ // Mapping table from Base64 characters to 6-bit nibbles. ++ private static byte[] map2 = new byte[128]; ++ static { ++ for (int i=0; i<map2.length; i++) map2[i] = -1; ++ for (int i=0; i<64; i++) map2[map1[i]] = (byte)i; } ++ ++ /** ++ * Encodes a string into Base64 format. ++ * No blanks or line breaks are inserted. ++ * @param s a String to be encoded. ++ * @return A String with the Base64 encoded data. ++ */ ++ public static String encodeString (String s) { ++ return new String(encode(s.getBytes())); } ++ ++ /** ++ * Encodes a byte array into Base64 format. ++ * No blanks or line breaks are inserted. ++ * @param in an array containing the data bytes to be encoded. ++ * @return A character array with the Base64 encoded data. ++ */ ++ public static char[] encode (byte[] in) { ++ return encode(in,in.length); } ++ ++ /** ++ * Encodes a byte array into Base64 format. ++ * No blanks or line breaks are inserted. ++ * @param in an array containing the data bytes to be encoded. ++ * @param iLen number of bytes to process in <code>in</code>. ++ * @return A character array with the Base64 encoded data. ++ */ ++ public static char[] encode (byte[] in, int iLen) { ++ int oDataLen = (iLen*4+2)/3; // output length without padding ++ int oLen = ((iLen+2)/3)*4; // output length including padding ++ char[] out = new char[oLen]; ++ int ip = 0; ++ int op = 0; ++ while (ip < iLen) { ++ int i0 = in[ip++] & 0xff; ++ int i1 = ip < iLen ? in[ip++] & 0xff : 0; ++ int i2 = ip < iLen ? in[ip++] & 0xff : 0; ++ int o0 = i0 >>> 2; ++ int o1 = ((i0 & 3) << 4) | (i1 >>> 4); ++ int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); ++ int o3 = i2 & 0x3F; ++ out[op++] = map1[o0]; ++ out[op++] = map1[o1]; ++ out[op] = op < oDataLen ? map1[o2] : '='; op++; ++ out[op] = op < oDataLen ? map1[o3] : '='; op++; } ++ return out; } ++ ++ /** ++ * Decodes a string from Base64 format. ++ * @param s a Base64 String to be decoded. ++ * @return A String containing the decoded data. ++ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. ++ */ ++ public static String decodeString (String s) { ++ return new String(decode(s)); } ++ ++ /** ++ * Decodes a byte array from Base64 format. ++ * @param s a Base64 String to be decoded. ++ * @return An array containing the decoded data bytes. ++ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. ++ */ ++ public static byte[] decode (String s) { ++ return decode(s.toCharArray()); } ++ ++ /** ++ * Decodes a byte array from Base64 format. ++ * No blanks or line breaks are allowed within the Base64 encoded data. ++ * @param in a character array containing the Base64 encoded data. ++ * @return An array containing the decoded data bytes. ++ * @throws IllegalArgumentException if the input is not valid Base64 encoded data. ++ */ ++ public static byte[] decode (char[] in) { ++ int iLen = in.length; ++ if (iLen%4 != 0) throw new IllegalArgumentException ("Length of Base64 encoded input string is not a multiple of 4."); ++ while (iLen > 0 && in[iLen-1] == '=') iLen--; ++ int oLen = (iLen*3) / 4; ++ byte[] out = new byte[oLen]; ++ int ip = 0; ++ int op = 0; ++ while (ip < iLen) { ++ int i0 = in[ip++]; ++ int i1 = in[ip++]; ++ int i2 = ip < iLen ? in[ip++] : 'A'; ++ int i3 = ip < iLen ? in[ip++] : 'A'; ++ if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) ++ throw new IllegalArgumentException ("Illegal character in Base64 encoded data."); ++ int b0 = map2[i0]; ++ int b1 = map2[i1]; ++ int b2 = map2[i2]; ++ int b3 = map2[i3]; ++ if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) ++ throw new IllegalArgumentException ("Illegal character in Base64 encoded data."); ++ int o0 = ( b0 <<2) | (b1>>>4); ++ int o1 = ((b1 & 0xf)<<4) | (b2>>>2); ++ int o2 = ((b2 & 3)<<6) | b3; ++ out[op++] = (byte)o0; ++ if (op<oLen) out[op++] = (byte)o1; ++ if (op<oLen) out[op++] = (byte)o2; } ++ return out; } ++ ++ // Dummy constructor. ++ private Base64Coder() {} ++ ++} +diff -Naur JavaViewer.orig/VncCanvas.java JavaViewer/VncCanvas.java +--- JavaViewer.orig/VncCanvas.java 2005-11-21 18:50:18.000000000 -0500 ++++ JavaViewer/VncCanvas.java 2010-11-30 22:57:50.000000000 -0500 +@@ -27,6 +27,13 @@ + import java.lang.*; + import java.util.zip.*; + ++// begin runge/x11vnc ++import java.util.Collections; ++// end runge/x11vnc ++ ++// begin runge/x11vnc ++// all the MouseWheel stuff below. ++// end runge/x11vnc + + // + // VncCanvas is a subclass of Canvas which draws a VNC desktop on it. +@@ -34,7 +41,7 @@ + + class VncCanvas + extends Canvas +- implements KeyListener, MouseListener, MouseMotionListener { ++ implements KeyListener, MouseListener, MouseMotionListener, MouseWheelListener { + + VncViewer viewer; + RfbProto rfb; +@@ -85,6 +92,22 @@ + + cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF); + ++// begin runge/x11vnc ++// kludge to not show any Java cursor in the canvas since we are ++// showing the soft cursor (should be a user setting...) ++Cursor dot = Toolkit.getDefaultToolkit().createCustomCursor( ++ Toolkit.getDefaultToolkit().createImage(new byte[4]), new Point(0,0), ++ "dot"); ++this.setCursor(dot); ++ ++// while we are at it... get rid of the keyboard traversals that ++// make it so we can't type a Tab character: ++this.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, ++ Collections.EMPTY_SET); ++this.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, ++ Collections.EMPTY_SET); ++// end runge/x11vnc ++ + colors = new Color[256]; + // sf@2005 - Now Default + for (int i = 0; i < 256; i++) +@@ -186,6 +209,7 @@ + inputEnabled = true; + addMouseListener(this); + addMouseMotionListener(this); ++ addMouseWheelListener(this); + if (viewer.showControls) { + viewer.buttonPanel.enableRemoteAccessControls(true); + } +@@ -193,6 +217,7 @@ + inputEnabled = false; + removeMouseListener(this); + removeMouseMotionListener(this); ++ removeMouseWheelListener(this); + if (viewer.showControls) { + viewer.buttonPanel.enableRemoteAccessControls(false); + } +@@ -202,6 +227,9 @@ + + public void setPixelFormat() throws IOException { + // sf@2005 - Adding more color modes ++ if (viewer.graftFtp) { ++ return; ++ } + if (viewer.options.eightBitColors > 0) + { + viewer.options.oldEightBitColors = viewer.options.eightBitColors; +@@ -237,6 +265,9 @@ + } + else + { ++// begin runge/x11vnc ++ viewer.options.oldEightBitColors = viewer.options.eightBitColors; ++// end runge/x11vnc + rfb.writeSetPixelFormat( + 32, + 24, +@@ -376,12 +407,14 @@ + // Start/stop session recording if necessary. + viewer.checkRecordingStatus(); + +- rfb.writeFramebufferUpdateRequest( +- 0, +- 0, +- rfb.framebufferWidth, +- rfb.framebufferHeight, +- false); ++ if (!viewer.graftFtp) { ++ rfb.writeFramebufferUpdateRequest( ++ 0, ++ 0, ++ rfb.framebufferWidth, ++ rfb.framebufferHeight, ++ false); ++ } + + // + // main dispatch loop +@@ -390,6 +423,9 @@ + while (true) { + // Read message type from the server. + int msgType = rfb.readServerMessageType(); ++ if (viewer.ftpOnly && msgType != RfbProto.rfbFileTransfer) { ++ System.out.println("msgType:" + msgType); ++ } + + // Process the message depending on its type. + switch (msgType) { +@@ -1332,6 +1368,9 @@ + public void mouseDragged(MouseEvent evt) { + processLocalMouseEvent(evt, true); + } ++ public void mouseWheelMoved(MouseWheelEvent evt) { ++ processLocalMouseWheelEvent(evt); ++ } + + public void processLocalKeyEvent(KeyEvent evt) { + if (viewer.rfb != null && rfb.inNormalProtocol) { +@@ -1367,6 +1406,19 @@ + evt.consume(); + } + ++ public void processLocalMouseWheelEvent(MouseWheelEvent evt) { ++ if (viewer.rfb != null && rfb.inNormalProtocol) { ++ synchronized(rfb) { ++ try { ++ rfb.writeWheelEvent(evt); ++ } catch (Exception e) { ++ e.printStackTrace(); ++ } ++ rfb.notify(); ++ } ++ } ++ } ++ + public void processLocalMouseEvent(MouseEvent evt, boolean moved) { + if (viewer.rfb != null && rfb.inNormalProtocol) { + if (moved) { +@@ -1532,9 +1584,14 @@ + else + { + result = +- 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF) +- << 16 | (pixBuf[i * 4 + 2] & 0xFF) +- << 8 | (pixBuf[i * 4 + 3] & 0xFF); ++// begin runge/x11vnc ++// 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF) ++// << 16 | (pixBuf[i * 4 + 2] & 0xFF) ++// << 8 | (pixBuf[i * 4 + 3] & 0xFF); ++ 0xFF000000 | (pixBuf[i * 4 + 2] & 0xFF) ++ << 16 | (pixBuf[i * 4 + 1] & 0xFF) ++ << 8 | (pixBuf[i * 4 + 0] & 0xFF); ++// end runge/x11vnc + } + } else { + result = 0; // Transparent pixel +@@ -1565,9 +1622,14 @@ + else + { + result = +- 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF) +- << 16 | (pixBuf[i * 4 + 2] & 0xFF) +- << 8 | (pixBuf[i * 4 + 3] & 0xFF); ++// begin runge/x11vnc ++// 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF) ++// << 16 | (pixBuf[i * 4 + 2] & 0xFF) ++// << 8 | (pixBuf[i * 4 + 3] & 0xFF); ++ 0xFF000000 | (pixBuf[i * 4 + 2] & 0xFF) ++ << 16 | (pixBuf[i * 4 + 1] & 0xFF) ++ << 8 | (pixBuf[i * 4 + 0] & 0xFF); ++// end runge/x11vnc + } + } else { + result = 0; // Transparent pixel +diff -Naur JavaViewer.orig/VncViewer.java JavaViewer/VncViewer.java +--- JavaViewer.orig/VncViewer.java 2006-05-24 15:14:40.000000000 -0400 ++++ JavaViewer/VncViewer.java 2010-03-27 18:00:28.000000000 -0400 +@@ -41,6 +41,7 @@ + import java.io.*; + import java.net.*; + import javax.swing.*; ++import java.util.Date; + + public class VncViewer extends java.applet.Applet + implements java.lang.Runnable, WindowListener { +@@ -80,11 +81,11 @@ + GridBagLayout gridbag; + ButtonPanel buttonPanel; + AuthPanel authenticator; +- VncCanvas vc; ++ VncCanvas vc = null; + OptionsFrame options; + ClipboardFrame clipboard; + RecordingFrame rec; +- FTPFrame ftp; // KMC: FTP Frame declaration ++ FTPFrame ftp = null; // KMC: FTP Frame declaration + + // Control session recording. + Object recordingSync; +@@ -96,7 +97,7 @@ + + // Variables read from parameter values. + String host; +- int port; ++ int port, vncserverport; + String passwordParam; + String encPasswordParam; + boolean showControls; +@@ -115,28 +116,75 @@ + int i; + // mslogon support 2 end + ++// begin runge/x11vnc ++boolean disableSSL; ++boolean GET; ++String CONNECT; ++String urlPrefix; ++String httpsPort; ++String oneTimeKey; ++String serverCert; ++String ftpDropDown; ++String proxyHost; ++String proxyPort; ++boolean forceProxy; ++boolean ignoreProxy; ++boolean trustAllVncCerts; ++boolean trustUrlVncCert; ++boolean debugCerts; ++boolean debugKeyboard; ++boolean mapF5_to_atsign; ++boolean forbid_Ctrl_Alt; ++ ++boolean ignoreMSLogonCheck; ++boolean delayAuthPanel; ++boolean ftpOnly; ++boolean graftFtp; ++boolean dsmActive; ++ ++boolean gotAuth; ++int authGot; ++// end runge/x11vnc ++ ++ + // + // init() + // + ++public void ftp_init() { ++ boolean show = false; ++ if (ftp != null) { ++ show = true; ++ } ++ ftp = null; ++ ++ ftp = new FTPFrame(this); // KMC: FTPFrame creation ++ ++ if (show) { ++ ftp.doOpen(); ++ rfb.readServerDriveList(); ++ } ++} ++ + public void init() { + + readParameters(); + + if (inSeparateFrame) { +- vncFrame = new Frame("Ultr@VNC"); +- if (!inAnApplet) { +- vncFrame.add("Center", this); +- } +- vncContainer = vncFrame; ++ vncFrame = new Frame("Ultr@VNC"); ++ if (!inAnApplet) { ++ vncFrame.add("Center", this); ++ } ++ vncContainer = vncFrame; + } else { +- vncContainer = this; ++ vncContainer = this; + } + + recordingSync = new Object(); + + options = new OptionsFrame(this); + clipboard = new ClipboardFrame(this); ++ + // authenticator = new AuthPanel(false); // mslogon support : go to connectAndAuthenticate() + if (RecordingFrame.checkSecurity()) + rec = new RecordingFrame(this); +@@ -147,10 +195,11 @@ + cursorUpdatesDef = null; + eightBitColorsDef = null; + +- if (inSeparateFrame) ++ if (inSeparateFrame && vncFrame != null) + vncFrame.addWindowListener(this); + +- ftp = new FTPFrame(this); // KMC: FTPFrame creation ++ ftp_init(); ++ + rfbThread = new Thread(this); + rfbThread.start(); + } +@@ -186,6 +235,30 @@ + gbc.weightx = 1.0; + gbc.weighty = 1.0; + ++ if (ftpOnly) { ++ if (showControls) { ++ buttonPanel.enableButtons(); ++ } ++ ActionListener taskPerformer = new ActionListener() { ++ public void actionPerformed(ActionEvent evt) { ++ vncFrame.setVisible(false); ++ ftp.setSavedLocations(); ++ if (ftp.isVisible()) { ++ ftp.doClose(); ++ } else { ++ ftp.doOpen(); ++ } ++ rfb.readServerDriveList(); ++ } ++ }; ++ Timer t = new Timer(300, taskPerformer); ++ t.setRepeats(false); ++ t.start(); ++ ++ vc.processNormalProtocol(); ++ return; ++ } ++ + // Add ScrollPanel to applet mode + + // Create a panel which itself is resizeable and can hold +@@ -286,6 +359,24 @@ + + void connectAndAuthenticate() throws Exception { + ++ if (graftFtp) { ++ rfb = new RfbProto(host, port, this); ++ rfb.desktopName = "ftponly"; ++ rfb.framebufferWidth = 12; ++ rfb.framebufferHeight = 12; ++ rfb.bitsPerPixel = 32; ++ rfb.depth = 24; ++ rfb.trueColour = true; ++ rfb.redMax = 255; ++ rfb.greenMax = 255; ++ rfb.blueMax = 255; ++ rfb.redShift = 16; ++ rfb.greenShift = 8; ++ rfb.blueShift = 0; ++ rfb.inNormalProtocol = true; ++ return; ++ } ++ + // If "ENCPASSWORD" parameter is set, decrypt the password into + // the passwordParam string. + +@@ -336,7 +427,22 @@ + // + + +- prologueDetectAuthProtocol() ; ++// begin runge/x11vnc ++ gotAuth = false; ++ if (delayAuthPanel) { ++ if (tryAuthenticate(null, null)) { ++ if (inSeparateFrame) { ++ vncFrame.pack(); ++ vncFrame.show(); ++ } ++ return; ++ } ++ } ++// prologueDetectAuthProtocol() ; ++ if (ignoreMSLogonCheck == false) { ++ prologueDetectAuthProtocol() ; ++ } ++// end runge/x11vnc + + authenticator = new AuthPanel(mslogon); + +@@ -371,6 +477,7 @@ + //mslogon support end + } + ++ int tries = 0; + while (true) { + // Wait for user entering a password, or a username and a password + synchronized(authenticator) { +@@ -390,6 +497,13 @@ + break; + //mslogon support end + ++// begin runge/x11vnc ++ gotAuth = false; ++ if (++tries > 2) { ++ throw new Exception("Incorrect password entered " + tries + " times."); ++ } ++// end runge/x11vnc ++ + // Retry on authentication failure. + authenticator.retry(); + } +@@ -405,9 +519,11 @@ + + void prologueDetectAuthProtocol() throws Exception { + +- rfb = new RfbProto(host, port, this); ++ if (!gotAuth) { ++ rfb = new RfbProto(host, port, this); + +- rfb.readVersionMsg(); ++ rfb.readVersionMsg(); ++ } + + System.out.println("RFB server supports protocol version " + + rfb.serverMajor + "." + rfb.serverMinor); +@@ -431,16 +547,36 @@ + + boolean tryAuthenticate(String us, String pw) throws Exception { + +- rfb = new RfbProto(host, port, this); ++ int authScheme; + +- rfb.readVersionMsg(); ++ if (!gotAuth) { ++ rfb = new RfbProto(host, port, this); + +- System.out.println("RFB server supports protocol version " + +- rfb.serverMajor + "." + rfb.serverMinor); ++ rfb.readVersionMsg(); + +- rfb.writeVersionMsg(); ++ System.out.println("RFB server supports protocol version: " + ++ rfb.serverMajor + "." + rfb.serverMinor); + +- int authScheme = rfb.readAuthScheme(); ++ rfb.writeVersionMsg(); ++ ++ authScheme = rfb.readAuthScheme(); ++ ++ gotAuth = true; ++ authGot = authScheme; ++ } else { ++ authScheme = authGot; ++ } ++// begin runge/x11vnc ++ if (delayAuthPanel && pw == null) { ++ if (authScheme == RfbProto.NoAuth) { ++ System.out.println("No authentication needed"); ++ return true; ++ } else { ++ return false; ++ } ++ } ++System.out.println("as: " + authScheme); ++// end runge/x11vnc + + switch (authScheme) { + +@@ -629,6 +765,10 @@ + + void doProtocolInitialisation() throws IOException { + ++ if (graftFtp) { ++ return; ++ } ++ + rfb.writeClientInit(); + + rfb.readServerInit(); +@@ -774,9 +914,28 @@ + fatalError("HOST parameter not specified"); + } + } ++ Date d = new Date(); ++ System.out.println("-\nSSL VNC Java Applet starting. " + d); + +- String str = readParameter("PORT", true); +- port = Integer.parseInt(str); ++ port = 0; ++ String str = readParameter("PORT", false); ++ if (str != null) { ++ port = Integer.parseInt(str); ++ } ++ // When there is a proxy VNCSERVERPORT may be inaccessible (inside firewall). ++ vncserverport = 0; ++ str = readParameter("VNCSERVERPORT", false); ++ if (str != null) { ++ vncserverport = Integer.parseInt(str); ++ } ++ if (port == 0 && vncserverport == 0) { ++ fatalError("Neither PORT nor VNCSERVERPORT parameters specified"); ++ } ++ if (port == 0) { ++ // Nevertheless, fall back to vncserverport if we have to. ++ System.out.println("using vncserverport: '" + vncserverport + "' for PORT."); ++ port = vncserverport; ++ } + + if (inAnApplet) { + str = readParameter("Open New Window", false); +@@ -804,6 +963,158 @@ + deferScreenUpdates = readIntParameter("Defer screen updates", 20); + deferCursorUpdates = readIntParameter("Defer cursor updates", 10); + deferUpdateRequests = readIntParameter("Defer update requests", 50); ++ ++// begin runge/x11vnc ++ // SSL ++ disableSSL = false; ++ str = readParameter("DisableSSL", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) ++ disableSSL = true; ++ ++ httpsPort = readParameter("httpsPort", false); ++ ++ // Extra GET, CONNECT string: ++ CONNECT = readParameter("CONNECT", false); ++ if (CONNECT != null) { ++ CONNECT = CONNECT.replaceAll(" ", ":"); ++ } ++ ++ GET = false; ++ str = readParameter("GET", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ GET = true; ++ } ++ if (str != null && str.equalsIgnoreCase("1")) { ++ GET = true; ++ } ++ ++ urlPrefix = readParameter("urlPrefix", false); ++ if (urlPrefix != null) { ++ urlPrefix = urlPrefix.replaceAll("%2F", "/"); ++ urlPrefix = urlPrefix.replaceAll("%2f", "/"); ++ urlPrefix = urlPrefix.replaceAll("_2F_", "/"); ++ if (urlPrefix.indexOf("/") != 0) { ++ urlPrefix = "/" + urlPrefix; ++ } ++ } else { ++ urlPrefix = ""; ++ } ++ System.out.println("urlPrefix: '" + urlPrefix + "'"); ++ ++ ftpDropDown = readParameter("ftpDropDown", false); ++ if (ftpDropDown != null) { ++ ftpDropDown = ftpDropDown.replaceAll("%2F", "/"); ++ ftpDropDown = ftpDropDown.replaceAll("%2f", "/"); ++ ftpDropDown = ftpDropDown.replaceAll("_2F_", "/"); ++ ftpDropDown = ftpDropDown.replaceAll("%20", " "); ++ System.out.println("ftpDropDown: '" + ftpDropDown + "'"); ++ } ++ ++ ++ oneTimeKey = readParameter("oneTimeKey", false); ++ if (oneTimeKey != null) { ++ System.out.println("oneTimeKey is set."); ++ } ++ ++ serverCert = readParameter("serverCert", false); ++ if (serverCert != null) { ++ System.out.println("serverCert is set."); ++ } ++ ++ forceProxy = false; ++ proxyHost = null; ++ proxyPort = null; ++ str = readParameter("forceProxy", false); ++ if (str != null) { ++ if (str.equalsIgnoreCase("Yes")) { ++ forceProxy = true; ++ } else if (str.equalsIgnoreCase("No")) { ++ forceProxy = false; ++ } else { ++ forceProxy = true; ++ String[] pieces = str.split(" "); ++ proxyHost = new String(pieces[0]); ++ if (pieces.length >= 2) { ++ proxyPort = new String(pieces[1]); ++ } else { ++ proxyPort = new String("8080"); ++ } ++ } ++ } ++ str = readParameter("proxyHost", false); ++ if (str != null) { ++ proxyHost = new String(str); ++ } ++ str = readParameter("proxyPort", false); ++ if (str != null) { ++ proxyPort = new String(str); ++ } ++ if (proxyHost != null && proxyPort == null) { ++ proxyPort = new String("8080"); ++ } ++ ++ ignoreProxy = false; ++ str = readParameter("ignoreProxy", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ ignoreProxy = true; ++ } ++ ++ trustAllVncCerts = false; ++ str = readParameter("trustAllVncCerts", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ trustAllVncCerts = true; ++ } ++ trustUrlVncCert = false; ++ str = readParameter("trustUrlVncCert", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ trustUrlVncCert = true; ++ } ++ debugCerts = false; ++ str = readParameter("debugCerts", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ debugCerts = true; ++ } ++ debugKeyboard = false; ++ str = readParameter("debugKeyboard", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ debugKeyboard = true; ++ } ++ mapF5_to_atsign = false; ++ str = readParameter("mapF5_to_atsign", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ mapF5_to_atsign = true; ++ } ++ forbid_Ctrl_Alt = false; ++ str = readParameter("forbid_Ctrl_Alt", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ forbid_Ctrl_Alt = true; ++ } ++ ignoreMSLogonCheck = false; ++ str = readParameter("ignoreMSLogonCheck", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ ignoreMSLogonCheck = true; ++ } ++ ftpOnly = false; ++ str = readParameter("ftpOnly", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ ftpOnly = true; ++ } ++ graftFtp = false; ++ str = readParameter("graftFtp", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ graftFtp = true; ++ } ++ dsmActive = false; ++ str = readParameter("dsmActive", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ dsmActive = true; ++ } ++ delayAuthPanel = false; ++ str = readParameter("delayAuthPanel", false); ++ if (str != null && str.equalsIgnoreCase("Yes")) { ++ delayAuthPanel = true; ++ } ++// end runge/x11vnc + } + + public String readParameter(String name, boolean required) { |