add libvncserver
[presencevnc] / libvnc / classes / ssl / ss_vncviewer
diff --git a/libvnc/classes/ssl/ss_vncviewer b/libvnc/classes/ssl/ss_vncviewer
new file mode 100755 (executable)
index 0000000..2231108
--- /dev/null
@@ -0,0 +1,2394 @@
+#!/bin/sh
+#
+# ss_vncviewer:  wrapper for vncviewer to use an stunnel SSL tunnel
+#                or an SSH tunnel.
+#
+# Copyright (c) 2006-2008 by Karl J. Runge <runge@karlrunge.com>
+#
+# You must have stunnel(8) installed on the system and in your PATH
+# (however, see the -ssh option below, in which case you will need ssh(1)
+# installed)  Note: stunnel is usually installed in an "sbin" subdirectory.
+#
+# You should have "x11vnc -ssl ..." or "x11vnc -stunnel ..." 
+# already running as the VNC server on the remote machine.
+# (or use stunnel on the server side for any other VNC server)
+#
+#
+# Usage: ss_vncviewer [cert-args] host:display <vncviewer-args>
+#
+# e.g.:  ss_vncviewer snoopy:0
+#        ss_vncviewer snoopy:0 -encodings "copyrect tight zrle hextile"
+#
+# [cert-args] can be:
+#
+#      -verify /path/to/cacert.pem             
+#      -mycert /path/to/mycert.pem             
+#      -crl    /path/to/my_crl.pem  (or directory)
+#      -proxy  host:port
+#
+# -verify specifies a CA cert PEM file (or a self-signed one) for
+#         authenticating the VNC server.
+#
+# -mycert specifies this client's cert+key PEM file for the VNC server to
+#        authenticate this client. 
+#
+# -proxy  try host:port as a Web proxy to use the CONNECT method
+#         to reach the VNC server (e.g. your firewall requires a proxy).
+#
+#         For the "double proxy" case use -proxy host1:port1,host2:port2
+#         (the first CONNECT is done through host1:port1 to host2:port2
+#         and then a 2nd CONNECT to the destination VNC server.)
+#
+#         Use socks://host:port, socks4://host:port, or socks5://host,port
+#         to force usage of a SOCKS proxy.  Also repeater://host:port and
+#         sslrepeater://host:port.
+#
+# -showcert  Only fetch the certificate using the 'openssl s_client'
+#            command (openssl(1) must in installed).
+#
+#    See http://www.karlrunge.com/x11vnc/#faq-ssl-ca for details on SSL
+#    certificates with VNC.
+#
+# A few other args (not related to SSL and certs):
+#
+# -2nd    Run the vncviewer a 2nd time if the first connections fails.
+#
+# -ssh    Use ssh instead of stunnel SSL.  ssh(1) must be installed and you
+#         must be able to log into the remote machine via ssh.
+#
+#         In this case "host:display" may be of the form "user@host:display"
+#         where "user@host" is used for the ssh login (see ssh(1) manpage).
+#
+#         If -proxy is supplied it can be of the forms: "gwhost" "gwhost:port"
+#         "user@gwhost" or "user@gwhost:port".  "gwhost" is an incoming ssh 
+#         gateway machine (the VNC server is not running there), an ssh -L
+#         redir is used to "host" in "host:display" from "gwhost". Any "user@"
+#         part must be in the -proxy string (not in "host:display").
+#
+#         Under -proxy use "gwhost:port" if connecting to any ssh port
+#         other than the default (22).  (even for the non-gateway case,
+#         -proxy must be used to specify a non-standard ssh port)
+#
+#         A "double ssh" can be specified via a -proxy string with the two
+#         hosts separated by a comma:
+#
+#             [user1@]host1[:port1],[user2@]host2[:port2]
+#
+#         in which case a ssh to host1 and thru it via a -L redir a 2nd
+#         ssh is established to host2.  
+#
+#         Examples:
+#
+#         ss_vncviewer -ssh bob@bobs-home.net:0
+#         ss_vncviewer -ssh -sshcmd 'x11vnc -localhost' bob@bobs-home.net:0
+#
+#         ss_vncviewer -ssh -proxy fred@mygate.com:2022 mymachine:0
+#         ss_vncviewer -ssh -proxy bob@bobs-home.net:2222 localhost:0
+#
+#         ss_vncviewer -ssh -proxy fred@gw-host,fred@peecee localhost:0
+#
+# -sshcmd cmd   Run "cmd" via ssh instead of the default "sleep 15"
+#               e.g. -sshcmd 'x11vnc -display :0 -localhost -rfbport 5900'
+#
+# -sshargs "args"  pass "args" to the ssh process, e.g. -L/-R port redirs.
+#
+# -sshssl Tunnel the SSL connection thru a SSH connection.  The tunnel as
+#         under -ssh is set up and the SSL connection goes thru it.  Use
+#         this if you want to have and end-to-end SSL connection but must
+#         go thru a SSH gateway host (e.g. not the vnc server).  Or use
+#         this if you need to tunnel additional services via -R and -L 
+#         (see -sshargs above).
+#
+#         ss_vncviewer -sshssl -proxy fred@mygate.com mymachine:0
+#
+# -listen (or -reverse) set up a reverse connection.
+#
+# -alpha  turn on cursor alphablending hack if you are using the
+#         enhanced tightvnc vncviewer.
+#
+# -grab   turn on XGrabServer hack if you are using the enhanced tightvnc
+#         vncviewer (e.g. for fullscreen mode in some windowmanagers like
+#         fvwm that do not otherwise work in fullscreen mode)
+#
+#
+# set VNCVIEWERCMD to whatever vncviewer command you want to use.
+#
+VNCIPCMD=${VNCVIEWERCMD:-vncip}
+VNCVIEWERCMD=${VNCVIEWERCMD:-vncviewer}
+#
+# Same for STUNNEL, e.g. set it to /path/to/stunnel or stunnel4, etc.
+#
+
+# turn on verbose debugging output
+if [ "X$SS_DEBUG" != "X" ]; then
+       set -xv 
+fi
+
+PATH=$PATH:/usr/sbin:/usr/local/sbin:/dist/sbin; export PATH
+
+localhost="localhost"
+if uname | grep Darwin >/dev/null; then
+       localhost="127.0.0.1"
+fi
+
+# work out which stunnel to use (debian installs as stunnel4)
+if [ "X$STUNNEL" = "X" ]; then
+       check_stunnel=1
+       if [ "X$SSVNC_BASEDIRNAME" != "X" ]; then
+               if [ -x "$SSVNC_BASEDIRNAME/stunnel" ]; then
+                       type stunnel > /dev/null 2>&1
+                       if [ $? = 0 ]; then
+                               # found ours
+                               STUNNEL=stunnel
+                               check_stunnel=0
+                       fi
+               fi
+       fi
+       if [ "X$check_stunnel" = "X1" ]; then
+               type stunnel4 > /dev/null 2>&1
+               if [ $? = 0 ]; then
+                       STUNNEL=stunnel4
+               else
+                       STUNNEL=stunnel
+               fi
+       fi
+fi
+
+help() {
+       tail -n +2 "$0" | sed -e '/^$/ q'
+}
+
+secondtry=""
+gotalpha=""
+use_ssh=""
+use_sshssl=""
+direct_connect=""
+ssh_sleep=15
+
+# sleep longer in -listen mode:
+if echo "$*" | grep '.*-listen' > /dev/null; then
+       ssh_sleep=1800
+fi
+
+
+ssh_cmd=""
+# env override of ssh_cmd:
+if [ "X$SS_VNCVIEWER_SSH_CMD" != "X" ]; then
+       ssh_cmd="$SS_VNCVIEWER_SSH_CMD"
+fi
+
+ssh_args=""
+showcert=""
+reverse=""
+
+ciphers=""
+anondh="ALL:RC4+RSA:+SSLv2:@STRENGTH"
+anondh_set=""
+stunnel_debug="6"
+if [ "X$SS_DEBUG" != "X" -o "X$SSVNC_VENCRYPT_DEBUG" != "X" -o "X$SSVNC_STUNNEL_DEBUG" != "X" ]; then
+       stunnel_debug="7"
+fi
+
+if [ "X$1" = "X-viewerflavor" ]; then
+       # special case, try to guess which viewer:
+       #
+       if echo "$VNCVIEWERCMD" | egrep -i '^(xmessage|sleep )' > /dev/null; then
+               echo "unknown"
+               exit 0
+       fi
+       if echo "$VNCVIEWERCMD" | grep -i chicken.of > /dev/null; then
+               echo "cotvnc"
+               exit 0
+       fi
+       if echo "$VNCVIEWERCMD" | grep -i ultra > /dev/null; then
+               echo "ultravnc"
+               exit 0
+       fi
+       # OK, run it for help output...
+       str=`$VNCVIEWERCMD -h 2>&1 | head -n 5`
+       if echo "$str" | grep -i 'TightVNC.viewer' > /dev/null; then
+               echo "tightvnc"
+       elif echo "$str" | grep -i 'RealVNC.Ltd' > /dev/null; then
+               echo "realvnc4"
+       elif echo "$str" | grep -i 'VNC viewer version 3' > /dev/null; then
+               echo "realvnc3"
+       else
+               echo "unknown"
+       fi
+       exit 0
+fi
+if [ "X$1" = "X-viewerhelp" ]; then
+       $VNCVIEWERCMD -h 2>&1
+       exit 0
+fi
+
+# grab our cmdline options:
+while [ "X$1" != "X" ]
+do
+    case $1 in 
+       "-verify")      shift; verify="$1"
+                ;;
+       "-mycert")      shift; mycert="$1"
+                ;;
+       "-crl")         shift; crl="$1"
+                ;;
+       "-proxy")       shift; proxy="$1"
+                ;;
+       "-ssh")         use_ssh=1
+                ;;
+       "-sshssl")      use_ssh=1
+                       use_sshssl=1
+                ;;
+       "-sshcmd")      shift; ssh_cmd="$1"
+                ;;
+       "-sshargs")     shift; ssh_args="$1"
+                ;;
+       "-anondh")      ciphers="ciphers=$anondh"
+                       anondh_set=1
+                ;;
+       "-ciphers")     shift; ciphers="ciphers=$1"
+                ;;
+       "-alpha")       gotalpha=1
+                ;;
+       "-showcert")    showcert=1
+                ;;
+       "-listen")      reverse=1
+                ;;
+       "-reverse")     reverse=1
+                ;;
+       "-2nd")         secondtry=1
+                ;;
+       "-grab")        VNCVIEWER_GRAB_SERVER=1; export VNCVIEWER_GRAB_SERVER
+                ;;
+       "-x11cursor")   VNCVIEWER_X11CURSOR=1; export VNCVIEWER_X11CURSOR
+                ;;
+       "-rawlocal")    VNCVIEWER_RAWLOCAL=1; export VNCVIEWER_RAWLOCAL
+                ;;
+       "-scale")       shift; SSVNC_SCALE="$1"; export SSVNC_SCALE
+                ;;
+       "-onelisten")   SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE
+                ;;
+       "-escape")      shift; VNCVIEWER_ESCAPE="$1"; export VNCVIEWER_ESCAPE
+                ;;
+       "-ssvnc_encodings")     shift; VNCVIEWER_ENCODINGS="$1"; export VNCVIEWER_ENCODINGS
+                ;;
+       "-rfbversion")  shift; VNCVIEWER_RFBVERSION="$1"; export VNCVIEWER_RFBVERSION
+                ;;
+       "-nobell")      VNCVIEWER_NOBELL=1; export VNCVIEWER_NOBELL
+                ;;
+       "-popupfix")    VNCVIEWER_POPUP_FIX=1; export VNCVIEWER_POPUP_FIX
+                ;;
+       "-realvnc4")    VNCVIEWER_IS_REALVNC4=1; export VNCVIEWER_IS_REALVNC4
+                ;;
+       "-h"*)  help; exit 0
+                ;;
+       "--h"*) help; exit 0
+                ;;
+       *)      break
+                ;;
+    esac
+    shift
+done
+
+# maxconn is something we added to stunnel, this disables it:
+if [ "X$SS_VNCVIEWER_NO_MAXCONN" != "X" ]; then
+       STUNNEL_EXTRA_OPTS=`echo "$STUNNEL_EXTRA_OPTS" | sed -e 's/maxconn/#maxconn/'`
+elif echo "$VNCVIEWERCMD" | egrep -i '^(xmessage|sleep )' > /dev/null; then
+       STUNNEL_EXTRA_OPTS=`echo "$STUNNEL_EXTRA_OPTS" | sed -e 's/maxconn/#maxconn/'`
+elif [ "X$reverse" != "X" ]; then
+       STUNNEL_EXTRA_OPTS=`echo "$STUNNEL_EXTRA_OPTS" | sed -e 's/maxconn/#maxconn/'`
+else
+       # new way (our patches).  other than the above, we set these:
+       if [ "X$SKIP_STUNNEL_ONCE" = "X" ]; then
+               STUNNEL_ONCE=1; export STUNNEL_ONCE
+       fi
+       if [ "X$SKIP_STUNNEL_MAX_CLIENTS" = "X" ]; then
+               STUNNEL_MAX_CLIENTS=1; export STUNNEL_MAX_CLIENTS
+       fi
+fi
+# always set this one:
+if [ "X$SKIP_STUNNEL_NO_SYSLOG" = "X" ]; then
+       STUNNEL_NO_SYSLOG=1; export STUNNEL_NO_SYSLOG
+fi
+
+# this is the -t ssh option (gives better keyboard response thru SSH tunnel)
+targ="-t"
+if [ "X$SS_VNCVIEWER_NO_T" != "X" ]; then
+       targ=""
+fi
+
+# set the alpha blending env. hack: 
+if [ "X$gotalpha" = "X1" ]; then
+       VNCVIEWER_ALPHABLEND=1
+       export VNCVIEWER_ALPHABLEND
+else
+       NO_ALPHABLEND=1
+       export NO_ALPHABLEND
+fi
+
+if [ "X$reverse" != "X" ]; then
+       ssh_sleep=1800
+       if [ "X$proxy" != "X" ]; then
+               # check proxy usage under reverse connection:
+               if [ "X$use_ssh" = "X" -a "X$use_sshssl" = "X" ]; then
+                       echo ""
+                       if echo "$proxy" | egrep -i "(repeater|vencrypt)://" > /dev/null; then
+                               :
+                       else
+                               echo "*Warning*: SSL -listen and a Web proxy does not make sense."
+                               sleep 2
+                       fi
+               elif echo "$proxy" | grep "," > /dev/null; then
+                       :
+               else
+                       echo ""
+                       echo "*Warning*: -listen and a single proxy/gateway does not make sense."
+                       sleep 2
+               fi
+               SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE
+       fi
+fi
+if [ "X$ssh_cmd" = "X" ]; then
+       # if no remote ssh cmd, sleep a bit:
+       ssh_cmd="sleep $ssh_sleep"
+fi
+
+# this should be a host:display:
+#
+orig="$1"
+shift
+
+dL="-L"
+if uname -sr | egrep 'SunOS 5\.[5-8]' > /dev/null; then
+       dL="-h"
+fi
+
+rchk() {
+       # a kludge to set $RANDOM if we are not bash:
+       if [ "X$BASH_VERSION" = "X" ]; then
+               RANDOM=`date +%S``sh -c 'echo $$'``ps -elf 2>&1 | sum 2>&1 | awk '{print $1}'`
+       fi
+}
+rchk
+
+# a portable, but not absolutely safe, tmp file creator
+mytmp() {
+       tf=$1
+       if type mktemp > /dev/null 2>&1; then
+               # if we have mktemp(1), use it:
+               tf2="$tf.XXXXXX"
+               tf2=`mktemp "$tf2"`
+               if [ "X$tf2" != "X" -a -f "$tf2" ]; then
+                       if [ "X$DEBUG_MKTEMP" != "X" ]; then
+                               echo "mytmp-mktemp: $tf2" 1>&2
+                       fi
+                       echo "$tf2"
+                       return
+               fi
+       fi
+       # fallback to multiple cmds:
+       rm -rf "$tf" || exit 1
+       if [ -d "$tf" ]; then
+               echo "tmp file $tf still exists as a directory."
+               exit 1
+       elif [ $dL "$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$DEBUG_MKTEMP" != "X" ]; then
+               echo "mytmp-touch: $tf" 1>&2
+       fi
+       echo "$tf"
+}
+
+# set up special case of ultravnc single click III mode:
+if echo "$proxy" | egrep "^sslrepeater://" > /dev/null; then
+       pstr=`echo "$proxy" | sed -e 's,sslrepeater://,,'`
+       pstr1=`echo "$pstr" | sed -e 's/+.*$//'`
+       pstr2=`echo "$pstr" | sed -e 's/^[^+]*+//'`
+       SSVNC_REPEATER="SCIII=$pstr2"; export SSVNC_REPEATER
+       orig=$pstr1
+       echo
+       echo "reset: SSVNC_REPEATER=$SSVNC_REPEATER orig=$orig proxy=''"
+       proxy=""
+fi
+if echo "$proxy" | egrep "vencrypt://" > /dev/null; then
+       vtmp="/tmp/ss_handshake${RANDOM}.$$.txt"
+       vtmp=`mytmp "$vtmp"`
+       SSVNC_PREDIGESTED_HANDSHAKE="$vtmp"
+       export SSVNC_PREDIGESTED_HANDSHAKE
+       #echo "SSVNC_PREDIGESTED_HANDSHAKE=$SSVNC_PREDIGESTED_HANDSHAKE"
+fi
+
+
+# check -ssh and -mycert/-verify conflict:
+if [ "X$use_ssh" = "X1" -a "X$use_sshssl" = "X" ]; then
+       if [ "X$mycert" != "X" -o "X$verify" != "X" ]; then
+               echo "-mycert and -verify cannot be used in -ssh mode" 
+               exit 1
+       fi
+fi
+
+# direct mode Vnc:// means show no warnings.
+# direct mode vnc:// will show warnings.
+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
+
+# interprest the pseudo URL proto:// strings:
+if echo "$orig" | grep '^vnc://' > /dev/null; then
+       orig=`echo "$orig" | sed -e 's,vnc://,,'`
+       verify=""
+       mycert=""
+       crl=""
+       use_ssh=""
+       use_sshssl=""
+       direct_connect=1
+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$SSVNC_ULTRA_DSM" != "X" ]; then
+        verify=""
+        mycert=""
+        crl=""
+        use_ssh=""
+        use_sshssl=""
+        direct_connect=1
+       if echo "$SSVNC_ULTRA_DSM" | grep 'noultra:' > /dev/null; then
+               SSVNC_NO_ULTRA_DSM=1; export SSVNC_NO_ULTRA_DSM
+       fi
+fi
+
+# (possibly) tell the vncviewer to only listen on lo: 
+if [ "X$reverse" != "X" -a "X$direct_connect" = "X" ]; then
+       VNCVIEWER_LISTEN_LOCALHOST=1
+       export VNCVIEWER_LISTEN_LOCALHOST
+fi
+
+# rsh mode is an internal/secret thing only I use.
+rsh=""
+if echo "$orig" | grep '^rsh://' > /dev/null; then
+       use_ssh=1
+       rsh=1
+       orig=`echo "$orig" | sed -e 's,rsh://,,'`
+elif echo "$orig" | grep '^rsh:' > /dev/null; then
+       use_ssh=1
+       rsh=1
+       orig=`echo "$orig" | sed -e 's,rsh:,,'`
+fi
+
+# play around with host:display port:
+if echo "$orig" | grep ':' > /dev/null; then
+       :
+else
+       # add or assume :0 if no ':'
+       if [ "X$reverse" = "X" ]; then
+               orig="$orig:0"
+       elif [ "X$orig" = "X" ]; then
+               orig=":0"
+       fi
+fi
+
+# extract host and disp number:
+host=`echo "$orig" | awk -F: '{print $1}'`
+disp=`echo "$orig" | awk -F: '{print $2}'`
+if [ "X$host" = "X" ]; then
+       host=$localhost
+fi
+if [ "X$disp" = "X" ]; then
+       port="" # probably -listen mode.
+elif [ $disp -lt 0 ]; then
+       # negative means use |n| without question:
+       port=`expr 0 - $disp`
+elif [ $disp -lt 200 ]; then
+       # less than 200 means 5900+n
+       if [ "X$reverse" = "X" ]; then
+               port=`expr $disp + 5900`
+       else
+               port=`expr $disp + 5500`
+       fi
+else
+       # otherwise use the number directly, e.g. 443, 2345
+       port=$disp
+fi
+
+# try to find an open listening port via netstat(1):
+inuse=""
+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 | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $1}' | sed 's/^.*\.//'`
+elif uname | egrep -i 'bsd|darwin' > /dev/null; then
+       inuse=`netstat -ant -f inet | egrep 'LISTEN|WAIT|ESTABLISH|CLOSE' | awk '{print $4}' | sed 's/^.*\.//'`
+# add others...
+fi
+
+# this is a crude attempt for unique ports tags, etc.
+date_sec=`date +%S`
+
+# these are special cases of no vnc, e.g. sleep or xmessage.
+# these are for using ssvnc as a general port redirector.
+if echo "$VNCVIEWERCMD" | grep '^sleep[        ][      ]*[0-9][0-9]*' > /dev/null; then
+       if [ "X$SS_VNCVIEWER_LISTEN_PORT" = "X" ]; then
+               p=`echo "$VNCVIEWERCMD" | awk '{print $3}'`
+               if [ "X$p" != "X" ]; then
+                       SS_VNCVIEWER_LISTEN_PORT=$p
+               fi
+       fi
+       p2=`echo "$VNCVIEWERCMD" | awk '{print $2}'`
+       VNCVIEWERCMD="eval sleep $p2; echo Local "
+elif echo "$VNCVIEWERCMD" | grep '^xmessage[   ][      ]*[0-9][0-9]*' > /dev/null; then
+       if [ "X$SS_VNCVIEWER_LISTEN_PORT" = "X" ]; then
+               p=`echo "$VNCVIEWERCMD" | awk '{print $2}'`
+               SS_VNCVIEWER_LISTEN_PORT=$p
+       fi
+fi
+
+# utility to find a free port to listen on.
+findfree() {
+       try0=$1
+       try=$try0
+       use0=""
+
+       if [ "X$SS_VNCVIEWER_LISTEN_PORT" != "X" ]; then
+               echo "$SS_VNCVIEWER_LISTEN_PORT"
+               return  
+       fi
+       if [ $try -ge 6000 ]; then
+               fmax=`expr $try + 1000`
+       else
+               fmax=6000
+       fi
+
+       while [ $try -lt $fmax ]
+       do
+               if [ "X$inuse" = "X" ]; then
+                       break
+               fi
+               if echo "$inuse" | grep -w $try > /dev/null; then
+                       :
+               else
+                       use0=$try
+                       break
+               fi
+               try=`expr $try + 1`
+       done
+       if [ "X$use0" = "X" ]; then
+               use0=`expr $date_sec + $try0`
+       fi
+
+       echo $use0
+}
+
+# utility for exiting; kills some helper processes,
+# removes files, etc.
+final() {
+       echo ""
+       if [ "X$tmp_cfg" != "X" ]; then
+               rm -f $tmp_cfg
+       fi
+       if [ "X$SS_VNCVIEWER_RM" != "X" ]; then
+               rm -f $SS_VNCVIEWER_RM 2>/dev/null
+       fi
+       if [ "X$tcert" != "X" ]; then
+               rm -f $tcert
+       fi
+       if [ "X$pssh" != "X" ]; then
+               echo "Terminating background ssh process"
+               echo kill -TERM "$pssh"
+               kill -TERM "$pssh" 2>/dev/null
+               sleep 1
+               kill -KILL "$pssh" 2>/dev/null
+               pssh=""
+       fi
+       if [ "X$stunnel_pid" != "X" ]; then
+               echo "Terminating background stunnel process"
+               echo kill -TERM "$stunnel_pid"
+               kill -TERM "$stunnel_pid" 2>/dev/null
+               sleep 1
+               kill -KILL "$stunnel_pid" 2>/dev/null
+               stunnel_pid=""
+       fi
+       if [ "X$dsm_pid" != "X" ]; then
+               echo "Terminating background ultravnc_dsm_helper process"
+               echo kill -TERM "$dsm_pid"
+               kill -TERM "$dsm_pid" 2>/dev/null
+               sleep 1
+               kill -KILL "$dsm_pid" 2>/dev/null
+               stunnel_pid=""
+       fi
+       if [ "X$tail_pid" != "X" ]; then
+               kill -TERM $tail_pid
+       fi
+}
+
+if [ "X$reverse" = "X" ]; then
+       # normal connections try 5930-5999:
+       if [ "X$showcert" = "X" ]; then
+               use=`findfree 5930`
+       else
+               # move away from normal place for (possibly many) -showcert
+               pstart=`date +%S`
+               pstart=`expr 6130 + $pstart + $pstart`
+               use=`findfree $pstart`
+       fi
+       if [ $use -ge 5900 ]; then
+               N=`expr $use - 5900`
+       else
+               N=$use
+       fi
+else
+       # reverse connections:
+       p2=`expr $port + 30`
+       use=`findfree $p2`
+       if [ $use -ge 5500 ]; then
+               N=`expr $use - 5500`
+       else
+               N=$use
+       fi
+fi
+
+# this is for my special use of ss_vncip -> vncip viewer.
+if echo "$0" | grep vncip > /dev/null; then
+       VNCVIEWERCMD="$VNCIPCMD"
+fi
+
+# trick for the undocumented rsh://host:port method.
+rsh_setup() {
+       if echo "$ssh_host" | grep '@' > /dev/null; then
+               ul=`echo "$ssh_host" | awk -F@ '{print $1}'`
+               ul="-l $ul"
+               ssh_host=`echo "$ssh_host" | awk -F@ '{print $2}'`
+       else
+               ul=""
+       fi
+       ssh_cmd=`echo "$ssh_cmd" | sed -e 's/ -localhost/ /g'`
+}
+
+# trick for the undocumented rsh://host:port method.
+rsh_viewer() {
+       trap "final" 0 2 15
+       if [ "X$PORT" = "X" ]; then
+               exit 1
+       elif [ $PORT -ge 5900 ]; then
+               vdpy=`expr $PORT - 5900`
+       else
+               vdpy=":$PORT"
+       fi
+       stty sane
+       echo "$VNCVIEWERCMD" "$@" $ssh_host:$vdpy
+       echo ""
+       $VNCVIEWERCMD "$@" $ssh_host:$vdpy
+       if [ $? != 0 ]; then
+               sleep 2
+               $VNCVIEWERCMD "$@" $ssh_host:$vdpy
+       fi
+}
+
+# this is the PPROXY tool.  used only here for now... 
+pcode() {
+       tf=$1
+       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 or SOCKS for client connections.
+
+use IO::Socket::INET;
+
+if (exists $ENV{PPROXY_SLEEP}) {
+       print STDERR "PPROXY_PID: $$\n";
+       sleep $ENV{PPROXY_SLEEP};
+}
+
+foreach my $var (qw(PPROXY_PROXY PPROXY_SOCKS PPROXY_DEST PPROXY_LISTEN
+    PPROXY_REVERSE PPROXY_REPEATER PPROXY_REMOVE PPROXY_KILLPID PPROXY_SLEEP)) {
+       if (0 || $ENV{SS_DEBUG} || $ENV{SSVNC_VENCRYPT_DEBUG}) {
+               print STDERR "$var: $ENV{$var}\n";
+       }
+} 
+
+if ($ENV{PPROXY_SOCKS} ne "" && $ENV{PPROXY_PROXY} !~ m,^socks5?://,i) {
+       if ($ENV{PPROXY_SOCKS} eq "5") {
+               $ENV{PPROXY_PROXY} = "socks5://$ENV{PPROXY_PROXY}";
+       } else {
+               $ENV{PPROXY_PROXY} = "socks://$ENV{PPROXY_PROXY}";
+       }
+}
+
+my $rfbSecTypeAnonTls  = 18;
+my $rfbSecTypeVencrypt = 19;
+
+my $rfbVencryptPlain        = 256;
+my $rfbVencryptTlsNone      = 257;
+my $rfbVencryptTlsVnc       = 258;
+my $rfbVencryptTlsPlain     = 259;
+my $rfbVencryptX509None     = 260;
+my $rfbVencryptX509Vnc      = 261;
+my $rfbVencryptX509Plain    = 262;
+
+my $handshake_file = "";
+if (exists $ENV{SSVNC_PREDIGESTED_HANDSHAKE})  {
+       $handshake_file = $ENV{SSVNC_PREDIGESTED_HANDSHAKE};
+}
+
+sub append_handshake {
+       my $str = shift;
+       if ($handshake_file) {
+               if (open(HSF, ">>$handshake_file")) {
+                       print HSF $str;
+                       close HSF;
+               }
+       }
+}
+
+my ($first, $second, $third) = split(/,/, $ENV{PPROXY_PROXY}, 3);
+my ($mode_1st, $mode_2nd, $mode_3rd) = ("", "", "");
+
+($first, $mode_1st) = url_parse($first);
+
+my ($proxy_host, $proxy_port) = split(/:/, $first);
+my $connect = $ENV{PPROXY_DEST};
+
+if ($second ne "") {
+       ($second, $mode_2nd) = url_parse($second);
+}
+
+if ($third ne "") {
+       ($third, $mode_3rd) = url_parse($third);
+}
+
+
+print STDERR "\n";
+print STDERR "PPROXY v0.2: 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";
+print STDERR "pproxy_params:    $ENV{PPROXY_PROXY}\n";
+print STDERR "pproxy_listen:    $ENV{PPROXY_LISTEN}\n";
+print STDERR "pproxy_reverse:   $ENV{PPROXY_REVERSE}\n";
+print STDERR "\n";
+if (1) {
+       print STDERR "pproxy 1st: $first\t- $mode_1st\n";
+       print STDERR "pproxy 2nd: $second\t- $mode_2nd\n";
+       print STDERR "pproxy 3rd: $third\t- $mode_3rd\n";
+       print STDERR "\n";
+}
+
+my $listen_handle = "";
+if ($ENV{PPROXY_REVERSE} ne "") {
+       my ($rhost, $rport) = split(/:/, $ENV{PPROXY_REVERSE});
+       $rport = 5900 unless $rport;
+       $listen_handle = IO::Socket::INET->new(
+               PeerAddr => $rhost,
+               PeerPort => $rport,
+               Proto => "tcp"
+       );
+       if (! $listen_handle) {
+               die "pproxy: $! -- PPROXY_REVERSE\n";
+       }
+       print STDERR "PPROXY_REVERSE: connected to $rhost $rport\n";
+
+} elsif ($ENV{PPROXY_LISTEN} ne "") {
+       my $listen_sock = "";
+       if ($ENV{PPROXY_LISTEN} =~ /^INADDR_ANY:(.*)/) {
+               my $p = $1;
+               $listen_sock = IO::Socket::INET->new(
+                       Listen    => 2,
+                       LocalPort => $p,
+                       Proto     => "tcp"
+               );
+       } else {
+               $listen_sock = IO::Socket::INET->new(
+                       Listen    => 2,
+                       LocalAddr => "127.0.0.1",
+                       LocalPort => $ENV{PPROXY_LISTEN},
+                       Proto     => "tcp"
+               );
+       }
+       if (! $listen_sock) {
+               die "pproxy: $! -- PPROXY_LISTEN\n";
+       }
+       my $ip;
+       ($listen_handle, $ip) = $listen_sock->accept();
+       if (! $listen_handle) {
+               die "pproxy: $!\n";
+       }
+       close $listen_sock;
+}
+
+my $sock = IO::Socket::INET->new(
+       PeerAddr => $proxy_host,
+       PeerPort => $proxy_port,
+       Proto => "tcp"
+);
+
+if (! $sock) {
+       my $err = $!;
+       unlink($0) if $ENV{PPROXY_REMOVE};
+       die "pproxy: $err\n";
+}
+
+unlink($0) if $ENV{PPROXY_REMOVE};
+
+if ($ENV{PPROXY_PROXY} =~ /^vencrypt:/ && $ENV{PPROXY_LISTEN} =~ /^INADDR_ANY:/) {
+       print STDERR "PPROXY: vencrypt+reverse: swapping listen socket with connect socket.\n";
+       my $tmp_swap = $sock;
+       $sock = $listen_handle;
+       $listen_handle = $tmp_swap;
+}
+
+$cur_proxy = $first;
+setmode($mode_1st);
+
+if ($second ne "") {
+       connection($second, 1);
+
+       setmode($mode_2nd);
+       $cur_proxy = $second;
+
+       if ($third ne "") {
+               connection($third, 2);
+               setmode($mode_3rd);
+               $cur_proxy = $third;
+               connection($connect, 3);
+       } else {
+               connection($connect, 2);
+       }
+} else {
+       connection($connect, 1);
+}
+
+$parent = $$;
+$child = fork;
+if (! defined $child) {
+       if ($ENV{PPROXY_KILLPID}) {
+               foreach my $p (split(/,/, $ENV{PPROXY_KILLPID})) {
+                       if ($p =~ /^(\+|-)/) {
+                               $p = $parent + $p;
+                       }
+                       kill "TERM", $p;
+               }
+       }
+       exit 1;
+}
+
+if ($child) {
+       print STDERR "pproxy parent\[$$]  STDIN -> socket\n";
+       if ($listen_handle) {
+               xfer($listen_handle, $sock);
+       } else {
+               xfer(STDIN, $sock);
+       }
+       select(undef, undef, undef, 0.25);
+       if (kill 0, $child) {
+               select(undef, undef, undef, 1.5);
+               print STDERR "pproxy\[$$]: kill TERM $child\n";
+               kill "TERM", $child;
+       }
+} else {
+       print STDERR "pproxy child \[$$]  socket -> STDOUT\n";
+       if ($listen_handle) {
+               xfer($sock, $listen_handle);
+       } else {
+               xfer($sock, STDOUT);
+       }
+       select(undef, undef, undef, 0.25);
+       if (kill 0, $parent) {
+               select(undef, undef, undef, 1.5);
+               print STDERR "pproxy\[$$]: kill TERM $parent\n";
+               kill "TERM", $parent;
+       }
+}
+if ($ENV{PPROXY_KILLPID} ne "") {
+       if ($ENV{PPROXY_KILLPID}) {
+               foreach my $p (split(/,/, $ENV{PPROXY_KILLPID})) {
+                       if ($p =~ /^(\+|-)/) {
+                               $p = $parent + $p;
+                       }
+                       print STDERR "kill TERM, $p (PPROXY_KILLPID)\n";
+                       kill "TERM", $p;
+               }
+       }
+}
+exit;
+
+sub url_parse {
+       my $hostport = shift;
+       my $mode = "http";
+       if ($hostport =~ m,^socks4?://(\S*)$,i) {
+               $mode = "socks4";
+               $hostport = $1;
+       } elsif ($hostport =~ m,^socks5://(\S*)$,i) {
+               $mode = "socks5";
+               $hostport = $1;
+       } elsif ($hostport =~ m,^https?://(\S*)$,i) {
+               $mode = "http";
+               $hostport = $1;
+       } elsif ($hostport =~ m,^repeater://(\S*)\+(\S*)$,i) {
+               # ultravnc repeater proxy.
+               $hostport = $1;
+               $mode = "repeater:$2";
+               if ($hostport !~ /:\d+/) {
+                       $hostport .= ":5900";
+               }
+       } elsif ($hostport =~ m,^vencrypt://(\S*)$,i) {
+               # vencrypt handshake.
+               $hostport = $1;
+               my $m = "connect";
+               if ($hostpost =~ /^(\S+)\+(\S+)$/) {
+                       $hostport = $1;
+                       $mode = $2;
+               }
+               $mode = "vencrypt:$m";
+               if ($hostport !~ /:\d+/) {
+                       $hostport .= ":5900";
+               }
+       }
+       return ($hostport, $mode);
+}
+
+sub setmode {
+       my $mode = shift;
+       $ENV{PPROXY_REPEATER} = "";
+       $ENV{PPROXY_VENCRYPT} = "";
+       if ($mode =~ /^socks/) {
+               if ($mode =~ /^socks5/) {
+                       $ENV{PPROXY_SOCKS} = 5;
+               } else {
+                       $ENV{PPROXY_SOCKS} = 1;
+               }
+       } elsif ($mode =~ /^repeater:(.*)/) {
+               $ENV{PPROXY_REPEATER} = $1;
+               $ENV{PPROXY_SOCKS} = "";
+       } elsif ($mode =~ /^vencrypt:(.*)/) {
+               $ENV{PPROXY_VENCRYPT} = $1;
+               $ENV{PPROXY_SOCKS} = "";
+       } else {
+               $ENV{PPROXY_SOCKS} = "";
+       }
+}
+
+sub connection {
+       my ($CONNECT, $w) = @_;
+
+       my $con = "";
+       my $msg = "";
+
+       if ($ENV{PPROXY_SOCKS} eq "5") {
+               # SOCKS5
+               my ($h, $p) = split(/:/, $CONNECT);
+               $con .= pack("C", 0x05);
+               $con .= pack("C", 0x01);
+               $con .= pack("C", 0x00);
+
+               $msg = "SOCKS5 via $cur_proxy to $h:$p\n\n";
+               print STDERR "proxy_request$w: $msg";
+
+               syswrite($sock, $con, length($con));
+
+               my ($n1, $n2, $n3, $n4, $n5, $n6);
+               my ($r1, $r2, $r3, $r4, $r5, $r6);
+               my ($s1, $s2, $s3, $s4, $s5, $s6);
+
+               $n1 = sysread($sock, $r1, 1);
+               $n2 = sysread($sock, $r2, 1);
+
+               $s1 = unpack("C", $r1);
+               $s2 = unpack("C", $r2);
+               if ($s1 != 0x05 || $s2 != 0x00) {
+                       print STDERR "SOCKS5 fail s1=$s1 s2=$s2 n1=$n1 n2=$n2\n";
+                       close $sock;
+                       exit(1);
+               }
+
+               $con = "";
+               $con .= pack("C", 0x05);
+               $con .= pack("C", 0x01);
+               $con .= pack("C", 0x00);
+               $con .= pack("C", 0x03);
+               $con .= pack("C", length($h));
+               $con .= $h;
+               $con .= pack("C", $p >> 8);
+               $con .= pack("C", $p & 0xff);
+
+               syswrite($sock, $con, length($con));
+
+               $n1 = sysread($sock, $r1, 1);
+               $n2 = sysread($sock, $r2, 1);
+               $n3 = sysread($sock, $r3, 1);
+               $n4 = sysread($sock, $r4, 1);
+               $s1 = unpack("C", $r1);
+               $s2 = unpack("C", $r2);
+               $s3 = unpack("C", $r3);
+               $s4 = unpack("C", $r4);
+
+               if ($s4 == 0x1) {
+                       sysread($sock, $r5, 4 + 2);
+               } elsif ($s4 == 0x3) {
+                       sysread($sock, $r5, 1);
+                       $s5 = unpack("C", $r5);
+                       sysread($sock, $r6, $s5 + 2);
+               } elsif ($s4 == 0x4) {
+                       sysread($sock, $r5, 16 + 2);
+               }
+
+               if ($s1 != 0x5 || $s2 != 0x0 || $s3 != 0x0) {
+                       print STDERR "SOCKS5 failed: s1=$s1 s2=$s2 s3=$s3 s4=$s4 n1=$n1 n2=$n2 n3=$n3 n4=$n4\n";
+                       close $sock;
+                       exit(1);
+               }
+
+       } elsif ($ENV{PPROXY_SOCKS} ne "") {
+               # SOCKS4 SOCKS4a
+               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);
+
+               $msg = "SOCKS4 via $cur_proxy to $h:$p\n\n";
+               if ($SOCKS_4a) {
+                       $con .= $h;
+                       $con .= pack("C", 0);
+                       $msg =~ s/SOCKS4/SOCKS4a/;
+               }
+               print STDERR "proxy_request$w: $msg";
+               syswrite($sock, $con, length($con));
+
+               my $ok = 1;
+               for (my $i = 0; $i < 8; $i++) {
+                       my $c;
+                       sysread($sock, $c, 1);
+                       my $s = unpack("C", $c);
+                       if ($i == 0) {
+                               $ok = 0 if $s != 0x0;
+                       } elsif ($i == 1) {
+                               $ok = 0 if $s != 0x5a;
+                       }
+               }
+               if (! $ok) {
+                       print STDERR "SOCKS4 failed.\n";
+                       close $sock;
+                       exit(1);
+               }
+       } elsif ($ENV{PPROXY_REPEATER} ne "") {
+               my $rep = $ENV{PPROXY_REPEATER};
+               print STDERR "repeater: $rep\n";
+               $rep .= pack("x") x 250;
+               syswrite($sock, $rep, 250);
+
+               my $ok = 1;
+               for (my $i = 0; $i < 12; $i++) {
+                       my $c;
+                       sysread($sock, $c, 1);
+                       print STDERR $c;
+               }
+       } elsif ($ENV{PPROXY_VENCRYPT} ne "") {
+               my $vencrypt = $ENV{PPROXY_VENCRYPT};
+               vencrypt_dialog($vencrypt);
+
+       } else {
+               # Web Proxy:
+               $con = "CONNECT $CONNECT HTTP/1.1\r\n";
+               $con   .= "Host: $CONNECT\r\n";
+               $con   .= "Connection: close\r\n\r\n";
+               $msg = $con;
+
+               print STDERR "proxy_request$w: via $cur_proxy:\n$msg";
+               syswrite($sock, $con, length($con));
+
+               my $rep = "";
+               my $n = 0;
+               while ($rep !~ /\r\n\r\n/ && $n < 30000) {
+                       my $c;
+                       sysread($sock, $c, 1);
+                       print STDERR $c;
+                       $rep .= $c;
+                       $n++;
+               }
+               if ($rep !~ m,HTTP/.* 200,) {
+                       print STDERR "HTTP CONNECT failed.\n";
+                       close $sock;
+                       exit(1);
+               }
+       }
+}
+
+sub vdie {
+       append_handshake("done\n");
+       close $sock;
+       exit(1);
+}
+
+sub anontls_handshake {
+       my ($vmode, $db) = @_;
+
+       print STDERR "PPROXY: Doing ANONTLS Handshake\n";
+
+       my $psec = pack("C", $rfbSecTypeAnonTls);
+       syswrite($sock, $psec, 1);
+
+       append_handshake("done\n");
+}
+
+sub vencrypt_handshake {
+       
+       my ($vmode, $db) = @_;
+
+       print STDERR "PPROXY: Doing VeNCrypt Handshake\n";
+
+       my $psec = pack("C", $rfbSecTypeVencrypt);
+
+       if (exists $ENV{SSVNC_TEST_SEC_TYPE}) {
+               my $fake = $ENV{SSVNC_TEST_SEC_TYPE};
+               print STDERR "PPROXY: sending sec-type: $fake\n";
+               $psec = pack("C", $fake);
+       }
+
+       syswrite($sock, $psec, 1);
+
+       my $vmajor;
+       my $vminor;
+       sysread($sock, $vmajor, 1);
+       sysread($sock, $vminor, 1);
+
+       vdie if $vmajor eq "" || $vminor eq "";
+
+       $vmajor = unpack("C", $vmajor);
+       $vminor = unpack("C", $vminor);
+       print STDERR "server vencrypt version $vmajor.$vminor\n" if $db;
+
+       if (exists $ENV{SSVNC_TEST_SEC_TYPE}) {
+               print STDERR "PPROXY: continuing on in test mode.\n";
+       } else {
+               vdie if $vmajor ne 0;
+               vdie if $vminor < 2;
+       }
+
+       $vmajor = pack("C", 0);
+       $vminor = pack("C", 2);
+       append_handshake("subversion=0.2\n");
+
+       syswrite($sock, $vmajor, 1);
+       syswrite($sock, $vminor, 1);
+
+       my $result;
+       sysread($sock, $result, 1);
+       print STDERR "result empty\n" if $db && $result eq "";
+
+       vdie if $result eq "";
+       $result = unpack("C", $result);
+       print STDERR "result=$result\n" if $db;
+
+       vdie if $result ne 0;
+
+       my $nsubtypes;
+       sysread($sock, $nsubtypes, 1);
+
+       vdie if $nsubtypes eq "";
+       $nsubtypes = unpack("C", $nsubtypes);
+       print STDERR "nsubtypes=$nsubtypes\n" if $db;
+
+       my %subtypes;
+
+       for (my $i = 0; $i < $nsubtypes; $i++) {
+               my $subtype = ""; 
+               sysread($sock, $subtype, 4);
+               vdie if length($subtype) != 4;
+
+               # XXX fix 64bit.
+               $subtype = unpack("N", $subtype);
+               print STDERR "subtype: $subtype\n" if $db;
+               $subtypes{$subtype} = 1;
+               append_handshake("sst$i=$subtype\n");
+       }
+
+       my $subtype = 0;
+       if (exists $subtypes{$rfbVencryptX509None})  {
+               $subtype = $rfbVencryptX509None;
+               print STDERR "selected rfbVencryptX509None\n" if $db;
+       } elsif (exists $subtypes{$rfbVencryptX509Vnc})  {
+               $subtype = $rfbVencryptX509Vnc;
+               print STDERR "selected rfbVencryptX509Vnc\n" if $db;
+       } elsif (exists $subtypes{$rfbVencryptX509Plain})  {
+               $subtype = $rfbVencryptX509Plain;
+               print STDERR "selected rfbVencryptX509Plain\n" if $db;
+       } elsif (exists $subtypes{$rfbVencryptTlsNone})  {
+               $subtype = $rfbVencryptTlsNone;
+               print STDERR "selected rfbVencryptTlsNone\n" if $db;
+       } elsif (exists $subtypes{$rfbVencryptTlsVnc})  {
+               $subtype = $rfbVencryptTlsVnc;
+               print STDERR "selected rfbVencryptTlsVnc\n" if $db;
+       } elsif (exists $subtypes{$rfbVencryptTlsPlain})  {
+               $subtype = $rfbVencryptTlsPlain;
+               print STDERR "selected rfbVencryptTlsPlain\n" if $db;
+       }
+
+       if (exists $ENV{SSVNC_TEST_SEC_SUBTYPE}) {
+               my $fake = $ENV{SSVNC_TEST_SEC_SUBTYPE};
+               print STDERR "PPROXY: sending sec-subtype: $fake\n";
+               $subtype = $fake;
+       }
+
+       append_handshake("subtype=$subtype\n");
+
+       my $pst = pack("N", $subtype);
+       syswrite($sock, $pst, 4); 
+
+       if (exists $ENV{SSVNC_TEST_SEC_SUBTYPE}) {
+               print STDERR "PPROXY: continuing on in test mode.\n";
+       } else {
+               vdie if $subtype == 0;
+       }
+
+       my $ok;
+       sysread($sock, $ok, 1);
+       $ok = unpack("C", $ok);
+       print STDERR "ok=$ok\n" if $db;
+
+       append_handshake("done\n");
+
+       vdie if $ok == 0;
+}
+
+sub vencrypt_dialog {
+       my $vmode = shift;
+       my $db = 0;
+
+       $db = 1 if exists $ENV{SS_DEBUG};
+       $db = 1 if exists $ENV{SSVNC_VENCRYPT_DEBUG};
+
+       append_handshake("mode=$vmode\n");
+
+       my $server_rfb = "";
+       #syswrite($sock, $rep, 250);
+       for (my $i = 0; $i < 12; $i++) {
+               my $c;
+               sysread($sock, $c, 1);
+               $server_rfb .= $c;
+               print STDERR $c;
+       }
+       print STDERR "server_rfb: $server_rfb\n" if $db;
+       append_handshake("server=$server_rfb");
+
+       my $minor = "";
+       if ($server_rfb =~ /^RFB 003\.(\d+)/) {
+               $minor = $1;
+       } else {
+               vdie;
+       }
+       my $viewer_rfb = "RFB 003.008\n";
+       if ($minor < 7) {
+               vdie;
+       } elsif ($minor == 7) {
+               $viewer_rfb = "RFB 003.007\n";
+       }
+       syswrite($sock, $viewer_rfb, 12);
+       append_handshake("viewer=$viewer_rfb");
+
+       my $nsec;
+
+       sysread($sock, $nsec, 1);
+       vdie if $nsec eq "";
+
+       $nsec = unpack("C", $nsec);
+
+       print STDERR "nsec: $nsec\n" if $db;
+       vdie if $nsec eq 0 || $nsec > 100;
+
+       my %sectypes = ();
+
+       for (my $i = 0; $i < $nsec; $i++) {
+               my $sec;
+               sysread($sock, $sec, 1);
+               vdie if $sec eq "";
+               $sec = unpack("C", $sec);
+               print STDERR "sec: $sec\n" if $db;
+               $sectypes{$sec} = 1;
+       }
+       
+       if (exists $sectypes{$rfbSecTypeVencrypt}) {
+               print STDERR "found rfbSecTypeVencrypt\n" if $db;
+               append_handshake("sectype=$rfbSecTypeVencrypt\n");
+               vencrypt_handshake($vmode, $db);
+       } elsif (exists $sectypes{$rfbSecTypeAnonTls}) {
+               print STDERR "found rfbSecTypeAnonTls\n" if $db;
+               append_handshake("sectype=$rfbSecTypeAnonTls\n");
+               anontls_handshake($vmode, $db);
+       } else {
+               print STDERR "No supported sec-type found\n" if $db;
+               vdie;
+       }
+}
+
+sub xfer {
+       my($in, $out) = @_;
+       $RIN = $WIN = $EIN = "";
+       $ROUT = "";
+       vec($RIN, fileno($in), 1) = 1;
+       vec($WIN, fileno($in), 1) = 1;
+       $EIN = $RIN | $WIN;
+
+       while (1) {
+               my $nf = 0;
+               while (! $nf) {
+                       $nf = select($ROUT=$RIN, undef, undef, undef);
+               }
+               my $len = sysread($in, $buf, 8192);
+               if (! defined($len)) {
+                       next if $! =~ /^Interrupted/;
+                       print STDERR "pproxy\[$$]: $!\n";
+                       last;
+               } elsif ($len == 0) {
+                       print STDERR "pproxy\[$$]: Input is EOF.\n";
+                       last;
+               }
+               my $offset = 0;
+               my $quit = 0;
+               while ($len) {
+                       my $written = syswrite($out, $buf, $len, $offset);
+                       if (! defined $written) {
+                               print STDERR "pproxy\[$$]: Output is EOF. $!\n";
+                               $quit = 1;
+                               last;
+                       }
+                       $len -= $written;
+                       $offset += $written;
+               }
+               last if $quit;
+       }
+       close($in);
+       close($out);
+}
+'
+       # '
+       # xpg_echo will expand \n \r, etc.
+       # try to unset and then test for it.
+       if type shopt > /dev/null 2>&1; then
+               shopt -u xpg_echo >/dev/null 2>&1
+       fi
+       v='print STDOUT "abc\n";'
+       echo "$v" > $tf
+       chmod 700 $tf
+
+       lc=`wc -l $tf | awk '{print $1}'`
+       if [ "X$lc" = "X1" ]; then
+               echo "$cod" > $tf
+       else
+               printf "%s" "$cod" > $tf
+               echo "" >> $tf
+       fi
+       # prime perl
+       perl -e 'use IO::Socket::INET; select(undef, undef, undef, 0.01)' >/dev/null 2>&1
+}
+
+# make_tcert is no longer invoked via the ssvnc gui (Listen mode).
+# make_tcert is for testing only now via -mycert BUILTIN
+make_tcert() {
+       tcert="/tmp/ss_vnc_viewer_tcert${RANDOM}.$$"
+       tcert=`mytmp "$tcert"`
+       cat > $tcert <<END
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAvkfXxb0wcxgrjV2ziFikjII+ze8iKcTBt47L0GM/c21efelN
++zZpJUUXLu4zz8Ryq8Q+sQgfNy7uTOpN9bUUaOk1TnD7gaDQnQWiNHmqbW2kL+DS
+OKngJVPo9dETAS8hf7+D1e1DBZxjTc1a4RQqWJixwpYj99ixWzu8VC2m/xXsjvOs
+jp4+DLBB490nbkwvstmhmiWm1CmI5O5xOkgioVNQqHvQMdVKOSz9PpbjvZiRX1Uo
+qoMrk+2NOqwP90TB35yPASXb9zXKpO7DLhkube+yYGf+yk46aD707L07Eb7cosFP
+S84vNZ9gX7rQ0UOwm5rYA/oZTBskgaqhtIzkLwIDAQABAoIBAD4ot/sXt5kRn0Ca
+CIkU9AQWlC+v28grR2EQW9JiaZrqcoDNUzUqbCTJsi4ZkIFh2lf0TsqELbZYNW6Y
+6AjJM7al4E0UqYSKJTv2WCuuRxdiRs2BMwthqyBmjeanev7bB6V0ybt7u3Y8xU/o
+MrTuYnr4vrEjXPKdLirwk7AoDbKsRXHSIiHEIBOq1+dUQ32t36ukdnnza4wKDLZc
+PKHiCdCk/wOGhuDlxD6RspqUAlRnJ8/aEhrgWxadFXw1hRhRsf/v1shtB0T3DmTe
+Jchjwyiw9mryb9JZAcKxW+fUc4EVvj6VdQGqYInQJY5Yxm5JAlVQUJicuuJEvn6A
+rj5osQECgYEA552CaHpUiFlB4HGkjaH00kL+f0+gRF4PANCPk6X3UPDVYzKnzmuu
+yDvIdEETGFWBwoztUrOOKqVvPEQ+kBa2+DWWYaERZLtg2cI5byfDJxQ3ldzilS3J
+1S3WgCojqcsG/hlxoQJ1dZFanUy/QhUZ0B+wlC+Zp1Q8AyuGQvhHp68CgYEA0lBI
+eqq2GGCdJuNHMPFbi8Q0BnX55LW5C1hWjhuYiEkb3hOaIJuJrqvayBlhcQa2cGqp
+uP34e9UCfoeLgmoCQ0b4KpL2NGov/mL4i8bMgog4hcoYuIi3qxN18vVR14VKEh4U
+RLk0igAYPU+IK2QByaQlBo9OSaKkcfm7U1/pK4ECgYAxr6VpGk0GDvfF2Tsusv6d
+GIgV8ZP09qSLTTJvvxvF/lQYeqZq7sjI5aJD5i3de4JhpO/IXQJzfZfWOuGc8XKA
+3qYK/Y2IqXXGYRcHFGWV/Y1LFd55mCADHlk0l1WdOBOg8P5iRu/Br9PbiLpCx9oI
+vrOXpnp03eod1/luZmqguwKBgQCWFRSj9Q7ddpSvG6HCG3ro0qsNsUMTI1tZ7UBX
+SPogx4tLf1GN03D9ZUZLZVFUByZKMtPLX/Hi7K9K/A9ikaPrvsl6GEX6QYzeTGJx
+3Pw0amFrmDzr8ySewNR6/PXahxPEuhJcuI31rPufRRI3ZLah3rFNbRbBFX+klkJH
+zTnoAQKBgDbUK/aQFGduSy7WUT7LlM3UlGxJ2sA90TQh4JRQwzur0ACN5GdYZkqM
+YBts4sBJVwwJoxD9OpbvKu3uKCt41BSj0/KyoBzjT44S2io2tj1syujtlVUsyyBy
+/ca0A7WBB8lD1D7QMIhYUm2O9kYtSCLlUTHt5leqGaRG38DqlX36
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDzDCCArQCCQDSzxzxqhyqLzANBgkqhkiG9w0BAQQFADCBpzELMAkGA1UEBhMC
+VVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxDzANBgNVBAcTBkJvc3RvbjETMBEG
+A1UEChMKTXkgQ29tcGFueTEcMBoGA1UECxMTUHJvZHVjdCBEZXZlbG9wbWVudDEZ
+MBcGA1UEAxMQd3d3Lm5vd2hlcmUubm9uZTEhMB8GCSqGSIb3DQEJARYSYWRtaW5A
+bm93aGVyZS5ub25lMB4XDTA3MDMyMzE4MDc0NVoXDTI2MDUyMjE4MDc0NVowgacx
+CzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNldHRzMQ8wDQYDVQQHEwZC
+b3N0b24xEzARBgNVBAoTCk15IENvbXBhbnkxHDAaBgNVBAsTE1Byb2R1Y3QgRGV2
+ZWxvcG1lbnQxGTAXBgNVBAMTEHd3dy5ub3doZXJlLm5vbmUxITAfBgkqhkiG9w0B
+CQEWEmFkbWluQG5vd2hlcmUubm9uZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAL5H18W9MHMYK41ds4hYpIyCPs3vIinEwbeOy9BjP3NtXn3pTfs2aSVF
+Fy7uM8/EcqvEPrEIHzcu7kzqTfW1FGjpNU5w+4Gg0J0FojR5qm1tpC/g0jip4CVT
+6PXREwEvIX+/g9XtQwWcY03NWuEUKliYscKWI/fYsVs7vFQtpv8V7I7zrI6ePgyw
+QePdJ25ML7LZoZolptQpiOTucTpIIqFTUKh70DHVSjks/T6W472YkV9VKKqDK5Pt
+jTqsD/dEwd+cjwEl2/c1yqTuwy4ZLm3vsmBn/spOOmg+9Oy9OxG+3KLBT0vOLzWf
+YF+60NFDsJua2AP6GUwbJIGqobSM5C8CAwEAATANBgkqhkiG9w0BAQQFAAOCAQEA
+vGomHEp6TVU83X2EBUgnbOhzKJ9u3fOI/Uf5L7p//Vxqow7OR1cguzh/YEzmXOIL
+ilMVnzX9nj/bvcLAuqEP7MR1A8f4+E807p/L/Sf49BiCcwQq5I966sGKYXjkve+T
+2GTBNwMSq+5kLSf6QY8VZI+qnrAudEQMeJByQhTZZ0dH8Njeq8EGl9KUio+VWaiW
+CQK6xJuAvAHqa06OjLmwu1fYD4GLGSrOIiRVkSXV8qLIUmzxdJaIRznkFWsrCEKR
+wAH966SAOvd2s6yOHMvyDRIL7WHxfESB6rDHsdIW/yny1fBePjv473KrxyXtbz7I
+dMw1yW09l+eEo4A7GzwOdw==
+-----END CERTIFICATE-----
+END
+       chmod 600 $tcert
+       echo "$tcert"
+}
+
+Kecho() {
+       if [ "X$USER" = "Xrunge" ]; then
+               echo "dbg: $*"
+       fi
+}
+
+if [ "X$use_ssh" = "X1" ]; then
+       #
+       # USING SSH
+       #
+       ssh_port="22"
+       ssh_host="$host"
+       vnc_host="$localhost"
+       # let user override ssh via $SSH
+       ssh=${SSH:-"ssh -x"}
+
+       if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ]; then
+               SSVNC_LIM_ACCEPT_PRELOAD="$SSVNC_BASEDIR/$SSVNC_UNAME/$SSVNC_LIM_ACCEPT_PRELOAD"
+       fi
+       if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ]; then
+               echo ""
+               echo "SSVNC_LIM_ACCEPT_PRELOAD=$SSVNC_LIM_ACCEPT_PRELOAD"
+       fi
+
+       if [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" -a -f "$SSVNC_LIM_ACCEPT_PRELOAD" ]; then
+               plvar=LD_PRELOAD
+               if uname | grep Darwin >/dev/null; then
+                       plvar="DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES"
+               fi
+               ssh="env $plvar=$SSVNC_LIM_ACCEPT_PRELOAD $ssh"
+       else
+               SSVNC_LIM_ACCEPT_PRELOAD=""
+       fi
+
+       if echo "$proxy" | egrep '(http|https|socks|socks4|socks5)://' > /dev/null; then
+               # Handle Web or SOCKS proxy(ies) for the initial connect.
+               Kecho host=$host
+               Kecho port=$port
+               pproxy=""
+               sproxy1=""
+               sproxy_rest=""
+               for part in `echo "$proxy" | tr ',' ' '`
+               do
+                       Kecho proxy_part=$part
+                       if [ "X$part" = "X" ]; then
+                               continue
+                       elif echo "$part" | egrep -i '^(http|https|socks|socks4|socks5)://' > /dev/null; then
+                               pproxy="$pproxy,$part"
+                       else
+                               if [ "X$sproxy1" = "X" ]; then
+                                       sproxy1="$part"
+                               else
+                                       sproxy_rest="$sproxy_rest,$part"
+                               fi
+                       fi
+               done
+               pproxy=`echo "$pproxy" | sed -e 's/^,,*//' -e 's/,,*/,/g'`
+               sproxy_rest=`echo "$sproxy_rest" | sed -e 's/^,,*//' -e 's/,,*/,/g'`
+
+               Kecho pproxy=$pproxy
+               Kecho sproxy1=$sproxy1
+               Kecho sproxy_rest=$sproxy_rest
+
+               sproxy1_host=""
+               sproxy1_port=""
+               sproxy1_user=""
+
+               if [ "X$sproxy1" != "X" ]; then
+                       sproxy1_host=`echo "$sproxy1" | awk -F: '{print $1}'`
+                       sproxy1_user=`echo "$sproxy1_host" | awk -F@ '{print $1}'`
+                       sproxy1_host=`echo "$sproxy1_host" | awk -F@ '{print $2}'`
+                       if [ "X$sproxy1_host" = "X" ]; then
+                               sproxy1_host=$sproxy1_user
+                               sproxy1_user=""
+                       else
+                               sproxy1_user="${sproxy1_user}@"
+                       fi
+                       sproxy1_port=`echo "$sproxy1" | awk -F: '{print $2}'`
+                       if [ "X$sproxy1_port" = "X" ]; then
+                               sproxy1_port="22"
+                       fi
+               else
+                       sproxy1_host=`echo "$host" | awk -F: '{print $1}'`
+                       sproxy1_user=`echo "$sproxy1_host" | awk -F@ '{print $1}'`
+                       sproxy1_host=`echo "$sproxy1_host" | awk -F@ '{print $2}'`
+                       if [ "X$sproxy1_host" = "X" ]; then
+                               sproxy1_host=$sproxy1_user
+                               sproxy1_user=""
+                       else
+                               sproxy1_user="${sproxy1_user}@"
+                       fi
+                       sproxy1_port=`echo "$host" | awk -F: '{print $2}'`
+                       if [ "X$sproxy1_port" = "X" ]; then
+                               sproxy1_port="22"
+                       fi
+               fi
+
+               Kecho sproxy1_host=$sproxy1_host
+               Kecho sproxy1_port=$sproxy1_port
+               Kecho sproxy1_user=$sproxy1_user
+
+               ptmp="/tmp/ss_vncviewer_ssh${RANDOM}.$$.pl"
+               ptmp=`mytmp "$ptmp"`
+               PPROXY_REMOVE=1; export PPROXY_REMOVE
+               proxy=$pproxy
+               port_save=$port
+               host_save=$host
+               if [ "X$sproxy1_host" != "X" ]; then
+                       host=$sproxy1_host
+               fi
+               if [ "X$sproxy1_port" != "X" ]; then
+                       port=$sproxy1_port
+               fi
+               host=`echo "$host" | sed -e 's/^.*@//'`
+               port=`echo "$port" | sed -e 's/^.*://'`
+               pcode "$ptmp"
+               port=$port_save
+               host=$host_save
+
+               nd=`findfree 6700`
+               PPROXY_LISTEN=$nd; export PPROXY_LISTEN
+               $ptmp &
+               sleep 2
+               ssh_args="$ssh_args -o NoHostAuthenticationForLocalhost=yes"
+               if [ "X$sproxy1" = "X" ]; then
+                       u=""
+                       if echo "$host" | grep '@' > /dev/null; then
+                               u=`echo "$host" | sed -e 's/@.*$/@/'`
+                       fi
+                       
+                       proxy="${u}$localhost:$nd"
+               else
+                       proxy="${sproxy1_user}$localhost:$nd"
+               fi
+               if [ "X$sproxy_rest" != "X" ]; then
+                       proxy="$proxy,$sproxy_rest"
+               fi
+               Kecho proxy=$proxy
+       fi
+
+       if echo "$proxy" | grep "," > /dev/null; then
+
+               proxy1=`echo "$proxy" | awk -F, '{print $1}'`
+               proxy2=`echo "$proxy" | awk -F, '{print $2}'`
+
+               # user1@gw1.com:port1,user2@ws2:port2
+               ssh_host1=`echo "$proxy1" | awk -F: '{print $1}'`
+               ssh_port1=`echo "$proxy1" | awk -F: '{print $2}'`
+               if [ "X$ssh_port1" != "X" ]; then
+                       ssh_port1="-p $ssh_port1"
+               fi
+               ssh_host2=`echo "$proxy2" | awk -F: '{print $1}'`
+               ssh_user2=`echo "$ssh_host2" | awk -F@ '{print $1}'`
+               ssh_host2=`echo "$ssh_host2" | awk -F@ '{print $2}'`
+               if [ "X$ssh_host2" = "X" ]; then
+                       ssh_host2=$ssh_user2
+                       ssh_user2=""
+               else
+                       ssh_user2="${ssh_user2}@"
+               fi
+               ssh_port2=`echo "$proxy2" | awk -F: '{print $2}'`
+               if [ "X$ssh_port2" = "X" ]; then
+                       ssh_port2="22"
+               fi
+               proxport=`findfree 3500`
+               echo
+               echo "Running 1st ssh proxy:"
+               echo "$ssh -f -x $ssh_port1 $targ -e none -o NoHostAuthenticationForLocalhost=yes -L $proxport:$ssh_host2:$ssh_port2 $ssh_host1 \"sleep 30\""
+               echo ""
+                     $ssh -f -x $ssh_port1 $targ -e none -o NoHostAuthenticationForLocalhost=yes -L $proxport:$ssh_host2:$ssh_port2 $ssh_host1 "sleep 30"
+               ssh_args="$ssh_args -o NoHostAuthenticationForLocalhost=yes"
+               sleep 1
+               stty sane
+               proxy="${ssh_user2}$localhost:$proxport"
+       fi
+
+       if [ "X$proxy" != "X" ]; then
+               ssh_port=`echo "$proxy" | awk -F: '{print $2}'`
+               if [ "X$ssh_port" = "X" ]; then
+                       ssh_port="22"
+               fi
+               ssh_host=`echo "$proxy" | awk -F: '{print $1}'`
+               vnc_host="$host"
+       fi
+
+       echo ""
+       echo "Running ssh:"
+       sz=`echo "$ssh_cmd" | wc -c`
+       if [ "$sz" -gt 300 ]; then
+               info="..."
+       else
+               info="$ssh_cmd"
+       fi
+
+       C=""
+       if [ "X$SS_VNCVIEWER_USE_C" != "X" ]; then
+               C="-C"
+       fi
+
+       getport=""
+       teeport=""
+       if echo "$ssh_cmd" | egrep "(PORT=|P=) " > /dev/null; then
+               getport=1
+               if echo "$ssh_cmd" | egrep "P= " > /dev/null; then
+                       teeport=1
+               fi
+
+               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$ssh_port" = "X22" ]; then
+               ssh_port=""
+       else
+               ssh_port="-p $ssh_port"
+       fi
+
+       if [ "X$SS_VNCVIEWER_SSH_ONLY" != "X" ]; then
+               echo "$ssh -x $ssh_port $targ $C $ssh_args $ssh_host \"$info\""
+               echo ""
+               $ssh -x $ssh_port $targ $C $ssh_args $ssh_host "$ssh_cmd"
+               exit $?
+
+       elif [ "X$SS_VNCVIEWER_NO_F" != "X" ]; then
+               echo "$ssh -x $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\""
+               echo ""
+               $ssh -x $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd"
+               rc=$?
+
+       elif [ "X$getport" != "X" ]; then
+               tport=/tmp/ss_vncviewer_tport${RANDOM}.$$
+               tport=`mytmp "$tport"`
+
+               if [ "X$rsh" != "X1" ]; then
+                       if echo "$ssh_cmd" | grep "sudo " > /dev/null; then
+                               echo ""
+                               echo "Initial ssh with 'sudo id' to prime sudo so hopefully the next one"
+                               echo "will require no password..."
+                               echo ""
+                               targ="-t"
+                               $ssh -x $ssh_port $targ $ssh_args $ssh_host "sudo id; tty"
+                               echo ""
+                       fi
+                       echo "$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\""
+                       echo ""
+                       $ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd" > $tport 
+                       if [ "X$teeport" = "X1" ]; then
+                               tail -f $tport 1>&2 &
+                               tail_pid=$!
+                       fi
+                       rc=$?
+               else
+                       rsh_setup
+                       echo "rsh $ul $ssh_host \"$ssh_cmd\""
+                       echo ""
+                       rsh $ul $ssh_host "$ssh_cmd" > $tport &
+                       sleep 1
+                       rc=0
+               fi
+
+               if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
+                       echo "sleep $SSVNC_EXTRA_SLEEP"
+                       sleep $SSVNC_EXTRA_SLEEP
+               fi
+
+               stty sane
+               i=0
+               if type perl > /dev/null 2>&1; then
+                       imax=50
+                       sleepit="perl -e 'select(undef, undef, undef, 0.20)'"
+               else
+                       imax=10
+                       sleepit="sleep 1"
+               fi
+               while [ $i -lt $imax ]; do
+                       #echo $sleepit
+                       eval $sleepit
+                       PORT=`grep "^PORT=" $tport | head -n 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 -n 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
+               rm -f $tport
+               if [ "X$rsh" = "X1" ]; then
+                       rsh_viewer "$@"
+                       exit $?
+               fi
+               PPROXY_SOCKS=1
+               if [ "X$SSVNC_SOCKS5" != "X" ]; then
+                       PPROXY_SOCKS=5
+               fi
+               export PPROXY_SOCKS
+               host="$localhost"
+               port="$PORT"
+               proxy="$localhost:$use"
+
+       else
+               if [ "X$rsh" != "X1" ]; then
+                       echo "$ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host \"$info\""
+                       echo ""
+                       $ssh -x -f $ssh_port $targ $C $ssh_redir $ssh_args $ssh_host "$ssh_cmd"
+                       rc=$?
+               else
+                       rsh_setup
+                       echo "rsh $ul $ssh_host \"$ssh_cmd\""
+                       echo ""
+                       rsh $ul $ssh_host "$ssh_cmd" &
+                       sleep 1
+                       PORT=$port
+                       rsh_viewer "$@"
+                       exit $?
+               fi
+       fi
+
+       if [ "$rc" != "0" ]; then
+               echo ""
+               echo "ssh to $ssh_host failed."
+               exit 1
+       fi
+       stty sane
+
+       c=0
+       pssh=""
+       while [ $c -lt 40 ]
+       do
+               p=`expr $pmark + $c`
+               pout=`ps -p "$p" 2>/dev/null | grep -v '^[      ]*PID' | sed -e 's/-L.*$//' -e 's/-x .*$//'`
+               if echo "$pout" | grep "ssh" > /dev/null; then
+                       if echo "$pout" | egrep -i 'ssh.*(-add|-agent|-ask|-keygen|-argv0|vnc)' >/dev/null; then
+                               :
+                       elif echo "$pout" | egrep -i 'scp|sshd' >/dev/null; then
+                               :
+                       else
+                               pssh=$p
+                               break
+                       fi
+               fi
+               c=`expr $c + 1`
+       done
+       if [ "X$getport" != "X" ]; then
+               :
+       elif [ "X$SSVNC_LIM_ACCEPT_PRELOAD" != "X" ] ; then
+               sleep 2
+       elif [ "X$ssh_cmd" = "Xsleep $ssh_sleep" ] ; then
+               #echo T sleep 1
+               sleep 1
+       elif echo "$ssh_cmd" | grep '^sleep ' >/dev/null; then
+               #echo T sleep 2
+               sleep 2
+       else
+               # let any command get started a bit.
+               #echo T sleep 5
+               sleep 5
+       fi
+       echo ""
+       #reset
+       stty sane
+       if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
+               echo "sleep $SSVNC_EXTRA_SLEEP"
+               sleep $SSVNC_EXTRA_SLEEP
+       fi
+       echo "ssh_pid='$pssh'"; echo
+       if [ "X$use_sshssl" = "X" -a "X$getport" = "X" ]; then
+               echo "Running viewer:"
+
+               trap "final" 0 2 15
+               if [ "X$reverse" = "X" ]; then
+                       echo "$VNCVIEWERCMD" "$@" $localhost:$N
+                       echo ""
+                       $VNCVIEWERCMD "$@" $localhost:$N
+                       if [ $? != 0 ]; then
+                               echo "vncviewer command failed: $?"
+                               if [ "X$secondtry" = "X1" ]; then
+                                       sleep 2
+                                       $VNCVIEWERCMD "$@" $localhost:$N
+                               fi
+                       fi
+               else
+                       echo ""
+                       echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode."
+                       echo ""
+                       N2=$N
+                       if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then
+                               N2=`echo "$N2" | sed -e 's/://g'`
+                               if [ $N2 -le 200 ]; then
+                                       N2=`expr $N2 + 5500`
+                               fi
+                       fi
+                       echo "$VNCVIEWERCMD" "$@" -listen $N2
+                       echo ""
+                       $VNCVIEWERCMD "$@" -listen $N2
+               fi
+
+               exit $?
+       else
+               use2=`findfree 5960`
+               host0=$host
+               port0=$port
+               host=$localhost
+               port=$use
+               use=$use2
+               N=`expr $use - 5900`
+               if [ "X$getport" != "X" ]; then
+                       host="$host0"
+                       port="$port0"
+               else
+                       proxy=""
+               fi
+       fi
+fi
+
+# create the stunnel config file:
+if [ "X$verify" != "X" ]; then
+       if [ -d $verify ]; then
+               verify="CApath = $verify"
+       else
+               verify="CAfile = $verify"
+       fi
+       verify="$verify
+verify = 2"
+fi
+if [ "X$mycert" != "X" ]; then
+       cert="cert = $mycert"
+fi
+if [ "X$crl" != "X" ]; then
+       if [ -d $crl ]; then
+               crl="CRLpath = $crl"
+       else
+               crl="CRLfile = $crl"
+       fi
+fi
+
+ptmp=""
+if [ "X$proxy" != "X" ]; then
+       ptmp="/tmp/ss_vncviewer${RANDOM}.$$.pl"
+       ptmp=`mytmp "$ptmp"`
+       PPROXY_REMOVE=1; export PPROXY_REMOVE
+       pcode "$ptmp"
+       if [ "X$showcert" != "X1" -a "X$direct_connect" = "X" ]; then
+               if uname | egrep 'Darwin|SunOS' >/dev/null; then
+                       vout=`echo "$proxy" | grep -i vencrypt`
+                       if [ "X$vout" != "X" -a "X$reverse" = "X1" ]; then
+                               # need to exec for reverse vencrypt
+                               connect="exec = $ptmp"
+                       else
+                               # on mac and solaris we need to listen on socket instead of stdio:
+                               nd=`findfree 6700`
+                               PPROXY_LISTEN=$nd
+                               export PPROXY_LISTEN
+                               if [ "X$reverse" = "X" ]; then
+                                       #$ptmp 2>/dev/null &
+                                       $ptmp &
+                               fi
+                               sleep 2
+                               host="$localhost"
+                               port="$nd"
+                               connect="connect = $localhost:$nd"
+                       fi
+               else
+                       # otherwise on unix we can exec it:
+                       connect="exec = $ptmp"
+               fi
+       else
+               connect="exec = $ptmp"
+       fi
+else
+       connect="connect = $host:$port"
+fi
+
+if [ "X$showcert" = "X1" ]; then
+       if [ "X$proxy" != "X" ]; then
+               PPROXY_LISTEN=$use
+               export PPROXY_LISTEN
+               if [ "X$SS_DEBUG" != "X" ]; then
+                       $ptmp &
+               else
+                       $ptmp 2>/dev/null &
+               fi
+               sleep 1
+               host="$localhost"
+               port="$use"
+       fi
+       cipher_args=""
+       if [ "X$ciphers" != "X" ]; then
+               cipher_args=`echo "$ciphers" | sed -e 's/ciphers=/-cipher /'`
+       fi
+       #echo "openssl s_client $cipher_args -connect $host:$port" 
+       if [ "X$reverse" = "X" ]; then
+               openssl s_client $cipher_args -prexit -connect $host:$port 2>&1 < /dev/null
+               rc=$?
+       else
+               tcert=""
+               if [ "X$mycert" = "X" ]; then
+                       tcert=`make_tcert`
+                       cert_args="-cert $tcert -CAfile $tcert"
+               else
+                       cert_args="-cert $mycert -CAfile $mycert"
+               fi
+               tmp_out=/tmp/showcert_out${RANDOM}.$$
+               tmp_out=`mytmp "$tmp_out"`
+               tmp_err=/tmp/showcert_err${RANDOM}.$$
+               tmp_err=`mytmp "$tmp_err"`
+
+               #echo "openssl s_server $cipher_args $cert_args -accept $port -verify 2 > $tmp_out 2> $tmp_err" 1>&2
+
+               perl -e "
+                       \$p = open(O, \"|openssl s_server $cipher_args $cert_args -accept $port -verify 2 1>$tmp_out 2> $tmp_err\");
+                       exit 1 unless \$p;
+                       while (1) {
+                               sleep 1;
+                               if (!open(F, \"<$tmp_out\")) {
+                                       kill \$p;
+                                       exit 1;
+                               }
+                               while (<F>) {
+                                       if (/RFB 00/) {
+                                               fsleep(0.25);
+                                               print O \"RFB 000.000\\n\";
+                                               fsleep(1.00);
+                                               kill \$p;
+                                               fsleep(0.25);
+                                               exit 0;
+                                       }
+                               }
+                               close F;
+                       }
+                       sub fsleep {
+                               select(undef, undef, undef, shift);
+                       }
+               ";
+
+               echo ""
+               cat $tmp_out
+               echo ""
+               echo "----2----"
+               cat $tmp_err
+               if grep BEGIN.CERTIFICATE $tmp_out >/dev/null; then
+                       rc=0
+               else
+                       rc=1
+               fi
+
+               rm -f $tmp_out $tmp_err
+       fi
+       if [ "X$SSVNC_PREDIGESTED_HANDSHAKE" != "X" ]; then
+               rm -f $SSVNC_PREDIGESTED_HANDSHAKE
+       fi
+       exit $rc
+fi
+
+if [ "X$direct_connect" != "X" ]; then
+       if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
+               SSVNC_NO_ENC_WARN=1
+               echo ""
+               echo "Using UltraVNC DSM Plugin key for encryption:"
+               echo ""
+               ustr=`echo "$SSVNC_ULTRA_DSM" | sed -e 's/pw=[^ ]*/pw=******/g'`
+               echo "  $ustr PORT HOST:PORT"
+               echo ""
+       elif [ "X$getport" = "X" ]; then
+               echo ""
+               echo "Running viewer for direct connection:"
+               if echo X"$@" | grep chatonly > /dev/null; then
+                       :
+               else
+                       echo ""
+                       echo "** NOTE: THERE WILL BE NO SSL OR SSH ENCRYPTION **"
+                       echo ""
+               fi
+       fi
+       x=""
+       if [ "X$SSVNC_NO_ENC_WARN" != "X" ]; then
+               if [ "X$getport" = "X" ]; then
+                       sleep 1
+               fi
+       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
+       if [ "X$x" = "Xn" ]; then
+               exit 1
+       fi
+       echo ""
+       if [ "X$ptmp" != "X" ]; then
+               if [ "X$reverse" = "X" ]; then
+                       PPROXY_LISTEN=$use
+                       export PPROXY_LISTEN
+               else
+                       PPROXY_REVERSE="$localhost:$use"
+                       export PPROXY_REVERSE
+                       pps=3
+                       if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
+                               pps=`expr $pps + $SSVNC_EXTRA_SLEEP`
+                       fi
+                       PPROXY_SLEEP=$pps; export PPROXY_SLEEP;
+                       PPROXY_KILLPID=+1; export PPROXY_KILLPID;
+               fi
+
+               $ptmp &
+
+               if [ "X$reverse" = "X" ]; then
+                       #sleep 2
+                       #echo T sleep 1
+                       sleep 1
+               fi
+               host="$localhost"
+               disp="$N"
+               port=`expr $disp + 5900`
+       fi
+       if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
+               echo "T sleep $SSVNC_EXTRA_SLEEP"
+               sleep $SSVNC_EXTRA_SLEEP
+       fi
+       if [ "X$reverse" = "X" ]; then
+               hostdisp="$host:$disp"
+               if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
+                       if [ "X$SSVNC_USE_OURS" = "X1" ]; then
+                               hostdisp="exec=$SSVNC_ULTRA_DSM 0 $host:$port"
+                       else
+                               pf=`findfree 5970`
+                               cmd="$SSVNC_ULTRA_DSM -$pf $host:$port"
+                               pf=`expr $pf - 5900`
+                               hostdisp="$localhost:$pf"
+                               ustr=`echo "$cmd" | sed -e 's/pw=[^ ]*/pw=******/g'`
+                               echo "Running:"
+                               echo
+                               echo "$ustr &"
+                               echo
+                               $cmd &
+                               dsm_pid=$!
+                               sleep 2
+                       fi
+               fi
+               hostdisp2=`echo "$hostdisp" | sed -e 's/pw=[^ ]*/pw=******/g'`
+               echo "$VNCVIEWERCMD" "$@" "$hostdisp2"
+               trap "final" 0 2 15
+               echo ""
+               $VNCVIEWERCMD "$@" "$hostdisp"
+               if [ $? != 0 ]; then
+                       echo "vncviewer command failed: $?"
+                       if [ "X$secondtry" = "X1" ]; then
+                               sleep 2
+                               $VNCVIEWERCMD "$@" "$hostdisp"
+                       fi
+               fi
+       else
+               echo ""
+               echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode."
+               echo ""
+               trap "final" 0 2 15
+               if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
+                       echo "NOTE: The ultravnc_dsm_helper only runs once.  So after the first LISTEN"
+                       echo "      ends, you may have to Press Ctrl-C and restart for another connection."
+                       echo ""
+                       SSVNC_LISTEN_ONCE=1; export SSVNC_LISTEN_ONCE
+                       VNCVIEWER_LISTEN_LOCALHOST=1
+                       export VNCVIEWER_LISTEN_LOCALHOST
+                       dport=`expr 5500 + $disp`
+                       cmd="$SSVNC_ULTRA_DSM $dport $localhost:$use"
+                       ustr=`echo "$cmd" | sed -e 's/pw=[^ ]*/pw=******/g'`
+                       echo "Running:"
+                       echo
+                       echo "$ustr &"
+                       echo
+                       $cmd &
+                       dsm_pid=$!
+                       sleep 2
+                       disp=$use
+                       if [ $disp -ge 5500 ]; then
+                               disp=`expr $disp - 5500`
+                       fi
+               fi
+               disp2=$disp
+               if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then
+                       disp2=`echo "$disp2" | sed -e 's/://g'`
+                       if [ $disp2 -le 200 ]; then
+                               disp2=`expr $disp2 + 5500`
+                       fi
+               fi
+               echo "$VNCVIEWERCMD" "$@" -listen $disp2
+               echo ""
+               $VNCVIEWERCMD "$@" -listen $disp2
+       fi
+       exit $?
+fi
+
+tmp_cfg=/tmp/ss_vncviewer${RANDOM}.$$
+tmp_cfg=`mytmp "$tmp_cfg"`
+
+stunnel_exec=""
+if [ "X$SSVNC_USE_OURS" != "X1" ]; then
+       :
+elif echo $STUNNEL_EXTRA_SVC_OPTS | grep '#stunnel-exec' > /dev/null; then
+       stunnel_exec="#"
+fi
+
+if [ "X$reverse" = "X" ]; then
+
+       if echo "$proxy" | grep "^repeater://" > /dev/null; then
+               if [ "X$cert" = "XBUILTIN" ]; then
+                       ttcert=`make_tcert`
+                       cert="cert = $ttcert"
+               fi
+               # Note for listen mode, an empty cert will cause stunnel to fail.
+               # The ssvnc gui will have already taken care of this.
+       fi
+
+       cat > "$tmp_cfg" <<END
+foreground = yes
+pid =
+client = yes
+debug = $stunnel_debug
+$ciphers
+$STUNNEL_EXTRA_OPTS
+$STUNNEL_EXTRA_OPTS_USER
+$cert
+$crl
+$verify
+
+${stunnel_exec}[vnc_stunnel]
+${stunnel_exec}accept = $localhost:$use
+$connect
+$STUNNEL_EXTRA_SVC_OPTS
+$STUNNEL_EXTRA_SVC_OPTS_USER
+
+END
+
+else
+       # REVERSE case:
+
+       stunnel_exec="" # doesn't work for listening.
+
+       p2=`expr 5500 + $N`
+       connect="connect = $localhost:$p2"
+       if [ "X$cert" = "XBUILTIN" ]; then
+               ttcert=`make_tcert`
+               cert="cert = $ttcert"
+       fi
+       # Note for listen mode, an empty cert will cause stunnel to fail.
+       # The ssvnc gui will have already taken care of this.
+
+
+       hloc=""
+       if [ "X$use_ssh" = "X1" ]; then
+               hloc="$localhost:"
+       fi
+       if echo "$proxy" | grep -i '^vencrypt:' > /dev/null; then
+               hloc="$localhost:"
+               pv=`findfree 5570`
+               proxy="vencrypt:$pv:$port"
+               port=$pv
+               if [ "X$anondh_set" = "X1" ]; then
+                       # not needed for ANONDH in this mode
+                       #ciphers="ciphers = ADH:@STRENGTH"
+                       :
+               fi
+       fi
+       cat > "$tmp_cfg" <<END
+foreground = yes
+pid =
+client = no
+debug = $stunnel_debug
+$ciphers
+$STUNNEL_EXTRA_OPTS
+$STUNNEL_EXTRA_OPTS_USER
+$cert
+$crl
+$verify
+
+[vnc_stunnel]
+accept = $hloc$port
+$connect
+$STUNNEL_EXTRA_SVC_OPTS
+$STUNNEL_EXTRA_SVC_OPTS_USER
+
+END
+
+fi
+
+echo ""
+echo "Using this stunnel configuration:"
+echo ""
+cat "$tmp_cfg" | uniq
+echo ""
+sleep 1
+
+if [ "X$stunnel_exec" = "X" ]; then
+       echo ""
+       echo "Running stunnel:"
+       echo "$STUNNEL $tmp_cfg"
+       st=`echo "$STUNNEL" | awk '{print $1}'`
+       $st -help > /dev/null 2>&1
+       $STUNNEL "$tmp_cfg" < /dev/tty > /dev/tty &
+       stunnel_pid=$!
+       echo ""
+
+       # pause here to let the user supply a possible passphrase for the
+       # mycert key:
+       if [ "X$mycert" != "X" ]; then
+               nsl=10
+               dsl=0
+               if [ ! -f $mycert ]; then
+                       dsl=0
+               elif grep -i 'Proc-Type.*ENCRYPTED' "$mycert" > /dev/null 2>/dev/null; then
+                       dsl=1
+               fi
+               if [ "X$dsl" = "X1" ]; then
+                       echo ""
+                       echo "(** pausing $nsl secs for possible certificate passphrase dialog **)"
+                       echo ""
+                       sleep $nsl
+                       echo "(** done pausing for passphrase **)"
+                       echo ""
+               fi
+       fi
+       #echo T sleep 1
+       sleep 1
+       rm -f "$tmp_cfg"
+fi
+
+
+echo ""
+if [ "X$SSVNC_EXTRA_SLEEP" != "X" ]; then
+       echo "sleep $SSVNC_EXTRA_SLEEP"
+       sleep $SSVNC_EXTRA_SLEEP
+fi
+echo "Running viewer:"
+if [ "X$reverse" = "X" ]; then
+       vnc_hp=$localhost:$N
+       if [ "X$stunnel_exec" != "X" ]; then
+               vnc_hp="exec=$STUNNEL $tmp_cfg"
+       fi
+       echo "$VNCVIEWERCMD" "$@" "$vnc_hp"
+       trap "final" 0 2 15
+       echo ""
+       $VNCVIEWERCMD "$@" "$vnc_hp"
+       if [ $? != 0 ]; then
+               echo "vncviewer command failed: $?"
+               if [ "X$secondtry" = "X1" ]; then
+                       sleep 2
+                       $VNCVIEWERCMD "$@" "$vnc_hp"
+               fi
+       fi
+else
+       echo ""
+       echo "NOTE: Press Ctrl-C to terminate viewer LISTEN mode."
+       echo ""
+       N2=$N
+       if [ "X$VNCVIEWER_IS_REALVNC4" = "X1" ]; then
+               N2=`echo "$N2" | sed -e 's/://g'`
+               if [ $N2 -le 200 ]; then
+                       N2=`expr $N2 + 5500`
+               fi
+       fi
+       echo "$VNCVIEWERCMD" "$@" -listen $N2
+       trap "final" 0 2 15
+       echo ""
+       if [ "X$proxy" != "X" ]; then
+               if echo "$proxy" | grep -i '^vencrypt:' > /dev/null; then
+                       pstunnel=`echo "$proxy" | awk -F: '{print $2}'`
+                       plisten=`echo "$proxy" | awk -F: '{print $3}'`
+                       PPROXY_LISTEN="INADDR_ANY:$plisten"; export PPROXY_LISTEN
+                       PPROXY_PROXY="vencrypt://$localhost:$pstunnel"; export PPROXY_PROXY
+                       PPROXY_DEST="$localhost:$pstunnel"; export PPROXY_DEST
+                       STUNNEL_ONCE=1; export STUNNEL_ONCE
+                       STUNNEL_MAX_CLIENTS=1; export STUNNEL_MAX_CLIENTS
+               else
+                       PPROXY_REVERSE="$localhost:$port"; export PPROXY_REVERSE
+                       PPROXY_SLEEP=1; export PPROXY_SLEEP;
+               fi
+               PPROXY_KILLPID=+1; export PPROXY_KILLPID;
+               $ptmp &
+       fi
+       $VNCVIEWERCMD "$@" -listen $N2
+fi
+
+sleep 1