#! /bin/sh -
#
# A script to configure the keyboard map on console
#
# Copyright (c) 2019-2020 Matias Fonzo, <selk@dragora.org>.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Exit immediately on any error
set -e

PROGRAM="${0##*/}"
TMPDIR="${TMPDIR:-$HOME}"
TMPFILE="${TMPDIR}/.${PROGRAM}.${RANDOM-0}$$"
OUTPUT="${TMPFILE}.data"
LOCKFILE=/var/lock/dragora-keymap.lockfile
KEYMAPS="${KEYMAPS:-/usr/share/keymaps/i386}"

chkstatus_or_exit()
{
    status=$?

    # Clean up temporary files
    rm -f -- "$TMPFILE" "$LOCKFILE"

    if test $status -ne 0
    then
        printf '%s\n' "" "Return status = $status" 1>&2
        exit 2;
    fi

    unset status
}

# Sanity checks

if test ! -d "$TMPDIR"
then
    echo "${PROGRAM}: \`${TMPDIR}' is not a qualified temporary directory" 1>&2
    exit 1;
fi
if test ! -w "$TMPDIR"
then
    echo "${PROGRAM}: \`${TMPDIR}' is not a writable temporary directory" 1>&2
    exit 1;
fi
if test ! -d "$KEYMAPS"
then
    echo "${PROGRAM}: Directory \`${KEYMAPS}' for keyboard maps does not exist as such" 1>&2
    exit 1;
fi

trap 'chkstatus_or_exit' EXIT HUP INT QUIT ABRT TERM

umask 077;      # Remove access for all but user.

# Unfortunately, loadkeys(1) is limited to the superuser;
# we set a lock to allow only one instance of the script.

if ( set -C ; echo ": $PROGRAM - locked" > $LOCKFILE ) 2> /dev/null
then
    true
else
    if test -e "$LOCKFILE"
    then
        echo "Only one instance of \`${PROGRAM}' is allowed." 1>&2
        exit 1;
    else
        echo "${PROGRAM}: \`${LOCKFILE}' lock failed." 1>&2
        exit 2;
    fi
fi

### Search for keyboard map files

search="$(find "$KEYMAPS" \( -type l -o -type f \) -name '*.map*' -print | LANG=C sort 2> /dev/tty)"

if test -z "$search"
then
    echo "No keyboard maps were found in \`${KEYMAPS}'." 1>&2
    exit 1;
fi

### Compose output file to be shown

# Header
printf '%s\n' \
 'dialog --colors \'                                         \
 ' --backtitle "\\Zb${PROGRAM} - Keyboard map selection" \'  \
 ' --title "MAIN MENU" --default-item "qwerty/us" --menu \'  \
 '"Welcome to \\Z3${PROGRAM}\\Zn!\\n\\n\'                    \
 'The following menu list is organized as keyboard \\n\'     \
 '\"layout/language\". \\n\\n\'                              \
 'Select a keyboard map for the console:" 20 56 6 \'         \
 > "$OUTPUT"

# Append 'search' to the body

for item in $search
do
    level="${item%/*}"		# Remove all except the last slash.
    level="${level##*/}"	# Starting-point under which it was found.
    item="${item%.map*}"	# Remove extension(s).
    item="${item##*/}"		# Get the base name.

    # Ignore unwanted map directories
    case $level in
    include | fgGIod)
        continue
        ;;
    *)
        echo "\"${level}/$item\"        \"\" \\" >> "$OUTPUT"
        ;;
    esac
done
unset item level search

# End of
printf "2> \$TMPFILE\\n\\n" >> "$OUTPUT"

# Import menu
. "$OUTPUT"

# Read answer from 'TMPFILE'

echo "" >> "$TMPFILE";		# Append new line for reading.
IFS= read -r REPLY < "$TMPFILE" || exit 2;

# Compose values by layout/map to be set

layout="${REPLY%/*}"
map="${REPLY##*/}"

unset REPLY

# Temporary files are not needed anymore
rm -f -- "$TMPFILE" "$OUTPUT"

umask 022;	# Remove write permission for group and other.

# Set keyboard map
loadkeys "${layout}/$map"

while true
do
    testkeys="$(
     dialog --colors \
      --no-mouse --no-cancel --no-ok \
      --backtitle "\\Zb${PROGRAM} - Keyboard map check" \
      --title "SELECTED KEYMAP: ${layout}/$map" \
      --inputbox \
"Try the chosen keyboard map by typing something.  Once satisfied\\n\
type \\Zb\\Z71\\Zn (or \\Zb\\Z7y\\Zn) then hit \\Zb\\Z7ENTER\\Zn \
to continue.  To choose a different keyboard map, type \\Zb\\Z72\\Zn (or \
\\Zb\\Z7n\\Zn) plus \\Zb\\Z7ENTER\\Zn." 10 68 2>&1 > /dev/tty
    )"
    case $testkeys in
    1 | Y | y)
        break
        ;;
    2 | N | n)
        rm -f -- "$LOCKFILE"
        exec "$0"
        ;;
    esac
done
unset testkeys

dialog --colors \
 --backtitle "\\Zb${PROGRAM} - Configuration file" \
 --title "/etc/rc.conf" --yesno \
"Would do you like to save this change for the next reboot?" 5 62
echo ""
echo "Setting 'RC_KEYMAP=${layout}/$map' on /etc/rc.conf ..."
echo ",s/^\\(RC_KEYMAP\\)=.*/\\1=${layout}\\/${map}/"$'\nw' | \
 ed /etc/rc.conf && echo Done.

