Home | History | Annotate | Download | only in ssl
      1 diff -Naur vnc_javasrc.orig/Makefile vnc_javasrc/Makefile
      2 --- vnc_javasrc.orig/Makefile	2004-03-04 08:34:25.000000000 -0500
      3 +++ vnc_javasrc/Makefile	2010-05-18 20:56:26.000000000 -0400
      4 @@ -4,6 +4,7 @@
      5  
      6  CP = cp
      7  JC = javac
      8 +JC_ARGS = -target 1.4 -source 1.4
      9  JAR = jar
     10  ARCHIVE = VncViewer.jar
     11  MANIFEST = MANIFEST.MF
     12 @@ -15,25 +16,29 @@
     13  	  DesCipher.class CapabilityInfo.class CapsContainer.class \
     14  	  RecordingFrame.class SessionRecorder.class AuthUnixLoginPanel.class \
     15  	  SocketFactory.class HTTPConnectSocketFactory.class \
     16 -	  HTTPConnectSocket.class ReloginPanel.class
     17 +	  HTTPConnectSocket.class ReloginPanel.class \
     18 +	  SSLSocketToMe.class
     19 +
     20 +SSL_CLASSES = SSLSocketToMe*.class TrustDialog.class
     21  
     22  SOURCES = VncViewer.java RfbProto.java AuthPanel.java VncCanvas.java \
     23  	  OptionsFrame.java ClipboardFrame.java ButtonPanel.java \
     24  	  DesCipher.java CapabilityInfo.java CapsContainer.java \
     25  	  RecordingFrame.java SessionRecorder.java AuthUnixLoginPanel.java \
     26  	  SocketFactory.java HTTPConnectSocketFactory.java \
     27 -	  HTTPConnectSocket.java ReloginPanel.java
     28 +	  HTTPConnectSocket.java ReloginPanel.java \
     29 +	  SSLSocketToMe.java
     30  
     31  all: $(CLASSES) $(ARCHIVE)
     32  
     33  $(CLASSES): $(SOURCES)
     34 -	$(JC) -target 1.1 -O $(SOURCES)
     35 +	$(JC) $(JC_ARGS) -O $(SOURCES)
     36  
     37  $(ARCHIVE): $(CLASSES) $(MANIFEST)
     38 -	$(JAR) cfm $(ARCHIVE) $(MANIFEST) $(CLASSES)
     39 +	$(JAR) cfm $(ARCHIVE) $(MANIFEST) $(CLASSES) $(SSL_CLASSES)
     40  
     41  install: $(CLASSES) $(ARCHIVE)
     42 -	$(CP) $(CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR)
     43 +	$(CP) $(CLASSES) $(SSL_CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR)
     44  
     45  export:: $(CLASSES) $(ARCHIVE) $(PAGES)
     46  	@$(ExportJavaClasses)
     47 diff -Naur vnc_javasrc.orig/RfbProto.java vnc_javasrc/RfbProto.java
     48 --- vnc_javasrc.orig/RfbProto.java	2004-03-04 08:34:25.000000000 -0500
     49 +++ vnc_javasrc/RfbProto.java	2010-11-30 22:05:12.000000000 -0500
     50 @@ -199,7 +199,21 @@
     51      host = h;
     52      port = p;
     53  
     54 -    if (viewer.socketFactory == null) {
     55 +    if (! viewer.disableSSL) {
     56 +	System.out.println("new SSLSocketToMe");
     57 +	SSLSocketToMe ssl;
     58 +	try {
     59 +		ssl = new SSLSocketToMe(host, port, v);
     60 +	} catch (Exception e) {
     61 +		throw new IOException(e.getMessage());
     62 +	}
     63 +
     64 +	try {
     65 +		sock = ssl.connectSock();
     66 +	} catch (Exception es) {
     67 +		throw new IOException(es.getMessage());
     68 +	}
     69 +    } else if (viewer.socketFactory == null) {
     70        sock = new Socket(host, port);
     71      } else {
     72        try {
     73 @@ -255,7 +269,7 @@
     74  	|| (b[10] < '0') || (b[10] > '9') || (b[11] != '\n'))
     75      {
     76        throw new Exception("Host " + host + " port " + port +
     77 -			  " is not an RFB server");
     78 +			  " is not an RFB server: " + b);
     79      }
     80  
     81      serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0');
     82 @@ -892,6 +906,38 @@
     83    final static int ALT_MASK   = InputEvent.ALT_MASK;
     84  
     85  
     86 +  void writeWheelEvent(MouseWheelEvent evt) throws IOException {
     87 +
     88 +    eventBufLen = 0;
     89 +
     90 +    int x = evt.getX();
     91 +    int y = evt.getY();
     92 +
     93 +    if (x < 0) x = 0;
     94 +    if (y < 0) y = 0;
     95 +
     96 +    int ptrmask;
     97 +
     98 +    int clicks = evt.getWheelRotation();
     99 +    System.out.println("writeWheelEvent: clicks: " + clicks);
    100 +    if (clicks > 0) {
    101 +    	ptrmask = 16;
    102 +    } else if (clicks < 0) {
    103 +    	ptrmask = 8;
    104 +    } else {
    105 +    	return;
    106 +    }
    107 +
    108 +    eventBuf[eventBufLen++] = (byte) PointerEvent;
    109 +    eventBuf[eventBufLen++] = (byte) ptrmask;
    110 +    eventBuf[eventBufLen++] = (byte) ((x >> 8) & 0xff);
    111 +    eventBuf[eventBufLen++] = (byte) (x & 0xff);
    112 +    eventBuf[eventBufLen++] = (byte) ((y >> 8) & 0xff);
    113 +    eventBuf[eventBufLen++] = (byte) (y & 0xff);
    114 +
    115 +    os.write(eventBuf, 0, eventBufLen);
    116 +  }
    117 +
    118    //
    119    // Write a pointer event message.  We may need to send modifier key events
    120    // around it to set the correct modifier state.
    121 @@ -992,6 +1038,19 @@
    122      boolean down = (evt.getID() == KeyEvent.KEY_PRESSED);
    123  
    124      int key;
    125 +	if (viewer.debugKeyboard) {
    126 +		System.out.println("----------------------------------------");
    127 +		System.out.println("evt.getKeyChar:      " + evt.getKeyChar());
    128 +		System.out.println("getKeyText:          " + KeyEvent.getKeyText(evt.getKeyCode()));
    129 +		System.out.println("evt.getKeyCode:      " + evt.getKeyCode());
    130 +		System.out.println("evt.getID:           " + evt.getID());
    131 +		System.out.println("evt.getKeyLocation:  " + evt.getKeyLocation());
    132 +		System.out.println("evt.isActionKey:     " + evt.isActionKey());
    133 +		System.out.println("evt.isControlDown:   " + evt.isControlDown());
    134 +		System.out.println("evt.getModifiers:    " + evt.getModifiers());
    135 +		System.out.println("getKeyModifiersText: " + KeyEvent.getKeyModifiersText(evt.getModifiers()));
    136 +		System.out.println("evt.paramString:     " + evt.paramString());
    137 +	}
    138      if (evt.isActionKey()) {
    139  
    140        //
    141 @@ -1025,6 +1084,13 @@
    142          return;
    143        }
    144  
    145 +      if(key == 0xffc2 && viewer.mapF5_to_atsign) {
    146 +	 if (viewer.debugKeyboard) {
    147 +	    System.out.println("Mapping: F5 -> AT ");
    148 +	 }
    149 +      	 key = 0x40;
    150 +      }
    151 +
    152      } else {
    153  
    154        //
    155 @@ -1036,6 +1102,7 @@
    156  
    157        key = keyChar;
    158  
    159 +
    160        if (key < 0x20) {
    161          if (evt.isControlDown()) {
    162            key += 0x60;
    163 @@ -1121,6 +1188,16 @@
    164    int oldModifiers = 0;
    165  
    166    void writeModifierKeyEvents(int newModifiers) {
    167 +    if(viewer.forbid_Ctrl_Alt) {
    168 +	if ((newModifiers & CTRL_MASK) != 0 && (newModifiers & ALT_MASK) != 0) {
    169 +		int orig = newModifiers;
    170 +		newModifiers &= ~ALT_MASK;
    171 +		newModifiers &= ~CTRL_MASK;
    172 +		if (viewer.debugKeyboard) {
    173 +			System.out.println("Ctrl+Alt modifiers: " + orig + " -> " + newModifiers);
    174 +		}
    175 +	}
    176 +    }
    177      if ((newModifiers & CTRL_MASK) != (oldModifiers & CTRL_MASK))
    178        writeKeyEvent(0xffe3, (newModifiers & CTRL_MASK) != 0);
    179  
    180 diff -Naur vnc_javasrc.orig/SSLSocketToMe.java vnc_javasrc/SSLSocketToMe.java
    181 --- vnc_javasrc.orig/SSLSocketToMe.java	1969-12-31 19:00:00.000000000 -0500
    182 +++ vnc_javasrc/SSLSocketToMe.java	2010-07-10 19:18:06.000000000 -0400
    183 @@ -0,0 +1,2067 @@
    184 +/*
    185 + * SSLSocketToMe.java: add SSL encryption to Java VNC Viewer.
    186 + *
    187 + * Copyright (c) 2006 Karl J. Runge <runge (a] karlrunge.com>
    188 + * All rights reserved.
    189 + *
    190 + *  This is free software; you can redistribute it and/or modify
    191 + *  it under the terms of the GNU General Public License as published by
    192 + *  the Free Software Foundation; version 2 of the License, or
    193 + *  (at your option) any later version.
    194 + *
    195 + *  This software is distributed in the hope that it will be useful,
    196 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    197 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    198 + *  GNU General Public License for more details.
    199 + *
    200 + *  You should have received a copy of the GNU General Public License
    201 + *  along with this software; if not, write to the Free Software
    202 + *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
    203 + *  USA.
    204 + *
    205 + */
    206 +
    207 +import java.net.*;
    208 +import java.io.*;
    209 +import javax.net.ssl.*;
    210 +import java.util.*;
    211 +
    212 +import java.security.*;
    213 +import java.security.cert.*;
    214 +import java.security.spec.*;
    215 +import java.security.cert.Certificate;
    216 +import java.security.cert.CertificateFactory;
    217 +
    218 +import java.awt.*;
    219 +import java.awt.event.*;
    220 +
    221 +public class SSLSocketToMe {
    222 +
    223 +	/* basic member data: */
    224 +	String host;
    225 +	int port;
    226 +	VncViewer viewer;
    227 +
    228 +	boolean debug = true;
    229 +	boolean debug_certs = false;
    230 +
    231 +	/* sockets */
    232 +	SSLSocket socket = null;
    233 +	SSLSocketFactory factory;
    234 +
    235 +	/* fallback for Proxy connection */
    236 +	boolean proxy_in_use = false;
    237 +	boolean proxy_failure = false;
    238 +	public DataInputStream is = null;
    239 +	public OutputStream os = null;
    240 +
    241 +	/* strings from user WRT proxy: */
    242 +	String proxy_auth_string = null;
    243 +	String proxy_dialog_host = null;
    244 +	int proxy_dialog_port = 0;
    245 +
    246 +	Socket proxySock;
    247 +	DataInputStream proxy_is;
    248 +	OutputStream proxy_os;
    249 +
    250 +	/* trust contexts */
    251 +	SSLContext trustloc_ctx;
    252 +	SSLContext trustall_ctx;
    253 +	SSLContext trustsrv_ctx;
    254 +	SSLContext trusturl_ctx;
    255 +	SSLContext trustone_ctx;
    256 +
    257 +	/* corresponding trust managers */
    258 +	TrustManager[] trustAllCerts;
    259 +	TrustManager[] trustSrvCert;
    260 +	TrustManager[] trustUrlCert;
    261 +	TrustManager[] trustOneCert;
    262 +
    263 +	/* client-side SSL auth key (oneTimeKey=...) */
    264 +	KeyManager[] mykey = null;
    265 +
    266 +	boolean user_wants_to_see_cert = true;
    267 +	String cert_fail = null;
    268 +
    269 +	/* cert(s) we retrieve from Web server, VNC server, or serverCert param: */
    270 +	java.security.cert.Certificate[] trustallCerts = null;
    271 +	java.security.cert.Certificate[] trustsrvCerts = null;
    272 +	java.security.cert.Certificate[] trusturlCerts = null;
    273 +
    274 +	/* utility to decode hex oneTimeKey=... and serverCert=... */
    275 +	byte[] hex2bytes(String s) {
    276 +		byte[] bytes = new byte[s.length()/2];
    277 +		for (int i=0; i<s.length()/2; i++) {
    278 +			int j = 2*i;
    279 +			try {
    280 +				int val = Integer.parseInt(s.substring(j, j+2), 16);
    281 +				if (val > 127) {
    282 +					val -= 256;
    283 +				}
    284 +				Integer I = new Integer(val);
    285 +				bytes[i] = Byte.decode(I.toString()).byteValue();
    286 +				
    287 +			} catch (Exception e) {
    288 +				;
    289 +			}
    290 +		}
    291 +		return bytes;
    292 +	}
    293 +
    294 +	SSLSocketToMe(String h, int p, VncViewer v) throws Exception {
    295 +		host = h;
    296 +		port = p;
    297 +		viewer = v;
    298 +
    299 +		debug_certs = v.debugCerts;
    300 +
    301 +		/* we will first try default factory for certification: */
    302 +
    303 +		factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
    304 +
    305 +		dbg("SSL startup: " + host + " " + port);
    306 +
    307 +
    308 +		/* create trust managers to be used if initial handshake fails: */
    309 +
    310 +		trustAllCerts = new TrustManager[] {
    311 +		    /*
    312 +		     * this one accepts everything.  Only used if user
    313 +		     * has disabled checking (trustAllVncCerts=yes)
    314 +		     * or when we grab the cert to show it to them in
    315 +		     * a dialog and ask them to manually verify/accept it.
    316 +		     */
    317 +		    new X509TrustManager() {
    318 +			public java.security.cert.X509Certificate[]
    319 +			    getAcceptedIssuers() {
    320 +				return null;
    321 +			}
    322 +			public void checkClientTrusted(
    323 +			    java.security.cert.X509Certificate[] certs,
    324 +			    String authType) {
    325 +				/* empty */
    326 +			}
    327 +			public void checkServerTrusted(
    328 +			    java.security.cert.X509Certificate[] certs,
    329 +			    String authType) {
    330 +				/* empty */
    331 +				dbg("ALL: an untrusted connect to grab cert.");
    332 +			}
    333 +		    }
    334 +		};
    335 +
    336 +		trustUrlCert = new TrustManager[] {
    337 +		    /*
    338 +		     * this one accepts only the retrieved server
    339 +		     * cert by SSLSocket by this applet and stored in
    340 +		     * trusturlCerts.
    341 +		     */
    342 +		    new X509TrustManager() {
    343 +			public java.security.cert.X509Certificate[]
    344 +			    getAcceptedIssuers() {
    345 +				return null;
    346 +			}
    347 +			public void checkClientTrusted(
    348 +			    java.security.cert.X509Certificate[] certs,
    349 +			    String authType) throws CertificateException {
    350 +				throw new CertificateException("No Clients (URL)");
    351 +			}
    352 +			public void checkServerTrusted(
    353 +			    java.security.cert.X509Certificate[] certs,
    354 +			    String authType) throws CertificateException {
    355 +				/* we want to check 'certs' against 'trusturlCerts' */
    356 +				if (trusturlCerts == null) {
    357 +					throw new CertificateException(
    358 +					    "No Trust url Certs array.");
    359 +				}
    360 +				if (trusturlCerts.length < 1) {
    361 +					throw new CertificateException(
    362 +					    "No Trust url Certs.");
    363 +				}
    364 +				if (certs == null) {
    365 +					throw new CertificateException(
    366 +					    "No this-certs array.");
    367 +				}
    368 +				if (certs.length < 1) {
    369 +					throw new CertificateException(
    370 +					    "No this-certs Certs.");
    371 +				}
    372 +				if (certs.length != trusturlCerts.length) {
    373 +					throw new CertificateException(
    374 +					    "certs.length != trusturlCerts.length " + certs.length + " " + trusturlCerts.length);
    375 +				}
    376 +				boolean ok = true;
    377 +				for (int i = 0; i < certs.length; i++)  {
    378 +					if (! trusturlCerts[i].equals(certs[i])) {
    379 +						ok = false;
    380 +						dbg("URL: cert mismatch at i=" + i);
    381 +						dbg("URL: cert mismatch cert" + certs[i]);
    382 +						dbg("URL: cert mismatch  url" + trusturlCerts[i]);
    383 +						if (cert_fail == null) {
    384 +							cert_fail = "cert-mismatch";
    385 +						}
    386 +					}
    387 +					if (debug_certs) {
    388 +						dbg("\n***********************************************");
    389 +						dbg("URL: cert info at i=" + i);
    390 +						dbg("URL: cert info cert" + certs[i]);
    391 +						dbg("===============================================");
    392 +						dbg("URL: cert info  url" + trusturlCerts[i]);
    393 +						dbg("***********************************************");
    394 +					}
    395 +				}
    396 +				if (!ok) {
    397 +					throw new CertificateException(
    398 +					    "Server Cert Chain != URL Cert Chain.");
    399 +				}
    400 +				dbg("URL: trusturlCerts[i] matches certs[i] i=0:" + (certs.length-1));
    401 +			}
    402 +		    }
    403 +		};
    404 +
    405 +		trustSrvCert = new TrustManager[] {
    406 +		    /*
    407 +		     * this one accepts cert given to us in the serverCert
    408 +		     * Applet Parameter we were started with.  It is
    409 +		     * currently a fatal error if the VNC Server's cert
    410 +		     * doesn't match it.
    411 +		     */
    412 +		    new X509TrustManager() {
    413 +			public java.security.cert.X509Certificate[]
    414 +			    getAcceptedIssuers() {
    415 +				return null;
    416 +			}
    417 +			public void checkClientTrusted(
    418 +			    java.security.cert.X509Certificate[] certs,
    419 +			    String authType) throws CertificateException {
    420 +				throw new CertificateException("No Clients (SRV)");
    421 +			}
    422 +			public void checkServerTrusted(
    423 +			    java.security.cert.X509Certificate[] certs,
    424 +			    String authType) throws CertificateException {
    425 +				/* we want to check 'certs' against 'trustsrvCerts' */
    426 +				if (trustsrvCerts == null) {
    427 +					throw new CertificateException(
    428 +					    "No Trust srv Certs array.");
    429 +				}
    430 +				if (trustsrvCerts.length < 1) {
    431 +					throw new CertificateException(
    432 +					    "No Trust srv Certs.");
    433 +				}
    434 +				if (certs == null) {
    435 +					throw new CertificateException(
    436 +					    "No this-certs array.");
    437 +				}
    438 +				if (certs.length < 1) {
    439 +					throw new CertificateException(
    440 +					    "No this-certs Certs.");
    441 +				}
    442 +				if (certs.length != trustsrvCerts.length) {
    443 +					throw new CertificateException(
    444 +					    "certs.length != trustsrvCerts.length " + certs.length + " " + trustsrvCerts.length);
    445 +				}
    446 +				boolean ok = true;
    447 +				for (int i = 0; i < certs.length; i++)  {
    448 +					if (! trustsrvCerts[i].equals(certs[i])) {
    449 +						ok = false;
    450 +						dbg("SRV: cert mismatch at i=" + i);
    451 +						dbg("SRV: cert mismatch cert" + certs[i]);
    452 +						dbg("SRV: cert mismatch  srv" + trustsrvCerts[i]);
    453 +						if (cert_fail == null) {
    454 +							cert_fail = "server-cert-mismatch";
    455 +						}
    456 +					}
    457 +					if (debug_certs) {
    458 +						dbg("\n***********************************************");
    459 +						dbg("SRV: cert info at i=" + i);
    460 +						dbg("SRV: cert info cert" + certs[i]);
    461 +						dbg("===============================================");
    462 +						dbg("SRV: cert info  srv" + trustsrvCerts[i]);
    463 +						dbg("***********************************************");
    464 +					}
    465 +				}
    466 +				if (!ok) {
    467 +					throw new CertificateException(
    468 +					    "Server Cert Chain != serverCert Applet Parameter Cert Chain.");
    469 +				}
    470 +				dbg("SRV: trustsrvCerts[i] matches certs[i] i=0:" + (certs.length-1));
    471 +			}
    472 +		    }
    473 +		};
    474 +
    475 +		trustOneCert = new TrustManager[] {
    476 +		    /*
    477 +		     * this one accepts only the retrieved server
    478 +		     * cert by SSLSocket by this applet we stored in
    479 +		     * trustallCerts that user has accepted or applet
    480 +		     * parameter trustAllVncCerts=yes is set.  This is
    481 +		     * for when we reconnect after the user has manually
    482 +		     * accepted the trustall cert in the dialog (or set
    483 +		     * trustAllVncCerts=yes applet param.)
    484 +		     */
    485 +		    new X509TrustManager() {
    486 +			public java.security.cert.X509Certificate[]
    487 +			    getAcceptedIssuers() {
    488 +				return null;
    489 +			}
    490 +			public void checkClientTrusted(
    491 +			    java.security.cert.X509Certificate[] certs,
    492 +			    String authType) throws CertificateException {
    493 +				throw new CertificateException("No Clients (ONE)");
    494 +			}
    495 +			public void checkServerTrusted(
    496 +			    java.security.cert.X509Certificate[] certs,
    497 +			    String authType) throws CertificateException {
    498 +				/* we want to check 'certs' against 'trustallCerts' */
    499 +				if (trustallCerts == null) {
    500 +					throw new CertificateException(
    501 +					    "No Trust All Server Certs array.");
    502 +				}
    503 +				if (trustallCerts.length < 1) {
    504 +					throw new CertificateException(
    505 +					    "No Trust All Server Certs.");
    506 +				}
    507 +				if (certs == null) {
    508 +					throw new CertificateException(
    509 +					    "No this-certs array.");
    510 +				}
    511 +				if (certs.length < 1) {
    512 +					throw new CertificateException(
    513 +					    "No this-certs Certs.");
    514 +				}
    515 +				if (certs.length != trustallCerts.length) {
    516 +					throw new CertificateException(
    517 +					    "certs.length != trustallCerts.length " + certs.length + " " + trustallCerts.length);
    518 +				}
    519 +				boolean ok = true;
    520 +				for (int i = 0; i < certs.length; i++)  {
    521 +					if (! trustallCerts[i].equals(certs[i])) {
    522 +						ok = false;
    523 +						dbg("ONE: cert mismatch at i=" + i);
    524 +						dbg("ONE: cert mismatch cert" + certs[i]);
    525 +						dbg("ONE: cert mismatch  all" + trustallCerts[i]);
    526 +					}
    527 +					if (debug_certs) {
    528 +						dbg("\n***********************************************");
    529 +						dbg("ONE: cert info at i=" + i);
    530 +						dbg("ONE: cert info cert" + certs[i]);
    531 +						dbg("===============================================");
    532 +						dbg("ONE: cert info  all" + trustallCerts[i]);
    533 +						dbg("***********************************************");
    534 +					}
    535 +				}
    536 +				if (!ok) {
    537 +					throw new CertificateException(
    538 +					    "Server Cert Chain != TRUSTALL Cert Chain.");
    539 +				}
    540 +				dbg("ONE: trustallCerts[i] matches certs[i] i=0:" + (certs.length-1));
    541 +			}
    542 +		    }
    543 +		};
    544 +
    545 +		/* 
    546 +		 * The above TrustManagers are used:
    547 +		 *
    548 +		 * 1) to retrieve the server cert in case of failure to
    549 +		 *    display it to the user in a dialog.
    550 +		 * 2) to subsequently connect to the server if user agrees.
    551 +		 */
    552 +
    553 +		/*
    554 +		 * build oneTimeKey cert+key if supplied in applet parameter:
    555 +		 */
    556 +		if (viewer.oneTimeKey != null && viewer.oneTimeKey.equals("PROMPT")) {
    557 +			ClientCertDialog d = new ClientCertDialog();
    558 +			viewer.oneTimeKey = d.queryUser();
    559 +		}
    560 +		if (viewer.oneTimeKey != null && viewer.oneTimeKey.indexOf(",") > 0) {
    561 +			int idx = viewer.oneTimeKey.indexOf(",");
    562 +
    563 +			String onetimekey = viewer.oneTimeKey.substring(0, idx);
    564 +			byte[] key = hex2bytes(onetimekey);
    565 +			String onetimecert = viewer.oneTimeKey.substring(idx+1);
    566 +			byte[] cert = hex2bytes(onetimecert);
    567 +
    568 +			KeyFactory kf = KeyFactory.getInstance("RSA");
    569 +			PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key );
    570 +			PrivateKey ff = kf.generatePrivate (keysp);
    571 +			if (debug_certs) {
    572 +				dbg("one time key " + ff);
    573 +			}
    574 +
    575 +			CertificateFactory cf = CertificateFactory.getInstance("X.509");
    576 +			Collection c = cf.generateCertificates(new ByteArrayInputStream(cert));
    577 +			Certificate[] certs = new Certificate[c.toArray().length];
    578 +			if (c.size() == 1) {
    579 +				Certificate tmpcert = cf.generateCertificate(new ByteArrayInputStream(cert));
    580 +				if (debug_certs) {
    581 +					dbg("one time cert" + tmpcert);
    582 +				}
    583 +				certs[0] = tmpcert;
    584 +			} else {
    585 +				certs = (Certificate[]) c.toArray();
    586 +			}
    587 +
    588 +			KeyStore ks = KeyStore.getInstance("JKS");
    589 +			ks.load(null, null);
    590 +			ks.setKeyEntry("onetimekey", ff, "".toCharArray(), certs);
    591 +			String da = KeyManagerFactory.getDefaultAlgorithm();
    592 +			KeyManagerFactory kmf = KeyManagerFactory.getInstance(da);
    593 +			kmf.init(ks, "".toCharArray());
    594 +
    595 +			mykey = kmf.getKeyManagers();
    596 +		}
    597 +
    598 +		/*
    599 +		 * build serverCert cert if supplied in applet parameter:
    600 +		 */
    601 +		if (viewer.serverCert != null) {
    602 +			CertificateFactory cf = CertificateFactory.getInstance("X.509");
    603 +			byte[] cert = hex2bytes(viewer.serverCert);
    604 +			Collection c = cf.generateCertificates(new ByteArrayInputStream(cert));
    605 +			trustsrvCerts = new Certificate[c.toArray().length];
    606 +			if (c.size() == 1) {
    607 +				Certificate tmpcert = cf.generateCertificate(new ByteArrayInputStream(cert));
    608 +				trustsrvCerts[0] = tmpcert;
    609 +			} else {
    610 +				trustsrvCerts = (Certificate[]) c.toArray();
    611 +			}
    612 +		}
    613 +
    614 +		/* the trust loc certs context: */
    615 +		try {
    616 +			trustloc_ctx = SSLContext.getInstance("SSL");
    617 +
    618 +			/*
    619 +			 * below is a failed attempt to get jvm's default
    620 +			 * trust manager using null (below) makes it so
    621 +			 * for HttpsURLConnection the server cannot be
    622 +			 * verified (no prompting.)
    623 +			 */
    624 +			if (false) {
    625 +				boolean didit = false;
    626 +				TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());  
    627 +				tmf.init((KeyStore) null);
    628 +				TrustManager [] tml = tmf.getTrustManagers();
    629 +				for (int i = 0; i < tml.length; i++) {
    630 +					TrustManager tm = tml[i];
    631 +					if (tm instanceof X509TrustManager) {
    632 +						TrustManager tm1[] = new TrustManager[1];
    633 +						tm1[0] = tm;
    634 +						trustloc_ctx.init(mykey, tm1, null);
    635 +						didit = true;
    636 +						break;
    637 +					}
    638 +				}
    639 +				if (!didit) {
    640 +					trustloc_ctx.init(mykey, null, null);
    641 +				}
    642 +			} else {
    643 +				/* we have to set trust manager to null */
    644 +				trustloc_ctx.init(mykey, null, null);
    645 +			}
    646 +
    647 +		} catch (Exception e) {
    648 +			String msg = "SSL trustloc_ctx FAILED.";
    649 +			dbg(msg);
    650 +			throw new Exception(msg);
    651 +		}
    652 +
    653 +		/* the trust all certs context: */
    654 +		try {
    655 +			trustall_ctx = SSLContext.getInstance("SSL");
    656 +			trustall_ctx.init(mykey, trustAllCerts, new
    657 +			    java.security.SecureRandom());
    658 +
    659 +		} catch (Exception e) {
    660 +			String msg = "SSL trustall_ctx FAILED.";
    661 +			dbg(msg);
    662 +			throw new Exception(msg);
    663 +		}
    664 +
    665 +		/* the trust url certs context: */
    666 +		try {
    667 +			trusturl_ctx = SSLContext.getInstance("SSL");
    668 +			trusturl_ctx.init(mykey, trustUrlCert, new
    669 +			    java.security.SecureRandom());
    670 +
    671 +		} catch (Exception e) {
    672 +			String msg = "SSL trusturl_ctx FAILED.";
    673 +			dbg(msg);
    674 +			throw new Exception(msg);
    675 +		}
    676 +
    677 +		/* the trust srv certs context: */
    678 +		try {
    679 +			trustsrv_ctx = SSLContext.getInstance("SSL");
    680 +			trustsrv_ctx.init(mykey, trustSrvCert, new
    681 +			    java.security.SecureRandom());
    682 +
    683 +		} catch (Exception e) {
    684 +			String msg = "SSL trustsrv_ctx FAILED.";
    685 +			dbg(msg);
    686 +			throw new Exception(msg);
    687 +		}
    688 +
    689 +		/* the trust the one cert from server context: */
    690 +		try {
    691 +			trustone_ctx = SSLContext.getInstance("SSL");
    692 +			trustone_ctx.init(mykey, trustOneCert, new
    693 +			    java.security.SecureRandom());
    694 +
    695 +		} catch (Exception e) {
    696 +			String msg = "SSL trustone_ctx FAILED.";
    697 +			dbg(msg);
    698 +			throw new Exception(msg);
    699 +		}
    700 +	}
    701 +
    702 +	/*
    703 +	 * we call this early on to 1) check for a proxy, 2) grab
    704 +	 * Browser/JVM accepted HTTPS cert.
    705 +	 */
    706 +	public void check_for_proxy_and_grab_vnc_server_cert() {
    707 +		
    708 +		trusturlCerts = null;
    709 +		proxy_in_use = false;
    710 +
    711 +		if (viewer.ignoreProxy) {
    712 +			/* applet param says skip it. */
    713 +			/* the downside is we do not set trusturlCerts for comparison later... */
    714 +			/* nor do we autodetect x11vnc for GET=1. */
    715 +			return;
    716 +		}
    717 +
    718 +		dbg("------------------------------------------------");
    719 +		dbg("Into check_for_proxy_and_grab_vnc_server_cert():");
    720 +
    721 +		dbg("TRYING HTTPS:");
    722 +		String ustr = "https://" + host + ":";
    723 +		if (viewer.httpsPort != null) {
    724 +			ustr += viewer.httpsPort;
    725 +		} else {
    726 +			ustr += port;
    727 +		}
    728 +		ustr += viewer.urlPrefix + "/check.https.proxy.connection";
    729 +		dbg("ustr is: " + ustr);
    730 +
    731 +		try {
    732 +			/* prepare for an HTTPS URL connection to host:port */
    733 +			URL url = new URL(ustr);
    734 +			HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
    735 +
    736 +			if (mykey != null) {
    737 +				/* with oneTimeKey (mykey) we can't use the default SSL context */
    738 +				if (trustsrvCerts != null) {
    739 +					dbg("passing trustsrv_ctx to HttpsURLConnection to provide client cert.");
    740 +					https.setSSLSocketFactory(trustsrv_ctx.getSocketFactory());	
    741 +				} else if (trustloc_ctx != null) {
    742 +					dbg("passing trustloc_ctx to HttpsURLConnection to provide client cert.");
    743 +					https.setSSLSocketFactory(trustloc_ctx.getSocketFactory());	
    744 +				}
    745 +			}
    746 +
    747 +			https.setUseCaches(false);
    748 +			https.setRequestMethod("GET");
    749 +			https.setRequestProperty("Pragma", "No-Cache");
    750 +			https.setRequestProperty("Proxy-Connection", "Keep-Alive");
    751 +			https.setDoInput(true);
    752 +
    753 +			dbg("trying https.connect()");
    754 +			https.connect();
    755 +
    756 +			dbg("trying https.getServerCertificates()");
    757 +			trusturlCerts = https.getServerCertificates();
    758 +
    759 +			if (trusturlCerts == null) {
    760 +				dbg("set trusturlCerts to null!");
    761 +			} else {
    762 +				dbg("set trusturlCerts to non-null");
    763 +			}
    764 +
    765 +			if (https.usingProxy()) {
    766 +				proxy_in_use = true;
    767 +				dbg("An HTTPS proxy is in use. There may be connection problems.");
    768 +			}
    769 +
    770 +			dbg("trying https.getContent()");
    771 +			Object output = https.getContent();
    772 +			dbg("trying https.disconnect()");
    773 +			https.disconnect();
    774 +			if (! viewer.GET) {
    775 +				String header = https.getHeaderField("VNC-Server");
    776 +				if (header != null && header.startsWith("x11vnc")) {
    777 +					dbg("detected x11vnc server (1), setting GET=1");
    778 +					viewer.GET = true;
    779 +				}
    780 +			}
    781 +
    782 +		} catch(Exception e) {
    783 +			dbg("HttpsURLConnection: " + e.getMessage());
    784 +		}
    785 +
    786 +		if (proxy_in_use) {
    787 +			dbg("exit check_for_proxy_and_grab_vnc_server_cert():");
    788 +			dbg("------------------------------------------------");
    789 +			return;
    790 +		} else if (trusturlCerts != null && !viewer.forceProxy) {
    791 +			/* Allow user to require HTTP check?  use forceProxy for now. */
    792 +			dbg("SKIPPING HTTP PROXY CHECK: got trusturlCerts, assuming proxy info is correct.");
    793 +			dbg("exit check_for_proxy_and_grab_vnc_server_cert():");
    794 +			dbg("------------------------------------------------");
    795 +			return;
    796 +		}
    797 +
    798 +		/*
    799 +		 * XXX need to remember scenario where this extra check
    800 +		 * gives useful info.  User's Browser proxy settings?
    801 +		 */
    802 +		dbg("TRYING HTTP:");
    803 +		ustr = "http://" + host + ":" + port;
    804 +		ustr += viewer.urlPrefix + "/index.vnc";
    805 +		dbg("ustr is: " + ustr);
    806 +
    807 +		try {
    808 +			/* prepare for an HTTP URL connection to the same host:port (but not httpsPort) */
    809 +			URL url = new URL(ustr);
    810 +			HttpURLConnection http = (HttpURLConnection)
    811 +			    url.openConnection();
    812 +
    813 +			http.setUseCaches(false);
    814 +			http.setRequestMethod("GET");
    815 +			http.setRequestProperty("Pragma", "No-Cache");
    816 +			http.setRequestProperty("Proxy-Connection", "Keep-Alive");
    817 +			http.setDoInput(true);
    818 +
    819 +			dbg("trying http.connect()");
    820 +			http.connect();
    821 +
    822 +			if (http.usingProxy()) {
    823 +				proxy_in_use = true;
    824 +				dbg("An HTTP proxy is in use. There may be connection problems.");
    825 +			}
    826 +			dbg("trying http.getContent()");
    827 +			Object output = http.getContent();
    828 +			dbg("trying http.disconnect()");
    829 +			http.disconnect();
    830 +			if (! viewer.GET) {
    831 +				String header = http.getHeaderField("VNC-Server");
    832 +				if (header != null && header.startsWith("x11vnc")) {
    833 +					dbg("detected x11vnc server (2), setting GET=1");
    834 +					viewer.GET = true;
    835 +				}
    836 +			}
    837 +		} catch(Exception e) {
    838 +			dbg("HttpURLConnection:  " + e.getMessage());
    839 +		}
    840 +		dbg("exit check_for_proxy_and_grab_vnc_server_cert():");
    841 +		dbg("------------------------------------------------");
    842 +	}
    843 +
    844 +	public Socket connectSock() throws IOException {
    845 +		/*
    846 +		 * first try a https connection to detect a proxy, and
    847 +		 * grab the VNC server cert at the same time:
    848 +		 */
    849 +		check_for_proxy_and_grab_vnc_server_cert();
    850 +
    851 +		boolean srv_cert = false;
    852 +		
    853 +		if (trustsrvCerts != null) {
    854 +			/* applet parameter suppled serverCert */
    855 +			dbg("viewer.trustSrvCert-0 using trustsrv_ctx");
    856 +			factory = trustsrv_ctx.getSocketFactory();
    857 +			srv_cert = true;
    858 +		} else if (viewer.trustAllVncCerts) {
    859 +			/* trust all certs (no checking) */
    860 +			dbg("viewer.trustAllVncCerts-0 using trustall_ctx");
    861 +			factory = trustall_ctx.getSocketFactory();
    862 +		} else if (trusturlCerts != null) {
    863 +			/* trust certs the Browser/JVM accepted in check_for_proxy... */
    864 +			dbg("using trusturl_ctx");
    865 +			factory = trusturl_ctx.getSocketFactory();
    866 +		} else {
    867 +			/* trust the local defaults */
    868 +			dbg("using trustloc_ctx");
    869 +			factory = trustloc_ctx.getSocketFactory();
    870 +		}
    871 +
    872 +		socket = null;
    873 +
    874 +		try {
    875 +			if (proxy_in_use && viewer.forceProxy) {
    876 +				throw new Exception("forcing proxy (forceProxy)");
    877 +			} else if (viewer.CONNECT != null) {
    878 +				throw new Exception("forcing CONNECT");
    879 +			}
    880 +
    881 +			int timeout = 6;
    882 +			if (timeout > 0) {
    883 +				socket = (SSLSocket) factory.createSocket();
    884 +				InetSocketAddress inetaddr = new InetSocketAddress(host, port);
    885 +				dbg("Using timeout of " + timeout + " secs to: " + host + ":" + port);
    886 +				socket.connect(inetaddr, timeout * 1000);
    887 +			} else {
    888 +				socket = (SSLSocket) factory.createSocket(host, port);
    889 +			}
    890 +
    891 +		} catch (Exception esock) {
    892 +			dbg("socket error: " + esock.getMessage());
    893 +			if (proxy_in_use || viewer.CONNECT != null) {
    894 +				proxy_failure = true;
    895 +				if (proxy_in_use) {
    896 +					dbg("HTTPS proxy in use. Trying to go with it.");
    897 +				} else {
    898 +					dbg("viewer.CONNECT reverse proxy in use. Trying to go with it.");
    899 +				}
    900 +				try {
    901 +					socket = proxy_socket(factory);
    902 +				} catch (Exception e) {
    903 +					dbg("proxy_socket error: " + e.getMessage());
    904 +				}
    905 +			} else {
    906 +				/* n.b. socket is left in error state to cause ex. below. */
    907 +			}
    908 +		}
    909 +
    910 +		try {
    911 +			socket.startHandshake();
    912 +
    913 +			dbg("The Server Connection Verified OK on 1st try.");
    914 +
    915 +			java.security.cert.Certificate[] currentTrustedCerts;
    916 +			BrowserCertsDialog bcd;
    917 +
    918 +			SSLSession sess = socket.getSession();
    919 +			currentTrustedCerts = sess.getPeerCertificates();
    920 +
    921 +			if (viewer.trustAllVncCerts) {
    922 +				dbg("viewer.trustAllVncCerts-1  keeping socket.");
    923 +			} else if (currentTrustedCerts == null || currentTrustedCerts.length < 1) {
    924 +				try {
    925 +					socket.close();
    926 +				} catch (Exception e) {
    927 +					dbg("socket is grumpy.");
    928 +				}
    929 +				socket = null;
    930 +				throw new SSLHandshakeException("no current certs");
    931 +			}
    932 +
    933 +			String serv = "";
    934 +			try {
    935 +				CertInfo ci = new CertInfo(currentTrustedCerts[0]);
    936 +				serv = ci.get_certinfo("CN");
    937 +			} catch (Exception e) {
    938 +				;
    939 +			}
    940 +
    941 +			if (viewer.trustAllVncCerts) {
    942 +				dbg("viewer.trustAllVncCerts-2  skipping browser certs dialog");
    943 +				user_wants_to_see_cert = false;
    944 +			} else if (viewer.serverCert != null && trustsrvCerts != null) {
    945 +				dbg("viewer.serverCert-1  skipping browser certs dialog");
    946 +				user_wants_to_see_cert = false;
    947 +			} else if (viewer.trustUrlVncCert) {
    948 +				dbg("viewer.trustUrlVncCert-1  skipping browser certs dialog");
    949 +				user_wants_to_see_cert = false;
    950 +			} else {
    951 +				/* have a dialog with the user: */
    952 +				bcd = new BrowserCertsDialog(serv, host + ":" + port);
    953 +				dbg("browser certs dialog begin.");
    954 +				bcd.queryUser();
    955 +				dbg("browser certs dialog finished.");
    956 +
    957 +				if (bcd.showCertDialog) {
    958 +					String msg = "user wants to see cert";
    959 +					dbg(msg);
    960 +					user_wants_to_see_cert = true;
    961 +					if (cert_fail == null) {
    962 +						cert_fail = "user-view";
    963 +					}
    964 +					throw new SSLHandshakeException(msg);
    965 +				} else {
    966 +					user_wants_to_see_cert = false;
    967 +					dbg("browser certs dialog: user said yes, accept it");
    968 +				}
    969 +			}
    970 +
    971 +		} catch (SSLHandshakeException eh)  {
    972 +			dbg("SSLHandshakeException: could not automatically verify Server.");
    973 +			dbg("msg: " + eh.getMessage());
    974 +
    975 +
    976 +			/* send a cleanup string just in case: */
    977 +			String getoutstr = "GET /index.vnc HTTP/1.0\r\nConnection: close\r\n\r\n";
    978 +
    979 +			try {
    980 +				OutputStream os = socket.getOutputStream();
    981 +				os.write(getoutstr.getBytes());
    982 +				socket.close();
    983 +			} catch (Exception e) {
    984 +				dbg("socket is grumpy!");
    985 +			}
    986 +
    987 +			/* reload */
    988 +
    989 +			socket = null;
    990 +
    991 +			String reason = null;
    992 +
    993 +			if (srv_cert) {
    994 +				/* for serverCert usage we make this a fatal error. */
    995 +				throw new IOException("Fatal: VNC Server's Cert does not match Applet Parameter 'serverCert=...'");
    996 +				/* see below in TrustDialog were we describe this case to user anyway */
    997 +			}
    998 +
    999 +			/*
   1000 +			 * Reconnect, trusting any cert, so we can grab
   1001 +			 * the cert to show it to the user in a dialog
   1002 +			 * for him to manually accept.  This connection
   1003 +			 * is not used for anything else.
   1004 +			 */
   1005 +			factory = trustall_ctx.getSocketFactory();
   1006 +			if (proxy_failure) {
   1007 +				socket = proxy_socket(factory);
   1008 +			} else {
   1009 +				socket = (SSLSocket) factory.createSocket(host, port);
   1010 +			}
   1011 +
   1012 +			if (debug_certs) {
   1013 +				dbg("trusturlCerts: " + trusturlCerts);
   1014 +				dbg("trustsrvCerts: " + trustsrvCerts);
   1015 +			}
   1016 +			if (trusturlCerts == null && cert_fail == null) {
   1017 +				cert_fail = "missing-certs";
   1018 +			}
   1019 +
   1020 +			try {
   1021 +				socket.startHandshake();
   1022 +
   1023 +				dbg("The TrustAll Server Cert-grab Connection (trivially) Verified OK.");
   1024 +
   1025 +				/* grab the cert: */
   1026 +				try {
   1027 +					SSLSession sess = socket.getSession();
   1028 +					trustallCerts = sess.getPeerCertificates();
   1029 +				} catch (Exception e) {
   1030 +					throw new Exception("Could not get " + 
   1031 +					    "Peer Certificate");	
   1032 +				}
   1033 +				if (debug_certs) {
   1034 +					dbg("trustallCerts: " + trustallCerts);
   1035 +				}
   1036 +
   1037 +				if (viewer.trustAllVncCerts) {
   1038 +					dbg("viewer.trustAllVncCerts-3.  skipping dialog, trusting everything.");
   1039 +				} else if (! browser_cert_match()) {
   1040 +					/*
   1041 +					 * close socket now, we will reopen after
   1042 +					 * dialog if user agrees to use the cert.
   1043 +					 */
   1044 +					try {
   1045 +						OutputStream os = socket.getOutputStream();
   1046 +						os.write(getoutstr.getBytes());
   1047 +						socket.close();
   1048 +					} catch (Exception e) {
   1049 +						dbg("socket is grumpy!!");
   1050 +					}
   1051 +					socket = null;
   1052 +
   1053 +					/* dialog with user to accept cert or not: */
   1054 +
   1055 +					TrustDialog td= new TrustDialog(host, port,
   1056 +					    trustallCerts);
   1057 +
   1058 +					if (cert_fail == null) {
   1059 +						;
   1060 +					} else if (cert_fail.equals("user-view")) {
   1061 +						reason = "Reason for this Dialog:\n\n"
   1062 +						       + "        You Asked to View the Certificate.";
   1063 +					} else if (cert_fail.equals("server-cert-mismatch")) {
   1064 +						/* this is now fatal error, see above. */
   1065 +						reason = "Reason for this Dialog:\n\n"
   1066 +						       + "        The VNC Server's Certificate does not match the Certificate\n"
   1067 +						       + "        specified in the supplied 'serverCert' Applet Parameter.";
   1068 +					} else if (cert_fail.equals("cert-mismatch")) {
   1069 +						reason = "Reason for this Dialog:\n\n"
   1070 +						       + "        The VNC Server's Certificate does not match the Website's\n"
   1071 +						       + "        HTTPS Certificate (that you previously accepted; either\n"
   1072 +						       + "        manually or automatically via Certificate Authority.)";
   1073 +					} else if (cert_fail.equals("missing-certs")) {
   1074 +						reason = "Reason for this Dialog:\n\n"
   1075 +						       + "        Not all Certificates could be obtained to check.";
   1076 +					}
   1077 +
   1078 +					if (! td.queryUser(reason)) {
   1079 +						String msg = "User decided against it.";
   1080 +						dbg(msg);
   1081 +						throw new IOException(msg);
   1082 +					}
   1083 +				}
   1084 +
   1085 +			} catch (Exception ehand2)  {
   1086 +				dbg("** Could not TrustAll Verify Server!");
   1087 +
   1088 +				throw new IOException(ehand2.getMessage());
   1089 +			}
   1090 +
   1091 +			/* reload again: */
   1092 +
   1093 +			if (socket != null) {
   1094 +				try {
   1095 +					socket.close();
   1096 +				} catch (Exception e) {
   1097 +					dbg("socket is grumpy!!!");
   1098 +				}
   1099 +				socket = null;
   1100 +			}
   1101 +
   1102 +			/*
   1103 +			 * Now connect a 3rd time, using the cert
   1104 +			 * retrieved during connection 2 (sadly, that
   1105 +			 * the user likely blindly agreed to...)
   1106 +			 */
   1107 +
   1108 +			factory = trustone_ctx.getSocketFactory();
   1109 +			if (proxy_failure) {
   1110 +				socket = proxy_socket(factory);
   1111 +			} else {
   1112 +				socket = (SSLSocket) factory.createSocket(host, port);
   1113 +			}
   1114 +
   1115 +			try {
   1116 +				socket.startHandshake();
   1117 +				dbg("TrustAll/TrustOne Server Connection Verified #3.");
   1118 +
   1119 +			} catch (Exception ehand3)  {
   1120 +				dbg("** Could not TrustAll/TrustOne Verify Server #3.");
   1121 +
   1122 +				throw new IOException(ehand3.getMessage());
   1123 +			}
   1124 +		}
   1125 +
   1126 +		/* we have socket (possibly null) at this point, so proceed: */
   1127 +
   1128 +		/* handle x11vnc GET=1, if applicable: */
   1129 +		if (socket != null && viewer.GET) {
   1130 +			String str = "GET ";
   1131 +			str += viewer.urlPrefix;
   1132 +			str += "/request.https.vnc.connection";
   1133 +			str += " HTTP/1.0\r\n";
   1134 +			str += "Pragma: No-Cache\r\n";
   1135 +			str += "\r\n";
   1136 +
   1137 +			System.out.println("sending: " + str);
   1138 +    			OutputStream os = socket.getOutputStream();
   1139 +			String type = "os";
   1140 +
   1141 +			if (type == "os") {
   1142 +				os.write(str.getBytes());
   1143 +				os.flush();
   1144 +				System.out.println("used OutputStream");
   1145 +			} else if (type == "bs") {
   1146 +				BufferedOutputStream bs = new BufferedOutputStream(os);
   1147 +				bs.write(str.getBytes());
   1148 +				bs.flush();
   1149 +				System.out.println("used BufferedOutputStream");
   1150 +			} else if (type == "ds") {
   1151 +				DataOutputStream ds = new DataOutputStream(os);
   1152 +				ds.write(str.getBytes());
   1153 +				ds.flush();
   1154 +				System.out.println("used DataOutputStream");
   1155 +			}
   1156 +			if (false) {
   1157 +				String rep = "";
   1158 +				DataInputStream is = new DataInputStream(
   1159 +				    new BufferedInputStream(socket.getInputStream(), 16384));
   1160 +				while (true) {
   1161 +					rep += readline(is);
   1162 +					if (rep.indexOf("\r\n\r\n") >= 0) {
   1163 +						break;
   1164 +					}
   1165 +				}
   1166 +				System.out.println("rep: " + rep);
   1167 +			}
   1168 +		}
   1169 +
   1170 +		dbg("SSL returning socket to caller.");
   1171 +		dbg("");
   1172 +
   1173 +		/* could be null, let caller handle that. */
   1174 +		return (Socket) socket;
   1175 +	}
   1176 +
   1177 +	boolean browser_cert_match() {
   1178 +		String msg = "Browser URL accept previously accepted cert";
   1179 +
   1180 +		if (user_wants_to_see_cert) {
   1181 +			return false;
   1182 +		}
   1183 +
   1184 +		if (viewer.serverCert != null || trustsrvCerts != null) {
   1185 +			if (cert_fail == null) {
   1186 +				cert_fail = "server-cert-mismatch";
   1187 +			}
   1188 +		}
   1189 +		if (trustallCerts != null && trusturlCerts != null) {
   1190 +		    if (trustallCerts.length == trusturlCerts.length) {
   1191 +			boolean ok = true;
   1192 +			/* check toath trustallCerts (socket) equals trusturlCerts (browser) */
   1193 +			for (int i = 0; i < trusturlCerts.length; i++)  {
   1194 +				if (! trustallCerts[i].equals(trusturlCerts[i])) {
   1195 +					dbg("BCM: cert mismatch at i=" + i);
   1196 +					dbg("BCM: cert mismatch  url" + trusturlCerts[i]);
   1197 +					dbg("BCM: cert mismatch  all" + trustallCerts[i]);
   1198 +					ok = false;
   1199 +				}
   1200 +			}
   1201 +			if (ok) {
   1202 +				System.out.println(msg);
   1203 +				if (cert_fail == null) {
   1204 +					cert_fail = "did-not-fail";
   1205 +				}
   1206 +				return true;
   1207 +			} else {
   1208 +				if (cert_fail == null) {
   1209 +					cert_fail = "cert-mismatch";
   1210 +				}
   1211 +				return false;
   1212 +			}
   1213 +		    }
   1214 +		}
   1215 +		if (cert_fail == null) {
   1216 +			cert_fail = "missing-certs";
   1217 +		}
   1218 +		return false;
   1219 +	}
   1220 +
   1221 +	private void dbg(String s) {
   1222 +		if (debug) {
   1223 +			System.out.println(s);
   1224 +		}
   1225 +	}
   1226 +
   1227 +	private int gint(String s) {
   1228 +		int n = -1;
   1229 +		try {
   1230 +			Integer I = new Integer(s);
   1231 +			n = I.intValue();
   1232 +		} catch (Exception ex) {
   1233 +			return -1;
   1234 +		}
   1235 +		return n;
   1236 +	}
   1237 +
   1238 +	/* this will do the proxy CONNECT negotiation and hook us up.  */
   1239 +
   1240 +	private void proxy_helper(String proxyHost, int proxyPort) {
   1241 +
   1242 +		boolean proxy_auth = false;
   1243 +		String proxy_auth_basic_realm = "";
   1244 +		String hp = host + ":" + port;
   1245 +		dbg("proxy_helper: " + proxyHost + ":" + proxyPort + " hp: " + hp);
   1246 +
   1247 +		/* we loop here a few times trying for the password case */
   1248 +		for (int k=0; k < 2; k++) {
   1249 +			dbg("proxy_in_use psocket: " + k);
   1250 +
   1251 +			if (proxySock != null) {
   1252 +				try {
   1253 +					proxySock.close();
   1254 +				} catch (Exception e) {
   1255 +					dbg("proxy socket is grumpy.");
   1256 +				}
   1257 +			}
   1258 +
   1259 +			proxySock = psocket(proxyHost, proxyPort);
   1260 +			if (proxySock == null) {
   1261 +				dbg("1-a sadly, returning a null socket");
   1262 +				return;
   1263 +			}
   1264 +
   1265 +			String req1 = "CONNECT " + hp + " HTTP/1.1\r\n"
   1266 +			    + "Host: " + hp + "\r\n";
   1267 +
   1268 +			dbg("requesting via proxy: " + req1);
   1269 +
   1270 +			if (proxy_auth) {
   1271 +				if (proxy_auth_string == null) {
   1272 +					ProxyPasswdDialog pp = new ProxyPasswdDialog(proxyHost, proxyPort, proxy_auth_basic_realm);
   1273 +					pp.queryUser();
   1274 +					proxy_auth_string = pp.getAuth();
   1275 +				}
   1276 +				//dbg("auth1: " + proxy_auth_string);
   1277 +
   1278 +				String auth2 = Base64Coder.encodeString(proxy_auth_string);
   1279 +				//dbg("auth2: " + auth2);
   1280 +
   1281 +				req1 += "Proxy-Authorization: Basic " + auth2 + "\r\n";
   1282 +				//dbg("req1: " + req1);
   1283 +
   1284 +				dbg("added Proxy-Authorization: Basic ... to request");
   1285 +			}
   1286 +			req1 += "\r\n";
   1287 +
   1288 +			try {
   1289 +				proxy_os.write(req1.getBytes());
   1290 +				String reply = readline(proxy_is);
   1291 +
   1292 +				dbg("proxy replied: " + reply.trim());
   1293 +
   1294 +				if (reply.indexOf("HTTP/1.") == 0 && reply.indexOf(" 407 ") > 0) {
   1295 +					proxy_auth = true;
   1296 +					proxySock.close();
   1297 +				} else if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) {
   1298 +					proxySock.close();
   1299 +					proxySock = psocket(proxyHost, proxyPort);
   1300 +					if (proxySock == null) {
   1301 +						dbg("2-a sadly, returning a null socket");
   1302 +						return;
   1303 +					}
   1304 +				}
   1305 +			} catch(Exception e) {
   1306 +				dbg("some proxy socket problem: " + e.getMessage());
   1307 +			}
   1308 +
   1309 +			/* read the rest of the HTTP headers */
   1310 +			while (true) {
   1311 +				String line = readline(proxy_is);
   1312 +				dbg("proxy line: " + line.trim());
   1313 +				if (proxy_auth) {
   1314 +					String uc = line.toLowerCase();
   1315 +					if (uc.indexOf("proxy-authenticate:") == 0) {
   1316 +						if (uc.indexOf(" basic ") >= 0) {
   1317 +							int idx = uc.indexOf(" realm");
   1318 +							if (idx >= 0) {
   1319 +								proxy_auth_basic_realm = uc.substring(idx+1);
   1320 +							}
   1321 +						}
   1322 +					}
   1323 +				}
   1324 +				if (line.equals("\r\n") || line.equals("\n")) {
   1325 +					break;
   1326 +				}
   1327 +			}
   1328 +			if (!proxy_auth || proxy_auth_basic_realm.equals("")) {
   1329 +				/* we only try once for the non-password case: */
   1330 +				break;
   1331 +			}
   1332 +		}
   1333 +	}
   1334 +
   1335 +	public SSLSocket proxy_socket(SSLSocketFactory factory) {
   1336 +		Properties props = null;
   1337 +		String proxyHost = null;
   1338 +		int proxyPort = 0;
   1339 +		String proxyHost_nossl = null;
   1340 +		int proxyPort_nossl = 0;
   1341 +		String str;
   1342 +
   1343 +		/* see if we can guess the proxy info from Properties: */
   1344 +		try {
   1345 +			props = System.getProperties();
   1346 +		} catch (Exception e) {
   1347 +			/* sandboxed applet might not be able to read it. */
   1348 +			dbg("props failed: " + e.getMessage());
   1349 +		}
   1350 +		if (viewer.proxyHost != null) {
   1351 +			dbg("Using supplied proxy " + viewer.proxyHost + " " + viewer.proxyPort + " applet parameters.");
   1352 +			proxyHost = viewer.proxyHost;
   1353 +			if (viewer.proxyPort != null) {
   1354 +				proxyPort = gint(viewer.proxyPort);
   1355 +			} else {
   1356 +				proxyPort = 8080;
   1357 +			}
   1358 +			
   1359 +		} else if (props != null) {
   1360 +			dbg("\n---------------\nAll props:");
   1361 +			props.list(System.out);
   1362 +			dbg("\n---------------\n\n");
   1363 +
   1364 +			/* scrape throught properties looking for proxy info: */
   1365 +
   1366 +			for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) {
   1367 +				String s = (String) e.nextElement();
   1368 +				String v = System.getProperty(s);
   1369 +				String s2 = s.toLowerCase();
   1370 +				String v2 = v.toLowerCase();
   1371 +
   1372 +				if (s2.indexOf("proxy.https.host") >= 0) {
   1373 +					proxyHost = v2;
   1374 +					continue;
   1375 +				}
   1376 +				if (s2.indexOf("proxy.https.port") >= 0) {
   1377 +					proxyPort = gint(v2);
   1378 +					continue;
   1379 +				}
   1380 +				if (s2.indexOf("proxy.http.host") >= 0) {
   1381 +					proxyHost_nossl = v2;
   1382 +					continue;
   1383 +				}
   1384 +				if (s2.indexOf("proxy.http.port") >= 0) {
   1385 +					proxyPort_nossl = gint(v2);
   1386 +					continue;
   1387 +				}
   1388 +			}
   1389 +
   1390 +			for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) {
   1391 +				String s = (String) e.nextElement();
   1392 +				String v = System.getProperty(s);
   1393 +				String s2 = s.toLowerCase();
   1394 +				String v2 = v.toLowerCase();
   1395 +
   1396 +				if (proxyHost != null && proxyPort > 0) {
   1397 +					break;
   1398 +				}
   1399 +
   1400 +				// look for something like: javaplugin.proxy.config.list = http=10.0.2.1:8082
   1401 +				if (s2.indexOf("proxy") < 0 && v2.indexOf("proxy") < 0) {
   1402 +					continue;
   1403 +				}
   1404 +				if (v2.indexOf("http") < 0) {
   1405 +					continue;
   1406 +				}
   1407 +
   1408 +				String[] pieces = v.split("[,;]");
   1409 +				for (int i = 0; i < pieces.length; i++) {
   1410 +					String p = pieces[i];
   1411 +					int j = p.indexOf("https");
   1412 +					if (j < 0) {
   1413 +						j = p.indexOf("http");
   1414 +						if (j < 0) {
   1415 +							continue;
   1416 +						}
   1417 +					}
   1418 +					j = p.indexOf("=", j);
   1419 +					if (j < 0) {
   1420 +						continue;
   1421 +					}
   1422 +					p = p.substring(j+1);
   1423 +					String [] hp = p.split(":");
   1424 +					if (hp.length != 2) {
   1425 +						continue;
   1426 +					}
   1427 +					if (hp[0].length() > 1 && hp[1].length() > 1) {
   1428 +
   1429 +						proxyPort = gint(hp[1]);
   1430 +						if (proxyPort < 0) {
   1431 +							continue;
   1432 +						}
   1433 +						proxyHost = new String(hp[0]);
   1434 +						break;
   1435 +					}
   1436 +				}
   1437 +			}
   1438 +		}
   1439 +		if (proxyHost != null) {
   1440 +			if (proxyHost_nossl != null && proxyPort_nossl > 0) {
   1441 +				dbg("Using http proxy info instead of https.");
   1442 +				proxyHost = proxyHost_nossl;
   1443 +				proxyPort = proxyPort_nossl;
   1444 +			}
   1445 +		}
   1446 +
   1447 +		if (proxy_in_use) {
   1448 +			if (proxy_dialog_host != null && proxy_dialog_port > 0) {
   1449 +				proxyHost = proxy_dialog_host;
   1450 +				proxyPort = proxy_dialog_port;
   1451 +			}
   1452 +			if (proxyHost != null) {
   1453 +				dbg("Lucky us! we figured out the Proxy parameters: " + proxyHost + " " + proxyPort);
   1454 +			} else {
   1455 +				/* ask user to help us: */
   1456 +				ProxyDialog pd = new ProxyDialog(proxyHost, proxyPort);
   1457 +				pd.queryUser();
   1458 +				proxyHost = pd.getHost(); 
   1459 +				proxyPort = pd.getPort();
   1460 +				proxy_dialog_host = new String(proxyHost);
   1461 +				proxy_dialog_port = proxyPort;
   1462 +				dbg("User said host: " + pd.getHost() + " port: " + pd.getPort());
   1463 +			}
   1464 +
   1465 +			proxy_helper(proxyHost, proxyPort);
   1466 +			if (proxySock == null) {
   1467 +				return null;
   1468 +			}
   1469 +		} else if (viewer.CONNECT != null) {
   1470 +			dbg("viewer.CONNECT psocket:");
   1471 +			proxySock = psocket(host, port);
   1472 +			if (proxySock == null) {
   1473 +				dbg("1-b sadly, returning a null socket");
   1474 +				return null;
   1475 +			}
   1476 +		}
   1477 +		
   1478 +		if (viewer.CONNECT != null) {
   1479 +			String hp = viewer.CONNECT;
   1480 +			String req2 = "CONNECT " + hp + " HTTP/1.1\r\n"
   1481 +			    + "Host: " + hp + "\r\n\r\n";
   1482 +
   1483 +			dbg("requesting2: " + req2);
   1484 +
   1485 +			try {
   1486 +				proxy_os.write(req2.getBytes());
   1487 +				String reply = readline(proxy_is);
   1488 +
   1489 +				dbg("proxy replied2: " + reply.trim());
   1490 +
   1491 +				if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) {
   1492 +					proxySock.close();
   1493 +					proxySock = psocket(proxyHost, proxyPort);
   1494 +					if (proxySock == null) {
   1495 +						dbg("2-b sadly, returning a null socket");
   1496 +						return null;
   1497 +					}
   1498 +				}
   1499 +			} catch(Exception e) {
   1500 +				dbg("proxy socket problem-2: " + e.getMessage());
   1501 +			}
   1502 +
   1503 +			while (true) {
   1504 +				String line = readline(proxy_is);
   1505 +				dbg("proxy line2: " + line.trim());
   1506 +				if (line.equals("\r\n") || line.equals("\n")) {
   1507 +					break;
   1508 +				}
   1509 +			}
   1510 +		}
   1511 +
   1512 +		Socket sslsock = null;
   1513 +		try {
   1514 +			sslsock = factory.createSocket(proxySock, host, port, true);
   1515 +		} catch(Exception e) {
   1516 +			dbg("sslsock prob: " + e.getMessage());
   1517 +			dbg("3 sadly, returning a null socket");
   1518 +		}
   1519 +
   1520 +		return (SSLSocket) sslsock;
   1521 +	}
   1522 +
   1523 +	Socket psocket(String h, int p) {
   1524 +		Socket psock = null;
   1525 +		try {
   1526 +			psock = new Socket(h, p);
   1527 +			proxy_is = new DataInputStream(new BufferedInputStream(
   1528 +			    psock.getInputStream(), 16384));
   1529 +			proxy_os = psock.getOutputStream();
   1530 +		} catch(Exception e) {
   1531 +			dbg("psocket prob: " + e.getMessage());
   1532 +			return null;
   1533 +		}
   1534 +
   1535 +		return psock;
   1536 +	}
   1537 +
   1538 +	String readline(DataInputStream i) {
   1539 +		byte[] ba = new byte[1];
   1540 +		String s = new String("");
   1541 +		ba[0] = 0;
   1542 +		try {
   1543 +			while (ba[0] != 0xa) {
   1544 +				ba[0] = (byte) i.readUnsignedByte();
   1545 +				s += new String(ba);
   1546 +			}
   1547 +		} catch (Exception e) {
   1548 +			;
   1549 +		}
   1550 +		return s;
   1551 +	}
   1552 +}
   1553 +
   1554 +class TrustDialog implements ActionListener {
   1555 +	String msg, host, text;
   1556 +	int port;
   1557 +	java.security.cert.Certificate[] trustallCerts = null;
   1558 +	boolean viewing_cert = false;
   1559 +	boolean trust_this_session = false;
   1560 +
   1561 +	/*
   1562 +	 * this is the gui to show the user the cert and info and ask
   1563 +	 * them if they want to continue using this cert.
   1564 +	 */
   1565 +
   1566 +	Button ok, cancel, viewcert;
   1567 +	TextArea textarea;
   1568 +	Checkbox accept, deny;
   1569 +	Dialog dialog;
   1570 +
   1571 +	String s1 = "Accept this certificate temporarily for this session";
   1572 +	String s2 = "Do not accept this certificate and do not connect to"
   1573 +	    + " this VNC server";
   1574 +	String ln = "\n---------------------------------------------------\n\n";
   1575 +		
   1576 +	TrustDialog (String h, int p, java.security.cert.Certificate[] s) {
   1577 +		host = h;
   1578 +		port = p;
   1579 +		trustallCerts = s;
   1580 +
   1581 +		msg = "VNC Server " + host + ":" + port + " Not Verified";
   1582 +	}
   1583 +
   1584 +	public boolean queryUser(String reason) {
   1585 +
   1586 +		/* create and display the dialog for unverified cert. */
   1587 +
   1588 +		Frame frame = new Frame(msg);
   1589 +
   1590 +		dialog = new Dialog(frame, true);
   1591 +
   1592 +		String infostr = "";
   1593 +		if (trustallCerts.length == 1) {
   1594 +			CertInfo ci = new CertInfo(trustallCerts[0]);
   1595 +			infostr = ci.get_certinfo("all");
   1596 +		}
   1597 +		if (reason != null) {
   1598 +			reason += "\n\n";
   1599 +		}
   1600 +
   1601 +		text = "\n" 
   1602 ++ "Unable to verify the identity of\n"
   1603 ++ "\n"
   1604 ++ "        " + host + ":" + port + "\n" 
   1605 ++ "\n"
   1606 ++ infostr
   1607 ++ "\n"
   1608 ++ "as a trusted VNC server.\n"
   1609 ++ "\n"
   1610 ++ reason
   1611 ++ "In General not being able to verify the VNC Server and/or your seeing this Dialog\n"
   1612 ++ "is due to one of the following:\n"
   1613 ++ "\n"
   1614 ++ " - Your requesting to View the Certificate before accepting.\n"
   1615 ++ "\n"
   1616 ++ " - The VNC server is using a Self-Signed Certificate or a Certificate\n"
   1617 ++ "   Authority not recognized by your Web Browser or Java Plugin runtime.\n"
   1618 ++ "\n"
   1619 ++ " - The use of an Apache SSL portal scheme employing CONNECT proxying AND\n"
   1620 ++ "   the Apache Web server has a certificate *different* from the VNC server's.\n"
   1621 ++ "\n"
   1622 ++ " - No previously accepted Certificate (via Web Broswer/Java Plugin) could be\n"
   1623 ++ "   obtained by this applet to compare the VNC Server Certificate against.\n"
   1624 ++ "\n"
   1625 ++ " - The VNC Server's Certificate does not match the one specified in the\n"
   1626 ++ "   supplied 'serverCert' Java Applet Parameter.\n"
   1627 ++ "\n"
   1628 ++ " - A Man-In-The-Middle attack impersonating as the VNC server that you wish\n"
   1629 ++ "   to connect to.  (Wouldn't that be exciting!!)\n"
   1630 ++ "\n"
   1631 ++ "By safely copying the VNC server's Certificate (or using a common Certificate\n"
   1632 ++ "Authority certificate) you can configure your Web Browser and Java Plugin to\n"
   1633 ++ "automatically authenticate this VNC Server.\n"
   1634 ++ "\n"
   1635 ++ "If you do so, then you will only have to click \"Yes\" when this VNC Viewer\n"
   1636 ++ "applet asks you whether to trust your Browser/Java Plugin's acceptance of the\n"
   1637 ++ "certificate (except for the Apache portal case above where they don't match.)\n"
   1638 ++ "\n"
   1639 ++ "You can also set the applet parameter 'trustUrlVncCert=yes' to automatically\n"
   1640 ++ "accept certificates already accepted/trusted by your Web Browser/Java Plugin,\n"
   1641 ++ "and thereby see no dialog from this VNC Viewer applet.\n"
   1642 +;
   1643 +
   1644 +		/* the accept / do-not-accept radio buttons: */
   1645 +		CheckboxGroup checkbox = new CheckboxGroup();
   1646 +		accept = new Checkbox(s1, true, checkbox);
   1647 +		deny   = new Checkbox(s2, false, checkbox);
   1648 +
   1649 +		/* put the checkboxes in a panel: */
   1650 +		Panel check = new Panel();
   1651 +		check.setLayout(new GridLayout(2, 1));
   1652 +
   1653 +		check.add(accept);
   1654 +		check.add(deny);
   1655 +
   1656 +		/* make the 3 buttons: */
   1657 +		ok = new Button("OK");
   1658 +		cancel = new Button("Cancel");
   1659 +		viewcert = new Button("View Certificate");
   1660 +
   1661 +		ok.addActionListener(this);
   1662 +		cancel.addActionListener(this);
   1663 +		viewcert.addActionListener(this);
   1664 +
   1665 +		/* put the buttons in their own panel: */
   1666 +		Panel buttonrow = new Panel();
   1667 +		buttonrow.setLayout(new FlowLayout(FlowLayout.LEFT));
   1668 +		buttonrow.add(viewcert);
   1669 +		buttonrow.add(ok);
   1670 +		buttonrow.add(cancel);
   1671 +
   1672 +		/* label at the top: */
   1673 +		Label label = new Label(msg, Label.CENTER);
   1674 +		label.setFont(new Font("Helvetica", Font.BOLD, 16));
   1675 +
   1676 +		/* textarea in the middle */
   1677 +		textarea = new TextArea(text, 38, 64,
   1678 +		    TextArea.SCROLLBARS_VERTICAL_ONLY);
   1679 +		textarea.setEditable(false);
   1680 +
   1681 +		/* put the two panels in their own panel at bottom: */
   1682 +		Panel bot = new Panel();
   1683 +		bot.setLayout(new GridLayout(2, 1));
   1684 +		bot.add(check);
   1685 +		bot.add(buttonrow);
   1686 +
   1687 +		/* now arrange things inside the dialog: */
   1688 +		dialog.setLayout(new BorderLayout());
   1689 +
   1690 +		dialog.add("North", label);
   1691 +		dialog.add("South", bot);
   1692 +		dialog.add("Center", textarea);
   1693 +
   1694 +		dialog.pack();
   1695 +		dialog.resize(dialog.preferredSize());
   1696 +
   1697 +		dialog.show();	/* block here til OK or Cancel pressed. */
   1698 +
   1699 +		return trust_this_session;
   1700 +	}
   1701 +
   1702 +	public synchronized void actionPerformed(ActionEvent evt) {
   1703 +
   1704 +		if (evt.getSource() == viewcert) {
   1705 +			/* View Certificate button clicked */
   1706 +			if (viewing_cert) {
   1707 +				/* show the original info text: */
   1708 +				textarea.setText(text);
   1709 +				viewcert.setLabel("View Certificate");
   1710 +				viewing_cert = false;
   1711 +			} else {
   1712 +				int i;
   1713 +				/* show all (likely just one) certs: */
   1714 +				textarea.setText("");
   1715 +				for (i=0; i < trustallCerts.length; i++) {
   1716 +					int j = i + 1;
   1717 +					textarea.append("Certificate[" +
   1718 +					    j + "]\n\n");
   1719 +					textarea.append(
   1720 +					    trustallCerts[i].toString());
   1721 +					textarea.append(ln);
   1722 +				}
   1723 +				viewcert.setLabel("View Info");
   1724 +				viewing_cert = true;
   1725 +
   1726 +				textarea.setCaretPosition(0);
   1727 +			}
   1728 +
   1729 +		} else if (evt.getSource() == ok) {
   1730 +			/* OK button clicked */
   1731 +			if (accept.getState()) {
   1732 +				trust_this_session = true;
   1733 +			} else {
   1734 +				trust_this_session = false;
   1735 +			}
   1736 +			//dialog.dispose();
   1737 +			dialog.hide();
   1738 +
   1739 +		} else if (evt.getSource() == cancel) {
   1740 +			/* Cancel button clicked */
   1741 +			trust_this_session = false;
   1742 +
   1743 +			//dialog.dispose();
   1744 +			dialog.hide();
   1745 +		}
   1746 +	}
   1747 +
   1748 +	String get_certinfo() {
   1749 +		String all = "";
   1750 +		String fields[] = {"CN", "OU", "O", "L", "C"};
   1751 +		int i;
   1752 +		if (trustallCerts.length < 1) {
   1753 +			all = "";
   1754 +			return all;
   1755 +		}
   1756 +		String cert = trustallCerts[0].toString();
   1757 +
   1758 +		/*
   1759 +		 * For now we simply scrape the cert string, there must
   1760 +		 * be an API for this... perhaps optionValue?
   1761 +		 */
   1762 +
   1763 +		for (i=0; i < fields.length; i++) {
   1764 +			int f, t, t1, t2;
   1765 +			String sub, mat = fields[i] + "=";
   1766 +			
   1767 +			f = cert.indexOf(mat, 0);
   1768 +			if (f > 0) {
   1769 +				t1 = cert.indexOf(", ", f);
   1770 +				t2 = cert.indexOf("\n", f);
   1771 +				if (t1 < 0 && t2 < 0) {
   1772 +					continue;
   1773 +				} else if (t1 < 0) {
   1774 +					t = t2;
   1775 +				} else if (t2 < 0) {
   1776 +					t = t1;
   1777 +				} else if (t1 < t2) {
   1778 +					t = t1;
   1779 +				} else {
   1780 +					t = t2;
   1781 +				}
   1782 +				if (t > f) {
   1783 +					sub = cert.substring(f, t);
   1784 +					all = all + "        " + sub + "\n";
   1785 +				}
   1786 +			}
   1787 +		}
   1788 +		return all;
   1789 +	}
   1790 +}
   1791 +
   1792 +class ProxyDialog implements ActionListener {
   1793 +	String guessedHost = null;
   1794 +	String guessedPort = null;
   1795 +	/*
   1796 +	 * this is the gui to show the user the cert and info and ask
   1797 +	 * them if they want to continue using this cert.
   1798 +	 */
   1799 +
   1800 +	Button ok;
   1801 +	Dialog dialog;
   1802 +	TextField entry;
   1803 +	String reply = "";
   1804 +
   1805 +	ProxyDialog (String h, int p) {
   1806 +		guessedHost = h;
   1807 +		try {
   1808 +			guessedPort = Integer.toString(p);
   1809 +		} catch (Exception e) {
   1810 +			guessedPort = "8080";
   1811 +		}
   1812 +	}
   1813 +
   1814 +	public void queryUser() {
   1815 +
   1816 +		/* create and display the dialog for unverified cert. */
   1817 +
   1818 +		Frame frame = new Frame("Need Proxy host:port");
   1819 +
   1820 +		dialog = new Dialog(frame, true);
   1821 +
   1822 +
   1823 +		Label label = new Label("Please Enter your https Proxy info as host:port", Label.CENTER);
   1824 +		//label.setFont(new Font("Helvetica", Font.BOLD, 16));
   1825 +		entry = new TextField(30);
   1826 +		ok = new Button("OK");
   1827 +		ok.addActionListener(this);
   1828 +
   1829 +		String guess = "";
   1830 +		if (guessedHost != null) {
   1831 +			guess = guessedHost + ":" + guessedPort;
   1832 +		}
   1833 +		entry.setText(guess);
   1834 +
   1835 +		dialog.setLayout(new BorderLayout());
   1836 +		dialog.add("North", label);
   1837 +		dialog.add("Center", entry);
   1838 +		dialog.add("South", ok);
   1839 +		dialog.pack();
   1840 +		dialog.resize(dialog.preferredSize());
   1841 +
   1842 +		dialog.show();	/* block here til OK or Cancel pressed. */
   1843 +		return;
   1844 +	}
   1845 +
   1846 +	public String getHost() {
   1847 +		int i = reply.indexOf(":");
   1848 +		if (i < 0) {
   1849 +			return "unknown";
   1850 +		}
   1851 +		String h = reply.substring(0, i);
   1852 +		return h;
   1853 +	}
   1854 +
   1855 +	public int getPort() {
   1856 +		int i = reply.indexOf(":");
   1857 +		int p = 8080;
   1858 +		if (i < 0) {
   1859 +			return p;
   1860 +		}
   1861 +		i++;
   1862 +		String ps = reply.substring(i);
   1863 +		try {
   1864 +			Integer I = new Integer(ps);
   1865 +			p = I.intValue();
   1866 +		} catch (Exception e) {
   1867 +			;
   1868 +		}
   1869 +		return p;
   1870 +	}
   1871 +
   1872 +	public synchronized void actionPerformed(ActionEvent evt) {
   1873 +		System.out.println(evt.getActionCommand());
   1874 +		if (evt.getSource() == ok) {
   1875 +			reply = entry.getText();
   1876 +			//dialog.dispose();
   1877 +			dialog.hide();
   1878 +		}
   1879 +	}
   1880 +}
   1881 +
   1882 +class ProxyPasswdDialog implements ActionListener {
   1883 +	String guessedHost = null;
   1884 +	String guessedPort = null;
   1885 +	String guessedUser = null;
   1886 +	String guessedPasswd = null;
   1887 +	String realm = null;
   1888 +	/*
   1889 +	 * this is the gui to show the user the cert and info and ask
   1890 +	 * them if they want to continue using this cert.
   1891 +	 */
   1892 +
   1893 +	Button ok;
   1894 +	Dialog dialog;
   1895 +	TextField entry1;
   1896 +	TextField entry2;
   1897 +	String reply1 = "";
   1898 +	String reply2 = "";
   1899 +
   1900 +	ProxyPasswdDialog (String h, int p, String realm) {
   1901 +		guessedHost = h;
   1902 +		try {
   1903 +			guessedPort = Integer.toString(p);
   1904 +		} catch (Exception e) {
   1905 +			guessedPort = "8080";
   1906 +		}
   1907 +		this.realm = realm;
   1908 +	}
   1909 +
   1910 +	public void queryUser() {
   1911 +
   1912 +		/* create and display the dialog for unverified cert. */
   1913 +
   1914 +		Frame frame = new Frame("Proxy Requires Username and Password");
   1915 +
   1916 +		dialog = new Dialog(frame, true);
   1917 +
   1918 +		//Label label = new Label("Please Enter your Web Proxy Username in the top Entry and Password in the bottom Entry", Label.CENTER);
   1919 +		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);
   1920 +		entry1 = new TextField(30);
   1921 +		entry2 = new TextField(30);
   1922 +		entry2.setEchoChar('*');
   1923 +		ok = new Button("OK");
   1924 +		ok.addActionListener(this);
   1925 +
   1926 +		dialog.setLayout(new BorderLayout());
   1927 +		dialog.add("North", label);
   1928 +		dialog.add("Center", entry1);
   1929 +		dialog.add("South",  entry2);
   1930 +		dialog.add("East", ok);
   1931 +		dialog.pack();
   1932 +		dialog.resize(dialog.preferredSize());
   1933 +
   1934 +		dialog.show();	/* block here til OK or Cancel pressed. */
   1935 +		return;
   1936 +	}
   1937 +
   1938 +	public String getAuth() {
   1939 +		return reply1 + ":" + reply2;
   1940 +	}
   1941 +
   1942 +	public synchronized void actionPerformed(ActionEvent evt) {
   1943 +		System.out.println(evt.getActionCommand());
   1944 +		if (evt.getSource() == ok) {
   1945 +			reply1 = entry1.getText();
   1946 +			reply2 = entry2.getText();
   1947 +			//dialog.dispose();
   1948 +			dialog.hide();
   1949 +		}
   1950 +	}
   1951 +}
   1952 +
   1953 +class ClientCertDialog implements ActionListener {
   1954 +
   1955 +	Button ok;
   1956 +	Dialog dialog;
   1957 +	TextField entry;
   1958 +	String reply = "";
   1959 +
   1960 +	ClientCertDialog() {
   1961 +		;
   1962 +	}
   1963 +
   1964 +	public String queryUser() {
   1965 +
   1966 +		/* create and display the dialog for unverified cert. */
   1967 +
   1968 +		Frame frame = new Frame("Enter SSL Client Cert+Key String");
   1969 +
   1970 +		dialog = new Dialog(frame, true);
   1971 +
   1972 +
   1973 +		Label label = new Label("Please Enter the SSL Client Cert+Key String 308204c0...,...522d2d0a", Label.CENTER);
   1974 +		entry = new TextField(30);
   1975 +		ok = new Button("OK");
   1976 +		ok.addActionListener(this);
   1977 +
   1978 +		dialog.setLayout(new BorderLayout());
   1979 +		dialog.add("North", label);
   1980 +		dialog.add("Center", entry);
   1981 +		dialog.add("South", ok);
   1982 +		dialog.pack();
   1983 +		dialog.resize(dialog.preferredSize());
   1984 +
   1985 +		dialog.show();	/* block here til OK or Cancel pressed. */
   1986 +		return reply;
   1987 +	}
   1988 +
   1989 +	public synchronized void actionPerformed(ActionEvent evt) {
   1990 +		System.out.println(evt.getActionCommand());
   1991 +		if (evt.getSource() == ok) {
   1992 +			reply = entry.getText();
   1993 +			//dialog.dispose();
   1994 +			dialog.hide();
   1995 +		}
   1996 +	}
   1997 +}
   1998 +
   1999 +class BrowserCertsDialog implements ActionListener {
   2000 +	Button yes, no;
   2001 +	Dialog dialog;
   2002 +	String vncServer;
   2003 +	String hostport;
   2004 +	public boolean showCertDialog = true;
   2005 +
   2006 +	BrowserCertsDialog(String serv, String hp) {
   2007 +		vncServer = serv;
   2008 +		hostport = hp;
   2009 +	}
   2010 +
   2011 +	public void queryUser() {
   2012 +
   2013 +		/* create and display the dialog for unverified cert. */
   2014 +
   2015 +		Frame frame = new Frame("Use Browser/JVM Certs?");
   2016 +
   2017 +		dialog = new Dialog(frame, true);
   2018 +
   2019 +		String m = "";
   2020 +m += "\n";
   2021 +m += "This VNC Viewer applet does not have its own keystore to track\n";
   2022 +m += "SSL certificates, and so cannot authenticate the certificate\n";
   2023 +m += "of the VNC Server:\n";
   2024 +m += "\n";
   2025 +m += "        " + hostport + "\n\n        " + vncServer + "\n";
   2026 +m += "\n";
   2027 +m += "on its own.\n";
   2028 +m += "\n";
   2029 +m += "However, it has noticed that your Web Browser and/or Java VM Plugin\n";
   2030 +m += "has previously accepted the same certificate.  You may have set\n";
   2031 +m += "this up permanently or just for this session, or the server\n";
   2032 +m += "certificate was signed by a CA cert that your Web Browser or\n";
   2033 +m += "Java VM Plugin has.\n";
   2034 +m += "\n";
   2035 +m += "If the VNC Server connection times out while you are reading this\n";
   2036 +m += "dialog, then restart the connection and try again.\n";
   2037 +m += "\n";
   2038 +m += "Should this VNC Viewer applet now connect to the above VNC server?\n";
   2039 +m += "\n";
   2040 +
   2041 +		TextArea textarea = new TextArea(m, 22, 64,
   2042 +		    TextArea.SCROLLBARS_VERTICAL_ONLY);
   2043 +		textarea.setEditable(false);
   2044 +		yes = new Button("Yes");
   2045 +		yes.addActionListener(this);
   2046 +		no = new Button("No, Let Me See the Certificate.");
   2047 +		no.addActionListener(this);
   2048 +
   2049 +		dialog.setLayout(new BorderLayout());
   2050 +		dialog.add("North", textarea);
   2051 +		dialog.add("Center", yes);
   2052 +		dialog.add("South", no);
   2053 +		dialog.pack();
   2054 +		dialog.resize(dialog.preferredSize());
   2055 +
   2056 +		dialog.show();	/* block here til Yes or No pressed. */
   2057 +		System.out.println("done show()");
   2058 +		return;
   2059 +	}
   2060 +
   2061 +	public synchronized void actionPerformed(ActionEvent evt) {
   2062 +		System.out.println(evt.getActionCommand());
   2063 +		if (evt.getSource() == yes) {
   2064 +			showCertDialog = false;
   2065 +			//dialog.dispose();
   2066 +			dialog.hide();
   2067 +		} else if (evt.getSource() == no) {
   2068 +			showCertDialog = true;
   2069 +			//dialog.dispose();
   2070 +			dialog.hide();
   2071 +		}
   2072 +		System.out.println("done actionPerformed()");
   2073 +	}
   2074 +}
   2075 +
   2076 +class CertInfo {
   2077 +	String fields[] = {"CN", "OU", "O", "L", "C"};
   2078 +	java.security.cert.Certificate cert;
   2079 +	String certString = "";
   2080 +
   2081 +	CertInfo(java.security.cert.Certificate c) {
   2082 +		cert = c;
   2083 +		certString = cert.toString();
   2084 +	}
   2085 +	
   2086 +	String get_certinfo(String which) {
   2087 +		int i;
   2088 +		String cs = new String(certString);
   2089 +		String all = "";
   2090 +
   2091 +		/*
   2092 +		 * For now we simply scrape the cert string, there must
   2093 +		 * be an API for this... perhaps optionValue?
   2094 +		 */
   2095 +		for (i=0; i < fields.length; i++) {
   2096 +			int f, t, t1, t2;
   2097 +			String sub, mat = fields[i] + "=";
   2098 +			
   2099 +			f = cs.indexOf(mat, 0);
   2100 +			if (f > 0) {
   2101 +				t1 = cs.indexOf(", ", f);
   2102 +				t2 = cs.indexOf("\n", f);
   2103 +				if (t1 < 0 && t2 < 0) {
   2104 +					continue;
   2105 +				} else if (t1 < 0) {
   2106 +					t = t2;
   2107 +				} else if (t2 < 0) {
   2108 +					t = t1;
   2109 +				} else if (t1 < t2) {
   2110 +					t = t1;
   2111 +				} else {
   2112 +					t = t2;
   2113 +				}
   2114 +				if (t > f) {
   2115 +					sub = cs.substring(f, t);
   2116 +					all = all + "        " + sub + "\n";
   2117 +					if (which.equals(fields[i])) {
   2118 +						return sub;
   2119 +					}
   2120 +				}
   2121 +			}
   2122 +		}
   2123 +		if (which.equals("all")) {
   2124 +			return all;
   2125 +		} else {
   2126 +			return "";
   2127 +		}
   2128 +	}
   2129 +}
   2130 +
   2131 +class Base64Coder {
   2132 +
   2133 +	// Mapping table from 6-bit nibbles to Base64 characters.
   2134 +	private static char[]    map1 = new char[64];
   2135 +	   static {
   2136 +	      int i=0;
   2137 +	      for (char c='A'; c<='Z'; c++) map1[i++] = c;
   2138 +	      for (char c='a'; c<='z'; c++) map1[i++] = c;
   2139 +	      for (char c='0'; c<='9'; c++) map1[i++] = c;
   2140 +	      map1[i++] = '+'; map1[i++] = '/'; }
   2141 +
   2142 +	// Mapping table from Base64 characters to 6-bit nibbles.
   2143 +	private static byte[]    map2 = new byte[128];
   2144 +	   static {
   2145 +	      for (int i=0; i<map2.length; i++) map2[i] = -1;
   2146 +	      for (int i=0; i<64; i++) map2[map1[i]] = (byte)i; }
   2147 +
   2148 +	/**
   2149 +	* Encodes a string into Base64 format.
   2150 +	* No blanks or line breaks are inserted.
   2151 +	* @param s  a String to be encoded.
   2152 +	* @return   A String with the Base64 encoded data.
   2153 +	*/
   2154 +	public static String encodeString (String s) {
   2155 +	   return new String(encode(s.getBytes())); }
   2156 +
   2157 +	/**
   2158 +	* Encodes a byte array into Base64 format.
   2159 +	* No blanks or line breaks are inserted.
   2160 +	* @param in  an array containing the data bytes to be encoded.
   2161 +	* @return    A character array with the Base64 encoded data.
   2162 +	*/
   2163 +	public static char[] encode (byte[] in) {
   2164 +	   return encode(in,in.length); }
   2165 +
   2166 +	/**
   2167 +	* Encodes a byte array into Base64 format.
   2168 +	* No blanks or line breaks are inserted.
   2169 +	* @param in   an array containing the data bytes to be encoded.
   2170 +	* @param iLen number of bytes to process in <code>in</code>.
   2171 +	* @return     A character array with the Base64 encoded data.
   2172 +	*/
   2173 +	public static char[] encode (byte[] in, int iLen) {
   2174 +	   int oDataLen = (iLen*4+2)/3;       // output length without padding
   2175 +	   int oLen = ((iLen+2)/3)*4;         // output length including padding
   2176 +	   char[] out = new char[oLen];
   2177 +	   int ip = 0;
   2178 +	   int op = 0;
   2179 +	   while (ip < iLen) {
   2180 +	      int i0 = in[ip++] & 0xff;
   2181 +	      int i1 = ip < iLen ? in[ip++] & 0xff : 0;
   2182 +	      int i2 = ip < iLen ? in[ip++] & 0xff : 0;
   2183 +	      int o0 = i0 >>> 2;
   2184 +	      int o1 = ((i0 &   3) << 4) | (i1 >>> 4);
   2185 +	      int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
   2186 +	      int o3 = i2 & 0x3F;
   2187 +	      out[op++] = map1[o0];
   2188 +	      out[op++] = map1[o1];
   2189 +	      out[op] = op < oDataLen ? map1[o2] : '='; op++;
   2190 +	      out[op] = op < oDataLen ? map1[o3] : '='; op++; }
   2191 +	   return out; }
   2192 +
   2193 +	/**
   2194 +	* Decodes a string from Base64 format.
   2195 +	* @param s  a Base64 String to be decoded.
   2196 +	* @return   A String containing the decoded data.
   2197 +	* @throws   IllegalArgumentException if the input is not valid Base64 encoded data.
   2198 +	*/
   2199 +	public static String decodeString (String s) {
   2200 +	   return new String(decode(s)); }
   2201 +
   2202 +	/**
   2203 +	* Decodes a byte array from Base64 format.
   2204 +	* @param s  a Base64 String to be decoded.
   2205 +	* @return   An array containing the decoded data bytes.
   2206 +	* @throws   IllegalArgumentException if the input is not valid Base64 encoded data.
   2207 +	*/
   2208 +	public static byte[] decode (String s) {
   2209 +	   return decode(s.toCharArray()); }
   2210 +
   2211 +	/**
   2212 +	* Decodes a byte array from Base64 format.
   2213 +	* No blanks or line breaks are allowed within the Base64 encoded data.
   2214 +	* @param in  a character array containing the Base64 encoded data.
   2215 +	* @return    An array containing the decoded data bytes.
   2216 +	* @throws    IllegalArgumentException if the input is not valid Base64 encoded data.
   2217 +	*/
   2218 +	public static byte[] decode (char[] in) {
   2219 +	   int iLen = in.length;
   2220 +	   if (iLen%4 != 0) throw new IllegalArgumentException ("Length of Base64 encoded input string is not a multiple of 4.");
   2221 +	   while (iLen > 0 && in[iLen-1] == '=') iLen--;
   2222 +	   int oLen = (iLen*3) / 4;
   2223 +	   byte[] out = new byte[oLen];
   2224 +	   int ip = 0;
   2225 +	   int op = 0;
   2226 +	   while (ip < iLen) {
   2227 +	      int i0 = in[ip++];
   2228 +	      int i1 = in[ip++];
   2229 +	      int i2 = ip < iLen ? in[ip++] : 'A';
   2230 +	      int i3 = ip < iLen ? in[ip++] : 'A';
   2231 +	      if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
   2232 +		 throw new IllegalArgumentException ("Illegal character in Base64 encoded data.");
   2233 +	      int b0 = map2[i0];
   2234 +	      int b1 = map2[i1];
   2235 +	      int b2 = map2[i2];
   2236 +	      int b3 = map2[i3];
   2237 +	      if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
   2238 +		 throw new IllegalArgumentException ("Illegal character in Base64 encoded data.");
   2239 +	      int o0 = ( b0       <<2) | (b1>>>4);
   2240 +	      int o1 = ((b1 & 0xf)<<4) | (b2>>>2);
   2241 +	      int o2 = ((b2 &   3)<<6) |  b3;
   2242 +	      out[op++] = (byte)o0;
   2243 +	      if (op<oLen) out[op++] = (byte)o1;
   2244 +	      if (op<oLen) out[op++] = (byte)o2; }
   2245 +	   return out; }
   2246 +
   2247 +	// Dummy constructor.
   2248 +	private Base64Coder() {}
   2249 +
   2250 +}
   2251 diff -Naur vnc_javasrc.orig/VncCanvas.java vnc_javasrc/VncCanvas.java
   2252 --- vnc_javasrc.orig/VncCanvas.java	2004-10-10 02:15:54.000000000 -0400
   2253 +++ vnc_javasrc/VncCanvas.java	2010-11-30 21:01:15.000000000 -0500
   2254 @@ -28,13 +28,14 @@
   2255  import java.lang.*;
   2256  import java.util.zip.*;
   2257  
   2258 +import java.util.Collections;
   2259  
   2260  //
   2261  // VncCanvas is a subclass of Canvas which draws a VNC desktop on it.
   2262  //
   2263  
   2264  class VncCanvas extends Canvas
   2265 -  implements KeyListener, MouseListener, MouseMotionListener {
   2266 +  implements KeyListener, MouseListener, MouseMotionListener, MouseWheelListener {
   2267  
   2268    VncViewer viewer;
   2269    RfbProto rfb;
   2270 @@ -81,6 +82,20 @@
   2271      cm8 = new DirectColorModel(8, 7, (7 << 3), (3 << 6));
   2272      cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
   2273  
   2274 +    // kludge to not show any Java cursor in the canvas since we are
   2275 +    // showing the soft cursor (should be a user setting...)
   2276 +    Cursor dot = Toolkit.getDefaultToolkit().createCustomCursor(
   2277 +        Toolkit.getDefaultToolkit().createImage(new byte[4]), new Point(0,0),
   2278 +        "dot");
   2279 +    this.setCursor(dot);
   2280 +
   2281 +    // while we are at it... get rid of the keyboard traversals that
   2282 +    // make it so we can't type a Tab character:
   2283 +    this.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
   2284 +        Collections.EMPTY_SET);
   2285 +    this.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
   2286 +        Collections.EMPTY_SET);
   2287 +
   2288      colors = new Color[256];
   2289      for (int i = 0; i < 256; i++)
   2290        colors[i] = new Color(cm8.getRGB(i));
   2291 @@ -169,6 +184,7 @@
   2292        inputEnabled = true;
   2293        addMouseListener(this);
   2294        addMouseMotionListener(this);
   2295 +      addMouseWheelListener(this);
   2296        if (viewer.showControls) {
   2297  	viewer.buttonPanel.enableRemoteAccessControls(true);
   2298        }
   2299 @@ -177,6 +193,7 @@
   2300        inputEnabled = false;
   2301        removeMouseListener(this);
   2302        removeMouseMotionListener(this);
   2303 +      removeMouseWheelListener(this);
   2304        if (viewer.showControls) {
   2305  	viewer.buttonPanel.enableRemoteAccessControls(false);
   2306        }
   2307 @@ -1190,6 +1207,9 @@
   2308    public void mouseDragged(MouseEvent evt) {
   2309      processLocalMouseEvent(evt, true);
   2310    }
   2311 +  public void mouseWheelMoved(MouseWheelEvent evt) {
   2312 +    processLocalMouseWheelEvent(evt);
   2313 +  }
   2314  
   2315    public void processLocalKeyEvent(KeyEvent evt) {
   2316      if (viewer.rfb != null && rfb.inNormalProtocol) {
   2317 @@ -1221,6 +1241,19 @@
   2318      evt.consume();
   2319    }
   2320  
   2321 +  public void processLocalMouseWheelEvent(MouseWheelEvent evt) {
   2322 +    if (viewer.rfb != null && rfb.inNormalProtocol) {
   2323 +      synchronized(rfb) {
   2324 +	try {
   2325 +	  rfb.writeWheelEvent(evt);
   2326 +	} catch (Exception e) {
   2327 +	  e.printStackTrace();
   2328 +	}
   2329 +	rfb.notify();
   2330 +      }
   2331 +    }
   2332 +  }
   2333 +
   2334    public void processLocalMouseEvent(MouseEvent evt, boolean moved) {
   2335      if (viewer.rfb != null && rfb.inNormalProtocol) {
   2336        if (moved) {
   2337 @@ -1387,9 +1420,9 @@
   2338  		result = cm8.getRGB(pixBuf[i]);
   2339  	      } else {
   2340  		result = 0xFF000000 |
   2341 -		  (pixBuf[i * 4 + 1] & 0xFF) << 16 |
   2342 -		  (pixBuf[i * 4 + 2] & 0xFF) << 8 |
   2343 -		  (pixBuf[i * 4 + 3] & 0xFF);
   2344 +		  (pixBuf[i * 4 + 2] & 0xFF) << 16 |
   2345 +		  (pixBuf[i * 4 + 1] & 0xFF) << 8 |
   2346 +		  (pixBuf[i * 4 + 0] & 0xFF);
   2347  	      }
   2348  	    } else {
   2349  	      result = 0;	// Transparent pixel
   2350 @@ -1403,9 +1436,9 @@
   2351  	      result = cm8.getRGB(pixBuf[i]);
   2352  	    } else {
   2353  	      result = 0xFF000000 |
   2354 -		(pixBuf[i * 4 + 1] & 0xFF) << 16 |
   2355 -		(pixBuf[i * 4 + 2] & 0xFF) << 8 |
   2356 -		(pixBuf[i * 4 + 3] & 0xFF);
   2357 +		(pixBuf[i * 4 + 2] & 0xFF) << 16 |
   2358 +		(pixBuf[i * 4 + 1] & 0xFF) << 8 |
   2359 +		(pixBuf[i * 4 + 0] & 0xFF);
   2360  	    }
   2361  	  } else {
   2362  	    result = 0;		// Transparent pixel
   2363 diff -Naur vnc_javasrc.orig/VncViewer.java vnc_javasrc/VncViewer.java
   2364 --- vnc_javasrc.orig/VncViewer.java	2004-03-04 08:34:25.000000000 -0500
   2365 +++ vnc_javasrc/VncViewer.java	2010-03-27 17:57:04.000000000 -0400
   2366 @@ -29,6 +29,7 @@
   2367  import java.awt.event.*;
   2368  import java.io.*;
   2369  import java.net.*;
   2370 +import java.util.*;
   2371  
   2372  public class VncViewer extends java.applet.Applet
   2373    implements java.lang.Runnable, WindowListener {
   2374 @@ -80,7 +81,7 @@
   2375    // Variables read from parameter values.
   2376    String socketFactory;
   2377    String host;
   2378 -  int port;
   2379 +  int port, vncserverport;
   2380    boolean showControls;
   2381    boolean offerRelogin;
   2382    boolean showOfflineDesktop;
   2383 @@ -88,6 +89,24 @@
   2384    int deferCursorUpdates;
   2385    int deferUpdateRequests;
   2386  
   2387 +  boolean disableSSL;
   2388 +  boolean GET;
   2389 +  String CONNECT;
   2390 +  String urlPrefix;
   2391 +  String httpsPort;
   2392 +  String oneTimeKey;
   2393 +  String serverCert;
   2394 +  String proxyHost;
   2395 +  String proxyPort;
   2396 +  boolean forceProxy;
   2397 +  boolean ignoreProxy;
   2398 +  boolean trustAllVncCerts;
   2399 +  boolean trustUrlVncCert;
   2400 +  boolean debugCerts;
   2401 +  boolean debugKeyboard;
   2402 +  boolean mapF5_to_atsign;
   2403 +  boolean forbid_Ctrl_Alt;
   2404 +
   2405    // Reference to this applet for inter-applet communication.
   2406    public static java.applet.Applet refApplet;
   2407  
   2408 @@ -282,10 +301,24 @@
   2409        validate();
   2410      }
   2411  
   2412 -    while (!tryAuthenticate()) {
   2413 -      authenticator.retry();
   2414 -      authenticatorUnixLogin.retry();
   2415 -    }
   2416 +	if (false) {
   2417 +		/* a bug on retries: 'Error: bad position: 8' sun.awt.X11.XTextFieldPeer.setCaretPosition(XTextFieldPeer.java:215) */
   2418 +		while (!tryAuthenticate()) {
   2419 +			authenticator.retry();
   2420 +			authenticatorUnixLogin.retry();
   2421 +		}
   2422 +	} else {
   2423 +		/* just try once and not forever... */
   2424 +		if (!tryAuthenticate()) {
   2425 +    			showConnectionStatus("Authentication Failed.");
   2426 +			showMessage("Authentication Failed.");
   2427 +			if (!offerRelogin) {
   2428 +				fatalError("auth failed.");
   2429 +			}
   2430 +		} else {
   2431 +			//showConnectionStatus("Authentication OK.");
   2432 +		}
   2433 +	}
   2434    }
   2435  
   2436  
   2437 @@ -428,7 +461,10 @@
   2438      gbc.ipadx = 100;
   2439      gbc.ipady = 50;
   2440      gridbag.setConstraints(authPanel, gbc);
   2441 +    try {
   2442      vncContainer.add(authPanel);
   2443 +    } catch (Exception e) {
   2444 +    }
   2445  
   2446      if (inSeparateFrame) {
   2447        vncFrame.pack();
   2448 @@ -590,9 +626,28 @@
   2449  	fatalError("HOST parameter not specified");
   2450        }
   2451      }
   2452 +    Date d = new Date();
   2453 +    System.out.println("-\nSSL VNC Java Applet starting.  " + d);
   2454  
   2455 -    String str = readParameter("PORT", true);
   2456 -    port = Integer.parseInt(str);
   2457 +    port = 0;
   2458 +    String str = readParameter("PORT", false);
   2459 +    if (str != null) {
   2460 +	port = Integer.parseInt(str);
   2461 +    }
   2462 +    // When there is a proxy VNCSERVERPORT may be inaccessible (inside firewall).
   2463 +    vncserverport = 0;
   2464 +    str = readParameter("VNCSERVERPORT", false);
   2465 +    if (str != null) {
   2466 +	vncserverport = Integer.parseInt(str);
   2467 +    }
   2468 +    if (port == 0 && vncserverport == 0) {
   2469 +	fatalError("Neither PORT nor VNCSERVERPORT parameters specified");
   2470 +    }
   2471 +    if (port == 0) {
   2472 +	// Nevertheless, fall back to vncserverport if we have to.
   2473 +	System.out.println("using vncserverport: '" + vncserverport + "' for PORT.");
   2474 +	port = vncserverport;
   2475 +    }
   2476  
   2477      if (inAnApplet) {
   2478        str = readParameter("Open New Window", false);
   2479 @@ -626,6 +681,121 @@
   2480  
   2481      // SocketFactory.
   2482      socketFactory = readParameter("SocketFactory", false);
   2483 +
   2484 +    // SSL
   2485 +    disableSSL = false;
   2486 +    str = readParameter("DisableSSL", false);
   2487 +    if (str != null && str.equalsIgnoreCase("Yes"))
   2488 +      disableSSL = true;
   2489 +
   2490 +    httpsPort = readParameter("httpsPort", false);
   2491 +
   2492 +    // Extra GET, CONNECT string:
   2493 +    CONNECT = readParameter("CONNECT", false);
   2494 +    if (CONNECT != null) {
   2495 +	CONNECT = CONNECT.replaceAll(" ", ":");
   2496 +    }
   2497 +
   2498 +    GET = false;
   2499 +    str = readParameter("GET", false);
   2500 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   2501 +      GET = true;
   2502 +    }
   2503 +    if (str != null && str.equalsIgnoreCase("1")) {
   2504 +      GET = true;
   2505 +    }
   2506 +
   2507 +    urlPrefix = readParameter("urlPrefix", false);
   2508 +    if (urlPrefix != null) {
   2509 +	urlPrefix = urlPrefix.replaceAll("%2F", "/");
   2510 +	urlPrefix = urlPrefix.replaceAll("%2f", "/");
   2511 +	urlPrefix = urlPrefix.replaceAll("_2F_", "/");
   2512 +	if (urlPrefix.indexOf("/") != 0) {
   2513 +		urlPrefix = "/" + urlPrefix;
   2514 +	}
   2515 +    } else {
   2516 +    	urlPrefix = "";
   2517 +    }
   2518 +    System.out.println("urlPrefix: '" + urlPrefix + "'");
   2519 +
   2520 +    oneTimeKey = readParameter("oneTimeKey", false);
   2521 +    if (oneTimeKey != null) {
   2522 +    	System.out.println("oneTimeKey is set.");
   2523 +    }
   2524 +
   2525 +    serverCert = readParameter("serverCert", false);
   2526 +    if (serverCert != null) {
   2527 +    	System.out.println("serverCert is set.");
   2528 +    }
   2529 +
   2530 +    forceProxy = false;
   2531 +    proxyHost = null;
   2532 +    proxyPort = null;
   2533 +    str = readParameter("forceProxy", false);
   2534 +    if (str != null) {
   2535 +	    if (str.equalsIgnoreCase("Yes")) {
   2536 +		forceProxy = true;
   2537 +	    } else if (str.equalsIgnoreCase("No")) {
   2538 +		forceProxy = false;
   2539 +	    } else {
   2540 +		forceProxy = true;
   2541 +		String[] pieces = str.split(" ");
   2542 +		proxyHost = new String(pieces[0]);
   2543 +		if (pieces.length >= 2) {
   2544 +			proxyPort = new String(pieces[1]);
   2545 +		} else {
   2546 +			proxyPort = new String("8080");
   2547 +		}
   2548 +	    }
   2549 +    }
   2550 +    str = readParameter("proxyHost", false);
   2551 +    if (str != null) {
   2552 +	proxyHost = new String(str);
   2553 +    }
   2554 +    str = readParameter("proxyPort", false);
   2555 +    if (str != null) {
   2556 +	proxyPort = new String(str);
   2557 +    }
   2558 +    if (proxyHost != null && proxyPort == null) {
   2559 +    	proxyPort = new String("8080");
   2560 +    }
   2561 +
   2562 +    ignoreProxy = false;
   2563 +    str = readParameter("ignoreProxy", false);
   2564 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   2565 +	ignoreProxy = true;
   2566 +    }
   2567 +
   2568 +    trustAllVncCerts = false;
   2569 +    str = readParameter("trustAllVncCerts", false);
   2570 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   2571 +	trustAllVncCerts = true;
   2572 +    }
   2573 +    trustUrlVncCert = false;
   2574 +    str = readParameter("trustUrlVncCert", false);
   2575 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   2576 +	trustUrlVncCert = true;
   2577 +    }
   2578 +    debugCerts = false;
   2579 +    str = readParameter("debugCerts", false);
   2580 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   2581 +	debugCerts = true;
   2582 +    }
   2583 +    debugKeyboard = false;
   2584 +    str = readParameter("debugKeyboard", false);
   2585 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   2586 +	debugKeyboard = true;
   2587 +    }
   2588 +    mapF5_to_atsign = false;
   2589 +    str = readParameter("mapF5_to_atsign", false);
   2590 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   2591 +	mapF5_to_atsign = true;
   2592 +    }
   2593 +    forbid_Ctrl_Alt = false;
   2594 +    str = readParameter("forbid_Ctrl_Alt", false);
   2595 +    if (str != null && str.equalsIgnoreCase("Yes")) {
   2596 +	forbid_Ctrl_Alt = true;
   2597 +    }
   2598    }
   2599  
   2600    public String readParameter(String name, boolean required) {
   2601