• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1diff -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)
47diff -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
180diff -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@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+}
2251diff -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
2363diff -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