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