summaryrefslogtreecommitdiffstats
path: root/classes
diff options
context:
space:
mode:
authorrunge <runge>2007-05-16 21:32:52 +0000
committerrunge <runge>2007-05-16 21:32:52 +0000
commit3110c0e32f2f1fe823917eebc33bedc44a84160c (patch)
tree5adec4f47905ebca5b36da5c5699d007f80654db /classes
parentc49eee2cf625d8cfcefd23c6a33e6c9488570fcc (diff)
downloadlibvncserver-3110c0e32f2f1fe823917eebc33bedc44a84160c.zip
libvncserver-3110c0e32f2f1fe823917eebc33bedc44a84160c.tar.gz
Add SSL support to UltraVNC Java Viewer (has filetransfer gui). Fix UltraVNC bugs and improve FTP gui a bit.
Diffstat (limited to 'classes')
-rw-r--r--classes/ssl/Makefile.am2
-rw-r--r--classes/ssl/README14
-rw-r--r--classes/ssl/SignedUltraViewerSSL.jarbin0 -> 91540 bytes
-rw-r--r--classes/ssl/SignedVncViewer.jarbin79005 -> 79003 bytes
-rw-r--r--classes/ssl/UltraViewerSSL.jarbin0 -> 88970 bytes
-rw-r--r--classes/ssl/VncViewer.jarbin76220 -> 76220 bytes
-rwxr-xr-xclasses/ssl/ss_vncviewer259
-rw-r--r--classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patchbin44072 -> 42592 bytes
-rw-r--r--classes/ssl/ultra.vnc27
-rw-r--r--classes/ssl/ultrasigned.vnc27
-rw-r--r--classes/ssl/ultravnc-102-JavaViewer-ssl-etc.patch2323
11 files changed, 2593 insertions, 59 deletions
diff --git a/classes/ssl/Makefile.am b/classes/ssl/Makefile.am
index b0d3664..29ad54d 100644
--- a/classes/ssl/Makefile.am
+++ b/classes/ssl/Makefile.am
@@ -1,2 +1,2 @@
-EXTRA_DIST=VncViewer.jar index.vnc SignedVncViewer.jar proxy.vnc README ss_vncviewer onetimekey
+EXTRA_DIST=VncViewer.jar index.vnc SignedVncViewer.jar proxy.vnc README ss_vncviewer onetimekey UltraViewerSSL.jar SignedUltraViewerSSL.jar ultra.vnc ultrasigned.vnc
diff --git a/classes/ssl/README b/classes/ssl/README
index 7c3115f..1b794e4 100644
--- a/classes/ssl/README
+++ b/classes/ssl/README
@@ -69,4 +69,18 @@ Running Java SSL VncViewer from the command line:
java -cp ./VncViewer.jar VncViewer HOST <thehost> PORT <theport>
substitute <thehost> and <theport> with the actual values.
+ You can add any other parameters, e.g.: ignoreProxy yes
+---------------------------------------------------------------
+UltraVNC:
+
+The UltraVNC java viewer has also been patched to support SSL. Various
+bugs in the UltraVNC java viewer were also fixed. This viewer can be
+useful because is support UltraVNC filetransfer, and so it works on
+Unix, etc.
+
+UltraViewerSSL.jar
+SignedUltraViewerSSL.jar
+ultra.vnc
+ultraproxy.vnc
+ultravnc-102-JavaViewer-ssl-etc.patch
diff --git a/classes/ssl/SignedUltraViewerSSL.jar b/classes/ssl/SignedUltraViewerSSL.jar
new file mode 100644
index 0000000..8a60f0d
--- /dev/null
+++ b/classes/ssl/SignedUltraViewerSSL.jar
Binary files differ
diff --git a/classes/ssl/SignedVncViewer.jar b/classes/ssl/SignedVncViewer.jar
index 1d60cb1..1244b2a 100644
--- a/classes/ssl/SignedVncViewer.jar
+++ b/classes/ssl/SignedVncViewer.jar
Binary files differ
diff --git a/classes/ssl/UltraViewerSSL.jar b/classes/ssl/UltraViewerSSL.jar
new file mode 100644
index 0000000..7543238
--- /dev/null
+++ b/classes/ssl/UltraViewerSSL.jar
Binary files differ
diff --git a/classes/ssl/VncViewer.jar b/classes/ssl/VncViewer.jar
index b4ac298..c2e416c 100644
--- a/classes/ssl/VncViewer.jar
+++ b/classes/ssl/VncViewer.jar
Binary files differ
diff --git a/classes/ssl/ss_vncviewer b/classes/ssl/ss_vncviewer
index a20f164..f7b4831 100755
--- a/classes/ssl/ss_vncviewer
+++ b/classes/ssl/ss_vncviewer
@@ -260,6 +260,12 @@ if [ "X$use_ssh" = "X1" -a "X$use_sshssl" = "X" ]; then
fi
fi
+if echo "$orig" | grep '^V[Nn][Cc]://' > /dev/null; then
+ SSVNC_NO_ENC_WARN=1
+ export SSVNC_NO_ENC_WARN
+ orig=`echo "$orig" | sed -e 's/^...:/vnc:/'`
+fi
+
if echo "$orig" | grep '^vnc://' > /dev/null; then
orig=`echo "$orig" | sed -e 's,vnc://,,'`
verify=""
@@ -271,9 +277,14 @@ elif echo "$orig" | grep '^vncs://' > /dev/null; then
orig=`echo "$orig" | sed -e 's,vncs://,,'`
elif echo "$orig" | grep '^vncssl://' > /dev/null; then
orig=`echo "$orig" | sed -e 's,vncssl://,,'`
+elif echo "$orig" | grep '^vnc+ssl://' > /dev/null; then
+ orig=`echo "$orig" | sed -e 's,vnc.ssl://,,'`
elif echo "$orig" | grep '^vncssh://' > /dev/null; then
orig=`echo "$orig" | sed -e 's,vncssh://,,'`
use_ssh=1
+elif echo "$orig" | grep '^vnc+ssh://' > /dev/null; then
+ orig=`echo "$orig" | sed -e 's,vnc.ssh://,,'`
+ use_ssh=1
fi
if [ "X$reverse" != "X" -a "X$direct_connect" = "X" ]; then
VNCVIEWER_LISTEN_LOCALHOST=1
@@ -314,6 +325,8 @@ if uname | grep Linux > /dev/null; then
inuse=`netstat -ant | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $4}' | sed 's/^.*://'`
elif uname | grep SunOS > /dev/null; then
inuse=`netstat -an -f inet -P tcp | grep LISTEN | awk '{print $1}' | sed 's/^.*\.//'`
+elif uname | grep -i bsd > /dev/null; then
+ inuse=`netstat -ant -f inet | grep LISTEN | awk '{print $4}' | sed 's/^.*\.//'`
# add others...
fi
@@ -412,6 +425,31 @@ if echo "$0" | grep vncip > /dev/null; then
VNCVIEWERCMD="$VNCIPCMD"
fi
+rchk() {
+ if [ "X$BASH_VERSION" = "X" ]; then
+ RANDOM=`date +%S``sh -c 'echo $$'``ps -elf 2>&1 | sum 2>&1 | awk '{print $1}'`
+ fi
+}
+rchk
+
+mytmp() {
+ tf=$1
+ rm -rf "$tf" || exit 1
+ if [ -d "$tf" ]; then
+ echo "tmp file $tf still exists as a directory."
+ exit 1
+ elif [ -L "$tf" ]; then
+ echo "tmp file $tf still exists as a symlink."
+ exit 1
+ elif [ -f "$tf" ]; then
+ echo "tmp file $tf still exists."
+ exit 1
+ fi
+ touch "$tf" || exit 1
+ chmod 600 "$tf" || exit 1
+ rchk
+}
+
if [ "X$use_ssh" = "X1" ]; then
ssh_port="22"
ssh_host="$host"
@@ -472,28 +510,88 @@ if [ "X$use_ssh" = "X1" ]; then
if [ "X$SS_VNCVIEWER_USE_C" != "X" ]; then
C="-C"
fi
- if [ "X$reverse" = "X" ]; then
+
+ getport=""
+ if echo "$ssh_cmd" | egrep "^(PORT=|P=)" > /dev/null; then
+ getport=1
+ PORT=""
+ ssh_cmd=`echo "$ssh_cmd" | sed -e 's/^PORT=[ ]*//' -e 's/^P=//'`
+ SSVNC_NO_ENC_WARN=1
+ if [ "X$use_sshssl" = "X" ]; then
+ direct_connect=1
+ fi
+ fi
+ if [ "X$getport" != "X" ]; then
+ ssh_redir="-D ${use}"
+ elif [ "X$reverse" = "X" ]; then
ssh_redir="-L ${use}:${vnc_host}:${port}"
else
ssh_redir="-R ${port}:${vnc_host}:${use}"
fi
pmark=`sh -c 'echo $$'`
+
# the -t option actually speeds up typing response via VNC!!
+
if [ "X$SS_VNCVIEWER_SSH_ONLY" != "X" ]; then
echo "$ssh -x -p $ssh_port $targ $C $ssh_args $ssh_host \"$info\""
echo ""
$ssh -x -p $ssh_port $targ $C $ssh_args $ssh_host "$ssh_cmd"
exit $?
+
elif [ "X$SS_VNCVIEWER_NO_F" != "X" ]; then
echo "$ssh -x -p $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\""
echo ""
$ssh -x -p $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd"
+ rc=$?
+
+ elif [ "X$getport" != "X" ]; then
+ echo "$ssh -x -f -p $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\""
+ echo ""
+
+ tport=/tmp/tport${RANDOM}.$$
+ mytmp $tport
+ $ssh -x -f -p $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd" > $tport
+ rc=$?
+
+ stty sane
+ i=0
+ while [ $i -lt 10 ]; do
+ sleep 1
+ PORT=`grep "^PORT=" $tport | head -1 | sed -e 's/PORT=//' -e 's/\r//g'`
+ if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then
+ break
+ fi
+ vnss=`sed -e 's/\r//g' $tport | egrep -i '^(New.* desktop is|A VNC server is already running).*:[0-9[0-9]*$' | head -1 | awk '{print $NF}'`
+ if [ "X$vnss" != "X" ]; then
+ PORT=`echo "$vnss" | awk -F: '{print $2}'`
+ if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then
+ if [ $PORT -lt 100 ]; then
+ PORT=`expr $PORT + 5900`
+ fi
+ fi
+ if echo "$PORT" | grep '^[0-9][0-9]*$' > /dev/null; then
+ break
+ fi
+ fi
+ i=`expr $i + 1`
+ done
+
+ echo "PORT=$PORT" 1>&2
+ PPROXY_SOCKS=1
+ export PPROXY_SOCKS
+ host="localhost"
+ port="$PORT"
+ proxy="localhost:$use"
+ rm -f $tport
+
else
echo "$ssh -x -f -p $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\""
echo ""
$ssh -x -f -p $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd"
+ rc=$?
fi
- if [ "$?" != "0" ]; then
+
+ if [ "$rc" != "0" ]; then
echo ""
echo "ssh to $ssh_host failed."
exit 1
@@ -511,7 +609,9 @@ if [ "X$use_ssh" = "X1" ]; then
fi
c=`expr $c + 1`
done
- if [ "X$ssh_cmd" = "Xsleep $ssh_sleep" ] ; then
+ if [ "X$getport" != "X" ]; then
+ :
+ elif [ "X$ssh_cmd" = "Xsleep $ssh_sleep" ] ; then
sleep 1
else
# let any command get started a bit.
@@ -521,7 +621,7 @@ if [ "X$use_ssh" = "X1" ]; then
#reset
stty sane
#echo "pssh=\"$pssh\""
- if [ "X$use_sshssl" = "X" ]; then
+ if [ "X$use_sshssl" = "X" -a "X$getport" = "X" ]; then
echo "Running viewer:"
trap "final" 0 2 15
@@ -547,7 +647,12 @@ if [ "X$use_ssh" = "X1" ]; then
port=$use
use=$use2
N=`expr $use - 5900`
- proxy=""
+ if [ "X$getport" != "X" ]; then
+ host="$host0"
+ port="$port0"
+ else
+ proxy=""
+ fi
fi
fi
@@ -565,53 +670,33 @@ if [ "X$mycert" != "X" ]; then
cert="cert = $mycert"
fi
-mytmp() {
- tf=$1
- rm -rf "$tf" || exit 1
- if [ -d "$tf" ]; then
- echo "tmp file $tf still exists as a directory."
- exit 1
- elif [ -L "$tf" ]; then
- echo "tmp file $tf still exists as a symlink."
- exit 1
- elif [ -f "$tf" ]; then
- echo "tmp file $tf still exists."
- exit 1
- fi
- touch "$tf" || exit 1
- chmod 600 "$tf" || exit 1
-}
-
-if echo "$RANDOM" | grep '[^0-9]' > /dev/null; then
- RANDOM=`date +%S`
-fi
-
pcode() {
tf=$1
- SSVNC_PROXY=$proxy; export SSVNC_PROXY
- SSVNC_DEST="$host:$port"; export SSVNC_DEST
+ PPROXY_PROXY=$proxy; export PPROXY_PROXY
+ PPROXY_DEST="$host:$port"; export PPROXY_DEST
cod='#!/usr/bin/perl
-# A hack to glue stunnel to a Web proxy for client connections.
+# A hack to glue stunnel to a Web proxy or SOCKS for client connections.
use IO::Socket::INET;
-my ($first, $second) = split(/,/, $ENV{SSVNC_PROXY});
+my ($first, $second) = split(/,/, $ENV{PPROXY_PROXY});
my ($proxy_host, $proxy_port) = split(/:/, $first);
-my $connect = $ENV{SSVNC_DEST};
+my $connect = $ENV{PPROXY_DEST};
-print STDERR "\nperl script for web proxing:\n";
+print STDERR "\nPPROXY v0.0: a tool for Web proxies and SOCKS connections.\n";
print STDERR "proxy_host: $proxy_host\n";
print STDERR "proxy_port: $proxy_port\n";
print STDERR "proxy_connect: $connect\n";
my $listen_handle = "";
-if ($ENV{SSVNC_LISTEN} != "") {
+if ($ENV{PPROXY_LISTEN} != "") {
my $listen_sock = IO::Socket::INET->new(
Listen => 2,
LocalAddr => "localhost",
- LocalPort => $ENV{SSVNC_LISTEN},
- Proto => "tcp");
+ LocalPort => $ENV{PPROXY_LISTEN},
+ Proto => "tcp"
+ );
if (! $listen_sock) {
die "perl proxy: $!\n";
}
@@ -625,7 +710,8 @@ if ($ENV{SSVNC_LISTEN} != "") {
my $sock = IO::Socket::INET->new(
PeerAddr => $proxy_host,
PeerPort => $proxy_port,
- Proto => "tcp");
+ Proto => "tcp"
+);
if (! $sock) {
unlink($0);
@@ -633,24 +719,77 @@ if (! $sock) {
}
my $con = "";
-if ($second ne "") {
+my $con0 = "";
+if ($ENV{PPROXY_SOCKS} ne "") {
+ $second = "";
+ my ($h, $p) = split(/:/, $connect);
+ $con .= pack("C", 0x04);
+ $con .= pack("C", 0x01);
+ $con .= pack("n", $p);
+
+ my $SOCKS_4a = 0;
+ if ($h eq "localhost" || $h eq "127.0.0.1") {
+ $con .= pack("C", 127);
+ $con .= pack("C", 0);
+ $con .= pack("C", 0);
+ $con .= pack("C", 1);
+ } elsif ($h =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {
+ $con .= pack("C", $1);
+ $con .= pack("C", $2);
+ $con .= pack("C", $3);
+ $con .= pack("C", $4);
+ } else {
+ $con .= pack("C", 0);
+ $con .= pack("C", 0);
+ $con .= pack("C", 0);
+ $con .= pack("C", 3);
+ $SOCKS_4a = 1;
+ }
+
+ $con .= "nobody";
+ $con .= pack("C", 0);
+
+ if ($SOCKS_4a) {
+ $con .= $h;
+ $con .= pack("C", 0);
+ }
+ $con0 = "SOCKS4 via $proxy_host:$proxy_port to $h:$p\n\n";
+
+} elsif ($second ne "") {
$con = "CONNECT $second HTTP/1.1\r\n";
$con .= "Host: $second\r\n\r\n";
+ $con0 = $con;
} else {
$con = "CONNECT $connect HTTP/1.1\r\n";
$con .= "Host: $connect\r\n\r\n";
+ $con0 = $con;
}
-print STDERR "proxy_request1:\n$con";
+print STDERR "proxy_request1:\n$con0";
print $sock $con;
unlink($0);
my $rep = "";
-while ($rep !~ /\r\n\r\n/) {
- my $c = getc($sock);
- print STDERR $c;
- $rep .= $c;
+if ($ENV{PPROXY_SOCKS} ne "") {
+ $rep = "HTTP/1.0 200";
+ for (my $i = 0; $i < 8; $i++) {
+ my $c;
+ sysread($sock, $c, 1);
+ my $s = unpack("C", $c);
+ if ($i == 0) {
+ $rep = "" if $s != 0x0;
+ } elsif ($i == 1) {
+ $rep = "" if $s != 0x5a;
+ }
+ }
+} else {
+ while ($rep !~ /\r\n\r\n/) {
+ my $c;
+ sysread($sock, $c, 1);
+ print STDERR $c;
+ $rep .= $c;
+ }
}
if ($rep !~ m,HTTP/.* 200,) {
die "proxy error: $rep\n";
@@ -665,7 +804,8 @@ if ($second ne "") {
$rep = "";
while ($rep !~ /\r\n\r\n/) {
- my $c = getc($sock);
+ my $c;
+ sysread($sock, $c, 1);
print STDERR $c;
$rep .= $c;
}
@@ -743,8 +883,8 @@ if [ "X$proxy" != "X" ]; then
if [ "X$showcert" != "X1" -a "X$direct_connect" = "X" ]; then
if uname | grep Darwin >/dev/null; then
nd=`expr $use + 333`
- SSVNC_LISTEN=$nd
- export SSVNC_LISTEN
+ PPROXY_LISTEN=$nd
+ export PPROXY_LISTEN
$ptmp 2>/dev/null &
sleep 3
host="localhost"
@@ -762,8 +902,8 @@ fi
if [ "X$showcert" = "X1" ]; then
if [ "X$proxy" != "X" ]; then
- SSVNC_LISTEN=$use
- export SSVNC_LISTEN
+ PPROXY_LISTEN=$use
+ export PPROXY_LISTEN
$ptmp 2>/dev/null &
sleep 3
host="localhost"
@@ -774,24 +914,29 @@ if [ "X$showcert" = "X1" ]; then
fi
if [ "X$direct_connect" != "X" ]; then
- echo ""
- echo "Running viewer for direct connection:"
- echo ""
- echo "** NOTE: THERE WILL BE NO SSL OR SSH ENCRYPTION **"
- echo ""
- if type printf > /dev/null 2>&1; then
+ if [ "X$getport" = "X" ]; then
+ echo ""
+ echo "Running viewer for direct connection:"
+ echo ""
+ echo "** NOTE: THERE WILL BE NO SSL OR SSH ENCRYPTION **"
+ echo ""
+ fi
+ if [ "X$SSVNC_NO_ENC_WARN" != "X" ]; then
+ sleep 1
+ elif type printf > /dev/null 2>&1; then
printf "Are you sure you want to continue? [y]/n "
+ read x
else
echo -n "Are you sure you want to continue? [y]/n "
+ read x
fi
- read x
if [ "X$x" = "Xn" ]; then
exit 1
fi
echo ""
if [ "X$ptmp" != "X" ]; then
- SSVNC_LISTEN=$use
- export SSVNC_LISTEN
+ PPROXY_LISTEN=$use
+ export PPROXY_LISTEN
$ptmp &
if [ "X$reverse" = "X" ]; then
sleep 2
@@ -816,8 +961,6 @@ if [ "X$direct_connect" != "X" ]; then
exit $?
fi
-##debug = 7
-## debug = 6
tmp=/tmp/ss_vncviewer${RANDOM}.$$
mytmp "$tmp"
diff --git a/classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch b/classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch
index f438655..0ce4474 100644
--- a/classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch
+++ b/classes/ssl/tightvnc-1.3dev7_javasrc-vncviewer-ssl.patch
Binary files differ
diff --git a/classes/ssl/ultra.vnc b/classes/ssl/ultra.vnc
new file mode 100644
index 0000000..23b6a31
--- /dev/null
+++ b/classes/ssl/ultra.vnc
@@ -0,0 +1,27 @@
+<!--
+ index.vnc - default HTML page for TightVNC Java viewer applet, to be
+ used with Xvnc. On any file ending in .vnc, the HTTP server embedded in
+ Xvnc will substitute the following variables when preceded by a dollar:
+ USER, DESKTOP, DISPLAY, APPLETWIDTH, APPLETHEIGHT, WIDTH, HEIGHT, PORT,
+ PARAMS. Use two dollar signs ($$) to get a dollar sign in the generated
+ HTML page.
+
+ NOTE: the $PARAMS variable is not supported by the standard VNC, so
+ make sure you have TightVNC on the server side, if you're using this
+ variable.
+-->
+
+<HTML>
+<TITLE>
+$USER's $DESKTOP desktop ($DISPLAY)
+</TITLE>
+<APPLET CODE=VncViewer.class ARCHIVE=UltraViewerSSL.jar
+ WIDTH=$APPLETWIDTH HEIGHT=$APPLETHEIGHT>
+<param name=PORT value=$PORT>
+<param name="Open New Window" value=yes>
+<param name="ignoreMSLogonCheck" value=yes>
+$PARAMS
+</APPLET>
+<BR>
+<A href="http://www.ultravnc.com/">UltraVNC site</A>
+</HTML>
diff --git a/classes/ssl/ultrasigned.vnc b/classes/ssl/ultrasigned.vnc
new file mode 100644
index 0000000..f7c08f8
--- /dev/null
+++ b/classes/ssl/ultrasigned.vnc
@@ -0,0 +1,27 @@
+<!--
+ index.vnc - default HTML page for TightVNC Java viewer applet, to be
+ used with Xvnc. On any file ending in .vnc, the HTTP server embedded in
+ Xvnc will substitute the following variables when preceded by a dollar:
+ USER, DESKTOP, DISPLAY, APPLETWIDTH, APPLETHEIGHT, WIDTH, HEIGHT, PORT,
+ PARAMS. Use two dollar signs ($$) to get a dollar sign in the generated
+ HTML page.
+
+ NOTE: the $PARAMS variable is not supported by the standard VNC, so
+ make sure you have TightVNC on the server side, if you're using this
+ variable.
+-->
+
+<HTML>
+<TITLE>
+$USER's $DESKTOP desktop ($DISPLAY)
+</TITLE>
+<APPLET CODE=VncViewer.class ARCHIVE=SignedUltraViewerSSL.jar
+ WIDTH=$APPLETWIDTH HEIGHT=$APPLETHEIGHT>
+<param name=PORT value=$PORT>
+<param name="Open New Window" value=yes>
+<param name="ignoreMSLogonCheck" value=yes>
+$PARAMS
+</APPLET>
+<BR>
+<A href="http://www.ultravnc.com/">UltraVNC site</A>
+</HTML>
diff --git a/classes/ssl/ultravnc-102-JavaViewer-ssl-etc.patch b/classes/ssl/ultravnc-102-JavaViewer-ssl-etc.patch
new file mode 100644
index 0000000..ceef727
--- /dev/null
+++ b/classes/ssl/ultravnc-102-JavaViewer-ssl-etc.patch
@@ -0,0 +1,2323 @@
+diff -Naur JavaViewer.orig/ButtonPanel.java JavaViewer/ButtonPanel.java
+--- JavaViewer.orig/ButtonPanel.java 2004-12-12 20:51:02.000000000 -0500
++++ JavaViewer/ButtonPanel.java 2007-05-16 15:50:54.000000000 -0400
+@@ -163,9 +163,12 @@
+ }
+ else if (evt.getSource() == ftpButton)
+ {
++// begin runge/x11vnc
++ viewer.ftp.setSavedLocations();
++// end runge/x11vnc
+ viewer.ftp.setVisible(!viewer.ftp.isVisible());
+ viewer.rfb.readServerDriveList();
+-
++
+ }
+ }
+ }
+diff -Naur JavaViewer.orig/FTPFrame.java JavaViewer/FTPFrame.java
+--- JavaViewer.orig/FTPFrame.java 2005-03-15 23:53:14.000000000 -0500
++++ JavaViewer/FTPFrame.java 2007-05-16 16:05:15.000000000 -0400
+@@ -26,6 +26,10 @@
+ import java.util.Vector;
+ import javax.swing.*;
+
++// begin runge/x11vnc
++import java.util.Arrays;
++// end runge/x11vnc
++
+
+ /*
+ * Created on Feb 25, 2004
+@@ -80,6 +84,17 @@
+ private File localSelection = null; // Holds the currently selected local file
+ private String remoteSelection = null; // Holds the currently selected remote file
+ public String selectedTable = null;
++
++// begin runge/x11vnc
++ private javax.swing.JButton viewButton = null;
++ public File saveLocalDirectory = null;
++ public long saveLocalDirectoryTime = 0;
++ public int saveLocalDirectoryCount = 0;
++ public String saveRemoteDirectory = null;
++ public long saveRemoteDirectoryTime = 0;
++ public int saveRemoteDirectoryCount = 0;
++ private boolean localCurrentIsDir = true;
++// end runge/x11vnc
+
+ // sf@2004 - Separate directories and files for better lisibility
+ private ArrayList DirsList;
+@@ -125,11 +140,59 @@
+
+ void refreshRemoteLocation()
+ {
++
+ remoteList.clear();
+ remoteFileTable.setListData(remoteList);
++System.out.println("refreshRemoteLocation '" + remoteLocation.getText() + "'"); // runge/x11vnc
+ viewer.rfb.readServerDirectory(remoteLocation.getText());
+ }
+
++// begin runge/x11vnc
++ public void setSavedLocations() {
++ saveLocalDirectory = currentLocalDirectory;
++ saveLocalDirectoryTime = System.currentTimeMillis();
++ saveLocalDirectoryCount = 0;
++
++ if (remoteLocation != null) {
++ saveRemoteDirectory = remoteLocation.getText();
++System.out.println("RemoteSave '" + saveRemoteDirectory + "'");
++ }
++ saveRemoteDirectoryTime = System.currentTimeMillis();
++ saveRemoteDirectoryCount = 0;
++ }
++
++ private File saveLocalHack(File dir) {
++ saveLocalDirectoryCount++;
++System.out.println("L " + saveLocalDirectoryCount + " dt: " + (System.currentTimeMillis() - saveLocalDirectoryTime) + " - " + saveLocalDirectory);
++ if (System.currentTimeMillis() > saveLocalDirectoryTime + 2000 || saveLocalDirectoryCount > 2) {
++ saveLocalDirectory = null;
++ }
++ if (saveLocalDirectory != null) {
++ currentLocalDirectory = saveLocalDirectory;
++ localLocation.setText(saveLocalDirectory.toString());
++ return saveLocalDirectory;
++ } else {
++ return dir;
++ }
++ }
++
++ private String saveRemoteHack(String indrive) {
++ saveRemoteDirectoryCount++;
++System.out.println("R " + saveRemoteDirectoryCount + " - " + saveRemoteDirectory);
++ if (saveRemoteDirectory != null && saveRemoteDirectoryCount > 1) {
++ saveRemoteDirectory = null;
++ }
++ if (saveRemoteDirectory != null) {
++ if (! saveRemoteDirectory.equals("")) {
++System.out.println("saveRemoteHack setText + refreshRemoteLocation '" + saveRemoteDirectory + "'");
++ return saveRemoteDirectory;
++ }
++ }
++ return indrive;
++ }
++// end runge/x11vnc
++
++
+ /*
+ * Prints the list of drives on the remote directory and returns a String[].
+ * str takes as string like A:fC:lD:lE:lF:lG:cH:c
+@@ -185,6 +248,7 @@
+ stopButton.setVisible(true);
+ stopButton.setEnabled(true);
+ receiveButton.setEnabled(false);
++ viewButton.setEnabled(false); // runge/x11vnc
+ remoteTopButton.setEnabled(false);
+ sendButton.setEnabled(false);
+ remoteFileTable.setEnabled(false);
+@@ -207,6 +271,7 @@
+ stopButton.setVisible(false);
+ stopButton.setEnabled(false);
+ receiveButton.setEnabled(true);
++ viewButton.setEnabled(true); // runge/x11vnc
+ remoteTopButton.setEnabled(true);
+ sendButton.setEnabled(true);
+ remoteFileTable.setEnabled(true);
+@@ -405,6 +470,7 @@
+ buttonPanel = new javax.swing.JPanel();
+ buttonPanel.setLayout(null);
+ buttonPanel.add(getReceiveButton(), null);
++ buttonPanel.add(getViewButton(), null); // runge/x11vnc
+ buttonPanel.add(getNewFolderButton(), null);
+ buttonPanel.add(getCloseButton(), null);
+ buttonPanel.add(getDeleteButton(), null);
+@@ -422,7 +488,7 @@
+ private javax.swing.JButton getSendButton() {
+ if (sendButton == null) {
+ sendButton = new javax.swing.JButton();
+- sendButton.setBounds(20, 30, 97, 25);
++ sendButton.setBounds(15, 30, 107, 25); // runge/x11vnc
+ sendButton.setText("Send >>");
+ sendButton.setName("sendButton");
+ sendButton.addActionListener(this);
+@@ -438,7 +504,7 @@
+ private javax.swing.JButton getReceiveButton() {
+ if (receiveButton == null) {
+ receiveButton = new javax.swing.JButton();
+- receiveButton.setBounds(20, 60, 97, 25);
++ receiveButton.setBounds(15, 60, 107, 25); // runge/x11vnc
+ receiveButton.setText("<< Receive");
+ receiveButton.setName("receiveButton");
+ receiveButton.addActionListener(this);
+@@ -453,7 +519,7 @@
+ private javax.swing.JButton getDeleteButton() {
+ if (deleteButton == null) {
+ deleteButton = new javax.swing.JButton();
+- deleteButton.setBounds(20, 110, 97, 25);
++ deleteButton.setBounds(15, 110, 107, 25); // runge/x11vnc
+ deleteButton.setText("Delete File");
+ deleteButton.setName("deleteButton");
+ deleteButton.addActionListener(this);
+@@ -468,7 +534,7 @@
+ private javax.swing.JButton getNewFolderButton() {
+ if (newFolderButton == null) {
+ newFolderButton = new javax.swing.JButton();
+- newFolderButton.setBounds(20, 140, 97, 25);
++ newFolderButton.setBounds(15, 140, 107, 25); // runge/x11vnc
+ newFolderButton.setText("New Folder");
+ newFolderButton.setName("newFolderButton");
+ newFolderButton.addActionListener(this);
+@@ -476,6 +542,24 @@
+ return newFolderButton;
+ }
+
++// begin runge/x11vnc
++ /**
++ * This method initializes viewButton
++ *
++ * @return javax.swing.JButton
++ */
++ private javax.swing.JButton getViewButton() {
++ if (viewButton == null) {
++ viewButton = new javax.swing.JButton();
++ viewButton.setBounds(15, 170, 107, 25);
++ viewButton.setText("View File");
++ viewButton.setName("viewButton");
++ viewButton.addActionListener(this);
++ }
++ return viewButton;
++ }
++// end runge/x11vnc
++
+ /**
+ * This method initializes stopButton
+ *
+@@ -486,7 +570,7 @@
+ if (stopButton == null)
+ {
+ stopButton = new javax.swing.JButton();
+- stopButton.setBounds(20, 200, 97, 25);
++ stopButton.setBounds(15, 200, 107, 25); // runge/x11vnc
+ stopButton.setText("Stop");
+ stopButton.setName("stopButton");
+ stopButton.addActionListener(this);
+@@ -503,7 +587,7 @@
+ private javax.swing.JButton getCloseButton() {
+ if (closeButton == null) {
+ closeButton = new javax.swing.JButton();
+- closeButton.setBounds(20, 325, 97, 25);
++ closeButton.setBounds(15, 325, 107, 25); // runge/x11vnc
+ closeButton.setText("Close");
+ closeButton.setName("closeButton");
+ closeButton.addActionListener(this);
+@@ -829,12 +913,19 @@
+ {
+ doReceive();
+ }
++// begin runge/x11vnc
++ else if (evt.getSource() == viewButton)
++ {
++ doView();
++ }
++// end runge/x11vnc
+ else if (evt.getSource() == localDrivesComboBox)
+ {
+ changeLocalDrive();
+ }
+ else if (evt.getSource() == remoteDrivesComboBox)
+ {
++System.out.println("remoteDrivesComboBox"); // runge/x11vnc
+ changeRemoteDrive();
+ remoteList.clear();
+ remoteFileTable.setListData(remoteList);
+@@ -845,6 +936,7 @@
+ }
+ else if (evt.getSource() == remoteTopButton)
+ {
++System.out.println("remoteTopButton"); // runge/x11vnc
+ changeRemoteDrive();
+ }
+ else if(evt.getSource() == deleteButton)
+@@ -979,6 +1071,56 @@
+ viewer.rfb.requestRemoteFile(remoteFileName,localDestinationPath);
+ }
+
++// begin runge/x11vnc
++ private void doView()
++ {
++ System.out.println("View Button Pressed");
++
++ if (selectedTable == null) {
++ return;
++ }
++ if (selectedTable.equals("remote")) {
++ viewRemote();
++ } else if (selectedTable.equals("local")) {
++ viewLocal();
++ }
++ }
++
++ private File doReceiveTmp()
++ {
++
++ if (remoteFileTable == null) {
++ return null;
++ }
++ String sFileName = ((String) this.remoteFileTable.getSelectedValue());
++ if (sFileName == null) {
++ return null;
++ }
++
++ // sf@2004 - Directory can't be transfered
++ if (sFileName.substring(0, 2).equals(" [") && sFileName.substring((sFileName.length() - 1), sFileName.length()).equals("]"))
++ {
++ return null;
++ }
++
++ File tmp = null;
++ try {
++ tmp = File.createTempFile("ULTRAFTP", ".txt");
++ } catch (Exception e) {
++ return null;
++ }
++
++ //updateHistory("Downloaded " + localSelection.toString());
++ String remoteFileName = this.remoteLocation.getText();
++ remoteFileName+= ((String) this.remoteFileTable.getSelectedValue()).substring(1);
++
++ String localDestinationPath = tmp.getAbsolutePath();
++ viewer.rfb.requestRemoteFile(remoteFileName,localDestinationPath);
++ System.out.println("ReceiveTmp: " + localDestinationPath);
++ return tmp;
++ }
++// end runge/x11vnc
++
+ private void doSend()
+ {
+ System.out.println("Send Button Pressed");
+@@ -1035,8 +1177,11 @@
+
+ if (!updateDriveList) {
+ String drive = remoteDrivesComboBox.getSelectedItem().toString().substring(0,1)+ ":\\";
++System.out.println("changeRemoteDrive-A " + drive); // runge/x11vnc
++ drive = saveRemoteHack(drive);
+ viewer.rfb.readServerDirectory(drive);
+ remoteLocation.setText(drive);
++System.out.println("changeRemoteDrive-B " + drive); // runge/x11vnc
+ }
+ remoteList.clear();
+ remoteFileTable.setListData(remoteList);
+@@ -1048,6 +1193,7 @@
+ private void changeLocalDrive()
+ {
+ File currentDrive = new File(localDrivesComboBox.getSelectedItem().toString());
++System.out.println("changeLocalDrive " + currentDrive.toString()); // runge/x11vnc
+ if(currentDrive.canRead())
+ {
+ localSelection = null;
+@@ -1060,6 +1206,7 @@
+ localStatus.setText("WARNING: Drive " + localDrivesComboBox.getSelectedItem().toString());
+ connectionStatus.setText(" > WARNING - Local Drive unavailable (possibly restricted access or media not present)");
+ }
++
+ }
+ /**
+ * Determines which FileTable was double-clicked and updates the table
+@@ -1101,7 +1248,7 @@
+ String name = (remoteFileTable.getSelectedValue().toString()).substring(1);
+ if( !name.substring(0, 2).equals(" ["))
+ remoteSelection = remoteLocation.getText() + name.substring(0, name.length());
+-
++
+ }
+
+ /*
+@@ -1115,10 +1262,38 @@
+ localFileTable.setBackground(new Color(255, 255, 255));
+ File currentSelection = new File(currentLocalDirectory, getTrimmedSelection());
+
+- if(currentSelection.isFile())
++// begin runge/x11vnc
++ // localSelection = currentSelection.getAbsoluteFile();
++ if(currentSelection.isFile()) {
+ localSelection = currentSelection.getAbsoluteFile();
++ localCurrentIsDir = false;
++ } else {
++ localCurrentIsDir = true;
++ }
++// end runge/x11vnc
+
+ }
++
++// begin runge/x11vnc
++ private void viewRemote() {
++ File tmp = doReceiveTmp();
++ if (tmp == null) {
++ return;
++ }
++ TextViewer tv = new TextViewer("Remote: " + remoteSelection, tmp, true);
++ }
++ private void viewLocal() {
++ if (localSelection == null) {
++ return;
++ }
++ if (localCurrentIsDir) {
++ return;
++ }
++ File loc = new File(localSelection.toString());
++ TextViewer tv = new TextViewer("Local: " + localSelection.toString(), loc, false);
++ }
++// end runge/x11vnc
++
+ /**
+ * Updates the Remote File Table based on selection. Called from mouseClicked handler
+ */
+@@ -1149,6 +1324,7 @@
+ remoteSelection = remoteLocation.getText() + name.substring(0, name.length());
+ drive = remoteLocation.getText();
+ // ??
++ viewRemote(); // runge/x11vnc
+ }
+ else
+ {
+@@ -1163,6 +1339,7 @@
+ }
+ //remoteLocation.setText(drive);
+ }
++
+ /**
+ * Updates the Local File Table based on selection. Called from MouseClicked handler
+ */
+@@ -1188,6 +1365,7 @@
+ else if (currentSelection.isFile())
+ {
+ localSelection = currentSelection.getAbsoluteFile();
++ viewLocal(); // runge/x11vnc
+ }
+ else if (currentSelection.isDirectory())
+ {
+@@ -1247,9 +1425,20 @@
+ */
+ public void changeLocalDirectory(File dir)
+ {
++ dir = saveLocalHack(dir); // runge/x11vnc
++
+ currentLocalDirectory = dir; // Updates Global
+ File allFiles[] = dir.listFiles(); // Reads files
+ String[] contents = dir.list();
++// begin runge/x11vnc
++System.out.println("changeLocalDirectory: " + dir.toString());
++ if (contents != null) {
++ java.util.Arrays.sort(contents, String.CASE_INSENSITIVE_ORDER);
++ for (int i = 0; i < contents.length; i++) {
++ allFiles[i] = new File(dir, contents[i]);
++ }
++ }
++// end runge/x11vnc
+
+ localList.clear();
+ localList.addElement(" [..]");
+@@ -1296,3 +1485,135 @@
+ }
+
+ } // @jve:visual-info decl-index=0 visual-constraint="10,10"
++
++// begin runge/x11vnc
++class TextViewer extends JFrame implements ActionListener {
++
++ JTextArea textArea = new JTextArea(35, 80);
++ File file = null;
++ JButton refreshButton;
++ JButton dismissButton;
++ Timer tim = null;
++ int rcnt = 0;
++ int tms = 250;
++ boolean delete_it = false;
++
++ public TextViewer(String s, File f, boolean d) {
++
++ delete_it = d;
++ file = f;
++
++ JScrollPane scrollPane = new JScrollPane(textArea,
++ JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
++ JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
++
++ textArea.setEditable(false);
++ textArea.setFont(new Font("Monospaced", Font.PLAIN, 12));
++
++
++ refreshButton = new JButton();
++ refreshButton.setText("Reload");
++ refreshButton.setName("refreshButton");
++ refreshButton.addActionListener(this);
++
++ dismissButton = new JButton();
++ dismissButton.setText("Dismiss");
++ dismissButton.setName("dismissButton");
++ dismissButton.addActionListener(this);
++
++ JPanel buttons = new JPanel();
++ buttons.setLayout(new BorderLayout());
++ buttons.add(refreshButton, BorderLayout.WEST);
++ buttons.add(dismissButton, BorderLayout.EAST);
++
++ JPanel content = new JPanel();
++ content.setLayout(new BorderLayout());
++ content.add(scrollPane, BorderLayout.CENTER);
++ content.add(buttons, BorderLayout.SOUTH);
++
++ ActionListener tsk = new ActionListener() {
++ public void actionPerformed(ActionEvent evt) {
++ // System.out.println("tsk");
++ refresh();
++ }
++ };
++ tim = new Timer(tms, tsk);
++ tim.start();
++
++ this.setContentPane(content);
++ this.setTitle("TextViewer - " + s);
++ this.pack();
++ this.setVisible(true);
++ }
++
++ private void refresh() {
++
++ rcnt++;
++ if (rcnt * tms > 3000 && tim != null) {
++ tim.stop();
++ tim = null;
++ }
++ BufferedReader input = null;
++ StringBuffer contents = new StringBuffer();
++ try {
++ if (input == null) {
++ input = new BufferedReader(new FileReader(file));
++ }
++ String line = null;
++ int i = 0;
++ while (( line = input.readLine()) != null) {
++ if (i == 0) {
++ // System.out.println("read");
++ }
++ i++;
++ contents.append(line);
++ contents.append(System.getProperty("line.separator"));
++ }
++ } catch (Exception e) {
++ ;
++ } finally {
++ try {
++ if (input != null) {
++ input.close();
++ input = null;
++ }
++ } catch (Exception e) {
++ ;
++ }
++ }
++
++ textArea.setText(contents.toString());
++ textArea.setCaretPosition(0);
++ }
++
++ public void actionPerformed(ActionEvent evt) {
++
++ if (evt.getSource() == refreshButton) {
++ refresh();
++ }
++ if (evt.getSource() == dismissButton) {
++ cleanse();
++ this.dispose();
++ }
++ }
++
++ private void cleanse() {
++ if (delete_it && file != null) {
++ try {
++ file.delete();
++ file = null;
++ } catch (Exception e) {
++ ;
++ }
++ }
++ }
++
++ protected void finalize() throws Throwable {
++ try {
++ cleanse();
++ } finally {
++ super.finalize();
++ }
++ }
++}
++// end runge/x11vnc
+diff -Naur JavaViewer.orig/OptionsFrame.java JavaViewer/OptionsFrame.java
+--- JavaViewer.orig/OptionsFrame.java 2005-11-21 18:50:16.000000000 -0500
++++ JavaViewer/OptionsFrame.java 2007-05-13 22:18:30.000000000 -0400
+@@ -144,7 +144,10 @@
+ choices[jpegQualityIndex].select("6");
+ choices[cursorUpdatesIndex].select("Enable");
+ choices[useCopyRectIndex].select("Yes");
+- choices[eightBitColorsIndex].select("64");
++// begin runge/x11vnc
++// choices[eightBitColorsIndex].select("64");
++ choices[eightBitColorsIndex].select("Full");
++// end runge/x11vnc
+ choices[mouseButtonIndex].select("Normal");
+ choices[viewOnlyIndex].select("No");
+ choices[shareDesktopIndex].select("Yes");
+diff -Naur JavaViewer.orig/RfbProto.java JavaViewer/RfbProto.java
+--- JavaViewer.orig/RfbProto.java 2006-05-24 15:14:40.000000000 -0400
++++ JavaViewer/RfbProto.java 2007-05-16 15:57:07.000000000 -0400
+@@ -199,6 +199,10 @@
+ // playback.
+ int numUpdatesInSession;
+
++// begin runge/x11vnc
++ int readServerDriveListCnt = -1;
++ long readServerDriveListTime = 0;
++// end runge/x11vnc
+ //
+ // Constructor. Make TCP connection to RFB server.
+ //
+@@ -207,7 +211,27 @@
+ viewer = v;
+ host = h;
+ port = p;
+- sock = new Socket(host, port);
++// begin runge/x11vnc
++// sock = new Socket(host, port);
++ if (! viewer.disableSSL) {
++ System.out.println("new SSLSocketToMe");
++ SSLSocketToMe ssl;
++ try {
++ ssl = new SSLSocketToMe(host, port, v);
++ } catch (Exception e) {
++ throw new IOException(e.getMessage());
++ }
++
++ try {
++ sock = ssl.connectSock();
++ } catch (Exception es) {
++ throw new IOException(es.getMessage());
++ }
++ } else {
++ sock = new Socket(host, port);
++ }
++// end runge/x11vnc
++
+ is =
+ new DataInputStream(
+ new BufferedInputStream(sock.getInputStream(), 16384));
+@@ -1263,11 +1287,47 @@
+ || dwFileAttributes == 369623040)
+ {
+ fileName = " [" + fileName + "]";
+- remoteDirsList.add(fileName); // sf@2004
++// begin runge/x11vnc
++// remoteDirsList.add(fileName); // sf@2004
++ int i = -1;
++ String t1 = fileName.toLowerCase();
++ for (int j = 0; j < remoteDirsList.size(); j++) {
++ String t = (String) remoteDirsList.get(j);
++ String t2 = t.toLowerCase();
++ if (t1.compareTo(t2) < 0) {
++ i = j;
++ break;
++ }
++ }
++ if (i >= 0) {
++ remoteDirsList.add(i, fileName);
++ } else {
++ remoteDirsList.add(fileName);
++ }
++// end runge/x11vnc
+ }
+ else
+ {
+- remoteFilesList.add(" " + fileName); // sf@2004
++// begin runge/x11vnc
++// remoteFilesList.add(" " + fileName); // sf@2004
++
++ fileName = " " + fileName;
++ int i = -1;
++ String t1 = fileName.toLowerCase();
++ for (int j = 0; j < remoteFilesList.size(); j++) {
++ String t = (String) remoteFilesList.get(j);
++ String t2 = t.toLowerCase();
++ if (t1.compareTo(t2) < 0) {
++ i = j;
++ break;
++ }
++ }
++ if (i >= 0) {
++ remoteFilesList.add(i, fileName);
++ } else {
++ remoteFilesList.add(fileName);
++ }
++// end runge/x11vnc
+ }
+
+ // a.add(fileName);
+@@ -1289,6 +1349,16 @@
+ remoteDirsList.clear();
+ remoteFilesList.clear();
+
++// begin runge/x11vnc
++ // Hack for double listing at startup... probably libvncserver bug..
++ readServerDriveListCnt++;
++ if (readServerDriveListCnt == 2) {
++ if (System.currentTimeMillis() - readServerDriveListTime < 1500) {
++System.out.println("readServerDriveListCnt skip " + readServerDriveListCnt);
++ return;
++ }
++ }
++// end runge/x11vnc
+ viewer.ftp.printDirectory(a);
+ }
+
+@@ -1312,6 +1382,10 @@
+ 0,
+ 0,
+ null);
++// begin runge/x11vnc
++ readServerDriveListCnt = 0;
++ readServerDriveListTime = System.currentTimeMillis();
++// end runge/x11vnc
+ }
+ catch (IOException e)
+ {
+diff -Naur JavaViewer.orig/SSLSocketToMe.java JavaViewer/SSLSocketToMe.java
+--- JavaViewer.orig/SSLSocketToMe.java 1969-12-31 19:00:00.000000000 -0500
++++ JavaViewer/SSLSocketToMe.java 2007-04-29 20:40:35.000000000 -0400
+@@ -0,0 +1,1421 @@
++/*
++ * SSLSocketToMe.java: add SSL encryption to Java VNC Viewer.
++ *
++ * Copyright (c) 2006 Karl J. Runge <runge@karlrunge.com>
++ * All rights reserved.
++ *
++ * This is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This software is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this software; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
++ * USA.
++ *
++ */
++
++import java.net.*;
++import java.io.*;
++import javax.net.ssl.*;
++import java.util.*;
++
++import java.security.*;
++import java.security.cert.*;
++import java.security.spec.*;
++import java.security.cert.Certificate;
++import java.security.cert.CertificateFactory;
++
++import java.awt.*;
++import java.awt.event.*;
++
++public class SSLSocketToMe {
++
++ /* basic member data: */
++ String host;
++ int port;
++ VncViewer viewer;
++ boolean debug = true;
++
++ /* sockets */
++ SSLSocket socket = null;
++ SSLSocketFactory factory;
++
++ /* fallback for Proxy connection */
++ boolean proxy_in_use = false;
++ boolean proxy_is_https = false;
++ boolean proxy_failure = false;
++ public DataInputStream is = null;
++ public OutputStream os = null;
++
++ String proxy_dialog_host = null;
++ int proxy_dialog_port = 0;
++
++ Socket proxySock;
++ DataInputStream proxy_is;
++ OutputStream proxy_os;
++
++ /* trust contexts */
++ SSLContext trustloc_ctx;
++ SSLContext trustall_ctx;
++ SSLContext trusturl_ctx;
++ SSLContext trustone_ctx;
++
++ TrustManager[] trustAllCerts;
++ TrustManager[] trustUrlCert;
++ TrustManager[] trustOneCert;
++
++ boolean use_url_cert_for_auth = true;
++ boolean user_wants_to_see_cert = true;
++
++ /* cert(s) we retrieve from VNC server */
++ java.security.cert.Certificate[] trustallCerts = null;
++ java.security.cert.Certificate[] trusturlCerts = null;
++
++ byte[] hex2bytes(String s) {
++ byte[] bytes = new byte[s.length()/2];
++ for (int i=0; i<s.length()/2; i++) {
++ int j = 2*i;
++ try {
++ int val = Integer.parseInt(s.substring(j, j+2), 16);
++ if (val > 127) {
++ val -= 256;
++ }
++ Integer I = new Integer(val);
++ bytes[i] = Byte.decode(I.toString()).byteValue();
++
++ } catch (Exception e) {
++ ;
++ }
++ }
++ return bytes;
++ }
++
++ SSLSocketToMe(String h, int p, VncViewer v) throws Exception {
++ host = h;
++ port = p;
++ viewer = v;
++
++ /* we will first try default factory for certification: */
++
++ factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
++
++ dbg("SSL startup: " + host + " " + port);
++
++ /* create trust managers used if initial handshake fails: */
++
++ trustAllCerts = new TrustManager[] {
++ /*
++ * this one accepts everything.
++ */
++ new X509TrustManager() {
++ public java.security.cert.X509Certificate[]
++ getAcceptedIssuers() {
++ return null;
++ }
++ public void checkClientTrusted(
++ java.security.cert.X509Certificate[] certs,
++ String authType) {
++ /* empty */
++ }
++ public void checkServerTrusted(
++ java.security.cert.X509Certificate[] certs,
++ String authType) {
++ /* empty */
++ dbg("ALL: an untrusted connect to grab cert.");
++ }
++ }
++ };
++
++ trustUrlCert = new TrustManager[] {
++ /*
++ * this one accepts only the retrieved server cert
++ * by SSLSocket by this applet.
++ */
++ new X509TrustManager() {
++ public java.security.cert.X509Certificate[]
++ getAcceptedIssuers() {
++ return null;
++ }
++ public void checkClientTrusted(
++ java.security.cert.X509Certificate[] certs,
++ String authType) throws CertificateException {
++ throw new CertificateException("No Clients");
++ }
++ public void checkServerTrusted(
++ java.security.cert.X509Certificate[] certs,
++ String authType) throws CertificateException {
++ if (trusturlCerts == null) {
++ throw new CertificateException(
++ "No Trust url Certs array.");
++ }
++ if (trusturlCerts.length < 1) {
++ throw new CertificateException(
++ "No Trust url Certs.");
++ }
++ if (trusturlCerts.length > 1) {
++ int i;
++ boolean ok = true;
++ for (i = 0; i < trusturlCerts.length - 1; i++) {
++ if (! trusturlCerts[i].equals(trusturlCerts[i+1])) {
++ ok = false;
++ }
++ }
++ if (! ok) {
++ throw new CertificateException(
++ "Too many Trust url Certs: "
++ + trusturlCerts.length
++ );
++ }
++ }
++ if (certs == null) {
++ throw new CertificateException(
++ "No this-certs array.");
++ }
++ if (certs.length < 1) {
++ throw new CertificateException(
++ "No this-certs Certs.");
++ }
++ if (certs.length > 1) {
++ int i;
++ boolean ok = true;
++ for (i = 0; i < certs.length - 1; i++) {
++ if (! certs[i].equals(certs[i+1])) {
++ ok = false;
++ }
++ }
++ if (! ok) {
++ throw new CertificateException(
++ "Too many this-certs: "
++ + certs.length
++ );
++ }
++ }
++ if (! trusturlCerts[0].equals(certs[0])) {
++ throw new CertificateException(
++ "Server Cert Changed != URL.");
++ }
++ dbg("URL: trusturlCerts[0] matches certs[0]");
++ }
++ }
++ };
++ trustOneCert = new TrustManager[] {
++ /*
++ * this one accepts only the retrieved server cert
++ * by SSLSocket by this applet.
++ */
++ new X509TrustManager() {
++ public java.security.cert.X509Certificate[]
++ getAcceptedIssuers() {
++ return null;
++ }
++ public void checkClientTrusted(
++ java.security.cert.X509Certificate[] certs,
++ String authType) throws CertificateException {
++ throw new CertificateException("No Clients");
++ }
++ public void checkServerTrusted(
++ java.security.cert.X509Certificate[] certs,
++ String authType) throws CertificateException {
++ if (trustallCerts == null) {
++ throw new CertificateException(
++ "No Trust All Server Certs array.");
++ }
++ if (trustallCerts.length < 1) {
++ throw new CertificateException(
++ "No Trust All Server Certs.");
++ }
++ if (trustallCerts.length > 1) {
++ int i;
++ boolean ok = true;
++ for (i = 0; i < trustallCerts.length - 1; i++) {
++ if (! trustallCerts[i].equals(trustallCerts[i+1])) {
++ ok = false;
++ }
++ }
++ if (! ok) {
++ throw new CertificateException(
++ "Too many Trust All Server Certs: "
++ + trustallCerts.length
++ );
++ }
++ }
++ if (certs == null) {
++ throw new CertificateException(
++ "No this-certs array.");
++ }
++ if (certs.length < 1) {
++ throw new CertificateException(
++ "No this-certs Certs.");
++ }
++ if (certs.length > 1) {
++ int i;
++ boolean ok = true;
++ for (i = 0; i < certs.length - 1; i++) {
++ if (! certs[i].equals(certs[i+1])) {
++ ok = false;
++ }
++ }
++ if (! ok) {
++ throw new CertificateException(
++ "Too many this-certs: "
++ + certs.length
++ );
++ }
++ }
++ if (! trustallCerts[0].equals(certs[0])) {
++ throw new CertificateException(
++ "Server Cert Changed != TRUSTALL.");
++ }
++ dbg("ONE: trustallCerts[0] matches certs[0]");
++ }
++ }
++ };
++
++ /*
++ * They are used:
++ *
++ * 1) to retrieve the server cert in case of failure to
++ * display it to the user.
++ * 2) to subsequently connect to the server if user agrees.
++ */
++
++ KeyManager[] mykey = null;
++
++ if (viewer.oneTimeKey != null && viewer.oneTimeKey.equals("PROMPT")) {
++ ClientCertDialog d = new ClientCertDialog();
++ viewer.oneTimeKey = d.queryUser();
++ }
++
++ if (viewer.oneTimeKey != null && viewer.oneTimeKey.indexOf(",") > 0) {
++ int idx = viewer.oneTimeKey.indexOf(",");
++
++ String onetimekey = viewer.oneTimeKey.substring(0, idx);
++ byte[] key = hex2bytes(onetimekey);
++ String onetimecert = viewer.oneTimeKey.substring(idx+1);
++ byte[] cert = hex2bytes(onetimecert);
++
++ KeyFactory kf = KeyFactory.getInstance("RSA");
++ PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key );
++ PrivateKey ff = kf.generatePrivate (keysp);
++ //dbg("ff " + ff);
++ String cert_str = new String(cert);
++
++ CertificateFactory cf = CertificateFactory.getInstance("X.509");
++ Collection c = cf.generateCertificates(new ByteArrayInputStream(cert));
++ Certificate[] certs = new Certificate[c.toArray().length];
++ if (c.size() == 1) {
++ Certificate tmpcert = cf.generateCertificate(new ByteArrayInputStream(cert));
++ //dbg("tmpcert" + tmpcert);
++ certs[0] = tmpcert;
++ } else {
++ certs = (Certificate[]) c.toArray();
++ }
++
++ KeyStore ks = KeyStore.getInstance("JKS");
++ ks.load(null, null);
++ ks.setKeyEntry("onetimekey", ff, "".toCharArray(), certs);
++ String da = KeyManagerFactory.getDefaultAlgorithm();
++ KeyManagerFactory kmf = KeyManagerFactory.getInstance(da);
++ kmf.init(ks, "".toCharArray());
++
++ mykey = kmf.getKeyManagers();
++ }
++
++
++ /* trust loc certs: */
++ try {
++ trustloc_ctx = SSLContext.getInstance("SSL");
++ trustloc_ctx.init(mykey, null, new
++ java.security.SecureRandom());
++
++ } catch (Exception e) {
++ String msg = "SSL trustloc_ctx FAILED.";
++ dbg(msg);
++ throw new Exception(msg);
++ }
++
++ /* trust all certs: */
++ try {
++ trustall_ctx = SSLContext.getInstance("SSL");
++ trustall_ctx.init(mykey, trustAllCerts, new
++ java.security.SecureRandom());
++
++ } catch (Exception e) {
++ String msg = "SSL trustall_ctx FAILED.";
++ dbg(msg);
++ throw new Exception(msg);
++ }
++
++ /* trust url certs: */
++ try {
++ trusturl_ctx = SSLContext.getInstance("SSL");
++ trusturl_ctx.init(mykey, trustUrlCert, new
++ java.security.SecureRandom());
++
++ } catch (Exception e) {
++ String msg = "SSL trusturl_ctx FAILED.";
++ dbg(msg);
++ throw new Exception(msg);
++ }
++
++ /* trust the one cert from server: */
++ try {
++ trustone_ctx = SSLContext.getInstance("SSL");
++ trustone_ctx.init(mykey, trustOneCert, new
++ java.security.SecureRandom());
++
++ } catch (Exception e) {
++ String msg = "SSL trustone_ctx FAILED.";
++ dbg(msg);
++ throw new Exception(msg);
++ }
++ }
++
++ boolean browser_cert_match() {
++ String msg = "Browser URL accept previously accepted cert";
++
++ if (user_wants_to_see_cert) {
++ return false;
++ }
++
++ if (trustallCerts != null && trusturlCerts != null) {
++ if (trustallCerts.length == 1 && trusturlCerts.length == 1) {
++ if (trustallCerts[0].equals(trusturlCerts[0])) {
++ System.out.println(msg);
++ return true;
++ }
++ }
++ }
++ return false;
++ }
++
++ public void check_for_proxy() {
++
++ boolean result = false;
++
++ trusturlCerts = null;
++ proxy_in_use = false;
++ if (viewer.ignoreProxy) {
++ return;
++ }
++
++ String ustr = "https://" + host + ":";
++ if (viewer.httpsPort != null) {
++ ustr += viewer.httpsPort;
++ } else {
++ ustr += port; // hmmm
++ }
++ ustr += viewer.urlPrefix + "/check.https.proxy.connection";
++ dbg("ustr is: " + ustr);
++
++
++ try {
++ URL url = new URL(ustr);
++ HttpsURLConnection https = (HttpsURLConnection)
++ url.openConnection();
++
++ https.setUseCaches(false);
++ https.setRequestMethod("GET");
++ https.setRequestProperty("Pragma", "No-Cache");
++ https.setRequestProperty("Proxy-Connection",
++ "Keep-Alive");
++ https.setDoInput(true);
++
++ https.connect();
++
++ trusturlCerts = https.getServerCertificates();
++ if (trusturlCerts == null) {
++ dbg("set trusturlCerts to null...");
++ } else {
++ dbg("set trusturlCerts to non-null");
++ }
++
++ if (https.usingProxy()) {
++ proxy_in_use = true;
++ proxy_is_https = true;
++ dbg("HTTPS proxy in use. There may be connection problems.");
++ }
++ Object output = https.getContent();
++ https.disconnect();
++ result = true;
++
++ } catch(Exception e) {
++ dbg("HttpsURLConnection: " + e.getMessage());
++ }
++
++ if (proxy_in_use) {
++ return;
++ }
++
++ ustr = "http://" + host + ":" + port;
++ ustr += viewer.urlPrefix + "/index.vnc";
++
++ try {
++ URL url = new URL(ustr);
++ HttpURLConnection http = (HttpURLConnection)
++ url.openConnection();
++
++ http.setUseCaches(false);
++ http.setRequestMethod("GET");
++ http.setRequestProperty("Pragma", "No-Cache");
++ http.setRequestProperty("Proxy-Connection",
++ "Keep-Alive");
++ http.setDoInput(true);
++
++ http.connect();
++
++ if (http.usingProxy()) {
++ proxy_in_use = true;
++ proxy_is_https = false;
++ dbg("HTTP proxy in use. There may be connection problems.");
++ }
++ Object output = http.getContent();
++ http.disconnect();
++
++ } catch(Exception e) {
++ dbg("HttpURLConnection: " + e.getMessage());
++ }
++ }
++
++ public Socket connectSock() throws IOException {
++
++ /*
++ * first try a https connection to detect a proxy, and
++ * also grab the VNC server cert.
++ */
++ check_for_proxy();
++
++ if (viewer.trustAllVncCerts) {
++ dbg("viewer.trustAllVncCerts-0 using trustall_ctx");
++ factory = trustall_ctx.getSocketFactory();
++ } else if (use_url_cert_for_auth && trusturlCerts != null) {
++ dbg("using trusturl_ctx");
++ factory = trusturl_ctx.getSocketFactory();
++ } else {
++ dbg("using trustloc_ctx");
++ factory = trustloc_ctx.getSocketFactory();
++ }
++
++ socket = null;
++ try {
++ if (proxy_in_use && viewer.forceProxy) {
++ throw new Exception("forcing proxy (forceProxy)");
++ } else if (viewer.CONNECT != null) {
++ throw new Exception("forcing CONNECT");
++ }
++
++ socket = (SSLSocket) factory.createSocket(host, port);
++
++ } catch (Exception esock) {
++ dbg("esock: " + esock.getMessage());
++ if (proxy_in_use || viewer.CONNECT != null) {
++ proxy_failure = true;
++ if (proxy_in_use) {
++ dbg("HTTPS proxy in use. Trying to go with it.");
++ } else {
++ dbg("viewer.CONNECT reverse proxy in use. Trying to go with it.");
++ }
++ try {
++ socket = proxy_socket(factory);
++ } catch (Exception e) {
++ dbg("err proxy_socket: " + e.getMessage());
++ }
++ }
++ }
++
++ try {
++ socket.startHandshake();
++ dbg("Server Connection Verified on 1st try.");
++
++ java.security.cert.Certificate[] currentTrustedCerts;
++ BrowserCertsDialog bcd;
++
++ SSLSession sess = socket.getSession();
++ currentTrustedCerts = sess.getPeerCertificates();
++
++ if (viewer.trustAllVncCerts) {
++ dbg("viewer.trustAllVncCerts-1");
++ } else if (currentTrustedCerts == null || currentTrustedCerts.length < 1) {
++ socket.close();
++ socket = null;
++ throw new SSLHandshakeException("no current certs");
++ }
++
++ String serv = "";
++ try {
++ CertInfo ci = new CertInfo(currentTrustedCerts[0]);
++ serv = ci.get_certinfo("CN");
++ } catch (Exception e) {
++ ;
++ }
++
++ if (viewer.trustAllVncCerts) {
++ dbg("viewer.trustAllVncCerts-2");
++ user_wants_to_see_cert = false;
++ } else if (viewer.trustUrlVncCert) {
++ dbg("viewer.trustUrlVncCert-1");
++ user_wants_to_see_cert = false;
++ } else {
++ bcd = new BrowserCertsDialog(serv, host + ":" + port);
++ bcd.queryUser();
++ if (bcd.showCertDialog) {
++ String msg = "user wants to see cert";
++ dbg(msg);
++ user_wants_to_see_cert = true;
++ throw new SSLHandshakeException(msg);
++ } else {
++ user_wants_to_see_cert = false;
++ dbg("bcd: user said yes, accept it");
++ }
++ }
++
++ } catch (SSLHandshakeException eh) {
++ dbg("Could not automatically verify Server.");
++ dbg("msg: " + eh.getMessage());
++
++ socket.close();
++ socket = null;
++
++ /*
++ * Reconnect, trusting any cert, so we can grab
++ * the cert to show it to the user. The connection
++ * is not used for anything else.
++ */
++ factory = trustall_ctx.getSocketFactory();
++ if (proxy_failure) {
++ socket = proxy_socket(factory);
++ } else {
++ socket = (SSLSocket) factory.createSocket(host, port);
++ }
++
++ try {
++ socket.startHandshake();
++ dbg("TrustAll Server Connection Verified.");
++
++ /* grab the cert: */
++ try {
++ SSLSession sess = socket.getSession();
++ trustallCerts = sess.getPeerCertificates();
++ } catch (Exception e) {
++ throw new Exception("Could not get " +
++ "Peer Certificate");
++ }
++
++ if (viewer.trustAllVncCerts) {
++ dbg("viewer.trustAllVncCerts-3");
++ } else if (! browser_cert_match()) {
++ /*
++ * close socket now, we will reopen after
++ * dialog if user agrees to use the cert.
++ */
++ socket.close();
++ socket = null;
++
++ /* dialog with user to accept cert or not: */
++
++ TrustDialog td= new TrustDialog(host, port,
++ trustallCerts);
++
++ if (! td.queryUser()) {
++ String msg = "User decided against it.";
++ dbg(msg);
++ throw new IOException(msg);
++ }
++ }
++
++ } catch (Exception ehand2) {
++ dbg("** Could not TrustAll Verify Server.");
++
++ throw new IOException(ehand2.getMessage());
++ }
++
++ /*
++ * Now connect a 3rd time, using the cert
++ * retrieved during connection 2 (that the user
++ * likely blindly agreed to).
++ */
++
++ factory = trustone_ctx.getSocketFactory();
++ if (proxy_failure) {
++ socket = proxy_socket(factory);
++ } else {
++ socket = (SSLSocket) factory.createSocket(host, port);
++ }
++
++ try {
++ socket.startHandshake();
++ dbg("TrustAll Server Connection Verified #3.");
++
++ } catch (Exception ehand3) {
++ dbg("** Could not TrustAll Verify Server #3.");
++
++ throw new IOException(ehand3.getMessage());
++ }
++ }
++
++ if (socket != null && viewer.GET) {
++ String str = "GET ";
++ str += viewer.urlPrefix;
++ str += "/request.https.vnc.connection";
++ str += " HTTP/1.0\r\n";
++ str += "Pragma: No-Cache\r\n";
++ str += "\r\n";
++ System.out.println("sending GET: " + str);
++ OutputStream os = socket.getOutputStream();
++ os.write(str.getBytes());
++ os.flush();
++ if (false) {
++ String rep = "";
++ DataInputStream is = new DataInputStream(
++ new BufferedInputStream(socket.getInputStream(), 16384));
++ while (true) {
++ rep += readline(is);
++ if (rep.indexOf("\r\n\r\n") >= 0) {
++ break;
++ }
++ }
++ System.out.println("rep: " + rep);
++ }
++ }
++
++ dbg("SSL returning socket to caller.");
++ return (Socket) socket;
++ }
++
++ private void dbg(String s) {
++ if (debug) {
++ System.out.println(s);
++ }
++ }
++
++ private int gint(String s) {
++ int n = -1;
++ try {
++ Integer I = new Integer(s);
++ n = I.intValue();
++ } catch (Exception ex) {
++ return -1;
++ }
++ return n;
++ }
++
++ public SSLSocket proxy_socket(SSLSocketFactory factory) {
++ Properties props = null;
++ String proxyHost = null;
++ int proxyPort = 0;
++ String proxyHost_nossl = null;
++ int proxyPort_nossl = 0;
++ String str;
++
++ /* see if we can guess the proxy info from Properties: */
++ try {
++ props = System.getProperties();
++ } catch (Exception e) {
++ dbg("props failed: " + e.getMessage());
++ }
++ if (props != null) {
++ dbg("\n---------------\nAll props:");
++ props.list(System.out);
++ dbg("\n---------------\n\n");
++
++ for (Enumeration e = props.propertyNames(); e.hasMoreElements(); ) {
++ String s = (String) e.nextElement();
++ String v = System.getProperty(s);
++ String s2 = s.toLowerCase();
++ String v2 = v.toLowerCase();
++
++ if (s2.indexOf("proxy") < 0 && v2.indexOf("proxy") < 0) {
++ continue;
++ }
++ if (v2.indexOf("https") < 0) {
++ continue;
++ }
++
++ if (s2.indexOf("proxy.https.host") >= 0) {
++ proxyHost = v2;
++ continue;
++ }
++ if (s2.indexOf("proxy.https.port") >= 0) {
++ proxyPort = gint(v2);
++ continue;
++ }
++ if (s2.indexOf("proxy.http.host") >= 0) {
++ proxyHost_nossl = v2;
++ continue;
++ }
++ if (s2.indexOf("proxy.http.port") >= 0) {
++ proxyPort_nossl = gint(v2);
++ continue;
++ }
++
++ String[] pieces = v.split("[,;]");
++ for (int i = 0; i < pieces.length; i++) {
++ String p = pieces[i];
++ int j = p.indexOf("https");
++ if (j < 0) {
++ continue;
++ }
++ j = p.indexOf("=", j);
++ if (j < 0) {
++ continue;
++ }
++ p = p.substring(j+1);
++ String [] hp = p.split(":");
++ if (hp.length != 2) {
++ continue;
++ }
++ if (hp[0].length() > 1 && hp[1].length() > 1) {
++
++ proxyPort = gint(hp[1]);
++ if (proxyPort < 0) {
++ continue;
++ }
++ proxyHost = new String(hp[0]);
++ break;
++ }
++ }
++ }
++ }
++ if (proxyHost != null) {
++ if (proxyHost_nossl != null && proxyPort_nossl > 0) {
++ dbg("Using http proxy info instead of https.");
++ proxyHost = proxyHost_nossl;
++ proxyPort = proxyPort_nossl;
++ }
++ }
++
++ if (proxy_in_use) {
++ if (proxy_dialog_host != null && proxy_dialog_port > 0) {
++ proxyHost = proxy_dialog_host;
++ proxyPort = proxy_dialog_port;
++ }
++ if (proxyHost != null) {
++ dbg("Lucky us! we figured out the Proxy parameters: " + proxyHost + " " + proxyPort);
++ } else {
++ /* ask user to help us: */
++ ProxyDialog pd = new ProxyDialog(proxyHost, proxyPort);
++ pd.queryUser();
++ proxyHost = pd.getHost();
++ proxyPort = pd.getPort();
++ proxy_dialog_host = new String(proxyHost);
++ proxy_dialog_port = proxyPort;
++ dbg("User said host: " + pd.getHost() + " port: " + pd.getPort());
++ }
++
++ dbg("proxy_in_use psocket:");
++ proxySock = psocket(proxyHost, proxyPort);
++ if (proxySock == null) {
++ dbg("1-a sadly, returning a null socket");
++ return null;
++ }
++ String hp = host + ":" + port;
++
++ String req1 = "CONNECT " + hp + " HTTP/1.1\r\n"
++ + "Host: " + hp + "\r\n\r\n";
++
++ dbg("requesting1: " + req1);
++
++ try {
++ proxy_os.write(req1.getBytes());
++ String reply = readline(proxy_is);
++
++ dbg("proxy replied1: " + reply.trim());
++
++ if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) {
++ proxySock.close();
++ proxySock = psocket(proxyHost, proxyPort);
++ if (proxySock == null) {
++ dbg("2-a sadly, returning a null socket");
++ return null;
++ }
++ }
++ } catch(Exception e) {
++ dbg("sock prob1: " + e.getMessage());
++ }
++
++ while (true) {
++ String line = readline(proxy_is);
++ dbg("proxy line1: " + line.trim());
++ if (line.equals("\r\n") || line.equals("\n")) {
++ break;
++ }
++ }
++ } else if (viewer.CONNECT != null) {
++ dbg("viewer.CONNECT psocket:");
++ proxySock = psocket(host, port);
++ if (proxySock == null) {
++ dbg("1-b sadly, returning a null socket");
++ return null;
++ }
++ }
++
++ if (viewer.CONNECT != null) {
++ String hp = viewer.CONNECT;
++ String req2 = "CONNECT " + hp + " HTTP/1.1\r\n"
++ + "Host: " + hp + "\r\n\r\n";
++
++ dbg("requesting2: " + req2);
++
++ try {
++ proxy_os.write(req2.getBytes());
++ String reply = readline(proxy_is);
++
++ dbg("proxy replied2: " + reply.trim());
++
++ if (reply.indexOf("HTTP/1.") < 0 && reply.indexOf(" 200") < 0) {
++ proxySock.close();
++ proxySock = psocket(proxyHost, proxyPort);
++ if (proxySock == null) {
++ dbg("2-b sadly, returning a null socket");
++ return null;
++ }
++ }
++ } catch(Exception e) {
++ dbg("sock prob2: " + e.getMessage());
++ }
++
++ while (true) {
++ String line = readline(proxy_is);
++ dbg("proxy line2: " + line.trim());
++ if (line.equals("\r\n") || line.equals("\n")) {
++ break;
++ }
++ }
++
++ }
++
++ Socket sslsock = null;
++ try {
++ sslsock = factory.createSocket(proxySock, host, port, true);
++ } catch(Exception e) {
++ dbg("sslsock prob: " + e.getMessage());
++ dbg("3 sadly, returning a null socket");
++ }
++
++ return (SSLSocket) sslsock;
++ }
++
++ Socket psocket(String h, int p) {
++ Socket psock = null;
++ try {
++ psock = new Socket(h, p);
++ proxy_is = new DataInputStream(new BufferedInputStream(
++ psock.getInputStream(), 16384));
++ proxy_os = psock.getOutputStream();
++ } catch(Exception e) {
++ dbg("psocket prob: " + e.getMessage());
++ return null;
++ }
++
++ return psock;
++ }
++
++ String readline(DataInputStream i) {
++ byte[] ba = new byte[1];
++ String s = new String("");
++ ba[0] = 0;
++ try {
++ while (ba[0] != 0xa) {
++ ba[0] = (byte) i.readUnsignedByte();
++ s += new String(ba);
++ }
++ } catch (Exception e) {
++ ;
++ }
++ return s;
++ }
++}
++
++class TrustDialog implements ActionListener {
++ String msg, host, text;
++ int port;
++ java.security.cert.Certificate[] trustallCerts = null;
++ boolean viewing_cert = false;
++ boolean trust_this_session = false;
++
++ /*
++ * this is the gui to show the user the cert and info and ask
++ * them if they want to continue using this cert.
++ */
++
++ Button ok, cancel, viewcert;
++ TextArea textarea;
++ Checkbox accept, deny;
++ Dialog dialog;
++
++ String s1 = "Accept this certificate temporarily for this session";
++ String s2 = "Do not accept this certificate and do not connect to"
++ + " this VNC server";
++ String ln = "\n---------------------------------------------------\n\n";
++
++ TrustDialog (String h, int p, java.security.cert.Certificate[] s) {
++ host = h;
++ port = p;
++ trustallCerts = s;
++
++ msg = "VNC Server " + host + ":" + port + " Not Verified";
++ }
++
++ public boolean queryUser() {
++
++ /* create and display the dialog for unverified cert. */
++
++ Frame frame = new Frame(msg);
++
++ dialog = new Dialog(frame, true);
++
++ String infostr = "";
++ if (trustallCerts.length == 1) {
++ CertInfo ci = new CertInfo(trustallCerts[0]);
++ infostr = ci.get_certinfo("all");
++ }
++
++ text = "\n"
+++ "Unable to verify the identity of\n"
+++ "\n"
+++ " " + host + ":" + port + "\n"
+++ "\n"
+++ infostr
+++ "\n"
+++ "as a trusted VNC server.\n"
+++ "\n"
+++ "This may be due to:\n"
+++ "\n"
+++ " - Your requesting to View the Certificate before accepting.\n"
+++ "\n"
+++ " - The VNC server using a Self-Signed Certificate.\n"
+++ "\n"
+++ " - The VNC server using a Certificate Authority not recognized by your\n"
+++ " Browser or Java Plugin runtime.\n"
+++ "\n"
+++ " - The use of an Apache SSL portal employing CONNECT proxying and the\n"
+++ " Apache web server has a certificate different from the VNC server's. \n"
+++ "\n"
+++ " - A Man-In-The-Middle attack impersonating as the VNC server you wish\n"
+++ " to connect to. (Wouldn't that be exciting!!)\n"
+++ "\n"
+++ "By safely copying the VNC server's Certificate (or using a common\n"
+++ "Certificate Authority certificate) you can configure your Web Browser or\n"
+++ "Java Plugin to automatically authenticate this Server.\n"
+++ "\n"
+++ "If you do so, then you will only have to click \"Yes\" when this VNC\n"
+++ "Viewer applet asks you whether to trust your Browser/Java Plugin's\n"
+++ "acceptance of the certificate. (except for the Apache portal case above.)\n"
++;
++
++ /* the accept / do-not-accept radio buttons: */
++ CheckboxGroup checkbox = new CheckboxGroup();
++ accept = new Checkbox(s1, true, checkbox);
++ deny = new Checkbox(s2, false, checkbox);
++
++ /* put the checkboxes in a panel: */
++ Panel check = new Panel();
++ check.setLayout(new GridLayout(2, 1));
++
++ check.add(accept);
++ check.add(deny);
++
++ /* make the 3 buttons: */
++ ok = new Button("OK");
++ cancel = new Button("Cancel");
++ viewcert = new Button("View Certificate");
++
++ ok.addActionListener(this);
++ cancel.addActionListener(this);
++ viewcert.addActionListener(this);
++
++ /* put the buttons in their own panel: */
++ Panel buttonrow = new Panel();
++ buttonrow.setLayout(new FlowLayout(FlowLayout.LEFT));
++ buttonrow.add(viewcert);
++ buttonrow.add(ok);
++ buttonrow.add(cancel);
++
++ /* label at the top: */
++ Label label = new Label(msg, Label.CENTER);
++ label.setFont(new Font("Helvetica", Font.BOLD, 16));
++
++ /* textarea in the middle */
++ textarea = new TextArea(text, 36, 64,
++ TextArea.SCROLLBARS_VERTICAL_ONLY);
++ textarea.setEditable(false);
++
++ /* put the two panels in their own panel at bottom: */
++ Panel bot = new Panel();
++ bot.setLayout(new GridLayout(2, 1));
++ bot.add(check);
++ bot.add(buttonrow);
++
++ /* now arrange things inside the dialog: */
++ dialog.setLayout(new BorderLayout());
++
++ dialog.add("North", label);
++ dialog.add("South", bot);
++ dialog.add("Center", textarea);
++
++ dialog.pack();
++ dialog.resize(dialog.preferredSize());
++
++ dialog.show(); /* block here til OK or Cancel pressed. */
++
++ return trust_this_session;
++ }
++
++ public synchronized void actionPerformed(ActionEvent evt) {
++
++ if (evt.getSource() == viewcert) {
++ /* View Certificate button clicked */
++ if (viewing_cert) {
++ /* show the original info text: */
++ textarea.setText(text);
++ viewcert.setLabel("View Certificate");
++ viewing_cert = false;
++ } else {
++ int i;
++ /* show all (likely just one) certs: */
++ textarea.setText("");
++ for (i=0; i < trustallCerts.length; i++) {
++ int j = i + 1;
++ textarea.append("Certificate[" +
++ j + "]\n\n");
++ textarea.append(
++ trustallCerts[i].toString());
++ textarea.append(ln);
++ }
++ viewcert.setLabel("View Info");
++ viewing_cert = true;
++
++ textarea.setCaretPosition(0);
++ }
++
++ } else if (evt.getSource() == ok) {
++ /* OK button clicked */
++ if (accept.getState()) {
++ trust_this_session = true;
++ } else {
++ trust_this_session = false;
++ }
++ dialog.dispose();
++
++ } else if (evt.getSource() == cancel) {
++ /* Cancel button clicked */
++ trust_this_session = false;
++
++ dialog.dispose();
++ }
++ }
++
++ String get_certinfo() {
++ String all = "";
++ String fields[] = {"CN", "OU", "O", "L", "C"};
++ int i;
++ if (trustallCerts.length < 1) {
++ all = "";
++ return all;
++ }
++ String cert = trustallCerts[0].toString();
++
++ /*
++ * For now we simply scrape the cert string, there must
++ * be an API for this... perhaps optionValue?
++ */
++
++ for (i=0; i < fields.length; i++) {
++ int f, t, t1, t2;
++ String sub, mat = fields[i] + "=";
++
++ f = cert.indexOf(mat, 0);
++ if (f > 0) {
++ t1 = cert.indexOf(", ", f);
++ t2 = cert.indexOf("\n", f);
++ if (t1 < 0 && t2 < 0) {
++ continue;
++ } else if (t1 < 0) {
++ t = t2;
++ } else if (t2 < 0) {
++ t = t1;
++ } else if (t1 < t2) {
++ t = t1;
++ } else {
++ t = t2;
++ }
++ if (t > f) {
++ sub = cert.substring(f, t);
++ all = all + " " + sub + "\n";
++ }
++ }
++ }
++ return all;
++ }
++}
++
++class ProxyDialog implements ActionListener {
++ String guessedHost = null;
++ String guessedPort = null;
++ /*
++ * this is the gui to show the user the cert and info and ask
++ * them if they want to continue using this cert.
++ */
++
++ Button ok;
++ Dialog dialog;
++ TextField entry;
++ String reply = "";
++
++ ProxyDialog (String h, int p) {
++ guessedHost = h;
++ try {
++ guessedPort = Integer.toString(p);
++ } catch (Exception e) {
++ guessedPort = "8080";
++ }
++ }
++
++ public void queryUser() {
++
++ /* create and display the dialog for unverified cert. */
++
++ Frame frame = new Frame("Need Proxy host:port");
++
++ dialog = new Dialog(frame, true);
++
++
++ Label label = new Label("Please Enter your https Proxy info as host:port", Label.CENTER);
++ //label.setFont(new Font("Helvetica", Font.BOLD, 16));
++ entry = new TextField(30);
++ ok = new Button("OK");
++ ok.addActionListener(this);
++
++ String guess = "";
++ if (guessedHost != null) {
++ guess = guessedHost + ":" + guessedPort;
++ }
++ entry.setText(guess);
++
++ dialog.setLayout(new BorderLayout());
++ dialog.add("North", label);
++ dialog.add("Center", entry);
++ dialog.add("South", ok);
++ dialog.pack();
++ dialog.resize(dialog.preferredSize());
++
++ dialog.show(); /* block here til OK or Cancel pressed. */
++ return;
++ }
++
++ public String getHost() {
++ int i = reply.indexOf(":");
++ if (i < 0) {
++ return "unknown";
++ }
++ String h = reply.substring(0, i);
++ return h;
++ }
++
++ public int getPort() {
++ int i = reply.indexOf(":");
++ int p = 8080;
++ if (i < 0) {
++ return p;
++ }
++ i++;
++ String ps = reply.substring(i);
++ try {
++ Integer I = new Integer(ps);
++ p = I.intValue();
++ } catch (Exception e) {
++ ;
++ }
++ return p;
++ }
++
++ public synchronized void actionPerformed(ActionEvent evt) {
++ System.out.println(evt.getActionCommand());
++ if (evt.getSource() == ok) {
++ reply = entry.getText();
++ dialog.dispose();
++ }
++ }
++}
++
++class ClientCertDialog implements ActionListener {
++
++ Button ok;
++ Dialog dialog;
++ TextField entry;
++ String reply = "";
++
++ ClientCertDialog() {
++ ;
++ }
++
++ public String queryUser() {
++
++ /* create and display the dialog for unverified cert. */
++
++ Frame frame = new Frame("Enter SSL Client Cert+Key String");
++
++ dialog = new Dialog(frame, true);
++
++
++ Label label = new Label("Please Enter the SSL Client Cert+Key String 308204c0...,...522d2d0a", Label.CENTER);
++ entry = new TextField(30);
++ ok = new Button("OK");
++ ok.addActionListener(this);
++
++ dialog.setLayout(new BorderLayout());
++ dialog.add("North", label);
++ dialog.add("Center", entry);
++ dialog.add("South", ok);
++ dialog.pack();
++ dialog.resize(dialog.preferredSize());
++
++ dialog.show(); /* block here til OK or Cancel pressed. */
++ return reply;
++ }
++
++ public synchronized void actionPerformed(ActionEvent evt) {
++ System.out.println(evt.getActionCommand());
++ if (evt.getSource() == ok) {
++ reply = entry.getText();
++ dialog.dispose();
++ }
++ }
++}
++
++class BrowserCertsDialog implements ActionListener {
++ Button yes, no;
++ Dialog dialog;
++ String vncServer;
++ String hostport;
++ public boolean showCertDialog = true;
++
++ BrowserCertsDialog(String serv, String hp) {
++ vncServer = serv;
++ hostport = hp;
++ }
++
++ public void queryUser() {
++
++ /* create and display the dialog for unverified cert. */
++
++ Frame frame = new Frame("Use Browser/JVM Certs?");
++
++ dialog = new Dialog(frame, true);
++
++ String m = "";
++m += "\n";
++m += "This VNC Viewer applet does not have its own keystore to track\n";
++m += "SSL certificates, and so cannot authenticate the certificate\n";
++m += "of the VNC Server:\n";
++m += "\n";
++m += " " + hostport + "\n\n " + vncServer + "\n";
++m += "\n";
++m += "on its own.\n";
++m += "\n";
++m += "However, it has noticed that your Web Browser or Java VM Plugin\n";
++m += "has previously accepted the same certificate. You may have set\n";
++m += "this up permanently or just for this session, or the server\n";
++m += "certificate was signed by a CA cert that your Web Browser or\n";
++m += "Java VM Plugin has.\n";
++m += "\n";
++m += "Should this VNC Viewer applet now connect to the above VNC server?\n";
++m += "\n";
++
++// String m = "\nShould this VNC Viewer applet use your Browser/JVM certs to\n";
++// m += "authenticate the VNC Server:\n";
++// m += "\n " + hostport + "\n\n " + vncServer + "\n\n";
++// m += "(NOTE: this *includes* any certs you have Just Now accepted in a\n";
++// m += "dialog box with your Web Browser or Java Applet Plugin)\n\n";
++
++ TextArea textarea = new TextArea(m, 20, 64,
++ TextArea.SCROLLBARS_VERTICAL_ONLY);
++ textarea.setEditable(false);
++ yes = new Button("Yes");
++ yes.addActionListener(this);
++ no = new Button("No, Let Me See the Certificate.");
++ no.addActionListener(this);
++
++ dialog.setLayout(new BorderLayout());
++ dialog.add("North", textarea);
++ dialog.add("Center", yes);
++ dialog.add("South", no);
++ dialog.pack();
++ dialog.resize(dialog.preferredSize());
++
++ dialog.show(); /* block here til Yes or No pressed. */
++ return;
++ }
++
++ public synchronized void actionPerformed(ActionEvent evt) {
++ System.out.println(evt.getActionCommand());
++ if (evt.getSource() == yes) {
++ showCertDialog = false;
++ dialog.dispose();
++ } else if (evt.getSource() == no) {
++ showCertDialog = true;
++ dialog.dispose();
++ }
++ }
++}
++
++class CertInfo {
++ String fields[] = {"CN", "OU", "O", "L", "C"};
++ java.security.cert.Certificate cert;
++ String certString = "";
++
++ CertInfo(java.security.cert.Certificate c) {
++ cert = c;
++ certString = cert.toString();
++ }
++
++ String get_certinfo(String which) {
++ int i;
++ String cs = new String(certString);
++ String all = "";
++
++ /*
++ * For now we simply scrape the cert string, there must
++ * be an API for this... perhaps optionValue?
++ */
++ for (i=0; i < fields.length; i++) {
++ int f, t, t1, t2;
++ String sub, mat = fields[i] + "=";
++
++ f = cs.indexOf(mat, 0);
++ if (f > 0) {
++ t1 = cs.indexOf(", ", f);
++ t2 = cs.indexOf("\n", f);
++ if (t1 < 0 && t2 < 0) {
++ continue;
++ } else if (t1 < 0) {
++ t = t2;
++ } else if (t2 < 0) {
++ t = t1;
++ } else if (t1 < t2) {
++ t = t1;
++ } else {
++ t = t2;
++ }
++ if (t > f) {
++ sub = cs.substring(f, t);
++ all = all + " " + sub + "\n";
++ if (which.equals(fields[i])) {
++ return sub;
++ }
++ }
++ }
++ }
++ if (which.equals("all")) {
++ return all;
++ } else {
++ return "";
++ }
++ }
++}
+diff -Naur JavaViewer.orig/VncCanvas.java JavaViewer/VncCanvas.java
+--- JavaViewer.orig/VncCanvas.java 2005-11-21 18:50:18.000000000 -0500
++++ JavaViewer/VncCanvas.java 2007-05-16 15:57:36.000000000 -0400
+@@ -27,6 +27,9 @@
+ import java.lang.*;
+ import java.util.zip.*;
+
++// begin runge/x11vnc
++import java.util.Collections;
++// end runge/x11vnc
+
+ //
+ // VncCanvas is a subclass of Canvas which draws a VNC desktop on it.
+@@ -85,6 +88,22 @@
+
+ cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF);
+
++// begin runge/x11vnc
++// kludge to not show any Java cursor in the canvas since we are
++// showing the soft cursor (should be a user setting...)
++Cursor dot = Toolkit.getDefaultToolkit().createCustomCursor(
++ Toolkit.getDefaultToolkit().createImage(new byte[4]), new Point(0,0),
++ "dot");
++this.setCursor(dot);
++
++// while we are at it... get rid of the keyboard traversals that
++// make it so we can't type a Tab character:
++this.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
++ Collections.EMPTY_SET);
++this.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
++ Collections.EMPTY_SET);
++// end runge/x11vnc
++
+ colors = new Color[256];
+ // sf@2005 - Now Default
+ for (int i = 0; i < 256; i++)
+@@ -237,6 +256,9 @@
+ }
+ else
+ {
++// begin runge/x11vnc
++ viewer.options.oldEightBitColors = viewer.options.eightBitColors;
++// end runge/x11vnc
+ rfb.writeSetPixelFormat(
+ 32,
+ 24,
+@@ -1532,9 +1554,14 @@
+ else
+ {
+ result =
+- 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF)
+- << 16 | (pixBuf[i * 4 + 2] & 0xFF)
+- << 8 | (pixBuf[i * 4 + 3] & 0xFF);
++// begin runge/x11vnc
++// 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF)
++// << 16 | (pixBuf[i * 4 + 2] & 0xFF)
++// << 8 | (pixBuf[i * 4 + 3] & 0xFF);
++ 0xFF000000 | (pixBuf[i * 4 + 2] & 0xFF)
++ << 16 | (pixBuf[i * 4 + 1] & 0xFF)
++ << 8 | (pixBuf[i * 4 + 0] & 0xFF);
++// end runge/x11vnc
+ }
+ } else {
+ result = 0; // Transparent pixel
+@@ -1565,9 +1592,14 @@
+ else
+ {
+ result =
+- 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF)
+- << 16 | (pixBuf[i * 4 + 2] & 0xFF)
+- << 8 | (pixBuf[i * 4 + 3] & 0xFF);
++// begin runge/x11vnc
++// 0xFF000000 | (pixBuf[i * 4 + 1] & 0xFF)
++// << 16 | (pixBuf[i * 4 + 2] & 0xFF)
++// << 8 | (pixBuf[i * 4 + 3] & 0xFF);
++ 0xFF000000 | (pixBuf[i * 4 + 2] & 0xFF)
++ << 16 | (pixBuf[i * 4 + 1] & 0xFF)
++ << 8 | (pixBuf[i * 4 + 0] & 0xFF);
++// end runge/x11vnc
+ }
+ } else {
+ result = 0; // Transparent pixel
+diff -Naur JavaViewer.orig/VncViewer.java JavaViewer/VncViewer.java
+--- JavaViewer.orig/VncViewer.java 2006-05-24 15:14:40.000000000 -0400
++++ JavaViewer/VncViewer.java 2007-05-15 15:09:10.000000000 -0400
+@@ -115,6 +115,22 @@
+ int i;
+ // mslogon support 2 end
+
++// begin runge/x11vnc
++boolean disableSSL;
++boolean GET;
++String CONNECT;
++String urlPrefix;
++String httpsPort;
++String oneTimeKey;
++boolean forceProxy;
++boolean ignoreProxy;
++boolean trustAllVncCerts;
++boolean trustUrlVncCert;
++
++boolean ignoreMSLogonCheck;
++// end runge/x11vnc
++
++
+ //
+ // init()
+ //
+@@ -336,7 +352,12 @@
+ //
+
+
+- prologueDetectAuthProtocol() ;
++// begin runge/x11vnc
++// prologueDetectAuthProtocol() ;
++ if (ignoreMSLogonCheck == false) {
++ prologueDetectAuthProtocol() ;
++ }
++// end runge/x11vnc
+
+ authenticator = new AuthPanel(mslogon);
+
+@@ -435,7 +456,7 @@
+
+ rfb.readVersionMsg();
+
+- System.out.println("RFB server supports protocol version " +
++ System.out.println("RFB server supports protocol version: " +
+ rfb.serverMajor + "." + rfb.serverMinor);
+
+ rfb.writeVersionMsg();
+@@ -804,6 +825,75 @@
+ deferScreenUpdates = readIntParameter("Defer screen updates", 20);
+ deferCursorUpdates = readIntParameter("Defer cursor updates", 10);
+ deferUpdateRequests = readIntParameter("Defer update requests", 50);
++
++// begin runge/x11vnc
++ // SSL
++ disableSSL = false;
++ str = readParameter("DisableSSL", false);
++ if (str != null && str.equalsIgnoreCase("Yes"))
++ disableSSL = true;
++
++ httpsPort = readParameter("httpsPort", false);
++
++ // Extra GET, CONNECT string:
++ CONNECT = readParameter("CONNECT", false);
++ if (CONNECT != null) {
++ CONNECT = CONNECT.replaceAll(" ", ":");
++ }
++
++ GET = false;
++ str = readParameter("GET", false);
++ if (str != null && str.equalsIgnoreCase("Yes")) {
++ GET = true;
++ }
++ if (str != null && str.equalsIgnoreCase("1")) {
++ GET = true;
++ }
++
++ urlPrefix = readParameter("urlPrefix", false);
++ if (urlPrefix != null) {
++ urlPrefix = urlPrefix.replaceAll("%2F", "/");
++ urlPrefix = urlPrefix.replaceAll("%2f", "/");
++ urlPrefix = urlPrefix.replaceAll("_2F_", "/");
++ if (urlPrefix.indexOf("/") != 0) {
++ urlPrefix = "/" + urlPrefix;
++ }
++ } else {
++ urlPrefix = "";
++ }
++ System.out.println("urlPrefix: '" + urlPrefix + "'");
++
++ oneTimeKey = readParameter("oneTimeKey", false);
++ if (oneTimeKey != null) {
++ System.out.println("oneTimeKey: is set");
++ }
++
++ forceProxy = false;
++ str = readParameter("forceProxy", false);
++ if (str != null && str.equalsIgnoreCase("Yes")) {
++ forceProxy = true;
++ }
++ ignoreProxy = false;
++ str = readParameter("ignoreProxy", false);
++ if (str != null && str.equalsIgnoreCase("Yes")) {
++ ignoreProxy = true;
++ }
++ trustAllVncCerts = false;
++ str = readParameter("trustAllVncCerts", false);
++ if (str != null && str.equalsIgnoreCase("Yes")) {
++ trustAllVncCerts = true;
++ }
++ trustUrlVncCert = false;
++ str = readParameter("trustUrlVncCert", false);
++ if (str != null && str.equalsIgnoreCase("Yes")) {
++ trustUrlVncCert = true;
++ }
++ ignoreMSLogonCheck = false;
++ str = readParameter("ignoreMSLogonCheck", false);
++ if (str != null && str.equalsIgnoreCase("Yes")) {
++ ignoreMSLogonCheck = true;
++ }
++// end runge/x11vnc
+ }
+
+ public String readParameter(String name, boolean required) {
OpenPOWER on IntegriCloud