#!/bin/bash

# Copyright (C) 2007-2023 X2Go Project - https://wiki.x2go.org
# Copyright (C) 2011-2023 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
# Copyright (C) 2011-2023 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de>
# Copyright (C) 2011-2023 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: $@"

SESSION_NAME=${1:-$X2GO_SESSION}

# set up paths
X2GO_SESSION_ROOT=${HOME}/.x2go
X2GO_SESSION_DIR=${X2GO_SESSION_ROOT}/C-${SESSION_NAME}

# client keyboard configuration
X2GO_CLIENT_KBD_FILE=${X2GO_SESSION_DIR}/keyboard

# if there is a directory at the location of the keyboard file, we consider this as blocking this script
if [ -d ${X2GO_CLIENT_KBD_FILE} ]; then
	$X2GO_LIB_PATH/x2gosyslog "$0" "info" "${X2GO_CLIENT_KBD_FILE} is blocked, not setting keyboard parameters from client-side settings"
	rm -Rf ${X2GO_CLIENT_KBD_FILE}
	exit 0
fi

# wait for the keyboard file to appear
i=0
while ! [ -f ${X2GO_CLIENT_KBD_FILE} ] && [ $i -lt 30 ]; do
	$X2GO_LIB_PATH/x2gosyslog "$0" "info" "Waiting for ${X2GO_CLIENT_KBD_FILE} to appear"
	sleep 1
	i=$((i+1))
done
if  ! [ -f ${X2GO_CLIENT_KBD_FILE} ]; then
	$X2GO_LIB_PATH/x2gosyslog "$0" "warning" "${X2GO_CLIENT_KBD_FILE} did not appear within 30s after agent startup"
	exit 0
fi

# Used to hold options to setxkbmap.
typeset -a setxkbmap_opts

# retrieve keyboard settings from keyboard file in X2Go session dir
read_keyboard_file() {
	# Cache file contents.
	typeset -a file_content
	typeset line=''
	while IFS='' read -r line; do
		file_content+=("${line}")
	done < "${X2GO_CLIENT_KBD_FILE}"

	# Append last line if not terminated by a newline.
	[[ "${line}" ]] && file_content+=("${line}")

	for line in "${file_content[@]}"; do
		# Extract the keys, their values and add to setxkbmap_opts.
		typeset key=''
		for key in "rules" "model" "layout" "variant" "options"; do
			# This does not support quotes characters within values. Shouldn't be necessary, anyway.
			# Matching escaped quote characters is possible, but complicated and not worth the effort.
			# Probably.
			typeset regexp='^[[:space:]]*'"${key}"'[[:space:]]*=[[:space:]]*"?([^"]*)"?[[:space:]]*'
			if [[ "${line}" =~ ${regexp} ]]; then
				typeset value="${BASH_REMATCH[1]}"

				if [ -n "${value}" ]; then
					# Handle a special substitution case for evdev-based rules.
					# FIXME: find out why that substitution is needed in the first place!
					[ "${key}" = 'rules' ] && value="${value//evdev/base}"

					# Even though the keyboard file contains "options" as the key,
					# setxkbmap expects a parameter called "-option".
					typeset option="${key}"
					[ "${option}" = 'options' ] && option='option'

					setxkbmap_opts+=("-${option}" "${value}")
				fi
			fi
		done
	done
}

reset_keymap() {
	setxkbmap -layout us -option "" -model pc104
}

update_keymap() {
	# update keyboard map
	setxkbmap "${setxkbmap_opts[@]}"
}

### main ###
$X2GO_LIB_PATH/x2gosyslog "$0" "notice" "Setting X keyboard according to ${X2GO_CLIENT_KBD_FILE}"
read_keyboard_file
reset_keymap
update_keymap

