#!/bin/sh
#
# Script to activate profiles (i.e. conditional extra stuff) for the various 
# desktop environments in Debian based on the data in the *.listing files in
# the /etc/desktop-profiles directory. Sourced by /etc/X11/Xsession.
#
# See the desktop-profiles(7) man page for an overview of how this works
#
# Code in this file has a couple of debian-specific parts:
#  - use of tempfile from debian-utils
#    (at start of execution, and in sort_profiles & activate_gnome functions)
#  - hardcoded default values for the different GNUSTEP_*_ROOT env variables
#    (in activate_gnustep function below)
#
# (c) 2004-2005 Bart Cornelis <cobaco AT skolelinux no>
###############################################################################

########################################################
# get utility functions for working with .listing files
########################################################
LIB=/usr/share/desktop-profiles/listingmodule;
if (test -r $LIB); then
  . $LIB;
  INSTALLED=true;
else
  # test for shell-library if absent then either:
  # - the package installation is corrupt
  # - the package is removed (this file is left as it's in /etc/ and
  #   thus treated as a conffile
  # We'll assume the latter.
  echo "Shell library $LIB is missing -> assuming desktop-profiles is removed (but not purged)" >> $ERRFILE;
  INSTALLED=false
fi;

#########################################################################
# Sort all profiles that have their requirements met by kind
# (result for each $KIND is saved in the corresponding env variable
#  except for gnome which is saved in $GNOME_FILE, which is a tempfile)
#########################################################################
sort_profiles(){

  #make sure we start with empty variables
  KDEDIRS='';XDG_CONFIG_DIRS='';XDG_DATA_DIRS='';CHOICESPATH='';GNUSTEP_PATHLIST='';UDEDIRS=''
 
  # get profiles that are have fulfilled requirements, and save result on file descriptor 3
  PROFILES=`tempfile`;
  exec 3<> $PROFILES;
  (# get profiles that are have fulfilled requirements
     cat $(list_listings) | grep -v -e "^[[:space:]]*#" -e "^[[:space:]]*$" | while read PROFILE; do
      if (test_profile_requirements "$PROFILE"); then
        echo $PROFILE;
      fi;
    done;
   #and sort them by preference 
  ) | sort --reverse --general-numeric-sort --field-separator=";" --key 4 > $PROFILES;

  # read from file descriptor 3 (not using pipe, because then the variables being
  # changed are in a subshell, which means they're unchanged outside the while loop)
  while read PROFILE <&3; do
  # sort per profile kind
    KIND=`echo "$PROFILE" | cut --fields 2 --delimiter ";"`;
    if (test "$KIND" = "KDE"); then 
      KDEDIRS="$KDEDIRS $(echo "$PROFILE" | cut --fields 3 --delimiter ";")";
    elif (test "$KIND" = "XDG_CONFIG"); then 
      XDG_CONFIG_DIRS="$XDG_CONFIG_DIRS $(echo "$PROFILE" | cut --fields 3 --delimiter ";")";
    elif (test "$KIND" = "XDG_DATA"); then 
      XDG_DATA_DIRS="$XDG_DATA_DIRS $(echo "$PROFILE" | cut --fields 3 --delimiter ";")";
    elif (test "$KIND" = "ROX"); then 
      CHOICESPATH="$CHOICESPATH $(echo "$PROFILE" | cut --fields 3 --delimiter ";")";
    elif (test "$KIND" = "GNUSTEP"); then 
      GNUSTEP_PATHLIST="$GNUSTEP_PATHLIST $(echo "$PROFILE" | cut --fields 3 --delimiter ";")";
    elif (test "$KIND" = "UDE"); then 
      UDEDIRS="$UDEDIRS $(echo "$PROFILE" | cut --fields 3 --delimiter ";")";
    elif (test "$KIND" = "GCONF"); then 
      echo "`echo "$PROFILE" | cut --fields 3 --delimiter ";"` " >> $GCONF_FILE;
    fi;	
  done;

  # close filedescriptor,and delete tempfile
  exec 3>&- ; 
  rm $PROFILES;
}

##########################################################
# Functions for activating the different kinds of profile
##########################################################
activate_KDE () {
  KDEDIRS=`echo "$KDEDIRS" | sed -e "s/^ *//" -e "s/ *$//" -e "s/ /:/g"`
  if (test "$KDEDIRS"x != x) &&
     (test "$KDEDIRS" != "$(cat $DEFAULT_LISTING | grep "^kde-prefix" | cut --fields 3 --delimiter ";" | sed -e  "s/^ *//" -e "s/ *$//" -e "s/ /:/g")"); then
    KDEDIRS=$(sh -c "echo $KDEDIRS");# FORCE expansion of variables in KDEDIRS if any
    export KDEDIRS;
  fi;
}

activate_XDG_CONFIG () {
  XDG_CONFIG_DIRS=`echo "$XDG_CONFIG_DIRS" | sed -e "s/^ *//" -e "s/ *$//" -e "s/ /:/g"`
  if (test "$XDG_CONFIG_DIRS"x != x) &&
     (test "$XDG_CONFIG_DIRS" != "$(cat $DEFAULT_LISTING | grep "^default-xdg_config_dirs" | cut --fields 3 --delimiter ";" | sed -e "s/^ *//" -e "s/ *$//" -e "s/ /:/g")"); then
    XDG_CONFIG_DIRS=$(sh -c "echo $XDG_CONFIG_DIRS");# FORCE expansion of variables in XDG_CONFIG_DIRS if any
    export XDG_CONFIG_DIRS;
  fi;
}

activate_XDG_DATA () {
  XDG_DATA_DIRS=`echo "$XDG_DATA_DIRS" | sed -e "s/^ *//" -e "s/ *$//" -e "s/ /:/g"`
  if (test "$XDG_DATA_DIRS"x != x) &&
     (test "$XDG_DATA_DIRS" != "$(cat $DEFAULT_LISTING | grep "^default-xdg_data_dirs" | cut --fields 3 --delimiter ";" | sed -e "s/^ *//" -e "s/ *$//" -e "s/ /:/g")"); then
    XDG_DATA_DIRS=$(sh -c "echo $XDG_DATA_DIRS");# FORCE expansion of variables in XDG_DATA_DIRS if any
    export XDG_DATA_DIRS;
  fi;
}

activate_ROX () {
  CHOICESPATH=`echo "$CHOICESPATH" | sed -e "s/^ *//" -e "s/ *$//" -e "s/ /:/g"`
  DEFAULT_CHOICES=$(cat $DEFAULT_LISTING | grep '^default-rox-system;' | cut --fields 3 --delimiter ";" | sed -e "s/^ *//" -e "s/ *$//" -e "s/ /:/g")
  DEFAULT_CHOICES="$(cat $DEFAULT_LISTING | grep '^default-rox-user;' | cut --fields 3 --delimiter ";" | sed -e "s/^ *//" -e "s/ *$//" -e "s/ /:/g"):$DEFAULT_CHOICES"
  if (test "$CHOICESPATH"x != x) &&
     (test "$CHOICESPATH" != "$DEFAULT_CHOICES"); then
    CHOICESPATH=$(sh -c "echo $CHOICESPATH");# FORCE expansion of variables in CHOICESPATH if any
    export CHOICESPATH;
  fi;
}

activate_UDE () {
  # don't s/ /:g/ in next line, UDE doesn't currently support combining profile dirs
  UDEDIRS=`echo "$UDEDIRS" | sed -e "s/^ *//" -e "s/ *$//"`
  if (test "$UDEDIRS"x != x) &&
     (test "$UDEDIRS" != "$(cat $DEFAULT_LISTING | grep "^ude-install-dir" | cut --fields 3 --delimiter ";")"); then
    # Take first dir and break, as UDE currently only supports one dir
    for dir in $UDEDIRS; do 
      UDEdir=$dir;
      break;
    done;  
    export UDEdir=$(sh -c "echo $UDEdir");# FORCE expansion of variables in UDEdir if any
  fi;
}

activate_GNUSTEP () {
  # default values as set in /usr/lib/GNUstep/System/Library/Makefiles/GNUstep.sh (On Debian)
  export GNUSTEP_USER_ROOT=${GNUSTEP_USER_ROOT:-`/usr/lib/GNUstep/System/Library/Makefiles/user_home user 2> /dev/null`};
  export GNUSTEP_LOCAL_ROOT=${GNUSTEP_LOCAL_ROOT:-/usr/local/lib/GNUstep/Local};
  export GNUSTEP_NETWORK_ROOT=${GNUSTEP_NETWORK_ROOT:-/usr/local/lib/GNUstep/Network};
  export GNUSTEP_SYSTEM_ROOT=${GNUSTEP_SYSTEM_ROOT:-/usr/lib/GNUstep/System};

  #should be in GNUSTEP_PATHLIST (see /usr/lib/GNUstep/System/Library/Makefiles/GNUstep.sh)
  GNUSTEP_PATHLIST=`echo "$GNUSTEP_PATHLIST" | sed -e "s/^ *//" -e "s/ *$//" -e "s/ /:/g"`
  
  # get default domains
  DEFAULT_DOMAINS=$(cat $DEFAULT_LISTING | grep "^gnustep-user-domain" | cut --fields 3 --delimiter ";" | sed -e  "s/^ *//" -e "s/ *$//" -e "s/ /:/g")
  DEFAULT_DOMAINS="$DEFAULT_DOMAINS:$(cat $DEFAULT_LISTING | grep "^gnustep-local-domain" | cut --fields 3 --delimiter ";" | sed -e  "s/^ *//" -e "s/ *$//" -e "s/ /:/g")"
  DEFAULT_DOMAINS="$DEFAULT_DOMAINS:$(cat $DEFAULT_LISTING | grep "^gnustep-network-domain" | cut --fields 3 --delimiter ";" | sed -e  "s/^ *//" -e "s/ *$//" -e "s/ /:/g")"
  DEFAULT_DOMAINS="$DEFAULT_DOMAINS:$(cat $DEFAULT_LISTING | grep "^gnustep-system-domain" | cut --fields 3 --delimiter ";" | sed -e  "s/^ *//" -e "s/ *$//" -e "s/ /:/g")"

  if (test "$GNUSTEP_PATHLIST"x != x) &&
     (test "$GNUSTEP_PATHLIST" != "$DEFAULT_DOMAINS"); then
    export GNUSTEP_PATHLIST=$(sh -c "echo $GNUSTEP_PATHLIST");# FORCE expansion of variables in GNUSTEP_PATHLIST if any
  else
    # if we're not setting things, then make sure we've not added to the environment
    if (test "$GNUSTEP_USER_ROOT" = "$(/usr/lib/GNUstep/System/Library/Makefiles/user_home user 2> /dev/null)"); then unset GNUSTEP_USER_ROOT; fi
    if (test "$GNUSTEP_LOCAL_ROOT" = "/usr/local/lib/GNUstep/Local"); then unset GNUSTEP_LOCAL_ROOT; fi
    if (test "$GNUSTEP_NETWORK_ROOT" = "/usr/local/lib/GNUstep/Network"); then unset GNUSTEP_NETWORK_ROOT; fi
    if (test "$GNUSTEP_SYSTEM_ROOT" = "/usr/lib/GNUstep/System"); then unset GNUSTEP_SYSTEM_ROOT; fi
  fi;
}

activate_GCONF () {
  # HACK WARNING:
  #
  # While GCONF allows multiple "configuration sources", there seems to be no clean way to
  # make the used "configuration sources" dependend on a condition (such as group membership).
  # One dirty way to get this ability is to generate a path file at login which will include
  # directives activating the profiles that have their requirements met.
  #
  # NOTE: this alone isn't enough, the system-wide path file (/etc/gconf/<gconf-version>/path)
  #       needs to contain a include directive for this generated file. (preferably it should 
  #       contain _only_ that include directive setting everything else up through profiles)
  
  # only generate path files for user if they will be included
  if (grep 'include *\$(ENV_MANDATORY_PATH)' /etc/gconf/2/path > /dev/null 2>&1 ) ||
     (grep 'include *\$(ENV_DEFAULTS_PATH)'  /etc/gconf/2/path > /dev/null 2>&1 ) ||
     (grep 'include *\$(ENV_MANDATORY_PATH)' /etc/gconf/1/path > /dev/null 2>&1 ) ||
     (grep 'include *\$(ENV_DEFAULTS_PATH)'  /etc/gconf/1/path > /dev/null 2>&1 ); then

    INCLUDED_HOME=false; 
    
    # We need to use random names in a directory only accessible by the user because of security:
    # - if (generated) path file isn't there all is fine
    # - if (generated) path file is there and the permissions on it allow $USER to write all is fine 
    #   (as it's regenerated on login)
    # - if (generated) path file is there (possibly changed by attacker) and the permissions on it do
    #   not allow $USER to write things are not fine (as regeneration fails, and configuration sources
    #   by attacker will be used).
    #   Attacker can be $USER hirself (to avoid mandatory settings form sysadmin), or if file is in a
    #   directory that's writeable by someone else a third party
    XDG_CACHE_HOME=${XDG_CACHE_HOME:-$HOME/.cache}; mkdir -p $XDG_CACHE_HOME;
    export MANDATORY_PATH=$(tempfile --directory $XDG_CACHE_HOME);
    export DEFAULTS_PATH=$(tempfile --directory $XDG_CACHE_HOME);
    
    # $XDG_CACHE_HOME is not supposed to contain anything that can't be deleted
    # so we can do this to avoid leaving old generated files from previous logins laying around
    rm -f $(grep '^# Generated by desktop-profiles package$' $XDG_CACHE_HOME/* | cut --delimiter ':' --fields 1);
    
    # add marker to generated file, both so we can find it again later, and to indicate origin
    echo "# Generated by desktop-profiles package" > "$MANDATORY_PATH";
    echo "# Generated by desktop-profiles package" > "$DEFAULTS_PATH";
    
    cat $GCONF_FILE | while read LINE; do
       if (test "$LINE" != 'xml:readwrite:$(HOME)/.gconf'); then
         if (test $INCLUDED_HOME = false); then
           echo $LINE >> "$MANDATORY_PATH";
         else	 
           echo $LINE >> "$DEFAULTS_PATH";
         fi;	 
       else  
         INCLUDED_HOME=true;
       fi  
    done;
  fi;  
}

#####################
# Start of execution
#####################

# Check is needed, as this file is a conffile and thus left after package
# deinstallation, yet it shouldn't do anything when the package is deinstalled
if (test $INSTALLED = true); then
  #################################
  # Check if user set any defaults
  #################################
  if (test -r /etc/default/desktop-profiles); then
    . /etc/default/desktop-profiles;
  fi;  

  #################################################
  # Make sure the variable we need are initialized
  #################################################
  LISTINGS_DIRS=${LISTINGS_DIRS:-'/etc/desktop-profiles'}
  ACTIVE_PROFILE_KINDS=${ACTIVE_PROFILE_KINDS:-''}
  DEFAULT_LISTING=/etc/desktop-profiles/desktop-profiles.listing
  PROFILE_PATH_FILES_DIR=${PROFILE_PATH_FILES_DIR:-'/var/cache/desktop-profiles/'}

  ############################################################
  # Actual activation of profiles
  # don't test requirements if no profile kinds are activated
  ############################################################
  if (test "$ACTIVE_PROFILE_KINDS"x != "x"); then
    # get temp file names
    GCONF_FILE=`tempfile`;

    # sort the profiles, whose requirements are met into:
    # - the appropriate environment variables
    # - $GCONF_FILE
    sort_profiles; 

    # activate the profiles of the active kinds
    for KIND in $ACTIVE_PROFILE_KINDS; do
      # || true is to avoid hanging x-startup when trying a non-existing KIND
      # which can happen e.g. due to typo's in the config file.
      activate_$KIND || true;
    done;

    # cleanup the tempfiles
    rm $GCONF_FILE 
  fi;  
fi;  
