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/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 2008-10-06 13:32:30.000000000 -0400 @@ -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); // } diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java --- JavaViewer.orig/SSLSocketToMe.java 1969-12-31 19:00:00.000000000 -0500 +++ JavaViewer/SSLSocketToMe.java 2009-08-13 09:16:42.000000000 -0400 @@ -0,0 +1,1727 @@ +/* + * SSLSocketToMe.java: add SSL encryption to Java VNC Viewer. + * + * Copyright (c) 2006 Karl J. Runge + * 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; + + /* sockets */ + SSLSocket socket = null; + SSLSocketFactory factory; + + /* fallback for Proxy connection */ + boolean proxy_in_use = false; + boolean proxy_is_https = false; + boolean proxy_failure = false; + public DataInputStream is = null; + public OutputStream os = null; + + 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 trusturl_ctx; + SSLContext trustone_ctx; + + TrustManager[] trustAllCerts; + TrustManager[] trustUrlCert; + TrustManager[] trustOneCert; + + boolean use_url_cert_for_auth = true; + boolean user_wants_to_see_cert = true; + + /* cert(s) we retrieve from VNC server */ + java.security.cert.Certificate[] trustallCerts = null; + java.security.cert.Certificate[] trusturlCerts = null; + + byte[] hex2bytes(String s) { + byte[] bytes = new byte[s.length()/2]; + for (int i=0; i 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; + + /* we will first try default factory for certification: */ + + factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); + + dbg("SSL startup: " + host + " " + port); + + /* create trust managers used if initial handshake fails: */ + + trustAllCerts = new TrustManager[] { + /* + * this one accepts everything. + */ + 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. + */ + 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"); + } + public void checkServerTrusted( + java.security.cert.X509Certificate[] certs, + String authType) throws CertificateException { + if (trusturlCerts == null) { + throw new CertificateException( + "No Trust url Certs array."); + } + if (trusturlCerts.length < 1) { + throw new CertificateException( + "No Trust url Certs."); + } + if (trusturlCerts.length > 1) { + int i; + boolean ok = true; + for (i = 0; i < trusturlCerts.length - 1; i++) { + if (! trusturlCerts[i].equals(trusturlCerts[i+1])) { + ok = false; + } + } + if (! ok) { + throw new CertificateException( + "Too many Trust url Certs: " + + trusturlCerts.length + ); + } + } + if (certs == null) { + throw new CertificateException( + "No this-certs array."); + } + if (certs.length < 1) { + throw new CertificateException( + "No this-certs Certs."); + } + if (certs.length > 1) { + int i; + boolean ok = true; + for (i = 0; i < certs.length - 1; i++) { + if (! certs[i].equals(certs[i+1])) { + ok = false; + } + } + if (! ok) { + throw new CertificateException( + "Too many this-certs: " + + certs.length + ); + } + } + if (! trusturlCerts[0].equals(certs[0])) { + throw new CertificateException( + "Server Cert Changed != URL."); + } + dbg("URL: trusturlCerts[0] matches certs[0]"); + } + } + }; + trustOneCert = new TrustManager[] { + /* + * this one accepts only the retrieved server cert + * by SSLSocket by this applet. + */ + 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"); + } + public void checkServerTrusted( + java.security.cert.X509Certificate[] certs, + String authType) throws CertificateException { + 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 (trustallCerts.length > 1) { + int i; + boolean ok = true; + for (i = 0; i < trustallCerts.length - 1; i++) { + if (! trustallCerts[i].equals(trustallCerts[i+1])) { + ok = false; + } + } + if (! ok) { + throw new CertificateException( + "Too many Trust All Server Certs: " + + trustallCerts.length + ); + } + } + if (certs == null) { + throw new CertificateException( + "No this-certs array."); + } + if (certs.length < 1) { + throw new CertificateException( + "No this-certs Certs."); + } + if (certs.length > 1) { + int i; + boolean ok = true; + for (i = 0; i < certs.length - 1; i++) { + if (! certs[i].equals(certs[i+1])) { + ok = false; + } + } + if (! ok) { + throw new CertificateException( + "Too many this-certs: " + + certs.length + ); + } + } + if (! trustallCerts[0].equals(certs[0])) { + throw new CertificateException( + "Server Cert Changed != TRUSTALL."); + } + dbg("ONE: trustallCerts[0] matches certs[0]"); + } + } + }; + + /* + * They are used: + * + * 1) to retrieve the server cert in case of failure to + * display it to the user. + * 2) to subsequently connect to the server if user agrees. + */ + + KeyManager[] mykey = null; + + 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); + //dbg("ff " + ff); + String cert_str = new String(cert); + + 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)); + //dbg("tmpcert" + 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(); + } + + + /* trust loc certs: */ + try { + trustloc_ctx = SSLContext.getInstance("SSL"); + trustloc_ctx.init(mykey, null, new + java.security.SecureRandom()); + + } catch (Exception e) { + String msg = "SSL trustloc_ctx FAILED."; + dbg(msg); + throw new Exception(msg); + } + + /* trust all certs: */ + 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); + } + + /* trust url certs: */ + 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); + } + + /* trust the one cert from server: */ + 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); + } + } + + boolean browser_cert_match() { + String msg = "Browser URL accept previously accepted cert"; + + if (user_wants_to_see_cert) { + return false; + } + + if (trustallCerts != null && trusturlCerts != null) { + if (trustallCerts.length == 1 && trusturlCerts.length == 1) { + if (trustallCerts[0].equals(trusturlCerts[0])) { + System.out.println(msg); + return true; + } + } + } + return false; + } + + public void check_for_proxy() { + + boolean result = false; + + trusturlCerts = null; + proxy_in_use = false; + if (viewer.ignoreProxy) { + return; + } + + String ustr = "https://" + host + ":"; + if (viewer.httpsPort != null) { + ustr += viewer.httpsPort; + } else { + ustr += port; // hmmm + } + ustr += viewer.urlPrefix + "/check.https.proxy.connection"; + dbg("ustr is: " + ustr); + + + try { + URL url = new URL(ustr); + HttpsURLConnection https = (HttpsURLConnection) + url.openConnection(); + + https.setUseCaches(false); + https.setRequestMethod("GET"); + https.setRequestProperty("Pragma", "No-Cache"); + https.setRequestProperty("Proxy-Connection", + "Keep-Alive"); + https.setDoInput(true); + + https.connect(); + + 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; + proxy_is_https = true; + dbg("HTTPS proxy in use. There may be connection problems."); + } + Object output = https.getContent(); + https.disconnect(); + result = true; + + } catch(Exception e) { + dbg("HttpsURLConnection: " + e.getMessage()); + } + + if (proxy_in_use) { + return; + } + + ustr = "http://" + host + ":" + port; + ustr += viewer.urlPrefix + "/index.vnc"; + + try { + 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); + + http.connect(); + + if (http.usingProxy()) { + proxy_in_use = true; + proxy_is_https = false; + dbg("HTTP proxy in use. There may be connection problems."); + } + Object output = http.getContent(); + http.disconnect(); + + } catch(Exception e) { + dbg("HttpURLConnection: " + e.getMessage()); + } + } + + public Socket connectSock() throws IOException { + + /* + * first try a https connection to detect a proxy, and + * also grab the VNC server cert. + */ + check_for_proxy(); + + if (viewer.trustAllVncCerts) { + dbg("viewer.trustAllVncCerts-0 using trustall_ctx"); + factory = trustall_ctx.getSocketFactory(); + } else if (use_url_cert_for_auth && trusturlCerts != null) { + dbg("using trusturl_ctx"); + factory = trusturl_ctx.getSocketFactory(); + } else { + 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("esock: " + 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("err proxy_socket: " + e.getMessage()); + } + } + } + + try { + socket.startHandshake(); + dbg("Server Connection Verified on 1st try."); + + java.security.cert.Certificate[] currentTrustedCerts; + BrowserCertsDialog bcd; + + SSLSession sess = socket.getSession(); + currentTrustedCerts = sess.getPeerCertificates(); + + if (viewer.trustAllVncCerts) { + dbg("viewer.trustAllVncCerts-1"); + } else if (currentTrustedCerts == null || currentTrustedCerts.length < 1) { + socket.close(); + 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"); + user_wants_to_see_cert = false; + } else if (viewer.trustUrlVncCert) { + dbg("viewer.trustUrlVncCert-1"); + user_wants_to_see_cert = false; + } else { + bcd = new BrowserCertsDialog(serv, host + ":" + port); + dbg("browser certs dialog START"); + bcd.queryUser(); + dbg("browser certs dialog DONE"); + if (bcd.showCertDialog) { + String msg = "user wants to see cert"; + dbg(msg); + user_wants_to_see_cert = true; + throw new SSLHandshakeException(msg); + } else { + user_wants_to_see_cert = false; + dbg("browser certs dialog: user said yes, accept it"); + } + } + + } catch (SSLHandshakeException eh) { + dbg("Could not automatically verify Server."); + dbg("msg: " + eh.getMessage()); + String getoutstr = "GET /index.vnc HTTP/1.0\r\nConnection: close\r\n\r\n"; + + OutputStream os = socket.getOutputStream(); + os.write(getoutstr.getBytes()); + socket.close(); + socket = null; + + /* + * Reconnect, trusting any cert, so we can grab + * the cert to show it to the user. The 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); + } + + try { + socket.startHandshake(); + dbg("TrustAll Server Connection Verified."); + + /* grab the cert: */ + try { + SSLSession sess = socket.getSession(); + trustallCerts = sess.getPeerCertificates(); + } catch (Exception e) { + throw new Exception("Could not get " + + "Peer Certificate"); + } + + if (viewer.trustAllVncCerts) { + dbg("viewer.trustAllVncCerts-3"); + } else if (! browser_cert_match()) { + /* + * close socket now, we will reopen after + * dialog if user agrees to use the cert. + */ + os = socket.getOutputStream(); + os.write(getoutstr.getBytes()); + socket.close(); + socket = null; + + /* dialog with user to accept cert or not: */ + + TrustDialog td= new TrustDialog(host, port, + trustallCerts); + + if (! td.queryUser()) { + 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()); + } + + if (socket != null) { + try { + socket.close(); + } catch (Exception e) { + ; + } + socket = null; + } + + /* + * Now connect a 3rd time, using the cert + * retrieved during connection 2 (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 Server Connection Verified #3."); + + } catch (Exception ehand3) { + dbg("** Could not TrustAll Verify Server #3."); + + throw new IOException(ehand3.getMessage()); + } + } + + 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 GET: " + 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."); + return (Socket) socket; + } + + 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; + } + + 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); + + for (int k=0; k < 2; k++) { + dbg("proxy_in_use psocket:"); + + if (proxySock != null) { + try { + proxySock.close(); + } catch (Exception e) { + ; + } + } + + 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: " + 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("sock prob: " + e.getMessage()); + } + + 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("")) { + 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) { + 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"); + + 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") < 0 && v2.indexOf("proxy") < 0) { + continue; + } + if (v2.indexOf("http") < 0) { + continue; + } + + 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; + } + + 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("sock prob2: " + 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() { + + /* 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"); + } + + text = "\n" ++ "Unable to verify the identity of\n" ++ "\n" ++ " " + host + ":" + port + "\n" ++ "\n" ++ infostr ++ "\n" ++ "as a trusted VNC server.\n" ++ "\n" ++ "This may be due to:\n" ++ "\n" ++ " - Your requesting to View the Certificate before accepting.\n" ++ "\n" ++ " - The VNC server using a Self-Signed Certificate.\n" ++ "\n" ++ " - The VNC server using a Certificate Authority not recognized by your\n" ++ " Browser or Java Plugin runtime.\n" ++ "\n" ++ " - The use of an Apache SSL portal employing CONNECT proxying and the\n" ++ " Apache web server has a certificate different from the VNC server's. \n" ++ "\n" ++ " - A Man-In-The-Middle attack impersonating as the VNC server 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\n" ++ "Certificate Authority certificate) you can configure your Web Browser or\n" ++ "Java Plugin to automatically authenticate this Server.\n" ++ "\n" ++ "If you do so, then you will only have to click \"Yes\" when this VNC\n" ++ "Viewer applet asks you whether to trust your Browser/Java Plugin's\n" ++ "acceptance of the certificate. (except for the Apache portal case above.)\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, 36, 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 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 += "Should this VNC Viewer applet now connect to the above VNC server?\n"; +m += "\n"; + +// String m = "\nShould this VNC Viewer applet use your Browser/JVM certs to\n"; +// m += "authenticate the VNC Server:\n"; +// m += "\n " + hostport + "\n\n " + vncServer + "\n\n"; +// m += "(NOTE: this *includes* any certs you have Just Now accepted in a\n"; +// m += "dialog box with your Web Browser or Java Applet Plugin)\n\n"; + + TextArea textarea = new TextArea(m, 20, 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; iin. + * @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 0) { viewer.options.oldEightBitColors = viewer.options.eightBitColors; @@ -237,6 +259,9 @@ } else { +// begin runge/x11vnc + viewer.options.oldEightBitColors = viewer.options.eightBitColors; +// end runge/x11vnc rfb.writeSetPixelFormat( 32, 24, @@ -376,12 +401,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 +417,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) { @@ -1532,9 +1562,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 +1600,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 2009-06-19 10:31:23.000000000 -0400 @@ -80,11 +80,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 +96,7 @@ // Variables read from parameter values. String host; - int port; + int port, vncserverport; String passwordParam; String encPasswordParam; boolean showControls; @@ -115,28 +115,70 @@ int i; // mslogon support 2 end +// begin runge/x11vnc +boolean disableSSL; +boolean GET; +String CONNECT; +String urlPrefix; +String httpsPort; +String oneTimeKey; +String ftpDropDown; +String proxyHost; +String proxyPort; +boolean forceProxy; +boolean ignoreProxy; +boolean trustAllVncCerts; +boolean trustUrlVncCert; + +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 +189,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 +229,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 +353,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 +421,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); @@ -390,6 +490,10 @@ break; //mslogon support end +// begin runge/x11vnc + gotAuth = false; +// end runge/x11vnc + // Retry on authentication failure. authenticator.retry(); } @@ -405,9 +509,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 +537,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); + + rfb.writeVersionMsg(); - int authScheme = rfb.readAuthScheme(); + 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 +755,10 @@ void doProtocolInitialisation() throws IOException { + if (graftFtp) { + return; + } + rfb.writeClientInit(); rfb.readServerInit(); @@ -775,8 +905,25 @@ } } - 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 +951,133 @@ 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"); + } + + 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; + } + 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) {