#!/bin/bash

# uncomment for very verbose script debugging...
#set -x

# Copyright (C) 2012-2017 by Debian Edu project, http://wiki.debian.org/DebianEdu
#       2012-2017, Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
#       2016, Daniel Teichmann <daniel.letsplay007@gmail.com>
#       2017, Benjamin Schlüter <bschlueter@posteo.de>

# Surf Kiosk Display 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.
#
# Surf Kiosk Display 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.

# dependencies:
#     surf
#     wmctrl
#     matchbox-window-manager
#     pulseaudio-utils
#     xprintidle
#     xdotool
#     xmodmap
#     x11-xkb-utils
#
# recommendations:
#     unclutter
#     pulseaudio
#     x11-xserver-utils

VERSION="0.0.5"

BROWSER=surf

# Can be configured at "/etc/default/${BROWSER}-display"
DEFAULT_WWW_URI="file:///usr/share/${BROWSER}-display/empty-page.html"
DEFAULT_RESOLUTION=""

# all displays that need to be changed
declare -A DISPLAYS

# launch pulseaudio daemon if not already running
WITH_PULSEAUDIO="yes"

# hide idle mouse pointer
HIDE_IDLE_POINTER="yes"

# disable right and middle pointer device click in browser sessions while keeping
# scrolling wheels' functionality intact... (consider "pointer" subcommand on
# xmodmap man page for details).
POINTER_BUTTON_MAP="1 0 0 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"

# default screensaver settings
SCREENSAVER_SETTINGS=""

# don't use an HTTP proxy by default
HTTP_PROXY_URL=""

# log to stderr, if not set to "yes" in one of the config files...
LOG_TO_SYSLOG=no

# interval of browser inactivity before the session is reset automatically (in seconds)
INACTIVITY_INTERVAL="300"

if type -p xrandr 1>/dev/null; then
	currentOutput=`echo "$(xrandr)" | grep -w 'connected' | sed -r -e 's/connected.*//' | head -n 1`
fi

if [ -r /etc/default/${BROWSER}-display ] && [ ! -d /etc/default/${BROWSER}-display ]; then
	. /etc/default/${BROWSER}-display
fi

if [ -r $HOME/.${BROWSER}-display/config ] && [ ! -d $HOME/.${BROWSER}-display/config ]; then
	. $HOME/.${BROWSER}-display/config
fi

if [ "x$LOG_TO_SYSLOG" = "xyes" ]; then
	OUTPUT="logger -t ${BROWSER}-display"
else
	OUTPUT="echo"
fi

workdir="$HOME/.${BROWSER}-display"
mkdir -p "$workdir"

session_lock="$workdir/.session-lock.$$"
browser_lock="$workdir/.surf-lock"

browser_config_dir=`mktemp -d -p "$workdir" ${BROWSER}-display-profile-XXXXXX`

# provide pulseaudio support in the browser session, if not
# already available...
if ! pacmd stat 1>/dev/null 2>/dev/null; then
	if [ "x$WITH_PULSEAUDIO" = "xyes" ]; then
		if which pulseaudio 1>/dev/null; then
			pulseaudio -D -n \
			           -L 'module-udev-detect' \
			           --exit-idle-time=65535
		fi
	fi
fi

# launch matchbox manager
if ! wmctrl -m 1>/dev/null 2>/dev/null; then
	if which matchbox-window-manager 1>/dev/null; then
		matchbox-window-manager 1>/dev/null 2>/dev/null&
	fi
fi

# use unclutter to hide idle mouse pointers
if [ "x$HIDE_IDLE_POINTER" = "xyes" ]; then
	if which unclutter 1>/dev/null; then
		unclutter 1>/dev/null 2>/dev/null &
	fi
fi

# hack mouse pointer functionality to e.g. disable "right-click" in browser session
sanitized_pointer_button_map=$(echo ${POINTER_BUTTON_MAP//[^0-9\ ]/} | sed -e 's/^\s*//' -e 's/\s*$//')
count_buttons_pointer_button_map=$(echo -n "${sanitized_pointer_button_map//[0-9]/}"| wc -m)

if which xmodmap 1>/dev/null; then
	if [ -n "$POINTER_BUTTON_MAP" ] && [ "x$POINTER_BUTTON_MAP" = "x$sanitized_pointer_button_map" ] && \
	  [ $count_buttons_pointer_button_map -lt 32 ]; then
		xmodmap -e "pointer = $POINTER_BUTTON_MAP"
	fi
else
	$OUTPUT "WARNING: Cannot strip down mouse/pointer button functionality. Make sure 'xmodmap' is installed."
fi

if which setxkbmap 1>/dev/null; then
	setxkbmap -option "terminate:ctrl_alt_bksp"
fi

# if FAKE_HOSTNAME is not empty, use that string for hostname
THIS_HOSTNAME=$(hostname -f)
if [ -n "$FAKE_HOSTNAME" ]; then
	THIS_HOSTNAME="$FAKE_HOSTNAME"
fi

if `echo ${!DISPLAYS[@]} | grep -q "$THIS_HOSTNAME"`; then 
	$OUTPUT "INFO: $THIS_HOSTNAME has extra properties. loading them.."

	if echo ${DISPLAYS[$THIS_HOSTNAME]} | grep -q "www_uri="; then
		WWW_URI=`echo ${DISPLAYS[$THIS_HOSTNAME]} | sed -r -e 's/(^|.*\|)www_uri=([^|]*).*/\2/'`
	else
		WWW_URI="$DEFAULT_WWW_URI"
	fi

	if echo ${DISPLAYS[$THIS_HOSTNAME]} | grep -q "res="; then
		RESOLUTION=`echo ${DISPLAYS[$THIS_HOSTNAME]} | sed -r -e 's/(^|.*\|)res=([^|]*).*/\2/'`
	else
		RESOLUTION="$DEFAULT_RESOLUTION"
	fi
else
	WWW_URI="$DEFAULT_WWW_URI"
	RESOLUTION="$DEFAULT_RESOLUTION"
fi

if ! echo "$WWW_URI" | grep -q -E "^(file://|http://|https://).*"; then
	$OUTPUT "ERROR: WWW_URI format not supported: $WWW_URI"
	$OUTPUT "       Use file://<path>/<index>.<html> or http(s)://<host>/<path>/<index>.<html>."
	$OUTPUT "       Doing nothing."
	exit -1
fi

if [ -n "${RESOLUTION}" ]; then
	if type -p xrandr 1>/dev/null; then
		xrandr -d :0 --output "$(echo $currentOutput)" --mode $RESOLUTION
	fi
fi

# Set screensaver settings
if which xset 1>/dev/null; then
	xset s ${SCREENSAVER_SETTINGS}
fi

# set some proxy related env variables, if requested...
if [ -n "$HTTP_PROXY_URL" ]; then
	export http_proxy="$HTTP_PROXY_URL"
	export https_proxy="$HTTP_PROXY_URL"
	export ftp_proxy="$HTTP_PROXY_URL"
fi

function cleanup {
	if type -p xrandr 1>/dev/null; then
		$OUTPUT "Info: resetting resolution"
		xrandr -d :0 --output "$(echo $currentOutput)" --auto
	fi

	if [ -r "$browser_lock" ]; then
		browser_pid=$(cat "$browser_lock" | sed -e 's/[^0-9]*//g')
		if [ -n "$browser_pid" ]; then
			kill -0 $browser_pid 2>/dev/null && kill "$browser_pid"
		fi
	fi

	if [ -d "$browser_config_dir" ]; then
		rm -R "$browser_config_dir"
	fi

	for rmfile in $browser_lock \
	              $session_lock \
	              ;
	do
		if [ -e "$rmfile" ]; then
			rm "$rmfile"
		fi
	done

}
trap "cleanup" SIGINT SIGTERM ERR EXIT

function browser_loop {
	if [ "x$INACTIVITY_INTERVAL" != "x0" ]; then
		(
			while [ -e "$session_lock" ]; do
				sleep 1
				if [ `xprintidle 2>/dev/null || echo 0` -gt $(($INACTIVITY_INTERVAL*1000)) ]; then
					echo -n "RESTART" > $browser_lock
					$OUTPUT "INFO: Triggering browser restart, too much idling around..."
					# reset X11 idle counter by some harmless key event
					xdotool key Shift
				fi
			done
		) &
	fi
}


function browser_session {

	if which "${BROWSER}" 1>/dev/null; then

		while [ -e "$session_lock" ]; do

			LANG=C ${BROWSER}				\
			           -a "A"				\
			           -B					\
			           -c "${browser_config_dir}/cookies"	\
			           -D					\
			           -F					\
			           -g					\
			           -I					\
			           -K					\
			           -m					\
			           -n					\
			           -P					\
			           -S					\
			           "${WWW_URI}" 1>/dev/null 2>/dev/null &

			browser_pid=$!

			echo -n "$browser_pid" > "$browser_lock"

			while [ -r "$browser_lock" ] && [ "$(cat $browser_lock)" != "RESTART" ] && [ -e "$session_lock" ]; do
				sleep 1
				if ! kill -0 "$browser_pid" 2>/dev/null; then
					if [ -e ${session_lock} ]; then
						rm "${session_lock}"
					fi
					if [ -d "${browser_config_dir}" ]; then
						rm -R "${browser_config_dir}"
					fi
					break

					browser_config_dir=`mktemp -d -p "$workdir" ${BROWSER}-display-profile-XXXXXX`

				fi
			done

			kill -0 "$browser_pid" 2>/dev/null && kill "$browser_pid"
			$OUTPUT "INFO: The surf application has terminated."

		done

	else
		$OUTPUT "ERROR: The surf application is not installed."
	fi

}


function create_lock {

	touch "$session_lock"

}

### MAIN ###

$OUTPUT "INFO: Surf Kiosk Display (version $VERSION)"
$OUTPUT "INFO: HOSTNAME set to: $THIS_HOSTNAME"

if [ -n "$WWW_URI" ]; then

	$OUTPUT "INFO: WWW_URI is configured. Using content from given URL: $WWW_URI"
	create_lock
	browser_loop

else

	$OUTPUT "ERROR: WWW_URI hasn't been configured. Doing nothing."
	exit 0

fi

browser_session

exit 0
