#!/bin/bash

# Copyright (C) 2007-2018 X2Go Project - http://wiki.x2go.org
# Copyright (C) 2007-2017 Oleksandr Shneyder <oleksandr.shneyder@obviously-nice.de>
# Copyright (C) 2007-2017 Heinz-Markus Graesing <heinz-m.graesing@obviously-nice.de>
#
# 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 2 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, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

X2GO_LIB_PATH="$(x2gopath 'libexec')"

"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'info' "$(basename "${0}") called with options: ${*}"

if ! SSH_PORT="$("${X2GO_LIB_PATH}/x2gogetrandomport")"; then
	typeset msg='Unable to get (pseudo-)randomized starting port value.'
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'err' "${msg}"

	# Make x2goclient fail.
	echo "${msg}" >&2
	exit '1'
fi

X2GO_PORT='50'

# some sanity checks before session startup...
if grep -E -- '^backend[ ]*=[ ]*postgres' '/etc/x2go/x2gosql/sql' &>'/dev/null' && [[ "${USER}" = 'root' ]]; then
	msg='The super-user "root" is not allowed to launch X2Go sessions.'
	echo "${msg}" >&2
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'err' "${msg}"
	exit '2'
elif [[ -z "${USER}" ]]; then
	msg='The $USER environment variable is not set. Aborting session startup.'
	echo "${msg}" >&2
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'err' "${msg}"
	exit '3'
elif [[ -z "${HOME}" ]]; then
	msg='The $HOME environment variable is not set. Aborting session startup.'
	echo "${msg}" >&2
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'err' "${msg}"
	exit '4'
elif ! iconv -f 'ASCII' -t 'ASCII' &>'/dev/null' <<< "${HOME}"; then
	msg='Your home directory path contains non-ASCII characters. Aborting session startup.'
	echo "${msg}" >&2
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'err' "${msg}"
	exit '5'
fi

# ${HOSTNAME} should be automatically set by bash via gethostname(2), IFF this
# variable is not already set in the environment.
#
# This leads to two problems:
#   - export HOSTNAME="malbox"; x2gostartagent will override the actual system
#     host name and lead to authorization failures when connecting to
#     x2goagent/nxagent later on.
#   - even if the above is not the case, we want to be sure to get the actual
#     system host name.
#
# Workaround: use hostname.
typeset current_host_name=''

if ! current_host_name="$(hostname)"; then
	typeset msg='Unable to retrieve machine'"'"'s hostname. This is required. Aborting session startup.'
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'err' "${msg}"

	# Make x2goclient fail.
	echo "${msg}" >&2
	exit '6'
fi

X2GO_TELEKINESIS_ENABLED="$("${X2GO_LIB_PATH}/x2goistrue" "$("${X2GO_LIB_PATH}/x2goqueryconfig" "telekinesis" "enable")")"

X2GO_ROOT="${HOME}/.x2go"
export NX_ROOT="${X2GO_ROOT}"

X2GO_NXAGENT_DEFAULT_OPTIONS='-extension GLX -nolisten tcp'

if [[ -r '/etc/x2go/x2goagent.options' ]]; then
	source '/etc/x2go/x2goagent.options'
fi

if [[ -z "${X2GO_NXAGENT_OPTIONS}" ]]; then
	X2GO_NXAGENT_OPTIONS="${X2GO_NXAGENT_DEFAULT_OPTIONS}"
fi

REMOTE='localhost'

# shadow sessions (via x2godesktopsharing) set the X2GO_CLIENT var in the process environment
# so either it is already set or we obtain it from SSH_CLIENT/SSH_CONNECTION
if [[ -z "${X2GO_CLIENT}" ]] && [[ -n "${SSH_CLIENT}" ]]; then
	X2GO_CLIENT="$(awk '{print $1}' <<< "${SSH_CLIENT}")"
elif [[ -z "${X2GO_CLIENT}" ]] && [[ -n "${SSH_CONNECTION}" ]]; then
	X2GO_CLIENT="$(awk '{print $1}' <<< "${SSH_CONNECTION}")"
fi
if [[ -z "${X2GO_CLIENT}" ]]; then
	msg='The $X2GO_CLIENT environment variable is not set. Possible reasons: $SSH_CLIENT not set or $SSH_CONNECTION not set. Or $X2GO_CLIENT not set by the "X2Go Desktop Sharing" applet. Aborting session startup.'
	echo "${msg}" >&2
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'err' "${msg}"
	exit '7'
fi

"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'debug' "client announced itself as "'"'"${X2GO_CLIENT}"'"'

typeset -i x2go_randr_xinerama='0'

# Extending optional parameters isn't trivially possible.
# Since we want this script to work with newer X2Go Client
# versions that supply a Xinerama configuration value and
# also with older ones that do not, we pass it in as an
# environment variable.
[[ -n "${X2GO_XINERAMA}" ]] && x2go_xinerama="$("${X2GO_LIB_PATH}/x2goistrue" "${X2GO_XINERAMA}")"

X2GO_GEOMETRY="${1}"; shift
X2GO_LINK="${1}"; shift
X2GO_PACK="${1}"; shift
X2GO_TYPE="${1}"; shift
X2GO_KBD_LAYOUT="${1}"; shift
X2GO_KBD_TYPE="${1}"; shift
X2GO_SET_KBD="${1}"; shift
X2GO_STYPE="${1}"; shift
X2GO_CMD="${1}"; shift
X2GO_RESIZE='1'
X2GO_FULLSCREEN='0'

X2GO_CLIPBOARD=''

: "${XAUTHORITY:="${HOME}/.Xauthority"}"


if [[ "${X2GO_STYPE}" = 'S' ]]; then

	SHADOW_MODE="$(awk '{split($0,a,"XSHAD"); print a[1]}' <<< "${X2GO_CMD}")"
	SHADOW_USER="$(awk '{split($0,a,"XSHAD"); print a[2]}' <<< "${X2GO_CMD}")"
	SHADOW_DESKTOP="$(awk '{split($0,a,"XSHAD"); print a[3]}' <<< "${X2GO_CMD}")"

	# FIXME: no client application actually passes in an additional user name.
	# This is most likely redundant and confuses things (esp. since it's an
	# optional parameter) needlessly.
	if [[ -z "${1}" ]]; then

		# can this line be removed?
		#echo "suser ${SHADOW_USER} user ${USER} " >>"/tmp/uagent"

		"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'debug' "shadow session requested: mode ${SHADOW_MODE}, user: ${SHADOW_USER}, desktop: ${SHADOW_DESKTOP}"
	else
		SHADREQ_USER="${1}"; shift
		"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'debug' "preparing shadow session request for user ${SHADREQ_USER}, agent starts for user ${USER}"
	fi

	if [[ "${SHADOW_USER}" != "${USER}" ]]; then

		"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'notice' "user "'"'"${USER}"'"'" requests desktop sharing from user "'"'"${SHADOW_USER}"'"'" for desktop "'"'"${SHADOW_DESKTOP}"'"'
		"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'debug' "executing command: x2godesktopsharing client ${X2GO_CLIENT} ${X2GO_GEOMETRY} ${X2GO_LINK} ${X2GO_PACK} ${X2GO_TYPE} ${X2GO_KBD_LAYOUT} ${X2GO_KBD_TYPE} ${X2GO_SET_KBD} ${X2GO_STYPE} ${X2GO_CMD} ${USER}"
		OUTPUT="$(x2godesktopsharing 'client' "${X2GO_CLIENT}" "${X2GO_GEOMETRY}" "${X2GO_LINK}" "${X2GO_PACK}" "${X2GO_TYPE}" "${X2GO_KBD_LAYOUT}" "${X2GO_KBD_TYPE}" "${X2GO_SET_KBD}" "${X2GO_STYPE}" "${X2GO_CMD}" "${USER}")"
		OUTPUT="$(sed -e 's/#012/ /g' <<< "${OUTPUT}")"
		"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'debug' "command result is: ${OUTPUT}"
		if [[ "${OUTPUT:0:4}" = 'DENY' ]]; then
			echo 'ACCESS DENIED' >&2
			DENIAL_REASON="${OUTPUT:5}"
			if [[ -z "${DENIAL_REASON}" ]]; then
				DENIAL_REASON="the user "'"'"${SHADOW_USER}"'"'" does not seem to have desktop sharing activated"
			fi
			"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'err' "ERROR: user ${SHADOW_USER} denied desktop sharing session"
			"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'err' "ERROR: reason: for desktop sharing denial ${DENIAL_REASON}"
			exit '8'
		fi
		X2GO_COOKIE="$(awk '{print $2}' <<< "${OUTPUT}")"
		X2GO_PORT="$(awk '{print $1}' <<< "${OUTPUT}")"

		"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'debug' "received shadow session information: cookie: ${X2GO_COOKIE}, port: ${X2GO_PORT}"
		xauth -f "${XAUTHORITY}" 'add' "${current_host_name}/unix:${X2GO_PORT}" "MIT-MAGIC-COOKIE-1" "${X2GO_COOKIE}"
		xauth -f "${XAUTHORITY}" 'add' "${current_host_name}:${X2GO_PORT}" "MIT-MAGIC-COOKIE-1" "${X2GO_COOKIE}"

		echo "${X2GO_PORT}"
		echo "${X2GO_COOKIE}"
		awk '{print $3}' <<< "${OUTPUT}"
		awk '{print $4}' <<< "${OUTPUT}"
		awk '{print $5}' <<< "${OUTPUT}"
		awk '{print $6}' <<< "${OUTPUT}"
		awk '{print $7}' <<< "${OUTPUT}"
		exit '0'
	fi
else
	X2GO_CLIPBOARD="${1}"; shift
fi

LIMIT="$(x2gosessionlimit)"
LWORD="$(awk '{print $1}' <<< "${LIMIT}")"

if [[ "${LWORD}" = 'LIMIT' ]]; then
	echo "${LIMIT}" >&2
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'err' "session limit has been reached for user "'"'"${USER}"'"'", cannot start new session"
	exit '9'
fi

export NX_CLIENT="${X2GO_LIB_PATH}/x2gosuspend-agent"

COLORDEPTH="$(awk '{split($0,a,"-depth_"); print a[2]}' <<< "${X2GO_TYPE}")"

SESSION_TYPE='D'
NOEXITPARAM=''

if [[ "${X2GO_STYPE}" = 'R' ]]; then
	SESSION_TYPE='R'
elif [[ "${X2GO_STYPE}" = 'P' ]]; then
	SESSION_TYPE='R'
	NOEXITPARAM='-norootlessexit'
elif [[ "${X2GO_STYPE}" = 'S' ]]; then
	SESSION_TYPE='S'
fi

if [[ -z "${X2GO_CLIENT}" ]]; then
	X2GO_CLIENT="${current_host_name}"
fi

# define the full path to the ss utility
ss="$(PATH="${PATH}:/usr/sbin:/sbin" type -P "ss")"

typeset -i retry='0'
typeset -i max_retry='10'
typeset output=''
for ((retry = 0; retry < max_retry; ++retry)); do
	typeset -i free_port="${X2GO_PORT}"
	if free_port="$("${X2GO_LIB_PATH}/x2gogetfreeport" "${current_host_name}" "${ss}" 'display' "${X2GO_PORT}")"; then
		X2GO_PORT="${free_port}"

		if [[ -n "${SHADREQ_USER}" ]]; then
			SESSION_NAME="${SHADREQ_USER}-${X2GO_PORT}-$(date '+%s')"
		else
			SESSION_NAME="${USER}-${X2GO_PORT}-$(date '+%s')"
		fi
		if [[ -n "${COLORDEPTH}" ]]; then
			SESSION_NAME="${SESSION_NAME}_st${SESSION_TYPE}${X2GO_CMD}_dp${COLORDEPTH}"
			SESSION_NAME="${SESSION_NAME//:/PP}"
		fi

		# sanitize session name
		SESSION_NAME="$(perl -pe 's/[^a-zA-Z0-9\.\_\-\@]//g' <<< "${SESSION_NAME}")"

		if [[ -n "${SHADREQ_USER}" ]]; then
			"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'debug' "initializing new shadow session with ID ${SESSION_NAME}"
			output="$("${X2GO_LIB_PATH}/x2goinsertshadowsession" "${X2GO_PORT}" "${current_host_name}" "${SESSION_NAME}" "${SHADREQ_USER}")"
		else
			"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'debug' "initializing new session with ID ${SESSION_NAME}"
			output="$("${X2GO_LIB_PATH}/x2goinsertsession" "${X2GO_PORT}" "${current_host_name}" "${SESSION_NAME}")"
		fi

		if [[ "${output}" = 'inserted' ]]; then
			break
		else
			"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'warning' "unable to insert display port into database. Retrying (run $((retry + 1)))."
		fi
	else
		"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'warning' "no free display number available, cannot start new session. Retrying (run $((retry + 1)))."
	fi
done

if [[ "${output}" != 'inserted' ]]; then
	typeset msg="Unable to find free display port or insert new session into database; parameters: port (${X2GO_PORT}), hostname (${current_host_name}) and session name (${SESSION_NAME})."
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'err' "${msg}"

	# Make x2goclient fail.
	echo "${msg}" >&2
	exit '10'
fi

if [[ "${X2GO_TELEKINESIS_ENABLED}" = '0' ]] || [[ "${X2GO_STYPE}" = 'S' ]] || ! type -p 'telekinesis-server' 1>'/dev/null'; then
	TEKICTRL_PORT='-1'
	TEKIDATA_PORT='-1'
	X2GO_TELEKINESIS_ENABLED='0'
fi

while [[ -z "${GR_PORT}" ]] || [[ -z "${SOUND_PORT}" ]] || [[ -z "${FS_PORT}" ]] || [[ -z "${TEKICTRL_PORT}" ]] || [[ -z "${TEKIDATA_PORT}" ]]; do
	output=''
	for ((retry = 0; retry < max_retry; ++retry)); do
		free_port='0'
		if free_port="$("${X2GO_LIB_PATH}/x2gogetfreeport" "${current_host_name}" "${ss}" 'lowlevel' "${SSH_PORT}")"; then
			SSH_PORT="${free_port}"

			output="$("${X2GO_LIB_PATH}/x2goinsertport" "${current_host_name}" "${SESSION_NAME}" "${SSH_PORT}")"

			if [[ "${output}" = 'inserted' ]]; then
				break
			else
				"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'warning' "unable to insert port into database. Retrying (run $((retry + 1)))."
			fi
		else
			"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'warning' "no free port available, cannot start new session. Retrying (run $((retry + 1)))."
		fi
	done

	if [[ "${output}" != 'inserted' ]]; then
		typeset msg="Unable to find free port or insert new session into database; parameters: hostname (${current_host_name}), session name (${SESSION_NAME}) and port (${SSH_PORT})."
		"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'err' "${msg}"

		# Make x2goclient fail.
		echo "${msg}" >&2
		exit '11'
	fi

	if [[ -z "${GR_PORT}" ]]; then
		GR_PORT="${SSH_PORT}"
	elif [[ -z "${SOUND_PORT}" ]]; then
		SOUND_PORT="${SSH_PORT}"
	elif [[ -z "${FS_PORT}" ]]; then
		FS_PORT="${SSH_PORT}"
	elif [[ -z "${TEKICTRL_PORT}" ]]; then
		TEKICTRL_PORT="${SSH_PORT}"
	elif [[ -z "${TEKIDATA_PORT}" ]]; then
		TEKIDATA_PORT="${SSH_PORT}"
	fi
done

# rootless sessions of geometry fullscreen are invalid
if [[ "${X2GO_GEOMETRY}" = 'fullscreen' ]] && [[ "${SESSION_TYPE}" = 'R' ]]; then
	X2GO_GEOMETRY=''
fi

# no geometry for desktop sessions shall result in fullscreen desktop sessions
if [[ "${X2GO_GEOMETRY}" = '' ]] && [[ "${SESSION_TYPE}" = 'D' ]]; then
	X2GO_GEOMETRY='fullscreen'
fi
if [[ "${X2GO_GEOMETRY}" = 'fullscreen' ]]; then
	X2GO_FULLSCREEN='1'
fi

# shadow sessions are never fullscreen session and adopt the original session's geometry
if [[ "${X2GO_STYPE}" = 'S' ]]; then
	X2GO_GEOMETRY="$(DISPLAY="${SHADOW_DESKTOP}" xwininfo -root | grep 'geometry')"
	X2GO_GEOMETRY="$(sed -e 's/ //g' <<< "${X2GO_GEOMETRY}")"
	X2GO_GEOMETRY="$(sed -e 's/-geometry//' <<< "${X2GO_GEOMETRY}")"
fi

if [[ ! -d "${X2GO_ROOT}" ]]; then
	mkdir -- "${X2GO_ROOT}"
fi

X2GO_TMP_ROOT="/tmp/.x2go-${USER}"
if [[ ! -d "${X2GO_TMP_ROOT}" ]]; then
	mkdir -- "${X2GO_TMP_ROOT}"
fi

SESSION_DIR="${X2GO_TMP_ROOT}/C-${SESSION_NAME}"
if [[ "${X2GO_TELEKINESIS_ENABLED}" != '0' ]] && [[ "${X2GO_STYPE}" != 'S' ]]; then
	mkdir -p -- "${SESSION_DIR}/telekinesis/remote/"
fi

STATE_FILE="${SESSION_DIR}/state"

# do not use $TMP or $TEMP here, the session.log file location has to be accessible by root
SESSION_LOG="${SESSION_DIR}/session.log"
mkdir -p -- "${SESSION_DIR}"
if [[ "${X2GO_STYPE}" = 'S' ]]; then
	chmod -f '0710' -- "${SESSION_DIR}"
	if groups "${USER}" | grep 'x2godesktopsharing' &>'/dev/null'; then
		"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'info' "user "'"'"${USER}"'"'" grants access to ${SESSION_DIR} for group "'"'"x2godesktopsharing"'"'
		chown -- ':x2godesktopsharing' "${SESSION_DIR}"
	fi
else
	chmod -f '0700' -- "${SESSION_DIR}"
fi
touch "${SESSION_LOG}"
chmod -f '0600' -- "${SESSION_LOG}"

if [[ ! -d "${X2GO_ROOT}/ssh" ]]; then
	mkdir -- "${X2GO_ROOT}/ssh"
fi

grep 'PPid' "/proc/${PPID}/status" >"${SESSION_DIR}/sshd.pid"


X2GO_COOKIE="$(mcookie)"


xauth -f "${XAUTHORITY}" 'add' "${current_host_name}/unix:${X2GO_PORT}" 'MIT-MAGIC-COOKIE-1' "${X2GO_COOKIE}"
xauth -f "${XAUTHORITY}" 'add' "${current_host_name}:${X2GO_PORT}" 'MIT-MAGIC-COOKIE-1' "${X2GO_COOKIE}"


typeset option_geometry=''
if [[ -n "${X2GO_GEOMETRY}" ]] && [[ "${X2GO_GEOMETRY}" != 'fullscreen' ]]; then
	option_geometry="geometry=${X2GO_GEOMETRY},"
fi

typeset tmp_regex='^(0|none|client|server|both|1)$'
if [[ -n "${X2GO_CLIPBOARD}" ]] && [[ "${X2GO_CLIPBOARD}" =~ ${tmp_regex} ]]; then
	clipboard=",clipboard=${X2GO_CLIPBOARD}"
else
	clipboard=",clipboard=both"
fi

typeset xinerama_option='1'
[[ "${x2go_xinerama}" = '0' ]] && xinerama_option='0'

if [[ "${X2GO_SET_KBD}" = '0' ]] || [[ "${X2GO_KBD_TYPE}" = 'auto' ]]; then
	X2GO_HOST="nx/nx,link=${X2GO_LINK},pack=${X2GO_PACK},limit=0,root=${SESSION_DIR},cache=8M,images=32M,type=${X2GO_TYPE},id=${SESSION_NAME},cookie=${X2GO_COOKIE},errors=${SESSION_LOG},kbtype=null/null,${option_geometry}xinerama=${xinerama_option},resize=${X2GO_RESIZE},fullscreen=${X2GO_FULLSCREEN},accept=${REMOTE},listen=${GR_PORT}${clipboard},client=linux,menu=0,state=${STATE_FILE}"
else
	X2GO_HOST="nx/nx,link=${X2GO_LINK},pack=${X2GO_PACK},limit=0,root=${SESSION_DIR},cache=8M,images=32M,type=${X2GO_TYPE},id=${SESSION_NAME},cookie=${X2GO_COOKIE},errors=${SESSION_LOG},kbtype=${X2GO_KBD_TYPE},${option_geometry}xinerama=${xinerama_option},resize=${X2GO_RESIZE},fullscreen=${X2GO_FULLSCREEN},accept=${REMOTE},listen=${GR_PORT}${clipboard},client=linux,menu=0,state=${STATE_FILE}"
fi


echo "${X2GO_HOST}:${X2GO_PORT}" >"${SESSION_DIR}/options"

NX_AGENT=":${X2GO_PORT}"
SAVED_DISPLAY="${DISPLAY}"

# Make shellcheck happy.
: "${SAVED_DISPLAY}"

DISPLAY="nx/nx,options=${SESSION_DIR}/options:${X2GO_PORT}"
export DISPLAY


if [[ -z "${X2GODPI}" ]]; then
	X2GODPIOPTION_=''
else
	X2GODPIOPTION_="-dpi ${X2GODPI}"
fi

NOLISTOPT=''
if [[ -z "${X2GOXDMCP}" ]] ;then
	XDMCPOPT=''
	if [[ "${X2GO_NXAGENT_OPTIONS}" != "${X2GO_NXAGENT_OPTIONS/ -nolisten tcp/}" ]]; then
		NOLISTOPT='-nolisten tcp'
	fi
else
	XDMCPOPT="-query ${X2GOXDMCP}"
fi

# run x2goserver-extensions for pre-start
x2gofeature 'X2GO_RUN_EXTENSIONS' &>'/dev/null' && x2goserver-run-extensions "${SESSION_NAME}" 'pre-start' || true

SESSION_WINDOW_TITLE="X2GO-${SESSION_NAME}"
agent_geometry=''
if [[ -n "${X2GO_GEOMETRY}" ]] && [[ "${X2GO_GEOMETRY}" != 'fullscreen' ]]; then
	agent_geometry="-geometry ${X2GO_GEOMETRY}"
fi

# systemd is prone to kill remaining sessions on user logouts.
# That sort of makes sense to clean up stray processes,
# but gets in the way of our persistent session scheme.
loginctl 'enable-linger' &>'/dev/null' || :

X2GO_AGENT_PID='0'
if [[ "${X2GO_STYPE}" = 'S' ]]; then
	# unset LD_LIBRARY_PATH for the case when x2gostartagent started from x2godesktopsharing
	unset LD_LIBRARY_PATH
	# set NX_TEMP to /tmp, make sure x2goagent starts when pam_tmpdir.so is in use
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'debug' "started nxagent: NX_TEMP=/tmp x2goagent X2GO_NXAGENT_OPTIONS ('${X2GO_NXAGENT_OPTIONS}') NOLISTOPT ('${NOLISTOPT}') X2GODPIOPTION_ ('${X2GODPIOPTION_}') -SESSION_TYPE ('-${SESSION_TYPE}') -auth \"XAUTHORITY\" ('\"${XAUTHORITY}\"') -shadow SHADOW_DESKTOP ('${SHADOW_DESKTOP}') -shadowmode SHADOW_MODE ('${SHADOW_MODE}') agent_geometry ('${agent_geometry}') -name \"SESSION_WINDOW_TITLE\" ('\"${SESSION_WINDOW_TITLE}\"') \"NX_AGENT\" ('\"${NX_AGENT}\"') 2>\"SESSION_LOG\" ('\"${SESSION_LOG}\"') &"
	NX_TEMP='/tmp' x2goagent ${X2GO_NXAGENT_OPTIONS} ${NOLISTOPT} ${X2GODPIOPTION_} -${SESSION_TYPE} -auth "${XAUTHORITY}" -shadow ${SHADOW_DESKTOP} -shadowmode ${SHADOW_MODE} ${agent_geometry} -name "${SESSION_WINDOW_TITLE}" "${NX_AGENT}" 2>"${SESSION_LOG}" &
else
	# set NX_TEMP to /tmp, make sure x2goagent starts when pam_tmpdir.so is in use
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'debug' "started nxagent: NX_TEMP=/tmp x2goagent X2GO_NXAGENT_OPTIONS ('${X2GO_NXAGENT_OPTIONS}') NOLISTOPT ('${NOLISTOPT}') X2GODPIOPTION_ ('${X2GODPIOPTION_}') XDMCPPOPT ('${XDMCPOPT}') -SESSION_TYPE ('-${SESSION_TYPE}') NOEXITPARAM ('${NOEXITPARAM}') -auth \"XAUTHORITY\" ('\"${XAUTHORITY}\"') agent_geometry ('${agent_geometry}') -name \"SESSION_WINDOW_TITLE\" ('\"${SESSION_WINDOW_TITLE}\"') \"NX_AGENT\" ('\"${NX_AGENT}\"') 2>\"SESSION_LOG\" ('\"${SESSION_LOG}\"') &"
	NX_TEMP='/tmp' x2goagent ${X2GO_NXAGENT_OPTIONS} ${NOLISTOPT} ${X2GODPIOPTION_} ${XDMCPOPT} -${SESSION_TYPE} ${NOEXITPARAM} -auth "${XAUTHORITY}" ${agent_geometry} -name "${SESSION_WINDOW_TITLE}" "${NX_AGENT}" 2>"${SESSION_LOG}" &
fi

ln -s -- "${SESSION_DIR}" "${X2GO_ROOT}/C-${SESSION_NAME}"

X2GO_AGENT_PID="${!}"

if [[ -n "${SHADREQ_USER}" ]]; then
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'info' "creating new shadow session: ${SESSION_NAME} ${X2GO_COOKIE} ${X2GO_AGENT_PID} ${X2GO_CLIENT} ${GR_PORT} ${SOUND_PORT} ${FS_PORT} ${SHADREQ_USER}"
	"${X2GO_LIB_PATH}/x2gocreateshadowsession" "${SESSION_NAME}" "${X2GO_COOKIE}" "${X2GO_AGENT_PID}" "${X2GO_CLIENT}" "${GR_PORT}" "${SOUND_PORT}" "${FS_PORT}" "${SHADREQ_USER}" >'/dev/null'
else
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'info' "creating new session: ${SESSION_NAME} ${X2GO_COOKIE} ${X2GO_AGENT_PID} ${X2GO_CLIENT} ${GR_PORT} ${SOUND_PORT} ${FS_PORT} ${TEKICTRL_PORT} ${TEKIDATA_PORT}"
	"${X2GO_LIB_PATH}/x2gocreatesession" "${SESSION_NAME}" "${X2GO_COOKIE}" "${X2GO_AGENT_PID}" "${X2GO_CLIENT}" "${GR_PORT}" "${SOUND_PORT}" "${FS_PORT}" "${TEKICTRL_PORT}" "${TEKIDATA_PORT}" >'/dev/null'
fi

if [[ "${X2GO_SET_KBD}" = '0' ]] || [[ "${X2GO_KBD_TYPE}" != 'auto' ]]; then
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'info' "blocking creation of agent's keyboard file ${SESSION_DIR}/keyboard as requested by session startup command"
	mkdir -p -- "${SESSION_DIR}/keyboard"
fi

if ps -p "${X2GO_AGENT_PID}" &>'/dev/null'; then
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'notice' "successfully started X2Go Agent session with ID ${SESSION_NAME}"

	# run x2goserver-extensions for post-start
	x2gofeature 'X2GO_RUN_EXTENSIONS' &>'/dev/null' && x2goserver-run-extensions "${SESSION_NAME}" 'post-start' || true
else
	typeset msg="Failed to start X2Go Agent session with ID ${SESSION_NAME}. X2Go Agent terminated unexpectedly. Aborting session startup."
	"${X2GO_LIB_PATH}/x2gosyslog" "${0}" 'err' "${msg}"

	# Make x2goclient fail.
	echo "${msg}" >&2

	# run x2goserver-extensions for fail-start
	x2gofeature 'X2GO_RUN_EXTENSIONS' &>'/dev/null' && x2goserver-run-extensions "${SESSION_NAME}" 'fail-start' || true

	exit '12'
fi

echo "${X2GO_PORT}"
echo "${X2GO_COOKIE}"
echo "${X2GO_AGENT_PID}"
echo "${SESSION_NAME}"
echo "${GR_PORT}"
echo "${SOUND_PORT}"
echo "${FS_PORT}"
if [[ "${X2GO_TELEKINESIS_ENABLED}" = '1' ]]; then
	echo "${TEKICTRL_PORT}"
	echo "${TEKIDATA_PORT}"
fi
