#!/bin/sh

# dexconf: Debian X server configuration file writer
#
# This tool is a backend which uses debconf database values.  It writes an
# XFree86 X server configuration file based on the information in the database.
#
# Author: Branden Robinson

# Copyright 2000--2004 Progeny Linux Systems, Inc.
#
# This is free software; you may 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,
# or (at your option) any later version.
#
# This 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 with
# the Debian operating system, in /usr/share/common-licenses/GPL;  if
# not, write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307 USA

set -e

# source debconf library
. /usr/share/debconf/confmodule

# display a usage message
usage () {
  cat <<EOF
Usage: $PROGNAME [OPTION ...]
  write an Xorg X server configuration file based on debconf database values
Options:
  -h, --help                                 display this usage message and exit
  -o FILE, --output=FILE                        write configuration file to FILE
This help message is intended only as a quick reference.  For a description of
the usage of $PROGNAME, see the $PROGNAME(1) manual page.
EOF
}

# the error-out function
bomb () {
  echo "$PROGNAME: error: $*" | fold -s -w "${COLUMNS:-80}" >&2
  exit 1
}

# wrapper around db_get to ensure that the info we try to retrieve exists; it
# is (almost) always a fatal error for the values to be null
fetch () {
  db_get "$1" || true
  if [ -z "$RET" ]; then
    ERRMSG="cannot generate configuration file; $1 not set.  Aborting."
    ERRMSG="$ERRMSG  Reconfigure the X server with \"dpkg-reconfigure"
    if [ -n "$XSERVERPKG" ]; then
      ERRMSG="$ERRMSG $XSERVERPKG"
    fi
    ERRMSG="$ERRMSG\" to correct this problem."
    bomb "$ERRMSG"
  fi
}

# convert a debconf comma-delimited list to a shell whitespace-delimited list
list_convert () {
  echo $(IFS=", "; set -- $RET; while [ $# -gt 0 ]; do echo \"$1\"; shift; done)
}

PROGNAME=${0##*/}
SHOWHELP=
EARLYEXIT=

GETOPT_OUTPUT=$(getopt --options ho: \
                       --longoptions help,output: \
                       -n "$PROGNAME" -- "$@")

if [ $? -ne 0 ]; then
    bomb "error while getting options; use \"$PROGNAME --help\" for help"
fi

eval set -- "$GETOPT_OUTPUT"

while :; do
    case "$1" in
        -f|--format)
          bomb "This option, and XFree86 3.x output, are no longer supported."
          ;;
        -h|--help) SHOWHELP=yes EARLYEXIT=yes ;;
        -o|--output) XF86CONFIG="$2"; shift ;;
        --) shift; break ;;
        *)
          bomb "unrecognized option \"$1\"; use \"$PROGNAME --help\" for help"
          ;;
    esac
    shift
done

if [ -n "$SHOWHELP" ]; then
    usage
fi

if [ -n "$EARLYEXIT" ]; then
    exit 0
fi


if which laptop-detect >/dev/null 2>&1; then
  if laptop-detect > /dev/null ; then
    LAPTOP=true
  fi
fi

DEXCONFTMPDIR=

trap 'if [ -e "$DEXCONFTMPDIR/backup" ] && [ -n "$XF86CONFIG" ]; then \
        cat "$DEXCONFTMPDIR/backup" >"$XF86CONFIG"; \
      fi; \
      exec 4<&-; \
      rm -rf "$DEXCONFTMPDIR"; \
      bomb "received signal; aborting"' HUP INT QUIT TERM

# Ensure we know how to write a configuation file for the X server in use.
fetch shared/default-x-server
XSERVERPKG="$RET"
case "$XSERVERPKG" in
  xserver-xorg|xserver-xorg-dbg|xserver-xorg-core)
    : ${XF86CONFIG:=/etc/X11/xorg.conf}
    REALCONFIG="/etc/X11/xorg.conf"
    SERVER="xorg"
    ;;
  *)
    bomb "this program does not know how to configure the \"$XSERVERPKG\" X" \
      "server"
esac

# Set up a temporary directory for the files we'll be writing.
TDIR_PARENT="${TMPDIR:-/tmp}"
TDIR="${TMPDIR:-/tmp}/dexconf-tmp-$$"

if [ ! -d "$TDIR_PARENT" ]; then
  bomb "cannot create temporary work directory; \"$TDIR_PARENT\" does not" \
    "exist or is not a directory"
fi

if [ ! -w "$TDIR_PARENT" ]; then
  bomb "cannot create temporary work directory in \"$TDIR_PARENT\"; directory" \
    "not writable"
fi

rm -rf "$TDIR"

if mkdir -m 0700 "$TDIR"; then
  DEXCONFTMPDIR="$TDIR"
else
  bomb "creation of temporary work directory \"$TDIR\" failed"
fi

# xorg.conf sections:
#   Files          File pathnames
#   ServerFlags    Server flags                      NOT USED BY DEXCONF
#   Module         Dynamic module loading
#   InputDevice    Input device description
#   Device         Graphics device description
#   VideoAdaptor   Xv video adaptor description      NOT USED BY DEXCONF
#   Monitor        Monitor description
#   Modes          Video modes descriptions          NOT USED BY DEXCONF
#   Screen         Screen configuration
#   ServerLayout   Overall layout
#   DRI            DRI-specific configuration
#   Vendor         Vendor-specific configuration     NOT USED BY DEXCONF

### HEADER

# Because debconf hijacks standard output and its confmodule uses file
# descriptor 3 for its own purposes, we will write our output to file descriptor
# 4 instead of standard output.

exec 4>"$DEXCONFTMPDIR/Header"
cat >&4 <<SECTION
# $REALCONFIG ($SERVER X Window System server configuration file)
#
# This file was generated by dexconf, the Debian X Configuration tool, using
# values from the debconf database.
#
# Edit this file with caution, and see the $REALCONFIG manual page.
# (Type "man $REALCONFIG" at the shell prompt.)
#
# This file is automatically updated on $XSERVERPKG package upgrades *only*
# if it has not been modified since the last upgrade of the $XSERVERPKG
# package.
#
# If you have edited this file but would like it to be automatically updated
# again, run the following command:
#   sudo dpkg-reconfigure -phigh $XSERVERPKG
SECTION

### FILES

fetch xserver-$SERVER/config/write_files_section
if [ "$RET" = "true" ]; then
  FONTSERVER=""
  if db_get shared/fontpath/fontserver; then
    if [ -n "$RET" ] ; then
      FONTSERVER="$RET"
    fi
  fi
  exec 4>"$DEXCONFTMPDIR/Files"
  cat >&4 <<SECTION
Section "Files"
SECTION
  if [ -n "$FONTSERVER" ] ; then
      cat >&4 <<SECTION
	FontPath	"$FONTSERVER"
SECTION
  fi
  cat >&4 <<SECTION
	FontPath	"/usr/share/fonts/X11/misc"
	FontPath	"/usr/X11R6/lib/X11/fonts/misc"
	FontPath	"/usr/share/fonts/X11/cyrillic"
	FontPath	"/usr/X11R6/lib/X11/fonts/cyrillic"
	FontPath	"/usr/share/fonts/X11/100dpi/:unscaled"
	FontPath	"/usr/X11R6/lib/X11/fonts/100dpi/:unscaled"
	FontPath	"/usr/share/fonts/X11/75dpi/:unscaled"
	FontPath	"/usr/X11R6/lib/X11/fonts/75dpi/:unscaled"
	FontPath	"/usr/share/fonts/X11/Type1"
	FontPath	"/usr/X11R6/lib/X11/fonts/Type1"
	FontPath	"/usr/share/fonts/X11/100dpi"
	FontPath	"/usr/X11R6/lib/X11/fonts/100dpi"
	FontPath	"/usr/share/fonts/X11/75dpi"
	FontPath	"/usr/X11R6/lib/X11/fonts/75dpi"
	# path to defoma fonts
	FontPath	"/var/lib/defoma/x-ttcidfont-conf.d/dirs/TrueType"
EndSection
SECTION
fi

### MODULE

# The module list is permitted to be null.
db_get xserver-$SERVER/config/modules || true
if [ -n "$RET" ]; then
  MODULES=$(list_convert "$RET")
  exec 4>"$DEXCONFTMPDIR/Module"
  printf "Section \"Module\"\n" >&4
  for MODULE in $MODULES; do
    printf "\tLoad\t$MODULE\n" >&4
  done
  printf "EndSection\n" >&4
fi

### KEYBOARD / INPUTDEVICE

fetch xserver-$SERVER/config/inputdevice/keyboard/rules
XKB_RULES="$RET"
fetch xserver-$SERVER/config/inputdevice/keyboard/model
XKB_MODEL="$RET"
fetch xserver-$SERVER/config/inputdevice/keyboard/layout
XKB_LAYOUT="$RET"
# XkbVariant and XkbOptions are permitted to be null.
db_get xserver-$SERVER/config/inputdevice/keyboard/variant
XKB_VARIANT="$RET"
db_get xserver-$SERVER/config/inputdevice/keyboard/options
XKB_OPTIONS="$RET"

exec 4>"$DEXCONFTMPDIR/InputDeviceKeyboard"
cat >&4 <<SECTION
Section "InputDevice"
	Identifier	"Generic Keyboard"
	Driver		"kbd"
	Option		"CoreKeyboard"
	Option		"XkbRules"	"$XKB_RULES"
	Option		"XkbModel"	"$XKB_MODEL"
	Option		"XkbLayout"	"$XKB_LAYOUT"
SECTION
if [ -n "$XKB_VARIANT" ]; then
  printf "\tOption\t\t\"XkbVariant\"\t\"$XKB_VARIANT\"\n" >&4
fi
if [ -n "$XKB_OPTIONS" ]; then
  printf "\tOption\t\t\"XkbOptions\"\t\"$XKB_OPTIONS\"\n" >&4
fi
printf "EndSection\n" >&4

### MOUSE / INPUTDEVICE

DO_EMULATE3BUTTONS=

fetch xserver-$SERVER/config/inputdevice/mouse/port
MOUSE_PORT="$RET"
fetch xserver-$SERVER/config/inputdevice/mouse/protocol
MOUSE_PROTOCOL="$RET"
fetch xserver-$SERVER/config/inputdevice/mouse/emulate3buttons
if [ "$RET" = "true" ]; then
  DO_EMULATE3BUTTONS=true
fi

exec 4>"$DEXCONFTMPDIR/InputDeviceMouse"
cat >&4 <<SECTION
Section "InputDevice"
	Identifier	"Configured Mouse"
	Driver		"mouse"
	Option		"CorePointer"
	Option		"Device"		"$MOUSE_PORT"
	Option		"Protocol"		"$MOUSE_PROTOCOL"
SECTION
if [ -n "$DO_EMULATE3BUTTONS" ]; then
  printf "\tOption\t\t\"Emulate3Buttons\"\t\"true\"\n" >&4
fi
printf "EndSection\n" >&4

if [ -n "$LAPTOP" ]; then
  cat >&4 <<SECTION

Section "InputDevice"
	Identifier	"Synaptics Touchpad"
	Driver		"synaptics"
	Option		"SendCoreEvents"	"true"
	Option		"Device"		"/dev/psaux"
	Option		"Protocol"		"auto-dev"
	Option		"HorizScrollDelta"	"0"
EndSection
SECTION
fi

### DEVICE

fetch xserver-$SERVER/config/device/identifier
DEVICE_IDENTIFIER="$RET"
fetch xserver-$SERVER/config/device/driver
DEVICE_DRIVER="$RET"
# BusID, VideoRam, and UseFBDev are permitted to be null.
db_get xserver-$SERVER/config/device/bus_id
DEVICE_BUSID="$RET"
db_get xserver-$SERVER/config/device/video_ram
DEVICE_VIDEO_RAM="$RET"
db_get xserver-$SERVER/config/device/use_fbdev
DEVICE_USE_FBDEV="$RET"
exec 4>"$DEXCONFTMPDIR/Device"
cat >&4 <<SECTION
Section "Device"
	Identifier	"$DEVICE_IDENTIFIER"
	Driver		"$DEVICE_DRIVER"
SECTION
if [ -n "$DEVICE_BUSID" ]; then
  printf "\tBusID\t\t\"$DEVICE_BUSID\"\n" >&4
fi
if [ -n "$DEVICE_VIDEO_RAM" ]; then
   printf "\tVideoRam\t$DEVICE_VIDEO_RAM\n" >&4
fi
if [ "$DEVICE_USE_FBDEV" = "true" ]; then
  printf "\tOption\t\t\"UseFBDev\"\t\t\"$DEVICE_USE_FBDEV\"\n" >&4
fi
printf "EndSection\n" >&4

### MONITOR

fetch xserver-$SERVER/config/monitor/identifier
MONITOR_IDENTIFIER="$RET"
fetch xserver-$SERVER/config/monitor/horiz-sync
MONITOR_HORIZ_SYNC="$RET"
fetch xserver-$SERVER/config/monitor/vert-refresh
MONITOR_VERT_REFRESH="$RET"
db_get xserver-$SERVER/config/monitor/use_sync_ranges
MONITOR_SYNC_RANGES="$RET"

exec 4>"$DEXCONFTMPDIR/Monitor"
cat >&4 <<SECTION
Section "Monitor"
	Identifier	"$MONITOR_IDENTIFIER"
	Option		"DPMS"
SECTION

if [ "$MONITOR_SYNC_RANGES" = "true" ]; then
cat >&4 <<SECTION
	HorizSync	$MONITOR_HORIZ_SYNC
	VertRefresh	$MONITOR_VERT_REFRESH
SECTION
fi

printf "EndSection\n" >&4

### SCREEN

fetch xserver-$SERVER/config/display/default_depth
DISPLAY_DEFAULT_DEPTH="$RET"
fetch xserver-$SERVER/config/display/modes
DISPLAY_MODES="$(list_convert $RET)"

exec 4>"$DEXCONFTMPDIR/Screen"
cat >&4 <<SECTION
Section "Screen"
	Identifier	"Default Screen"
	Device		"$DEVICE_IDENTIFIER"
	Monitor		"$MONITOR_IDENTIFIER"
	DefaultDepth	$DISPLAY_DEFAULT_DEPTH
SECTION
for DEPTH in 1 4 8 15 16 24; do
  printf "\tSubSection \"Display\"\n" >&4
  printf "\t\tDepth\t\t$DEPTH\n" >&4
  if [ -n "$DISPLAY_MODES" ]; then
    printf "\t\tModes\t\t$DISPLAY_MODES\n" >&4
  fi
  printf "\tEndSubSection\n" >&4
done
printf "EndSection\n" >&4

### SERVERLAYOUT

exec 4>"$DEXCONFTMPDIR/ServerLayout"
cat >&4 <<SECTION
Section "ServerLayout"
	Identifier	"Default Layout"
	Screen		"Default Screen"
	InputDevice	"Generic Keyboard"
	InputDevice	"Configured Mouse"
SECTION
if [ -n "$LAPTOP" ]; then
  printf "\tInputDevice\t\"Synaptics Touchpad\"\n" >&4
fi
printf "EndSection\n" >&4

### DRI
exec 4>"$DEXCONFTMPDIR/DRI"
cat >&4 <<SECTION
Section "DRI"
	Mode	0666
EndSection
SECTION

# Close file descriptor 4 before we delete temporary files
exec 4<&-

# Tell debconf to stop listening to us.
db_stop

# Write the configuration file.  Put a blank line before every section we write
# except the first.

OUTFILE="$DEXCONFTMPDIR/dexconf-out"
umask 022
: >"$OUTFILE"

SPACER=
for SECTION in Header Files Module InputDeviceKeyboard InputDeviceMouse \
               Device Monitor Screen ServerLayout DRI; do
  if [ -e "$DEXCONFTMPDIR/$SECTION" ]; then
    eval $SPACER
    cat "$DEXCONFTMPDIR/$SECTION" >>"$OUTFILE"
    SPACER='echo "" >>"$OUTFILE"'
  fi
done

# Ensure we can write to our destination if it already exits.
if [ -e "$XF86CONFIG" ]; then
  if [ ! -w "$XF86CONFIG" ]; then
    bomb "unable to write to \"$XF86CONFIG\""
  fi
fi

BACKUP=
# Create a backup of the existing configuration file if it already exists.
if [ -e "$XF86CONFIG" ]; then
  cat "$XF86CONFIG" >"$DEXCONFTMPDIR/backup"
  BACKUP=true
fi

# Move the new file into place.
if ! cat "$OUTFILE" >"$XF86CONFIG"; then
  # Failed; try to restore the backup.
  if [ -n "$BACKUP" ]; then
    cat "$DEXCONFTMPDIR/backup" >"$XF86CONFIG"
  fi
fi

rm -rf "$DEXCONFTMPDIR"

exit 0

# vim:set ai et sts=2 sw=2 tw=80:
