#!/bin/sh -eu

. shell-error

is_touchpad="${IS_TOUCHPAD:-is_touchpad}"
mouseconf="${MOUSECONF:-mouseconf}"
serial_mouse_scan="${SERIALMOUSESCAN:-serial_mouse_scan}"
mousedb="${MOUSEDB:-/usr/share/alterator-x11/mousedb}"

def_x11_driver="mouse"
def_x11_device="/dev/input/mice"

def_gpm_type="ps/2"
def_gpm_device="/dev/input/mice"

xorg_config="/etc/X11/xorg.conf"
gpm_config="/etc/sysconfig/mouse"

dry_run=
libXiconfig=1

usage() {
	local rc="${1:-0}"
	cat <<-EOF
	Usage: ${0##*/} [Options] [(xorg|gpm)]

	Program used to setup Xorg and/or GPM configuration.

	Options:
	 --dry-run              Do nothing (for debug).
	 -c, --xorg-conf=FILE   Define Xorg config file (default: $xorg_config).
	 -g, --gpm-conf=FILE    Define GPM config file (default: $gpm_config).
	 -x, --no-libxiconfig   Make Xorg config for using without libXiconfig (add all input sections)
	 -h, --help             Show this message.
	EOF
	exit $rc
}

parsedb() {
	local name= prefix= line= rc=1 found=
	name="$1"; shift
	keyword="$1"; shift

	name="${name#\"}"
	name="${name%\"}"
	name="\"$name\""

	while read line; do
		case "$line" in
			${name})
				rc=0
				;;
			+${keyword}*)
				[ "$rc" = "0" ] || continue
				printf %s\\n "$line" | sed -n -e 's,[[:space:]]\+, ,g' -e "s,^+$keyword ,,p"
				found=1
				;;
			\"*)
				[ "$rc" = "1" ] || break
				;;
		esac
	done < "$mousedb"

	[ -n "$found" ] || rc=2

	return $rc
}

check_touchpad() {
	local h dev rc=1
	[ -f "$(getconf LIBDIR)/X11/modules/input/synaptics_drv.so" ] ||
		return $rc

	for h in $handlers; do
		dev="/dev/input/$h"
		[ -c "$dev" ] && $is_touchpad "$dev" || continue
		rc=0
		break
	done
	return $rc
}

setup_xorg() {
	local driver device

	driver="$(parsedb "$name" "x11.driver")" ||
		driver="$def_x11_driver"

	if ! device="$(check_touchpad)"; then
		device="$(parsedb "$name" "x11.device")" ||
			device="$def_x11_device"
	fi

	printf 'Identifier "%s|%s"\n' \
		"$(printf '%s\n' "$name" |sed -e 's/[[:space:]]\+/ /g' -e 's/["\\]//g')" \
		"$num"
	printf 'Driver "%s"\n' "$driver"
	printf 'Option "Device" "%s"\n' "$device"
	parsedb "$name" "x11.line" ||
		parsedb "default" "x11.line"
}

setup_gpm() {
	local mousetype device

	mousetype="$(parsedb "$name" "gpm.type")" ||
		type="$def_gpm_type"

	device="$(parsedb "$name" "gpm.device")" ||
		device="$def_gpm_device"

	printf 'MOUSETYPE="%s"\n' "$mousetype"
	printf 'device="%s"\n' "${device#/dev/}"
}

xorg_remove_all() {
	"$mouseconf" -s -c "$xorg_config" |
		xargs -ri "$mouseconf" -d -c "$xorg_config" '{}'
}

# setup mice found at /proc/bus/input/devices
read_proc() {
	local prefix line
	num=0
	while read prefix line; do
		case "$prefix" in
			P:)	phys=${line#Phys=} ;;
			N:)	name="${line#Name=}" ;;
			H:)	handlers="${line#Handlers=}" ;;
			"")
				[ -z "${handlers##*mouse*}" ] || continue
				[ -n "$phys" ] || continue

				if [ -z "${subsystem##*xorg*}" ]; then
				  if [ -z "$dry_run" ]; then
				    [ -n "$libXiconfig" ] ||
				      setup_xorg | "$mouseconf" -a -c "$xorg_config"
				  else
				    setup_xorg
				  fi
				fi
	
				if [ -z "${subsystem##*gpm*}" ]; then
					[ -z "$dry_run" ] &&
						setup_gpm > "$gpm_config" ||
						setup_gpm
				fi

				name= handlers=
				num=$(($num+1))
				;;
		esac
	done < /proc/bus/input/devices
}

setup_xorg_serial()
{
    local device="$1";shift

    printf 'Identifier "%s"\n' "$device"
    printf 'Driver "%s"\n' "mouse"
    printf 'Option "Device" "/dev/%s"\n' "$device"
    printf 'Option "Protocol" "%s"\n' "microsoft"
}

read_serial()
{
    "$serial_mouse_scan"|
	while read device;do
	    [ -z "$dry_run" ] &&
		setup_xorg_serial "$device"| "$mouseconf" -a -c "$xorg_config" ||
		setup_xorg_serial "$device"
	done
}

TEMP=`getopt -n $PROG -o c:,g:,h,x -l xorg-conf:,gpm-conf:,dry-run,help,libXiconfig -- "$@"` || usage 1
eval set -- "$TEMP"
while :; do
	case "$1" in
	    	--dry-run) dry_run=1
			;;
		-c|--xorg-conf) shift
			xorg_config="$(readlink -ev "$1")"
			;;
		-g|--gpm-conf) shift
			gpm_config="$(readlink -ev "$1")"
			;;
		-x|--no-libxiconfig)
			libXiconfig=
			;;
		-h|--help) usage
			;;
		--) shift; break
			;;
		*) fatal "unrecognized option: $1"
			;;
	esac
	shift
done

subsystem="xorg gpm"
[ "$#" -eq 0 ] || subsystem="$*"

case  "$subsystem" in
	xorg|gpm|"xorg gpm") ;;
	*) usage 1 ;;
esac

if [ -z "${subsystem##*xorg*}" -a ! -w "$xorg_config" ]; then
  fatal "$xorg_config: Permission denied"
fi

if [ -z "${subsystem##*gpm*}" -a ! -w "$gpm_config" ]; then
  fatal "$gpm_config: Permission denied"
fi

[ -n "${subsystem##*xorg*}" -o -n "$dry_run" ] ||
  xorg_remove_all ||
  fatal "Unable to clean $xorg_config"


# configure ps/2 and usb mice from /proc/bus/input/devices
# With libXiconfig we don't need configuration for
# ps and usb mice in X.
read_proc

# configure serial mice
read_serial

# if we don't use libXiconfig and we have no configured mice yet
# use /dev/ttyS0 as a fallback
if [ -z "$libXiconfig" -a -z "$("$mouseconf" -s -c "$xorg_config")" ]; then
     [ -z "$dry_run" ] &&
       ( setup_xorg_serial "ttyS0" | "$mouseconf" -a -c "$xorg_config" ) ||
       setup_xorg_serial "ttyS0"
fi
