#!/bin/sh
#
# ident "$Id$ SMI"
#
#*******************************************************************************
#
# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
#*******************************************************************************
#

# Sanitize environment
PATH=/usr/bin:/bin
export PATH

short_usage()
{
 echo 1>&2 "Usage: "
 echo 1>&2 "    kioskconfig <subcommand> <options>"
 echo 1>&2 "    kioskconfig -h"
 exit 1
}

show_usage()
{
# TODO implement command-specific help  
cat 1>&2 <<!    
Usage: 
    kioskconfig enable  [-d display|-f display-file] [-c config-file]
    kioskconfig apply   [-d display|-f display-file] [-c config-file]
    kioskconfig disable [-d display|-f display-file|-a]
    kioskconfig print   [-d display|-f display-file|-a]
    kioskconfig list
    kioskconfig reset
    kioskconfig help
    kioskconfig -h
!
}

usage()
{
 show_usage   
 exit ${1:-1}
}

help()
{
# TODO implement command-specific help  
  show_usage  
  cat 1>&2 <<!    
 
Subcommands:    
  enable  - Enable and configure kiosk sessions on one or more displays.
  apply   - Apply kiosk configuration which includes policy 
            on one or more displays.
  disable - Disable kiosk sessions on one or more displays.
  print   - Print kiosk configuration, including policy, 
	    on one or more displays.
  list    - List displays on which kiosk is enabled
  reset   - Remove kiosk configuration for all configured displays.
  help    - Print this help message.

Options:
  -a                 Operate on all currently configured displays.
  -c <config-file>   Specify a session configuration file to apply to the 
                     affected displays. The default session configuration file 
		     is /etc/opt/SUNWkio/session.conf.
  -d <display>       Specify a single display to apply kiosk configuration to.
  -f <display-file>  Specify a file listing display identifiers for which 
                     kiosk configuration should be applied. The default 
		     display file is /etc/opt/SUNWkio/displays.
  -h                 Print a short usage message.
!

 exit 0
}

#
## Configure a single display
#
configureDisplay()
{
 inCommand=$1
 inRawDisplay=$2
 inConfigFile=$3

 theDisplay="`normalizeDisplay $inRawDisplay`"
 if [ -z "$theDisplay" ] ; then
  echo 1>&2 "Not a valid display identifier: '$inRawDisplay'"
  if [ $inCommand = enable -o $inCommand = apply ] ; then
   echo "Not configuring display '$inRawDisplay'"
   return 1 
  fi 
# Other operations are safe on non-nomalized identifiers
  theDisplay="$inRawDisplay"
 fi 

 case $inCommand in
  enable)
   applyConfig 1 $theDisplay "$inConfigFile" ;;
  apply)
   applyConfig 0 $theDisplay "$inConfigFile" ;;
  list)
   listConfig $theDisplay ;;
  print)
   printConfig $theDisplay ;;
  disable)
   disableDisplay $theDisplay ;;
  *)
   echo 1>&2 "Internal Error: Trying to execute invalid command for selected display."
   exit 1;;
 esac
}

#
## Enable a single display
#
applyConfig()
{
 inForceEnable=$1
 inDisplay=$2
 inConfigFile=$3

 echo "Configuring display $inDisplay"

 theDisplayFile="$KIOSK_VAR_DIR/config/$inDisplay"
 #
 ## create the display specific configuration file
 #
 cp "$inConfigFile" "$theDisplayFile"
 if [ $? -ne 0 ] ; then
  echo 1>&2 "Error: Couldn't create configuration file '$theDisplayFile'"
  return 1
 fi
 if [ $inForceEnable -eq 1 ] ; then
  echo KIOSK_ENABLED=yes >> "$theDisplayFile"
  if [ $? -ne 0 ] ; then
   rm -f "$theDisplayFile" > /dev/null 2>&1
   echo 1>&2 "Error: Couldn't create configuration file '$theDisplayFile'"
   return 1
  fi
 fi
 chmod a+r "$theDisplayFile" > /dev/null 2>&1
 if [ $? -ne 0 ] ; then
  echo 1>&2 "Error: Couldn't change permissions of the file '$theDisplayFile'"
  return 1
 fi 
 return 0
}

#
## disable a single display
#
disableDisplay()
{
 inDisplay=$1

 echo "Configuring display $inDisplay"

 theDisplayFile="$KIOSK_VAR_DIR/config/$inDisplay"
 rm -f "$theDisplayFile" > /dev/null 2>&1
 theRC=$?
 if [ $theRC -ne 0 ] ; then
  echo 1>&2 "Error: Couldn't remove configuration file '$theDisplayFile'"
 fi 
 return $theRC
}

#
## print stored configuration for a single display
#
printConfig()
{
 inDisplay=$1

 theDisplayFile="$KIOSK_VAR_DIR/config/$inDisplay"
 echo "# $inDisplay"
 if [ -f "$theDisplayFile" ] ; then
  cat "$theDisplayFile"
 fi  
}

#
## list a display, if enabled
#
listConfig()
{
 inDisplay=$1

 theDisplayFile="$KIOSK_VAR_DIR/config/$inDisplay"
 if [ -f $theDisplayFile ] ; then
  theEnabledState=`sed -n 's/^KIOSK_ENABLED=//p' $theDisplayFile | tail -1`
  if [ -n "$theEnabledState" ] ; then
   if [ $theEnabledState = "yes" ] ; then
    echo $inDisplay
   fi	
  fi   
 fi 
}

#
## process a display file
#
configureDisplays()
{
 inCommand=$1
 inDisplayFile=$2
 inConfigFile=$3

 theRC=0
 awk '{ if ( NF > 0 && index( $1, "#" ) != 1 ) print $1 }' "$inDisplayFile" |
  while read theReadDisplay ; do
   configureDisplay $inCommand $theReadDisplay "$inConfigFile"
   if [ $? -ne 0 ] ; then
    theRC=1
   fi
  done 
 return $theRC
}

#
## do something to all configured displays
#
configureAllDisplays()
{
 inCommand=$1

 theRC=0
 theConfigDir="$KIOSK_VAR_DIR/config"
 
 if [ -d "$theConfigDir" ] ; then
  for curDisplay in `ls $theConfigDir` 
  do
   configureDisplay $inCommand $curDisplay
   if [ $? -ne 0 ] ; then
     theRC=1
   fi
  done 
 fi 
 return $theRC
}

#
## throw away all existing configuration
#
resetAllDisplays()
{
 theConfigDir="$KIOSK_VAR_DIR/config"
 
 if [ -d "$theConfigDir" ] ; then
  configureAllDisplays disable
  rmdir $theConfigDir
 fi
}

#
## main
#

#
## Load utilities and setup basic Kiosk Environment
#
theUtilsFile=/opt/SUNWkio/lib/utils.sh
if [ ! -r $theUtilsFile ] ; then
 echo 1>&2 "Error: can't read Kiosk utils file '$theUtilsFile'"
 exit 1
else
 . $theUtilsFile
if [ $? -ne 0 ] ; then
  echo 1>&2 "Error: failed to load Kiosk utils file '$theUtilsFile'"
  exit 1
 fi
fi

#
## parse args
#
if [ $# -lt 1 ] ; then
 short_usage 
fi

theCommand=$1
configSingleDisplay=0
configAllDisplays=0
needDisplay=1
createConfig=0
needWriteAccess=1
shift

case "$theCommand" in
 enable|apply)
  createConfig=1
  ;;
 disable)
  ;;
 print)
  needWriteAccess=0
  ;;
 list)
  needDisplay=0
  needWriteAccess=0
  ;;
 reset)
  needDisplay=0
  ;;
 help)
  help
  ;;
 -h|-\?)
  usage 0
  ;;
 -*)
  echo 1>&2 "Error: Invalid option '$theCommand' specified."
  short_usage
  ;;
 *)
  echo 1>&2 "Error: Invalid command '$theCommand' specified."
  usage
  ;;
esac

while getopts "ad:f:c:h" theOption ; do
 case $theOption in
  a) 
   if [ $needDisplay -ne 1 ] ; then
    echo 1>&2 "Error: No display or display file supported with this command"
    usage
   fi 
   if [ ! -z "$theDisplayArg" ] ; then
    echo 1>&2 "Error: Multiple display or display file options specified"
    usage
   fi
   if [ $createConfig -ne 0 ] ; then
    echo 1>&2 "Error: Cannot apply this command to \"all\" displays"
    usage
   fi 
   configAllDisplays=1
   theDisplayArg="ALL" # Mark display argument as set
   ;;

  d|f)
   if [ $needDisplay -ne 1 ] ; then
    echo 1>&2 "Error: No display or display file supported with this command"
    usage
   fi 
   if [ ! -z "$theDisplayArg" ] ; then
    echo 1>&2 "Error: Multiple display or display file options specified"
    usage
   fi
   if [ -z "$OPTARG" ] ; then
    echo 1>&2 "Error: Invalid display or display file specified"
    exit 1
   fi
   if [ $theOption = d ] ; then
    configSingleDisplay=1
   fi
   theDisplayArg=$OPTARG
   ;;

  c) 
   if [ $createConfig -ne 1 ] ; then
    echo 1>&2 "Error: No configuration file supported with this command"
    usage
   fi 
   if [ ! -z "$theConfigFile" ] ; then
    echo 1>&2 "Error: Multiple config files specified"
    usage
   fi
   if [ -z "$OPTARG" ] ; then
    echo 1>&2 "Error: Invalid config file specified"
    exit 1
   fi
   theConfigFile=$OPTARG
   ;;

  h)
   usage 0
   ;;

  \?)
   usage
   ;;
 esac
done

if [ $# -ge $OPTIND ] ; then
 usage
fi

if [ -z "$theDisplayArg" ] ; then
 theDisplayArg=$KIOSK_CONFIG_DIR/displays
fi
if [ -z "$theConfigFile" ] ; then
 theConfigFile=$KIOSK_CONFIG_DIR/session.conf
fi

#
## Sanity
#
if [ $needDisplay -eq 1 ] ; then
 if [ $configSingleDisplay -eq 0 -a \
      $configAllDisplays   -eq 0 -a \
      ! -f "$theDisplayArg" ] ; then
  echo 1>&2 "Error: Can't access the display file '$theDisplayArg'"
  exit 1
 fi 
fi
if [ $createConfig -eq 1 ] ; then
 if [ ! -f "$theConfigFile" ] ; then
  echo 1>&2 "Error: Can't access the configuration file '$theConfigFile'"
  exit 1
 fi
fi

## At least logically we'll need to write to $KIOSK_VAR_DIR/config so we 
## can test for this and exit early if we don't have sufficient permission.
##
## Note: Failure in the case of chmoding to the existing mode of the directory
##       is undocumented ( although it appears that failure does occur on all
##       relevant platforms ). Adding a touch which is ( almost ) guaranteed to
##       require a change to the directory and hence is a reasonable test.
#
if [ $createConfig -eq 1 ] ; then
 mkdir -m 755 -p "$KIOSK_VAR_DIR/config"
 if [ $? -ne 0 ] ; then
  echo 1>&2 "Error: Unable to correctly create configuration directory '$KIOSK_VAR_DIR/config'"
  exit 1
 fi
fi
if [ $needWriteAccess -eq 1 ] ; then
 if [ -d "$KIOSK_VAR_DIR/config" ] ; then
  touch "$KIOSK_VAR_DIR/config"
  if [ $? -ne 0 ] ; then
   echo 1>&2 "Error: It appears that you have insufficient permission to modify the configuration directory '$KIOSK_VAR_DIR/config'"
   exit 1
  fi
 fi
fi 

#
## Configure
#
if [ $theCommand = "reset" ] ; then
 resetAllDisplays 
elif [ $needDisplay -ne 1 ] || [ $configAllDisplays -eq 1 ] ; then
 configureAllDisplays $theCommand 
elif [ $configSingleDisplay -eq 1 ] ; then
 configureDisplay $theCommand "$theDisplayArg" "$theConfigFile"
else
 configureDisplays $theCommand "$theDisplayArg" "$theConfigFile"
fi
