#!/bin/bash

# Free implementation of nxserver components
#
# nxnode does accept (for now):
# 
#	--startsession
#	--terminate
#	--smbmount 
#		(smbmount is not implemented yet)
#
# Copyright (c) 2004 by Fabian Franz.
#
# License: GNU GPL, version 2
#
# SVN: $Id: nxnode 580 2008-08-22 00:44:43Z fabianx $
#
# 21.06.2004: - Full reconnection support

# Read the config file
. $(PATH=$(cd $(dirname $0) && pwd):$PATH which nxloadconfig) --userconf

#
# -----------------------------------------------------------------------------
# Startup of nxnode
# -----------------------------------------------------------------------------
#

DELIM="NX>"

[ -n "$2" ] && DELIM="NX-$2>"

echo "$DELIM 1000 NXNODE - Version $NX_VERSION $NX_LICENSE"

if [ "$1" != "--check" -a "$1" != "--setkey" -a "$1" != "--agent" -a "$1" != "--slave" ]
then 
	read CMDLINE

	CMDLINE="a=b&$CMDLINE"
fi

#
# -----------------------------------------------------------------------------
# Various helper functions
# -----------------------------------------------------------------------------
#

stringinstring()
{
	case "$2" in
		*$1*)
			return 0
		;;
	esac
	
	return 1
}

getparam()
{
	stringinstring "&$1=" "$CMDLINE" || return 1
	
	echo "$CMDLINE" |  tr "&" "\n" | egrep "^"$1"=" | awk -F= '{ VAL=$2 } END { print VAL }' | sed 's|%24|$|'
	
	return 0
}

find_app()
{
	set -- $*
	which $1 2>/dev/null
}

getparam_sessionid()
{
	sessionid=$(getparam sessionid)
	
	[ -n "$sessionid" ] || sessionid=$(getparam session_id)
	if [ -z "$sessionid" ]
	then
		echo "NX> 500 Error: Fatal - Missing parameter session id." 1>&2
		exit 1
	fi
	
	echo $sessionid
}

#
# -----------------------------------------------------------------------------
# Node functions module
# -----------------------------------------------------------------------------
#

#
# node_terminate_agent <session id>
#

node_terminate_agent()
{
	NODE_AGENT_PID=$(cat "$USER_FAKE_HOME/.nx/C-$1/pids/agent" 2>/dev/null)
	[ -n "$NODE_AGENT_PID" ] && kill $NODE_AGENT_PID 2>/dev/null
}

#
# node_terminate_session <session id>
#
#	Used local vars: $virtualdesktop, $rootless
#
#	Used config vars: $COMMAND_XAUTH, $SESSION_LOG_CLEAN
#

node_terminate_session()
{
	#
	# Cleanup session
	#

	[ -d "$USER_FAKE_HOME/.nx/C-$1/" ] || return

	# Kill nxagent
	
	NODE_AGENT_PID=$(cat "$USER_FAKE_HOME/.nx/C-$1/pids/agent" 2>/dev/null)
	
	if [ -n "$NODE_AGENT_PID" ]
	then
		kill $NODE_AGENT_PID 2>/dev/null
		if ! [ "$virtualdesktop" = "0" -a "$rootless" != "1" ]
		then
			sleep 1
			kill -0 $NODE_AGENT_PID 2>/dev/null && kill -9 $NODE_AGENT_PID 2>/dev/null
		fi
	fi

	# Kill tail process
	
	NODE_TAIL_PID=$(cat "$USER_FAKE_HOME/.nx/C-$sess_id/pids/tail" 2>/dev/null)
	[ -n "$NODE_TAIL_PID" ] && kill $NODE_TAIL_PID 2>/dev/null

	# JJK: Kill running services
	# FF: Seems this is needed also here ...
	node_stop_services

	# Remove display information
	
	NODE_DISPLAY=$(echo $1 | awk 'BEGIN {FS="-"} {i=NF-1; print $i}')
	rm -f /tmp/.X$NODE_DISPLAY-lock
	rm -f /tmp/.X11-unix/X$NODE_DISPLAY
	
	# Remove magic cookie information
	
	$COMMAND_XAUTH -v source "$USER_FAKE_HOME/.nx/C-$1/scripts/authority" >/dev/null 2>&1

	# Preserve or remove session information
	
	[ "$SESSION_LOG_CLEAN" = "1" ] && rm -rf "$USER_FAKE_HOME/.nx/C-$1/"
	
	[ "$SESSION_LOG_CLEAN" = "0" -a "$2" = "failed" ] && mv "$USER_FAKE_HOME/.nx/C-$1/" "$USER_FAKE_HOME/.nx/F-C-$1"
	[ "$SESSION_LOG_CLEAN" = "0" -a "$2" != "failed" ] && mv "$USER_FAKE_HOME/.nx/C-$1/" "$USER_FAKE_HOME/.nx/T-C-$1"
}

#
# node_fail_restore_session <session id>
#

# TODO: Kill still running tail -f process.

node_fail_restore_session()
{
	echo "NX> 1004 Error: Could not resume session. nxagent process could not be found."
	
	NODE_TAIL_PID=$(cat "$USER_FAKE_HOME/.nx/C-$sess_id/pids/tail" 2>/dev/null)
	[ -n "$NODE_TAIL_PID" ] && kill $NODE_TAIL_PID
	[ -n "$NODE_TAIL_PID" ] && echo "NX 1004> kill $NODE_TAIL_PID"
	
	node_terminate_session "$1" "failed"
	exit 1
}

#
# node_suspend_session <session id>
#

node_suspend_session()
{
	NODE_AGENT_PID=$(cat "$USER_FAKE_HOME/.nx/C-$1/pids/agent" 2>/dev/null)

	if [ -n "$NODE_AGENT_PID" ]
	then
		kill -0 $NODE_AGENT_PID || return 1
		kill -HUP $NODE_AGENT_PID && return 0
	fi

	return 1
}

#
# node_find_application <type>
#
#	Used config vars: $COMMAND_START_KDE, $COMMAND_START_GNOME,
#			  $COMMAND_START_CDE, $COMMAND_XTERM, $USER_X_STARTUP_SCRIPT,
#			  $DEFAULT_X_SESSION

node_find_application()
{
	NODE_STARTX=""

	case $1 in
		shadow|windows|vnc)
			:
		;;
		unix-kde)
			NODE_STARTX=$COMMAND_START_KDE
		;;
		unix-gnome)
			NODE_STARTX=$COMMAND_START_GNOME
		;;
		unix-cde)
			NODE_STARTX=$COMMAND_START_CDE
		;;
		unix-application|windows-helper|vnc-helper)
			[ "$application" = "xterm" ] && application=$COMMAND_XTERM
			NODE_STARTX=$application
		;;
		unix-console)
			NODE_STARTX=$COMMAND_XTERM
		;;
		unix-default|*)
			if [ -x "$HOME/$USER_X_STARTUP_SCRIPT" ]; then
				NODE_STARTX="$HOME/$USER_X_STARTUP_SCRIPT"
			elif which "$DEFAULT_X_SESSION" >/dev/null 2>&1 ; then
				NODE_STARTX="$DEFAULT_X_SESSION"
			else
				NODE_STARTX=$COMMAND_XTERM
			fi
		;;
	esac

	echo "$NODE_STARTX"
}

#
# node_start_applications
#
#	Used local vars: $type, $application, $sess_id, $mediahelper,
#		         $virtualdesktop, $rootless, $display
#
#	Used config vars: <several>
#

node_start_applications()
{
	# close input and output file descriptors
	exec 0<&-
	exec 1>&-
	exec 2>&-

	#
	# Prepare application startup
	#
	
	. /etc/profile
	[ "$ENABLE_SOURCE_BASH_PROFILE" = "1" -a -f ~/.bash_profile ] && . ~/.bash_profile

	mkdir -p "$USER_FAKE_HOME/.nx/C-$sess_id/pids/apps/"

	#
	# Which application do we start?
	#

	NODE_APPLICATION=$(node_find_application "$type")
	
	# For rdesktop/VNC, there is no application to start
	[ -n "$NODE_APPLICATION" ] || return

	#
	# Check if we want to use a mediahelper
	#

	if [ "$mediahelper" = "esd" ]
	then
		# Set Espeaker variable
		let ESPEAKER=$display+7000
		export ESPEAKER="127.0.0.1:$ESPEAKER"
		
		# Do not spawn new ESD daemons
		export ESD_NO_SPAWN="yes"
			
		# Check for config file directive
		if [ "$ENABLE_ESD_PRELOAD" = "1" -a -x "$(find_app $ESD_BIN_PRELOAD)" ]
		then
			NODE_APPLICATION="$ESD_BIN_PRELOAD $NODE_APPLICATION"
			echo "Info: NXNODE - Using $ESD_BIN_PRELOAD wrapper script." >> "$USER_FAKE_HOME/.nx/C-$sess_id/session"
		fi
	elif [ "$mediahelper" = "artsd" ]
	then
		# Overwrite users mcoprc
		echo -n "GlobalComm=Arts::X11GlobalComm" > $HOME/.mcoprc
		if [ "$ENABLE_ARTSD_PRELOAD" = "1" -a -x "$(find_app $ARTSD_BIN_PRELOAD)" ]
		then
			NODE_APPLICATION="$ARTSD_BIN_PRELOAD $NODE_APPLICATION"
			echo "Info: NXNODE - Using $ARTSD_BIN_PRELOAD wrapper script." >> "$USER_FAKE_HOME/.nx/C-$sess_id/session"
		fi
	fi

	[ "$cups" = "1" -a "$ENABLE_CUPS_SERVER_EXPORT" = "1" ] && export CUPS_SERVER="$USER_FAKE_HOME/.nx/C-$sess_id/cups/cups.sock"
	
	if [ "$ENABLE_SAMBA_PRELOAD" = "1" -a -x "$PATH_BIN/nxredir" ]
	then
		let NXSAMBA_PORT=$display+3000
		export NXSAMBA_PORT
		NODE_APPLICATION="$PATH_BIN/nxredir $NODE_APPLICATION"
		echo "Info: NXNODE - Using nxredir wrapper script to forward SMB ports 139 and 445 to port $NXSAMBA_PORT." >> "$USER_FAKE_HOME/.nx/C-$sess_id/session"
	fi

	#
	# Do we need to PRELOAD any libraries?
	#	

	[ "$virtualdesktop" = "0" -a "$rootless" != "1" ] && export LD_PRELOAD="$APPLICATION_LIBRARY_PRELOAD:$LD_PRELOAD"

	#
	# Should we start a window manager?
	#
	
	if [ "$virtualdesktop" = "1" -a "$type" = "unix-application" -a "$DEFAULT_X_WM" != "" -a -x "$(find_app $DEFAULT_X_WM)" ]
	then
		DISPLAY=:$display $DEFAULT_X_WM >>"$USER_FAKE_HOME/.nx/C-$sess_id/session" 2>&1 &
		NODE_WM_PID=$!
	fi

	echo "Xft.dpi: 96" | DISPLAY=:$display xrdb -merge >>"$USER_FAKE_HOME/.nx/C-$sess_id/session" 2>&1
	[ -d /etc/X11/Xresources ] && xrdb -display :$display -merge /etc/X11/Xresources/* >>"$USER_FAKE_HOME/.nx/C-$sess_id/session" 2>&1

	#
	# Startup the application
	#
	
	DISPLAY=:$display $NODE_APPLICATION >>"$USER_FAKE_HOME/.nx/C-$sess_id/session" 2>&1 &
	NODE_APP_PID=$!
	
	mkdir -p "$USER_FAKE_HOME/.nx/C-$sess_id/pids/"
	echo "$NODE_APP_PID" >"$USER_FAKE_HOME/.nx/C-$sess_id/pids/apps/$NODE_APP_PID"
	wait $NODE_APP_PID

	#
	# Kill or wait for the started window manager
	#	
	
	if [ -n "$NODE_WM_PID" ]
	then
		# kill the WM after application is finished?
		[ "$KILL_DEFAULT_X_WM" = "1" ] && kill $NODE_WM_PID 2>/dev/null
		# or just wait until it finishes?
		[ "$KILL_DEFAULT_X_WM" = "1" ] || wait $NODE_WM_PID
	fi
	rm -f "$USER_FAKE_HOME/.nx/C-$sess_id/pids/apps/$NODE_APP_PID"

	# Do not terminate agent in case of rootless agent mode.
	# The agent times out after a while by itself anyway.
	
	[ "$virtualdesktop" = "1" -o "$rootless" != "1" ] && node_terminate_agent "$sess_id"
}

#
# node_persistent_session
#
#	Is the user allowed to run a persistent session?
#

node_agent_persistent_session()
{
	P="-nopersistent"
	OLD_IFS=$IFS
	IFS=","
	[ "$ENABLE_PERSISTENT_SESSION" = "all" ] && P="-persistent"
	[ "$ENABLE_PERSISTENT_SESSION" = "all" ] || for USERNAME in $ENABLE_PERSISTENT_SESSION; do
		[ "${USERNAME:0:1}" != "@" ] && [ "$USER" = "$USERNAME" ] && P="-persistent" && break ;
		[ "${USERNAME:0:1}" = "@" ] && [ -z $(groups "$USER" | egrep "^${USERNAME:1}:") ] && P="-persistent" && break ;
	done
	for USERNAME in $DISABLE_PERSISTENT_SESSION; do
		[ "${USERNAME:0:1}" != "@" ] && [ "$USER" = "$USERNAME" ] && P="-nopersistent" && break ;
		[ "${USERNAME:0:1}" = "@" ] && [ -z $(groups "$USER" | egrep "^${USERNAME:1}:") ] && P="-nopersistent" && break ;
	done
	IFS=$OLD_IFS
	echo "$P"
}

#
# node_start_agent
#

node_start_agent()
{
	# Ok, now we do some wicked fd magic.
	#
	# first part:
	#	
	# nxagent's fd #2 -> fd #3
	
	# second part:
	#
	# fd #1 -> #4
	# fd #3 -> #1
	# tee | node_start_monitor

	# third part
	# fd #4 -> #1

	# => all output of nxagent goes to tee | node_start_monitor, while
	#    leaving all other output flow through like normally.
	
	# preparations
	exec 3>&2
	exec 4>&1

	{
	
	{

	#
	# Setup environment
	#

	export DISPLAY="nx/nx,options=$USER_FAKE_HOME/.nx/C-$sess_id/options:$display"
	export XAUTHORITY="$USER_FAKE_HOME/.nx/C-$sess_id/authority"
	export HOME="$USER_FAKE_HOME"
	export NX_CLIENT="$PATH_BIN/nxdialog"

	#
	# Setup optional parameters for nxagent
	#

	# keyboard
	
	K=""
	# backwards compatibility
	[ -n "$keyboard" ] && K="-keyboard $keyboard"
	[ -n "$kbtype" ] && K="-kbtype $kbtype"

	# backingstore
	
	B=""
	if [ -n "$backingstore" -a "$ENABLE_1_5_0_BACKEND" = "1" ]
	then
		[ "$backingstore" != 1 ] && B="-bs $backingstore"
		[ "$backingstore" = 1 ] && B="+bs"
	fi

	# geometry
	
	G=""
	[ -n "$geometry" ] && G="-geometry $geometry"

	# type of session
	
	R="-D"
	[ "$rootless" = "1" ] && R="-R"

	# Setup fullscreen parameters
	
	vncfullscreen=""
	[ "$geometry" = "fullscreen" -a "$type" = "vnc" ] && vncfullscreen="-fullscreen" && G=""
	
	[ "$geometry" = "fullscreen" -a "$type" = "windows" ] && G="-geometry `echo $screeninfo | cut -d"x" -f1,2`"

	#
	# Start the wanted nxagent
	#

	if [ "$type" = "windows" ]
	then
		# nxdesktop session (Windows RDP)

		[ "$SET_LD_LIBRARY_PATH" = "1" ] && export LD_LIBRARY_PATH="$AGENT_LIBRARY_PATH:$LD_LIBRARY_PATH"
		# Setup optional parameters
		
		U=""
		P=""
		D=""
		[ -n "$agent_user" ] && U="-u $agent_user"
		[ -n "$agent_password" ] && P="-p -"
		[ -n "$agent_domain" ] && D="-d $agent_domain"

		# Start the agent
		
		echo "$agent_password" | $PATH_BIN/nxdesktop -name "NX - $user@$SERVER_NAME:$display - $session (GPL Edition)" -option "$USER_FAKE_HOME/.nx/C-$sess_id/options" $K $G $U $P $D $agent_server $AGENT_EXTRA_OPTIONS_RDP 2>&3 &

	elif [ "$type" = "vnc" ]
	then
		# nxviewer session (VNC RFB)
		
		[ "$SET_LD_LIBRARY_PATH" = "1" ] && export LD_LIBRARY_PATH="$AGENT_LIBRARY_PATH:$LD_LIBRARY_PATH"
		# Setup password
		
		mkdir -p "$USER_FAKE_HOME/.nx/C-$sess_id/scripts/"
		echo "$agent_password" | $PATH_BIN/nxpasswd "$USER_FAKE_HOME/.nx/C-$sess_id/scripts/.passwd" doit

		# Start x11vnc
		if [ -n "$shadowdisplay" ]
		then
			(
				viewonly=""
				[ "$ENABLE_INTERACTIVE_SESSION_SHADOWING" != "1" ] && viewonly="-viewonly"
				
				DISPLAY="$shadowhost:$shadowdisplay" x11vnc -localhost $viewonly -timeout 120 -rfbauth "$USER_FAKE_HOME/.nx/C-$sess_id/scripts/.passwd" >"$USER_FAKE_HOME/.nx/C-$sess_id/scripts/.vnc_port" 2>&3 &
			)
			sleep 2
			agent_port=$(cat "$USER_FAKE_HOME/.nx/C-$sess_id/scripts/.vnc_port" | egrep "^PORT=" | cut -d'=' -f 2)
			[ -z "agent_port" ] && agent_port="0"
			# note the :: is not a mistake, but rather a hint for nxviewer to use this as a port and not 
			# interpret it as a display.
			agent_server="127.0.0.1::$agent_port"
			rm -f "$USER_FAKE_HOME/.nx/C-$sess_id/scripts/.vnc_port"
		fi
		
		# Start the agent
		
		$PATH_BIN/nxviewer -encodings tight hextile copyrect raw -passwd "$USER_FAKE_HOME/.nx/C-$sess_id/scripts/.passwd" -name "NX - $user@$SERVER_NAME:$display - $session (GPL Edition)" -option "$USER_FAKE_HOME/.nx/C-$sess_id/options" $vncfullscreen $G $K $agent_server $AGENT_EXTRA_OPTIONS_RFB 2>&3 &

	elif [ "$R" = "-R" -a "$rootless" != "1" ]
	then
		# nxproxy single application mode session
		[ "$SET_LD_LIBRARY_PATH" = "1" ] && export LD_LIBRARY_PATH="$PROXY_LIBRARY_PATH:$LD_LIBRARY_PATH"
		$PATH_BIN/nxproxy -C :$display $PROXY_EXTRA_OPTIONS 2>&3 &
	else
		# nxagent session (X11)
		[ "$SET_LD_LIBRARY_PATH" = "1" ] && export LD_LIBRARY_PATH="$AGENT_LIBRARY_PATH:$LD_LIBRARY_PATH"
		
		# Setup optional parameters

		P=$(node_agent_persistent_session)
		FP=""
		[ -n "$AGENT_FONT_SERVER" ] && FP="-fp $AGENT_FONT_SERVER"
		
		if [ "$type" = "shadow" ]
		then
			R="-S -shadow $shadowhost:$shadowdisplay -shadowmode $ENABLE_INTERACTIVE_SESSION_SHADOWING"
			P="-nopersistent"
		fi
		
		# Start the agent
		
		PATH="$PATH_BIN:$PATH" $PATH_BIN/nxagent $P $R -name "NX - $user@$SERVER_NAME:$display - $session (GPL Edition)" -option "$USER_FAKE_HOME/.nx/C-$sess_id/options" $K $G $B $FP $AGENT_EXTRA_OPTIONS_X :$display 2>&3 &
	fi
	
	#
	# Wait for the agent
	#
	
	NODE_AGENT_PID=$!
	mkdir -p "$USER_FAKE_HOME/.nx/C-$sess_id/pids/"
	echo "$NODE_AGENT_PID" >"$USER_FAKE_HOME/.nx/C-$sess_id/pids/agent"
	wait $NODE_AGENT_PID

	NODE_AGENT_EXIT_STATUS=$?
	NODE_FAILED=""
	if [ $NODE_AGENT_EXIT_STATUS -ne 0 ]
	then
		echo "NX> 1004 Error: NX Agent exited with exit status 1. To troubleshoot set SESSION_LOG_CLEAN=0 in node.conf and investigate \"$USER_FAKE_HOME/.nx/F-C-$sess_id/session\". You might also want to try: ssh -X myserver; $PATH_BIN/nxnode --agent to test the basic functionality. Session log follows:"
		cat "$USER_FAKE_HOME/.nx/C-$sess_id/session" 1>&2
		NODE_FAILED="failed"
	fi
	echo "NX> 1006 Session status: closed"
	
	#
	# Cleanup session information
	#	
	
	rm -f "$USER_FAKE_HOME/.nx/C-$sess_id/pids/agent"
	node_terminate_session "$sess_id" "$NODE_FAILED"
	
	# remove possible leftovers of nxagent
	rm -f /tmp/.X$display-lock
	rm -f /tmp/.X11-unix/X$display
	} 3>&1 1>&4 | tee "$USER_FAKE_HOME/.nx/C-$sess_id/session" | node_start_monitor; } 4>&1
}

#
# node_cupsd_stop
#
#	Used local vars: $sess_id
#

node_cupsd_stop()
{
	#
	# Cleanup userspace cups daemon	
	#
	
	[ -e "$USER_FAKE_HOME/.nx/C-$sess_id/pids/cupsd" ] || return
	
	NODE_CUPSD_PID=$(cat "$USER_FAKE_HOME/.nx/C-$sess_id/pids/cupsd")
	
	# Check for a running userspace cupsd, look if its still active 
	# and kill it if so
	( [ -n "$NODE_CUPSD_PID" ] && kill -0 $NODE_CUPSD_PID && kill $NODE_CUPSD_PID && sleep 2 && kill -0 $NODE_CUPSD_PID && kill -9 $NODE_CUPSD_PID ) 2>/dev/null
	
	# delete pid file
	rm -f "$USER_FAKE_HOME/.nx/C-$sess_id/pids/cupsd"
	
	# remove all printers
	echo >"$USER_FAKE_HOME/.nx/C-$sess_id/cups/printers.conf"
}

#
# node_cupsd_setup
#
#	Used local vars: $sess_id, $display
#

node_cupsd_setup()
{
	let NODE_CUPSD_PORT=$display+9000 # offset 9000 for userspace cupsd's
	export NODE_CUPSD_PORT
	
	export NODE_CUPSD_SOCKET="$USER_FAKE_HOME/.nx/C-$sess_id/cups/cups.sock"
	
	mkdir -p "$USER_FAKE_HOME/.nx/C-$sess_id/pids/"
	[ -e "$USER_FAKE_HOME/.nx/C-$sess_id/pids/cupsd" ] && return
	touch "$USER_FAKE_HOME/.nx/C-$sess_id/pids/cupsd"
	
	mkdir -p "$USER_FAKE_HOME/.nx/C-$sess_id/cups/spool/tmp" "$USER_FAKE_HOME/.nx/C-$sess_id/cups/spool/certs" "$USER_FAKE_HOME/.nx/C-$sess_id/cups/ppd" "$USER_FAKE_HOME/.nx/C-$sess_id/cups/cache"

cat <<EOF > $USER_FAKE_HOME/.nx/C-$sess_id/cups/cupsd.conf
AccessLog /dev/null
ErrorLog error_log
PageLog page_log
LogLevel info
TempDir $USER_FAKE_HOME/.nx/C-$sess_id/cups/spool/tmp
RequestRoot $USER_FAKE_HOME/.nx/C-$sess_id/cups/spool
ServerRoot $USER_FAKE_HOME/.nx/C-$sess_id/cups/
StateDir $USER_FAKE_HOME/.nx/C-$sess_id/cups/
CacheDir $USER_FAKE_HOME/.nx/C-$sess_id/cups/cache

Listen $NODE_CUPSD_SOCKET
Browsing Off
ServerName localhost
PidFile $USER_FAKE_HOME/.nx/C-$sess_id/pids/cupsd

<Location />
Order Deny,Allow
Deny From All
Allow from 127.0.0.1
</Location>

# Allow everything for anonymous, because we are protected through UNIX socket
<Policy default>
  <Limit All>
    AuthType None
    Order deny,allow
  </Limit>
</Policy>
EOF

	touch "$USER_FAKE_HOME/.nx/C-$sess_id/cups/printers.conf" "$USER_FAKE_HOME/.nx/C-$sess_id/cups/classes.conf"

	# copy mime.* files
	cp -af "$CUPS_ETC"/mime.* "$USER_FAKE_HOME/.nx/C-$sess_id/cups/"

	# start cupsd
	$COMMAND_CUPSD -c "$USER_FAKE_HOME/.nx/C-$sess_id/cups/cupsd.conf" &>/dev/null </dev/null

	# setup KDE
	if [ "$ENABLE_KDE_CUPS" = "1" -a -e "$KDE_PRINTRC" ]
	then
		if egrep -q "^Host=" "$KDE_PRINTRC"
		then
			[ "$ENABLE_KDE_CUPS_DYNAMIC" = "1" ] && $COMMAND_PERL -pi -e 's,^Host=.*,Host[\$ie]=\$\('"$PATH_BIN/nxcups-gethost"'),g' "$KDE_PRINTRC"
			[ "$ENABLE_KDE_CUPS_DYNAMIC" != "1" ] && $COMMAND_PERL -pi -e 's,^Host=.*,Host='"$NODE_CUPSD_SOCKET"',g' "$KDE_PRINTRC"
		else
			echo "[CUPS]" >> "$KDE_PRINTRC"
			[ "$ENABLE_KDE_CUPS_DYNAMIC" = "1" ] && echo "Host[\$ie]=\$($PATH_BIN/nxcups-gethost)" >> "$KDE_PRINTRC"
			[ "$ENABLE_KDE_CUPS_DYNAMIC" != "1" ] && echo "Host=$NODE_CUPSD_SOCKET" >> "$KDE_PRINTRC"
		fi
	fi
}

#
# node_cupsd_reload
#
#	Used local vars: $sess_id
#

node_cupsd_reload()
{
	[ -e "$USER_FAKE_HOME/.nx/C-$sess_id/pids/cupsd" ] || return
	NODE_CUPSD_PID=$(cat "$USER_FAKE_HOME/.nx/C-$sess_id/pids/cupsd")
	[ -n "$NODE_CUPSD_PID" ] && kill -0 $NODE_CUPSD_PID && kill -HUP $NODE_CUPSD_PID
}

node_cupsd_get_socket()
{
	node_cupsd_setup
	echo $NODE_CUPSD_SOCKET
}

node_umount_smb()
{
	[ -e "$USER_FAKE_HOME/.nx/C-$sess_id/scripts/mpoint" ] || return
	cat "$USER_FAKE_HOME/.nx/C-$sess_id/scripts/mpoint" | while read mpoint
	do
		$COMMAND_SMBUMOUNT "$mpoint" >/dev/null 2>/dev/null
	done
}

node_stop_services()
{
	node_umount_smb
	node_cupsd_stop
}

node_emergency_exit()
{
	# umount shares & stop printers
	node_stop_services

	# kill the session
	node_terminate_session "$sess_id" "failed"

	echo "NX> 1004 Error: Emergency exit due to kill signal."
}

#
# Monitoring the nxagent: Its also kind of a "state-machine" 
#                         as it has to keep track of different 
#                         connection states and react differently.
#

node_start_monitor_2_0_0()
{
	NODE_TAIL_PID=""
	NODE_SUSPEND_STATUS="$2"

	while read line 
	do
		#
		# Catch tail pid
		#
		
		if stringinstring "Info: tail -f running with pid" "$line"
		then
			NODE_TAIL_PID=$(echo $line | cut -d"'" -f2)
			echo "$NODE_TAIL_PID" >"$USER_FAKE_HOME/.nx/C-$sess_id/pids/tail"
		fi

		#
		# Catch NXAGENT SMB Port (sometimes the port differs from what we got from nxserver)
		#
		
		if stringinstring "Info: Listening * SMB connections on port" "$line"
		then
			SMBMOUNT_PORT=$(echo $line | cut -d"'" -f2)
			echo "$SMBMOUNT_PORT" >"$USER_FAKE_HOME/.nx/C-$sess_id/scripts/mport"
		fi

		#
		# Session messages
		#

		if stringinstring "Session: Starting session at" "$line"
		then
			echo "NX> 1009 Session status: starting"
		fi
		
		if stringinstring "Session: Suspending session at" "$line"
		then
			echo "NX> 1009 Session status: suspending"
		fi
		
		if stringinstring "Session: Terminating session at" "$line"
		then
			echo "NX> 1009 Session status: terminating"
		fi
		
		if stringinstring "Session: Resuming session at" "$line"
		then
			echo "NX> 1009 Session status: resuming"
		fi


		#
		# Session suspend
		#

		if stringinstring "Session: Session suspended at" "$line"
		then
			echo "NX> 1005 Session status: suspended"
			# umount shares & stop printers

			if [ "$NODE_SUSPEND_STATUS" = "Running" ]
			then
				node_suspend_session "$sess_id"
				NODE_SUSPEND_STATUS=""
			else
				node_stop_services
			fi
		fi

		#
		# Watchdog termination
		#

		if stringinstring "Info: Watchdog running with pid" "$line"
		then
			NODE_WATCHDOG_PID=$(echo $line | cut -d"'" -f2)
		fi

		if stringinstring "Info: Waiting the watchdog process to complete." "$line"
		then
			# Kill the watchdog
			kill $NODE_WATCHDOG_PID 2>/dev/null
		fi
		
		#
		# Session is running
		#
		
		if stringinstring "Info: Waiting for connection from" "$line"
		then
			echo "NX> 710 Session status: running"
			echo "NX> 1002 Commit"
			echo "NX> 1006 Session status: running"
		fi

		#
		# Reconnection success!
		#
		
		if stringinstring "Session: Session resumed at" "$line"
		then
			echo "NX> 718 Session restore succeded"
			if [ "$1" = "restore" ]
			then
				kill $NODE_TAIL_PID
				break
			fi
		fi

		#
		# Reconnection failure
		#
		
		if stringinstring "Session: Display failure detected at" "$line"
		then
			echo "NX> 596 Error: Session $1 failed. Reason was: $line"
			if [ "$1" = "restore" ]
			then
				kill $NODE_TAIL_PID
				break
			fi
		fi
	done
	
	trap "" EXIT
	
	[ "$1" = "restore" ] ||	node_stop_services
	# close all open file descriptors
	exec 0<&-
	exec 1>&-
	exec 2>&-
	exit 0
}

node_start_monitor_1_5_0()
{
	NODE_RUNNING=0
	NODE_TAIL_PID=""
	NODE_SUSPEND_STATUS="$2"

	while read line 
	do
		#
		# Catch tail pid
		#
		
		if stringinstring "Info: tail -f running with pid" "$line"
		then
			NODE_TAIL_PID=$(echo $line | cut -d"'" -f2)
			echo "$NODE_TAIL_PID" >"$USER_FAKE_HOME/.nx/C-$sess_id/pids/tail"
		fi

		#
		# Catch NXAGENT SMB Port (sometimes the port differs from what we got from nxserver)
		#

		if stringinstring "Info: Listening for SMB connections on port" "$line"
		then
			SMBMOUNT_PORT=$(echo $line | cut -d"'" -f2)
			echo "$SMBMOUNT_PORT" >"$USER_FAKE_HOME/.nx/C-$sess_id/scripts/mport"
		fi


		#
		# Session suspend
		#

		if stringinstring "Info: Session suspended." "$line"
		then
			echo "NX> 1005 Session status: suspended"
			# umount shares & stop printers

			if [ "$NODE_SUSPEND_STATUS" = "Running" ]
			then
				node_suspend_session "$sess_id"
				NODE_SUSPEND_STATUS=""
			else
				node_stop_services
			fi
		fi

		#
		# Proxy termination
		#

		if stringinstring "Info: Waiting for a further signal to complete." "$line"
		then
			# Kill the proxy
			kill -HUP $NODE_PROXY_PID 2>/dev/null
		fi
		
		#
		# Session end
		#
		
		if stringinstring "Info: End of session requested by " "$line" && [ "$RECONNECT" = "0" ] && ! stringinstring "'SIGHUP'" "$line"
		then
			echo "NX> 1009 Session status: terminating"
			kill -HUP $NODE_PROXY_PID 2>/dev/null
		fi
		
		#
		# Session is running
		#
		
		if stringinstring "Info: Waiting for connection from" "$line"
		then
			echo "NX> 710 Session status: running"
			echo "NX> 1002 Commit"
			echo "NX> 1006 Session status: running"
		fi

		#
		# Status = Running - Do _not_ fail anymore.
		#

		if stringinstring "Info: Connection with remote proxy established." "$line"
		then
			NODE_RUNNING=1
		fi
	
		#
		# Catch proxy pid
		#
		
		if stringinstring "Info: Proxy running in server mode with pid" "$line"
		then
			NODE_PROXY_PID=$(echo $line | cut -d"'" -f2)
		fi
		
		#
		# Reconnection success!
		#
		
		if stringinstring "Info: Reconnection succeded." "$line"
		then
			echo "NX> 718 Session restore succeded"
			if [ "$1" = "restore" ]
			then
				kill $NODE_TAIL_PID
				break
			fi
		fi

		#
		# Reconnection failure
		#
		
		if stringinstring "Info: Reconnection failed:" "$line"
		then
			echo "NX> 1005 Session status: suspended"
			echo "NX> 596 Error: Session restore failed. Reason was: $line"
			if [ "$1" = "restore" ]
			then
				kill $NODE_TAIL_PID
				break
			fi
		fi
	done
	
	trap "" EXIT

	[ "$1" = "restore" ] ||	node_stop_services
	# close all open file descriptors
	exec 0<&-
	exec 1>&-
	exec 2>&-
	exit 0
}

#
# node_start_monitor <start|restore> <Running|Suspended>
#

node_start_monitor()
{
	if [ "$ENABLE_1_5_0_BACKEND" = "1" ]
	then
		node_start_monitor_1_5_0 "$@"
	else
		node_start_monitor_2_0_0 "$@"
	fi

}

#
# -----------------------------------------------------------------------------
# startsession - Start a new session.
# -----------------------------------------------------------------------------
#

startsession()
{

	# user=knoppix&userip=192.168.1.66&uniqueid=6A8269CC467264EAEF6349D062689755&display=1000&session=lappi%5ffull&type=unix%2dkde&cache=8M&images=32M&cookie=84765070afee043cf83f85d21130145f&link=lan&render=1&backingstore=when_requested&imagecompressionmethod=0&geometry=fullscreen&keyboard=fr&media=0&samba=1&agent_server=&agent_user=&agent_password=

	user=$(getparam user)
	userip=$(getparam userip)
	uniqueid=$(getparam uniqueid)
	display=$(getparam display)
	session=$(getparam session)
	type=$(getparam type | sed 's/%2d/-/g')
	application=$(getparam application)
	cache=$(getparam cache)
	images=$(getparam images)
	cookie=$(getparam cookie)
	link=$(getparam link)
	virtualdesktop=$(getparam virtualdesktop)
	render=$(getparam render)
	backingstore=$(getparam backingstore)
	imagecompressionmethod=$(getparam imagecompressionmethod)
	imagecompressionlevel=$(getparam imagecompressionlevel)
	geometry=$(getparam geometry)
	keyboard=$(getparam keyboard)
	kbtype=$(getparam kbtype)
	media=$(getparam media)
	mediahelper=$(getparam mediahelper)
	sync=$(getparam sync)
	samba=$(getparam samba)
	cups=$(getparam cups)
	agent_server=$(getparam agent_server | sed 's/%3A/:/g')
	agent_user=$(getparam agent_user)
	agent_password=$(getparam agent_password)
	agent_domain=$(getparam agent_domain)
	screeninfo=$(getparam screeninfo)
	nodelay=$(getparam nodelay)
	[ "$PROXY_TCP_NODELAY" = "0" ] && nodelay=0

	# 1.5.0 options
	rdpcolors=$(getparam rdpcolors)
	rdpcache=$(getparam rdpcache)
	http=$(getparam http)
	
	# nxclient > 1.5.0-106 variables
	resize=$(getparam resize)
	keybd=$(getparam keybd)

	# backwards compatibility for keybd parameter
	[ -z "$keybd" ] && keybd=$(getparam aux)
	aux=$(getparam aux)

	kbload=$(getparam kbload)
	keymap=$(getparam keymap)

	rootless=0
	# Its still the clients decision
	[ "$ENABLE_ROOTLESS_MODE" = "1" ] &&  rootless=$(getparam rootless)

	# Rootless fix from 2x nxserver 1.5.0
	realtype=$type
	[ "$type" = "unix-application" -o "$type" = "unix-default" ] && realtype="unix-desktop"

	# NX 2.1.0 file-sharing port options
	client=$(getparam client)

	smbport=""

	if [ "$samba" = "1" ]
	then
		# We know from protocol traces that client=linux,winnt,macosx are valid values.
		# I hope with smbclientproto=smb on default and smbclientproto=cifs on all valid
		# values we get support for all those systems.

		smbproto="$SAMBA_MOUNT_SHARE_PROTOCOL"

		if [ "$smbproto" = "both" ]
		then
			smbproto="smbfs"

			[ "$client" = "linux" ] && smbproto="cifs"
			[ "$client" = "winnt" ] && smbproto="cifs"
			[ "$client" = "macosx" ] && smbproto="cifs"

			# FIXME: This is a rather wild guess
			[ "$client" = "win9x" ] && smbproto="smbfs"
		fi

		if [ "$smbproto" = "cifs" ]
		then
			smbport=445
			COMMAND_SMBMOUNT=$COMMAND_SMBMOUNT_CIFS
			COMMAND_SMBUMOUNT=$COMMAND_SMBUMOUNT_CIFS
		elif [ "$smbproto" = "none" ] # none
		then
			# we set this to true so that the 
			# SMB mount does not give an error message.

			COMMAND_SMBMOUNT=/bin/true
			COMMAND_SMBUMOUNT=/bin/true
		else # smbfs
			smbport=139
		fi
	fi
	
	# FreeNX specific variables
	clientproto=$(getparam clientproto)
	status=$(getparam status)
	host=$(getparam host)
	
	# New NX 3.0 shadow mode related variables
	shadowusername=$(getparam shadowusername)
	shadowcookie=$(getparam shadowcookie)
	shadowdisplay=$(getparam shadowdisplay)
	shadowhost=$(getparam shadowhost)

	
	sess_id="$SERVER_NAME-$display-$uniqueid"
	NXSESSION_DIRECTORY="$USER_FAKE_HOME/.nx/C-$sess_id"
	
	# export the agent_* options for the helper scripts
	if [ "$(getparam freenx_export_agents)" = "1" ]
	then
		export agent_user
		export agent_password
		export agent_server
		export agent_domain
		export windows_app=$application
		agent_keyboard=""
		[ "$ENABLE_EXTERNAL_NXDESKTOP_KEYBOARD" = "1" ] && agent_keyboard=$(echo "$keyboard" | cut -d'/' -f2)
		export agent_keyboard
		export NXSESSION_DIRECTORY
		export AGENT_EXTRA_OPTIONS_RFB
		export AGENT_EXTRA_OPTIONS_RDP
		export COMMAND_RDESKTOP
		export COMMAND_VNCVIEWER
		export COMMAND_VNCPASSWD
		export COMMAND_X11VNC
		export PATH_BIN
		export shadowdisplay
		export shadowhost
		export shadowuser
		export shadowcookie

		export ENABLE_SESSION_SHADOWING_AUTHORIZATION
		export ENABLE_INTERACTIVE_SESSION_SHADOWING

		# We do not want to suspend such a session
		# as RDP/RFB are both suspendable as well
		ENABLE_PERSISTENT_SESSION=""
	fi

	fullscreen=$(getparam fullscreen)
	[ "$geometry" = "fullscreen" ] && fullscreen="1"

	[ "$EXPORT_USERIP" = "1" ] && export NXUSERIP="$userip"

	ssl_tunnel=$(getparam encryption)
	[ -z "$ssl_tunnel" ] && ssl_tunnel=0
	
	if [ "$ssl_tunnel" = "1" ]
	then
		# we need to use the IP of the "calling" server now
		userip=$(echo $SSH_CLIENT $SSH2_CLIENT | cut -d" " -f1 | sed 's/::ffff://g')
		# If host is the same, use 127.0.0.1, else fallback to default
		[ -z "$userip" -a "$host" = "127.0.0.1" ] && userip="127.0.0.1"
		[ -z "$userip" ] && userip="*"
	fi
	
	# ok, lets make the session dir first:
	
	sess_id="$SERVER_NAME-$display-$uniqueid"
	[ "$EXPORT_SESSIONID" = "1" ] && export NXSESSIONID="$sess_id"
	
	OLD_UMASK=$(umask)
	umask 0022
	mkdir -p $USER_FAKE_HOME
	umask 0077
	mkdir -p "$USER_FAKE_HOME/.nx/C-$sess_id"
	umask $OLD_UMASK
	
	# cache=8M,images=32M,pack=nopack,link=lan,type=unix-kde,cleanup=0,accept=192.168.1.66,cookie=E38A94A77F975443AF04EC911881B120,id=Knoppix-1000-6A8269CC467264EAEF6349D062689755,samba=1,render=1:1000
	
	PACK=""
	[ -z "$imagecompressionlevel" ] && imagecompressionlevel="9"
	
	[ "$imagecompressionmethod" = "0" ] && PACK="pack=nopack,"
	[ "$imagecompressionmethod" = "1" ] && PACK="pack=16m-jpeg-$imagecompressionlevel,"
	[ "$imagecompressionmethod" = "2" ] && PACK="pack=16m-png-9,"
	
	proxy_cookie=$(echo $[$RANDOM*$RANDOM] | $COMMAND_MD5SUM | cut -d" " -f1)

	# all newer clients support fake cookie authentication
	if [ "$clientproto" != "1.4.0" ]
	then
		# enable fake cookie authentication
		cookie=$proxy_cookie
	fi

	# write options file
	[ -z "$samba" ] && samba=0
	[ -z "$media" ] && media=0
	[ -z "$nodelay" ] && nodelay=1

	clipboard="$ENABLE_CLIPBOARD"
	menu="$ENABLE_PULLDOWN_MENU"

	CACHE="cache=$cache,"
	[ -z "$cache" ] && CACHE=""
	IMAGES="images=$images,"
	[ -z "$images" ] && IMAGES=""

	ACCEPT="accept=$userip,"
	[ "$userip" = "*" ] && ACCEPT=""

if [ "$1" = "application" ]
then
	# This needs to be set, else nxagent is terminated
	rootless="1"
	virtualdesktop="0"
	node_start_applications &
	echo "NX> 596 Application $application started successfully."
	return
fi

	OLD_UMASK=$(umask)
	umask 0077

cat << EOF > "$USER_FAKE_HOME/.nx/C-$sess_id/options"
${keyboard:+keyboard=$keyboard,}${kbtype:+kbtype=$kbtype,}${kbload:+kbload=$kbload,}${keymap:+keymap=$keymap,}${resize:+resize=$resize,}${CACHE}${IMAGES}${PACK}link=$link,nodelay=$nodelay,type=$realtype,cleanup=0,${ACCEPT}cookie=$proxy_cookie,id=$sess_id,samba=$samba,media=$media${sync:+,sync=$sync}${cups:+,cups=$cups}${keybd:+,keybd=$keybd}${aux:+,aux=$aux}${http:+,http=$http}${rdpcolors:+,rdpcolors=$rdpcolors}${rdpcache:+,rdpcache=$rdpcache}${fullscreen:+,fullscreen=1}${clipboard:+,clipboard=$clipboard}${menu:+,menu=$menu}:$display
EOF
	umask $OLD_UMASK
#samba=$samba,
	#cache=$cache,images=$images,pack=nopack,link=$link,type=$type,cleanup=0,accept=$userip,cookie=$proxy_cookie,id=$sess_id
#samba=$samba,media=$media,render=$render:$display

	# write xauth script file

$COMMAND_XAUTH >/dev/null 2>&1 <<EOF
add localhost:$display MIT-MAGIC-COOKIE-1 $cookie
add :$display MIT-MAGIC-COOKIE-1 $cookie
exit
EOF

$COMMAND_XAUTH -f "$USER_FAKE_HOME/.nx/C-$sess_id/authority" >/dev/null 2>&1 <<EOF
add localhost:$display MIT-MAGIC-COOKIE-1 $cookie
add :$display MIT-MAGIC-COOKIE-1 $cookie
exit
EOF

	mkdir -m700 "$USER_FAKE_HOME/.nx/C-$sess_id/scripts/" 2>/dev/null || chmod 700 "$USER_FAKE_HOME/.nx/C-$sess_id/scripts/"

cat << EOF >"$USER_FAKE_HOME/.nx/C-$sess_id/scripts/authority"
remove localhost:$display
remove :$display
exit
EOF

	export SHADOW_XAUTHORITY="$USER_FAKE_HOME/.nx/C-$sess_id/authority"

	# If we have a shadow cookie, we add it to xauth session authority file as well
	if [ -n "$shadowcookie" ]
	then
		$COMMAND_XAUTH -f "$SHADOW_XAUTHORITY" add "$shadowhost:$shadowdisplay" MIT-MAGIC-COOKIE-1 "$shadowcookie"
	elif [ -n "$shadowdisplay" ]
	then
		# we need to merge in the normal .Xauthority file
		$COMMAND_XAUTH -f "$SHADOW_XAUTHORITY" merge "$HOME/.Xauthority"
	fi

if [ "$1" = "restore" ]
then
	echo > "$USER_FAKE_HOME/.nx/C-$sess_id/session"
	sh -c 'echo "Info: tail -f running with pid '\'\$$\''."; exec tail -n1 -f '"$USER_FAKE_HOME"'/.nx/C-'"$sess_id"'/session' | node_start_monitor "$1" "$status" &

	MONITOR_PID=$!
	export MONITOR_PID

	mkdir -p "$USER_FAKE_HOME/.nx/C-$sess_id/pids/"
	echo "$MONITOR_PID" > "$USER_FAKE_HOME/.nx/C-$sess_id/pids/monitor"

	node_suspend_session "$sess_id" || { echo "Info: Reconnection failed: NX Agent process could not be found." >>"$USER_FAKE_HOME/.nx/C-$sess_id/session"; node_fail_restore_session "$sess_id"; }
else
	node_start_agent &
	node_start_applications &
fi

if which "$NODE_AUTOSTART" >/dev/null 2>&1
then
	# go into background immediately
	NXSESSIONID="$sess_id" DISPLAY=:$display "$NODE_AUTOSTART" "$1" >/dev/null 2>&1 &
	# dont't wait for this child!
	disown $!
fi
	
cat << EOF
NX> 700 Session id: $sess_id
NX> 705 Session display: $display
NX> 703 Session type: $type
NX> 701 Proxy cookie: $proxy_cookie
NX> 702 Proxy IP: $userip
NX> 706 Agent cookie: $cookie
NX> 704 Session cache: $type
NX> 707 SSL tunneling: $ssl_tunnel
EOF

# File-sharing port options
if [ "$samba" = "1" -a -n "$smbport" ]
then
	echo "NX> 709 File-sharing port: $smbport"
	echo "$smbport" >"$USER_FAKE_HOME/.nx/C-$sess_id/scripts/smbport"
fi

# collection ...

# NX> 1004 Error:
#Session 'Knoppix-1000-40EFB9F64FA55C64C41C72CA39EBD720' has failed after reaching usable state. Session directory '/home/knoppix/.nx/F-C-Knoppix-1000-40EFB9F64FA55C64C41C72CA39EBD720' will be not deleted to allow for further investigation.

if [ -n "$MONITOR_PID" ]
then
	wait "$MONITOR_PID"
	rm -f "$USER_FAKE_HOME/.nx/C-$sess_id/pids/monitor"
	rm -f "$USER_FAKE_HOME/.nx/C-$sess_id/pids/tail"
fi
wait # for all children
}

#
# -----------------------------------------------------------------------------
# cmd_node functions - changes lots of small variables
# -----------------------------------------------------------------------------
#

cmd_node_terminate()
{
	sessionid=$(getparam_sessionid)
	echo "$DELIM 716 Terminating session $sessionid on user request."
	display=$(cd $USER_FAKE_HOME/.nx/; echo C-$SERVER_NAME-*-$sessionid | awk 'BEGIN {FS="-"} {i=NF-1; print $i}')
	node_terminate_session "$SERVER_NAME-$display-$sessionid"
}

cmd_node_suspend()
{
	sessionid=$(getparam_sessionid)
	echo "$DELIM 716 Suspending session $sessionid on user request."
	display=$(cd $USER_FAKE_HOME/.nx/; echo C-$SERVER_NAME-*-$sessionid | awk 'BEGIN {FS="-"} {i=NF-1; print $i}') 
	node_suspend_session "$SERVER_NAME-$display-$sessionid"
}

cmd_node_smbmount()
{
	sessionid=$(getparam_sessionid)
	port=$(getparam port)
	username=$(getparam username)
	password=$(getparam password)
	share=$(getparam share)
	computername=$(getparam computername)
	dir=$(getparam dir | sed 's|$(SHARES)|MyShares|g')
	# rdir=$(getparam dir | sed 's|$(SHARES)/||g')
	display=$(cd $USER_FAKE_HOME/.nx/; echo C-$SERVER_NAME-*-$sessionid | awk 'BEGIN {FS="-"} {i=NF-1; print $i}') 
	mkdir -p "$HOME/$dir"
	# wait up to 30 sec until nxagent has opened the listener port for samba connections
	for (( i=30; $i; --i ))
	do
		[ -f "$USER_FAKE_HOME/.nx/C-$SERVER_NAME-$display-$sessionid/scripts/mport" ] && break
		sleep 1
	done
	# sometimes the samba port we get from nxserver is not the right one, so let's get it from nxagent
	realport=$(cat "$USER_FAKE_HOME/.nx/C-$SERVER_NAME-$display-$sessionid/scripts/mport")
	[ -n "$realport" ] && port=$realport
	error=$(PASSWD="$password" $COMMAND_SMBMOUNT "//$computername/$share" "$HOME/$dir" -o username="$username",ip=127.0.0.1,port=$port 2>&1)
	if [ $? -eq 0 ]
	then
		$PATH_BIN/nxdialog -dialog ok -caption "NXServer Message" -message "Info: Share: '//$computername/$share' mounted on: '$HOME/$dir'" -display :$display &
		echo "$HOME/$dir" >> "$USER_FAKE_HOME/.nx/C-$SERVER_NAME-$display-$sessionid/scripts/mpoint"
	else
		$PATH_BIN/nxdialog -dialog ok -caption "NXServer Message" -message "Info: Share: '//$computername/$share' failed to mount: $error" -display :$display &
	fi
}

cmd_node_addprinter()
{
	sessionid=$(getparam_sessionid)
	type=$(getparam type)
	port=$(getparam port)
	username=$(getparam username)
	password=$(getparam password)
	share=$(getparam share)
	printer=$(getparam printer)
	computername=$(getparam computername)
	public=$(getparam public)
	model=$(getparam model)
	defaultPrinter=$(getparam defaultPrinter)
	display=$(cd $USER_FAKE_HOME/.nx/; echo C-$SERVER_NAME-*-$sessionid | awk 'BEGIN {FS="-"} {i=NF-1; print $i}') 
	sess_id="$SERVER_NAME-$display-$sessionid"
	
	# this will also setup the userspace cupsd
	export CUPS_SERVER=$(node_cupsd_get_socket)
	
	if [ "$type" = "smb" ]
	then
		if [ -x "$CUPS_BACKEND/nxsmb" ]
		then
			smbport=$(cat "$USER_FAKE_HOME/.nx/C-$sess_id/scripts/smbport" 2>/dev/null)
			[ -z "$smbport" ] && smbport=139 # should not happen

			if [ "$smbport" = "445" ]
			then
				smbproto="cifs"
			else
				smbproto="smb"
			fi

			DEVICE_URI="nxsmb://$username:$password@127.0.0.1:$port/$smbproto/$share"
		else
			DEVICE_URI="smb://$username:$password@127.0.0.1:$port/$share"
		fi
		NAME="$share"
		ENABLE_CUPS_SEAMLESS="0"
	else
		DEVICE_URI="nxipp://$username:$password@127.0.0.1:$port/printers/$printer"
		NAME="$printer"
	fi
	export PATH_BIN

	if [ "$ENABLE_CUPS_SEAMLESS" != "1" ]
	then
		MODEL=$($PATH_BIN/nxdialog -printer "$NAME" -display :$display)
		[ -z "$MODEL" -o "$MODEL" = "cancel: aborted" ] && return
	else
		sleep $CUPS_SEAMLESS_DELAY
		MODEL="download_cached"
	fi
	
	PUBLIC="-u allow:$USER"
	[ "$public" == "1" ] && PUBLIC=""

	if [ "$MODEL" = "download_new" -o "$MODEL" = "download_cached" ]
	then
		mkdir -p "$USER_FAKE_HOME/.nx/config/ppd/"
		if [ "$MODEL" = "download_new" -o ! -r "$USER_FAKE_HOME/.nx/config/ppd/$printer.ppd" ]
		then
			curl --proxy "" --digest -o "$USER_FAKE_HOME/.nx/config/ppd/$printer.ppd" "http://$username:$password@127.0.0.1:$port/ppd/${printer}_nxdl.ppd" >>"$USER_FAKE_HOME/.nx/C-$sess_id/cups/curl.log" 2>&1
		RC=$?
		[ $RC -eq 0 -a "$ENABLE_CUPS_SEAMLESS" != "1" ] && $PATH_BIN/nxdialog --message "Download successful." -display :$display
		[ $RC -ne 0 -a "$ENABLE_CUPS_SEAMLESS" != "1" ] && $PATH_BIN/nxdialog --message "Download failed. Log is: $USER_FAKE_HOME/.nx/C-$sess_id/cups/curl.log" -display :$display
		fi
		MODEL="$USER_FAKE_HOME/.nx/config/ppd/$printer.ppd"
	fi
	
	if [ ! -r "$MODEL" ]
	then
		# Foomatic and co
		/usr/sbin/lpadmin -p "$NAME" -E -v "$DEVICE_URI" -m "$MODEL" $PUBLIC
	else
		/usr/sbin/lpadmin -p "$NAME" -E -v "$DEVICE_URI" -P "$MODEL" $PUBLIC
	fi

	[ "$defaultPrinter" = "1" ] && /usr/sbin/lpadmin -d "$NAME"
}

nxnode_func()
{

case "$1" in 
	--startsession)
		startsession
	;;
	--resumesession)
		startsession "restore"
	;;
	--applicationsession)
		startsession "application"
	;;
	--terminate)
		cmd_node_terminate
	;;
	--suspend)
		cmd_node_suspend
	;;
	--smbmount)
		cmd_node_smbmount &>/dev/null </dev/null &
	;;
	--addprinter)
		cmd_node_addprinter &>/dev/null </dev/null &
	;;
	--check)
		echo "NX> 716 finished"
	;;
	--agent)
		echo "NX> 716 Starting NX Agent ..."
		shift
		[ "$SET_LD_LIBRARY_PATH" = "1" ] && export LD_LIBRARY_PATH="$AGENT_LIBRARY_PATH:$LD_LIBRARY_PATH"
		PATH="$PATH:$PATH_BIN" $PATH_BIN/nxagent -name "NX Agent Test - Args: $@" $@
		echo "NX> 716 NX Agent exited with status: $?"
	;;
	--setkey)
		mkdir -m 700 -p $HOME/.ssh
		if ! grep -q "$(cat $NX_ETC_DIR/users.id_dsa.pub)" $HOME/.ssh/$SSH_AUTHORIZED_KEYS 2>/dev/null
		then
			cat $NX_ETC_DIR/users.id_dsa.pub >> $HOME/.ssh/$SSH_AUTHORIZED_KEYS
			chmod 600 $HOME/.ssh/$SSH_AUTHORIZED_KEYS
			echo "NX> 716 Public key added to: $HOME/.ssh/$SSH_AUTHORIZED_KEYS"
		else
			echo "NX> 716 Public key is already present in: $HOME/.ssh/$SSH_AUTHORIZED_KEYS"
		fi
	;;
	*)
		echo "NX> 500 Error: Command not found"
	;;
esac

}


if [ "$1" = "--slave" ]
then
	# New slave mode accepts more than 1 command at a time
	echo "NX> 716 Slave mode started successfully."
	NODE_SESSION=""

	while read CMD
	do
		[ "$CMD" = "--quit" ] && break
		
		if [ "$CMD" != "--check" -a "$CMD" != "--setkey" -a "$CMD" != "--agent" ]
		then 
			read CMDLINE

			CMDLINE="a=b&$CMDLINE"
		fi
		
		if [ "$CMD" = "--startsession" -o "$CMD" = "--resumesession" ]
		then
			export SLAVE_PID="$$"
			( echo "$CMDLINE" | "$0" "$CMD"; kill "$SLAVE_PID"; ) &
			NODE_SESSION="$!"
		else
			DELIM=""
			[ -n "$NODE_SESSION" ] && DELIM="$NODE_SESSION->$CMD"
			( echo "$CMDLINE" | "$0" "$CMD" "$DELIM"; ) &
		fi

	done
else
	nxnode_func "$@"
fi

echo "$DELIM 1001 Bye."
