#!/bin/bash
#
# ss_vncviewer:  wrapper for vncviewer to use an stunnel SSL tunnel
#                or an SSH tunnel.
#
# Copyright (c) 2006-2009 by Karl J. Runge <runge@karlrunge.com>
#
# ss_vncviewer 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; either version 2 of the License, or (at
# your option) any later version.
# 
# ss_vncviewer 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 ss_vncviewer; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
# or see <http://www.gnu.org/licenses/>.
# 
# 
# 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).  On ssvnc 1.0.27 and
#            later the bundled command 'ultravnc_dsm_helper' is used.
#
#    See http://www.karlrunge.com/x11vnc/faq.html#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}
if [ "X$SSVNC_TURBOVNC" != "X" ]; then
	if echo "$VNCVIEWERCMD" | grep '\.turbovnc' > /dev/null; then
		:
	else
		if type "$VNCVIEWERCMD.turbovnc" > /dev/null 2>/dev/null; then
			VNCVIEWERCMD="$VNCVIEWERCMD.turbovnc"
		fi
	fi
fi
#
# Same for STUNNEL, e.g. set it to /path/to/stunnel or stunnel4, etc.
#

# turn on verbose debugging output
if [ "X$SS_DEBUG" != "X" -a "X$SS_DEBUG" != "X0" ]; 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)
stunnel_set_here=""
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
	stunnel_set_here=1
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 'VNC viewer version 3' > /dev/null; then
		echo "realvnc3"
	elif echo "$str" | grep -i 'VNC viewer .*Edition 4' > /dev/null; then
		echo "realvnc4"
	elif echo "$str" | grep -i 'RealVNC.Ltd' > /dev/null; then
		echo "realvnc4"
	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"
			ULTRAVNC_DSM_HELPER_SHOWCERT_ADH=1
			export ULTRAVNC_DSM_HELPER_SHOWCERT_ADH
			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
                ;;
	"-sendclipboard")	VNCVIEWER_SEND_CLIPBOARD=1; export VNCVIEWER_SEND_CLIPBOARD
                ;;
	"-sendalways")	VNCVIEWER_SEND_ALWAYS=1; export VNCVIEWER_SEND_ALWAYS
                ;;
	"-recvtext")	shift; VNCVIEWER_RECV_TEXT="$1"; export VNCVIEWER_RECV_TEXT
                ;;
	"-escape")	shift; VNCVIEWER_ESCAPE="$1"; export VNCVIEWER_ESCAPE
                ;;
	"-ssvnc_encodings")	shift; VNCVIEWER_ENCODINGS="$1"; export VNCVIEWER_ENCODINGS
                ;;
	"-ssvnc_extra_opts")	shift; VNCVIEWERCMD_EXTRA_OPTS="$1"; export VNCVIEWERCMD_EXTRA_OPTS
                ;;
	"-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

		# we now try to PPROXY_LOOP_THYSELF, set this var to disable that.
		#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

have_uvnc_dsm_helper_showcert=""
if [ "X$showcert" = "X1" -a "X$SSVNC_USE_S_CLIENT" = "X" -a "X$reverse" = "X" ]; then
	if type ultravnc_dsm_helper >/dev/null 2>&1; then
		if ultravnc_dsm_helper -help 2>&1 | grep -w showcert >/dev/null; then
			have_uvnc_dsm_helper_showcert=1
		fi
	fi
fi
have_uvnc_dsm_helper_ipv6=""
if [ "X$SSVNC_ULTRA_DSM" != "X" ]; then
	if type ultravnc_dsm_helper >/dev/null 2>&1; then
		if ultravnc_dsm_helper -help 2>&1 | grep -iw ipv6 >/dev/null; then
			have_uvnc_dsm_helper_ipv6=1
		fi
	fi
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
	if [ "X$SSVNC_USE_OURS" = "X" ]; then
		NEED_VENCRYPT_VIEWER_BRIDGE=1
	fi
fi
if [ "X$SSVNC_USE_OURS" = "X" ]; then
	VNCVIEWERCMD_EXTRA_OPTS=""
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

# 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 ':[0-9][0-9]*$' > /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:

# try to see if it is ipv6 address:
ipv6=0
if echo "$orig" | grep '\[' > /dev/null; then
	# ipv6 [fe80::219:dbff:fee5:3f92%eth1]:5900
	host=`echo "$orig" | sed -e 's/\].*$//' -e 's/\[//'`
	disp=`echo "$orig" | sed -e 's/^.*\]://'`
	ipv6=1
elif echo "$orig" | grep ':..*:' > /dev/null; then
	# ipv6 fe80::219:dbff:fee5:3f92%eth1:5900
	host=`echo "$orig" | sed -e 's/:[^:]*$//'`
	disp=`echo "$orig" | sed -e 's/^.*://'`
	ipv6=1
else
	# regular host:port
	host=`echo "$orig" | awk -F: '{print $1}'`
	disp=`echo "$orig" | awk -F: '{print $2}'`
fi

if [ "X$reverse" != "X" -a "X$STUNNEL_LISTEN" = "X" -a "X$host" != "X" ]; then
	STUNNEL_LISTEN=$host
	echo "set STUNNEL_LISTEN=$STUNNEL_LISTEN"
fi

if [ "X$host" = "X" ]; then
	host=$localhost
fi

if [ "X$SSVNC_IPV6" = "X0" ]; then
	# disable checking for it.
	ipv6=0
#elif [ "X$reverse" != "X" -a "X$ipv6" = "X1" ]; then
#	ipv6=0
elif [ "X$ipv6" = "X1" ]; then
	:
elif echo "$host" | grep '^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' > /dev/null; then
	:
else
	# regular hostname, can't be sure...
	gout=""
	if type getent > /dev/null 2>/dev/null; then
		gout=`getent hosts "$host" 2>/dev/null`
	fi
	if echo "$gout" | grep ':.*:' > /dev/null; then
		if echo "$gout" | grep '^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' > /dev/null; then
			:
		else
			echo "ipv6: "`echo "$gout" | grep ':.*:' | head -n 1`
			ipv6=1
		fi
	fi
	if [ "X$ipv6" = "X0" ]; then
		hout=""
		if type host > /dev/null 2>/dev/null; then
			host "$host" >/dev/null 2>&1
			host "$host" >/dev/null 2>&1
			hout=`host "$host" 2>/dev/null`
		fi
		if echo "$hout" | grep -i 'has ipv6 address' > /dev/null; then
			if echo "$hout" | grep -i 'has address' > /dev/null; then
				:
			else
				echo "ipv6: "`echo "$hout" | grep -i 'has ipv6 address' | head -n 1`
				ipv6=1
			fi
		fi
	fi
	if [ "X$ipv6" = "X0" ]; then
		dout=""
		if type dig > /dev/null 2>/dev/null; then
		dout=`dig -t any "$host" 2>/dev/null`
		fi
		if echo "$dout" | grep -i "^$host" | grep '[ 	]AAAA[ 	]' > /dev/null; then
			if echo "$dout" | grep -i "^$host" | grep '[ 	]A[ 	]' > /dev/null; then
				:
			else
				echo "ipv6: "`echo "$dout" | grep -i '[ 	]AAAA[ 	]' | head -n 1`
				ipv6=1
			fi
		fi
	fi
	if [ "X$ipv6" = "X0" ]; then
		sout=`env LOOKUP="$host" \
		      perl -e '	eval {use Socket};  exit 0 if $@;
				eval {use Socket6}; exit 0 if $@;
				@res = getaddrinfo($ENV{LOOKUP}, "daytime", AF_UNSPEC, SOCK_STREAM);
				$ipv4 = 0;
				$ipv6 = 0;
				$ip6 = "";
				while (scalar(@res) >= 5) {
					($family, $socktype, $proto, $saddr, $canon, @res) = @res;
					$ipv4 = 1 if $family == AF_INET;
					$ipv6 = 1 if $family == AF_INET6;
					if ($family == AF_INET6 && $ip6 eq "") {
						my ($host, $port) = getnameinfo($saddr, NI_NUMERICHOST | NI_NUMERICSERV);
						$ip6 = $host;
					}
				}
				if (! $ipv4 && $ipv6) {
					print "AF_INET6_ONLY: $ENV{LOOKUP}: $ip6\n";
				}
				exit 0;
			' 2>/dev/null`
		if echo "$sout" | grep AF_INET6_ONLY > /dev/null; then
			echo "$sout"
			ipv6=1
		fi
	fi
fi
if [ "X$ipv6" = "X1" ]; then
	echo "ipv6: addr=$host disp=$disp"
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

if [ "X$ipv6" = "X1" -a "X$direct_connect" = "X1" ]; then
	if [ "X$proxy" = "X" -a "X$reverse" = "X" ]; then
		if [ "X$SSVNC_ULTRA_DSM" != "X" -a "X$have_uvnc_dsm_helper_ipv6" = "X1" ]; then
			:
		elif [ "X$SSVNC_NO_IPV6_PROXY" != "X" ]; then
			:
		elif [ "X$SSVNC_NO_IPV6_PROXY_DIRECT" != "X" ]; then
			:
		elif [ "X$SSVNC_USE_OURS" = "X1" ]; then
			# requires 1.0.27 and later ssvncviewer binary
			:
		else
			proxy="ipv6://$host:$port"
			echo "direct connect: set proxy=$proxy"
		fi
	fi
fi

# (possibly) tell the vncviewer to only listen on lo: 
if [ "X$reverse" != "X" ]; then
	if [ "X$direct_connect" = "X" -o "X$proxy" != "X" -o "X$STUNNEL_LISTEN" != "X" ]; then
		VNCVIEWER_LISTEN_LOCALHOST=1
		export VNCVIEWER_LISTEN_LOCALHOST
	fi
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$tail_pid2" != "X" ]; then
		kill -TERM $tail_pid2
	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

if echo "$VNCVIEWERCMD" | egrep -i '^(xmessage|sleep )' > /dev/null; then
	:
elif [ "X$VNCVIEWERCMD_EXTRA_OPTS" != "X" ]; then
	VNCVIEWERCMD="$VNCVIEWERCMD $VNCVIEWERCMD_EXTRA_OPTS"
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
}

check_perl() {
	if type "$1" > /dev/null 2>&1; then
		:
	elif [ ! -x "$1" ]; then
		echo ""
		echo "*******************************************************"
		echo "** Problem finding the Perl command '$1': **"
		echo ""
		type "perl"
		echo ""
		echo "** Perhaps you need to install the Perl package. **"
		echo "*******************************************************"
		echo ""
		sleep 5
	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
	check_perl /usr/bin/perl

	cod='#!/usr/bin/perl

# A hack to glue stunnel to a Web or SOCKS proxy, UltraVNC repeater for
# client connections.
# Also acts as a VeNCrypt bridge (by redirecting to stunnel.)

use IO::Socket::INET;

my $have_inet6 = "";
eval "use IO::Socket::INET6;";
$have_inet6 = 1 if $@ eq "";

#my $have_sock6 = "";
#eval "use Socket; use Socket6;";
#$have_sock6 = 1 if $@ eq "";

if (exists $ENV{PPROXY_LOOP_THYSELF}) {
	# used for reverse vnc, run a repeating outer loop.
	print STDERR "PPROXY_LOOP: $ENV{PPROXY_LOOP_THYSELF}\n";
	my $rm = $ENV{PPROXY_REMOVE};
	my $lp = $ENV{PPROXY_LOOP_THYSELF};
	delete $ENV{PPROXY_REMOVE};
	delete $ENV{PPROXY_LOOP_THYSELF};
	$ENV{PPROXY_LOOP_THYSELF_MASTER} = $$;
	my $pid = $$;
	my $dbg = 0;
	my $c = 0;
	use POSIX ":sys_wait_h";
	while (1) {
		$pid = fork();
		last if ! defined $pid;
		if ($pid eq "0") {
			last;
		}
		$c++;
		print STDERR "\nPPROXY_LOOP: pid=$$ child=$pid count=$c\n";
		while (1) {
			waitpid(-1, WNOHANG);
			fsleep(0.25);
			if (! kill 0, $pid) {
				print STDERR "PPROXY_LOOP: child=$pid gone.\n";
				last;
			}
			print STDERR "PPROXY_LOOP: child=$pid alive.\n" if $dbg;
			if (! -f $lp) {
				print STDERR "PPROXY_LOOP: flag file $lp gone, killing $pid\n";
				kill TERM, $pid;
				fsleep(0.1);
				wait;
				last;
			}
			print STDERR "PPROXY_LOOP: file exists $lp\n" if $dbg;
		}
		last if ! -f $lp;
		fsleep(0.25);
	}
	if ($pid ne "0") {
		unlink($0) if $rm;
		exit 0;
	}
}

if (exists $ENV{PPROXY_SLEEP} && $ENV{PPROXY_SLEEP} > 0) {
	print STDERR "PPROXY_PID: $$\n";
	sleep $ENV{PPROXY_SLEEP};
}

foreach my $var (qw(
		PPROXY_DEST
		PPROXY_KILLPID
		PPROXY_LISTEN
		PPROXY_PROXY
		PPROXY_REMOVE
		PPROXY_REPEATER
		PPROXY_REVERSE
		PPROXY_SLEEP
		PPROXY_SOCKS
		PPROXY_VENCRYPT
		PPROXY_VENCRYPT_VIEWER_BRIDGE
    )) {
	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};
}

my $have_gettimeofday = 0;
eval "use Time::HiRes;";
if ($@ eq "") {
	$have_gettimeofday = 1;
}
sub gettime {
	my $t = "0.0";
	if ($have_gettimeofday) {
		$t = Time::HiRes::gettimeofday();
	}
	return $t;
}

my $listen_handle = "";
my $sock = "";
my $parent = $$;

my $initial_data = "";

if ($ENV{PPROXY_VENCRYPT_VIEWER_BRIDGE}) {
	my ($from, $to) = split(/,/, $ENV{PPROXY_VENCRYPT_VIEWER_BRIDGE});
	do_vencrypt_viewer_bridge($from, $to);
	exit 0;
}

my ($first, $second, $third) = split(/,/, $ENV{PPROXY_PROXY}, 3);
my ($mode_1st, $mode_2nd, $mode_3rd) = ("", "", "");

($first, $mode_1st) = url_parse($first);

my (                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  