#!/bin/sh
# A simple NX client
# Copyright(C) 2010 Miguel Angel Alvarez <maacruz@gmail.com>

# This program 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 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

#set -x

WMCTRL=$(which wmctrl)
XBINDKEYS=$(which xbindkeys)

cleanup()
{
	[[ $xbkpid ]]&&kill $xbkpid&&echo snx: xbindkeys stopped
	exit
}

# main
MODE="-R"
while [[ "${1#-}" != "$1" ]]; do
	case "${1#-}" in
	"d"|"D")
		MODE="-D"
		shift
		;;
	"u"|"U")
		USESSHTUNNEL=0
		shift
		;;
	*)
		echo A simple nx client for the NITs
		echo Usage: snx [-d] [-u] [user@host[:port]] [command]
		echo environment variable SSHACCOUNT can be set to user@host to avoid typing
		echo the address every time
		echo an alternate ssh port can be given in the host address
		echo if command is not provided a xterm will be opened
		echo remote windows are locally managed, unless \"-d\" is provided
		echo \"-d\" opens a remote desktop
		echo \"-u\" uses direct tcp connection to remote host instead of ssh tunnel
		echo        beware, data is sent unencrypted
		echo Install telescope if you have problems \(in N8x0\) with \"lost\"
		echo windows or switching from/to the nx desktop
		echo For N900, Ctrl+Return keybinding works as fullscreen key and
		echo gives the input focus to the active window
		echo
		echo Examples:
		echo Open kde3 desktop: snx -d user@host startkde
		echo Open firefox: snx user@host firefox
		echo Open xterm: snx user@host
		echo Some kde3 fun in your tablet: snx user@host \"kicker --nofork\"
		echo "If SSHACCOUNT is defined (export SSHACCOUNT=user@host): snx [command]"
		echo to override SSHACCOUNT: snx otheruser@otherhost command
		exit 1
		;;
	esac
done
if [[ $# == 2 ]]; then
	SSHACCOUNT="$1"
	shift
fi
if [[ "$SSHACCOUNT" == "" ]]; then
	if [[ "$1" != "" ]]; then
		SSHACCOUNT="$1"
		shift
	else
		echo Please provide your ssh account
		exit 1
	fi
fi

SSHPORT=$(echo $SSHACCOUNT|cut -d ":" -f 2)
SSHACCOUNT=$(echo $SSHACCOUNT|cut -d ":" -f 1)
if [[ "$SSHACCOUNT" == "$SSHPORT" ]]; then
	unset SSHPORT
else
	SSHPORT="-p "$SSHPORT
fi

if [[ $WMCTRL ]]&&[[ $XBINDKEYS ]]; then
	if [[ $(busybox ps|awk '$5 ~ /xbindkeys$/ {print $1}') ]]; then
		echo snx: xbindkeys is already running
	else
		$XBINDKEYS -n -f /etc/xbindkeysrc.snx -fg /dev/none &
		xbkpid=$!
		trap cleanup SIGINT SIGTERM SIGHUP SIGQUIT
		echo snx: Starting xbindkeys, fullscreen key will work on nx windows
	fi
fi

# if remote command is not provided, use xterm
COMMAND="$1"
[[ "$COMMAND" == "" ]]&&COMMAND="xterm -fg \"#000000\" -bg \"#ffffff\""

# NXDISPLAY is hardcoded by now, so only one session by host
NXDISPLAY=1011
NXPORT=$(expr 4000 + $NXDISPLAY)

# xmodmap hack to make the keyboard work
# Fn (N810 keycode 216, N900 keycode 108) has to be changed to ISO_Group_Latch to work (ISO_Level3_Shift doesn't, why?)
# Chr locks/unlocks upper 4 levels
# Fn + Shift locks shift
# N810 (keycode 135): Fn + Chr locks/unlocks Fn
if [[ "$OSSO_PRODUCT_NAME" == "N900" ]]; then
	KEYMAP=$(echo -e "$(DISPLAY=:0 xmodmap -pke|awk '(NF>3)&&($2!=50)&&($2!=37)&&($2!=108) { if (NF>7) {$6 = $8; if (NF>8) $7 = $9; else $7 = $8}; print $0 }')""\nkeycode 50 = Shift_L Shift_L Shift_Lock Shift_Lock Shift_L Shift_L Shift_L Shift_L\nkeycode 37 = Control_L Control_L Multi_key ISO_Prev_Group ISO_Next_Group ISO_Next_Group ISO_First_Group ISO_First_Group\nkeycode 108 = ISO_Group_Latch")
else
	KEYMAP=$(echo -e "$(DISPLAY=:0 xmodmap -pke|awk '(NF>3)&&($2!=50)&&($2!=135)&&($2!=216)')""\nkeycode 50 = Shift_L Shift_L Shift_Lock Shift_Lock Shift_L Shift_L Shift_L Shift_L\nkeycode 135 = Multi_key ISO_Prev_Group ISO_Next_Group ISO_Next_Group ISO_First_Group ISO_First_Group ISO_First_Group ISO_First_Group\nkeycode 216 = ISO_Group_Latch")
fi
# Make sure we are connected
dbus-send --system --print-reply --type=method_call --dest=com.nokia.icd /com/nokia/icd com.nokia.icd.connect string:"[ANY]" uint32:0 >/dev/null

# To avoid the whole thing showing in process listing in the remote server
# send some of the code through stdin into the remote side 
if [ "$USESSHTUNNEL" == "0" ]; then
REMOTE_ENVIRON=$(cat<<END
export KEYMAP=\""$KEYMAP"\"
export DISPLAY=nx/nx,link=modem:$NXDISPLAY
END
)
else
REMOTE_ENVIRON=$(cat<<END
export KEYMAP=\""$KEYMAP"\"
export DISPLAY=nx/nx,link=modem,accept=127.0.0.1:$NXDISPLAY
END
)
fi
# Start a ssh tunnel and run nxagent in the remote side
# when nxagent is awaiting for connection launch nxproxy in this side
# In the remote side once nxagent has a session started launch the command
# and when the command finishes kill nxagent
# In the local side once the session has started wait for the NX window to appear and make it fullscreen if in desktop mode
# Session is non persisten because I haven't managed to reconnect
if [ "$USESSHTUNNEL" == "0" ]; then
	NXHOST=$(echo $SSHACCOUNT|cut -d "@" -f 2)
else
	SSHTUNNEL="-L $NXPORT:localhost:$NXPORT"
	NXHOST="localhost"
fi
echo Connecting to $SSHACCOUNT...
echo $REMOTE_ENVIRON|ssh $SSHPORT $SSHTUNNEL "$SSHACCOUNT" \
	"eval $(cat)\ 
	nxagent -nopersistent $MODE :$NXDISPLAY 2>&1|while read line; do \
		echo "\$line"
		if [[ \"\${line#Session: Session started}\" != \"\$line\" ]]; then
			export DISPLAY=:$NXDISPLAY
			echo \"$KEYMAP\"|xmodmap -
			echo RUNNING >&2
			"$COMMAND"
			sleep 5
	 		agentpid=\$(ps axj |awk -v ppid=\$\$ '(\$1 == ppid)&&(\$10 ~ /nxagent$/) {print \$2}') >&2
			[[ \$agentpid ]]&&kill \$agentpid
		fi
	done"|while read line; do
		echo Server says: $line
		if [[ "${line#Info: Waiting for connection}" != "$line" ]]; then
			nxproxy -S $NXHOST:$NXDISPLAY 2>&1|while read line; do
				echo Client says: $line
				if [[ $WMCTRL ]]&&[[ "${line#Session: Session started}" != "$line" ]]&&[[ "$MODE" == "-D" ]]; then
					t=0
					while [[ ! $WID ]]&&[[ $t -lt 300 ]]; do
						WID=$(wmctrl -l|awk '(NF == 4)&&($4 == "NX") {print $1}')
						/usr/share/snx/usleep 100000
						let t+=1
					done
					[[ $WID ]]&&wmctrl -i -r $WID -b toggle,fullscreen&&/usr/share/snx/set-focus $WID
				fi
			done
		fi
	done

cleanup

