# -*-shell-script-*-

###
#
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Copyright 2002 Mike Hearn (mike@theoretic.com)
# Copyright 2002,2003 Hongli Lai (h.lai@chello.nl)
#
###


export autopackage_version="0.7"

[ -e /etc/autopackage/config ] && source /etc/autopackage/config;
[ -e ${XDG_CONFIG_HOME:-~/.config}/autopackage/config ] && source ${XDG_CONFIG_HOME:-~/.config}/autopackage/config;

# use by package prep and install scripts
if [[ "$meta_dir" == "" ]]; then
    meta_dir=`pwd`
fi
export apkg_logfile="$meta_dir/log"
export apkg_filelist="$meta_dir/filelist"
export apkg_uninstalldirs="$meta_dir/uninstalldirs"

if [[ ! -d "$TMP" ]]; then
    TMP=/tmp
fi

if [[ "$autopackage_config_version" == "" ]] && [ -d "$autopackage_prefix/share/autopackage" ]; then
    echo "No configuration data found in /etc/autopackage/config or ~/.config/autopackage/config";
    exit 1;
fi

# if sideloading then directory will not exist and source files within this directory
oPWD_funclib=`pwd`
if [ -d "$autopackage_prefix/share/autopackage" ]; then
    cd "$autopackage_prefix/share/autopackage"
fi

source "apkg-bashlib"
source "apkg-db"
source "apkg-defs"
source "apkg-dep"
source "apkg-failsafelib"
source "apkg-io"
source "apkg-script-utils"
cd "$oPWD_funclib"

# sanity action for removing possible system/user aliases
unalias cp 2>/dev/null
unalias mkdir 2>/dev/null
unalias mv 2>/dev/null
unalias rm 2>/dev/null
unalias rmdir 2>/dev/null

# if group and user are the same and are not
# system uids then allow group writeable files
if [[ "`id -gn`" == "`id -un`" ]] && [ `id -u` -gt 99 ]; then
    umask 002
else
    umask 022
fi

# first trace
trace funclib: imports completed


##
# _initializeAutopackage
#
# Function to initialize certain variables for use by Autopackage support code.
# This beginning logic order is necessary such that when autopackage is not installed
# that the variables can build up properly.
#
function _initializeAutopackage() {

	trace called

	# add autopackage installation prefix to $PATH
	if [ -d "$autopackage_prefix/share/autopackage" ] && ! isInList "$autopackage_prefix/share/autopackage" "$PATH"; then
		# autopackage is cvs installed
		trace using cvs installed directories and modifying PATH
		export PATH=$autopackage_prefix/libexec/autopackage:$autopackage_prefix/share/autopackage:$autopackage_prefix/bin:$PATH
	elif [ -d "$autopackage_prefix/share" ] && ! isInList "$autopackage_prefix/share" "$PATH"; then
		# autopackage is not installed
		trace using cvs directories and modifying PATH
		export PATH=$autopackage_prefix/libexec:$autopackage_prefix/share:$autopackage_prefix/bin:$PATH
	fi
	trace PATH=$PATH

	# determine package installation prefix, if not passed in as an argument
	export PREFIX=`_userPrefix`

	# determine package database location which could reference global or user
	_initializePackageDB

	if [[ "${#_skel_dirs[@]}" == 0 ]]; then
		# Add directories from AUTOPACKAGE_SKELETON_DIR environment variable
		if [[ "$AUTOPACKAGE_SKELETON_DIRS" != "" ]]; then
			local oIFS="$IFS"
			local IFS=$'\n'
			_skel_dirs=(`echo "$AUTOPACKAGE_SKELETON_DIRS" | tr ':' '\n'`)
			IFS="$oIFS"
		fi

		# Add spec dir
		if [[ "$_apspec_dir" != "" ]]; then
			trace using spec skeleton dir $_apsec_dir/skeletons
			_skel_dirs[${#_skel_dirs[@]}]="$_apspec_dir/skeletons"
		fi

		# Add standard skeleton dirs
		if [ -d "$autopackage_prefix/share/autopackage/skeletons" ]; then
			# autopackage is installed
			trace using installed directories and modifying _skel_dirs
			_skel_dirs[${#_skel_dirs[@]}]="$autopackage_prefix/share/autopackage/skeletons"
		else
			# autopackage is not installed
			trace using not installed cvs directories and modifying _skel_dirs
			_skel_dirs[${#_skel_dirs[@]}]="$autopackage_prefix/share/skeletons"
		fi

		# Add database skeleton dirs for verify mode
		if [[ "$_context" == "verify" ]]; then
			_skel_dirs[${#_skel_dirs[@]}]="$autopackage_user_db_location"
			_skel_dirs[${#_skel_dirs[@]}]="$autopackage_global_db_location"
		fi

	fi
	trace _skel_dirs=${_skel_dirs[@]}

	# get list of user languages
	if [[ "$language_list" == "" ]]; then
		export language_list="`getLanguages`"
	else
		trace language_list=$language_list
	fi

	# determine environment of destination machine
	if [[ "$AUTOPACKAGE_DISTRIBUTION_ID" == "" ]]; then
		_determineMachine
	else
		trace AUTOPACKAGE_DISTRIBUTION_ID=$AUTOPACKAGE_DISTRIBUTION_ID
	fi

	if [[ "$apkg_md5sum_command" == "" ]]; then
		locateCommand md5sum
		export apkg_md5sum_command="$lc_location"
	fi
	trace apkg_md5sum_command=$apkg_md5sum_command

	if [[ "$cpu_architecture" == "" ]]; then
		locateCommand arch
		cpu_architecture=`"$lc_location"`

		case "$cpu_architecture" in

			i386 | i486 | i586 | i686 | athlon)
			export cpu_architecture="x86";;

		esac

	fi
	trace cpu_architecture=$cpu_architecture

	trace finished
	return 0

}


##
# _determineMachine
#
# Determine the state of the machine to which the installation is going to happen.
# The runtime state is added to package environment files.
#
# The distribution release text can be forced with $AUTOPACKAGE_DISTRIBUTION_TEXT
# to test this function and all distribution information can be forced in any case
# with $AUTOPACKAGE_LSB_VERSION, $AUTOPACKAGE_DISTRIBUTION_ID, $AUTOPACKAGE_DISTRIBUTION_RELEASE,
# $AUTOPACKAGE_DISTRIBUTION_CODENAME, $AUTOPACKAGE_DISTRIBUTION_DESCRIPTION.
#
function _determineMachine() {

	local LSB_VERSION
	local DISTRIB_DISTRO
	local DISTRIB_RELEASE
	local DISTRIB_CODENAME
	local DISTRIB_DESCRIPTION
	local release_text
	local release_DISTRO
	local release_RELEASE
	local release_CODENAME
	local release_DESCRIPTION

	# Force distribution release text
	if [[ "$AUTOPACKAGE_DISTRIBUTION_TEXT" != "" ]]; then
		release_text="$AUTOPACKAGE_DISTRIBUTION_TEXT"

	# Look for lsb release file
	elif [ -e "/etc/lsb-release" ]; then

		source /etc/lsb-release
		# allow force of lsb release file infomation
		# remove capitals and spaces from distribution id
		DISTRIB_ID=(`echo "$DISTRIB_ID" | tr '[:upper:]' '[:lower:]' | sed 's/ //g'`)
		if [ "$LSB_VERSION" ] && [[ "$AUTOPACKAGE_LSB_VERSION" == "" ]]; then export AUTOPACKAGE_LSB_VERSION="$LSB_VERSION"; fi;
		if [ "$DISTRIB_ID" ] && [[ "$AUTOPACKAGE_DISTRIBUTION_ID" == "" ]]; then export AUTOPACKAGE_DISTRIBUTION_ID="$DISTRIB_ID"; fi;
		if [ "$DISTRIB_RELEASE" ] && [[ "$AUTOPACKAGE_DISTRIBUTION_RELEASE" == "" ]]; then export AUTOPACKAGE_DISTRIBUTION_RELEASE="$DISTRIB_RELEASE"; fi;
		if [ "$DISTRIB_CODENAME" ] && [[ "$AUTOPACKAGE_DISTRIBUTION_CODENAME" == "" ]]; then export AUTOPACKAGE_DISTRIBUTION_CODENAME="$DISTRIB_CODENAME"; fi;
		if [ "$DISTRIB_DESCRIPTION" ] && [[ "$AUTOPACKAGE_DISTRIBUTION_DESCRIPTION" == "" ]]; then export AUTOPACKAGE_DISTRIBUTION_DESCRIPTION="$DISTRIB_DESCRIPTION"; fi;

	# Look for slackware release file
	elif [ -e "/etc/slack-version" ]; then

		release_text=`cat "/etc/slack-version"`

	else

		local oIFS="$IFS"
		local IFS=$'\n'

		# Cycle through the release files found in /etc/
		for release_filename in `ls /etc/ | grep release | grep -v lsb-release`; do

			# Release files could be linked so the release filename must match release text
			if [ -r "/etc/$release_filename" ]; then
				release_text=`cat "/etc/$release_filename"`
				release_distro=`echo "$release_filename" | awk 'BEGIN {FS="-"} { print $1 }'`

				# compare as lower case text
				release_distro=(`echo "$release_distro" | tr '[:upper:]' '[:lower:]'`)
				release_filename=(`echo "$release_filename" | tr '[:upper:]' '[:lower:]' | sed 's/ //g'`)
				release_match=`echo "$release_text" | sed 's/ //g' | grep -i "$release_distro"`

				if [ "$release_match" ]; then
					release_DISTRO="$release_distro"
					break
				fi

			fi

		done

		IFS="$oIFS"

	fi

	# From the matched release file, make release text match variables in a lsb-release file
	if [ "$release_text" ]; then

		# Disect the release text and do tests against the text to determine text context
		for text in $release_text; do

			unset text_test

			if [ `expr index "$text" '[0123456789]'` -eq "1" ]; then
				release_RELEASE="$text"
				continue
			fi

			text_test=`echo "$text" | grep '('`
			if [[ "$text_test" != "" ]]; then
				# check that codename does not contain any numbers contained in like i586
				if [ `expr index "$text_test" '[0123456789]'` -eq "0" ]; then
					release_CODENAME=`echo "$text_test" | sed 's/(//' | sed 's/)//'`
				fi
				continue
			fi

		done

		unset text_test
		text_test=`echo "$release_text" | grep ' Linux '`
		if [[ "$text_test" != "" ]] && [[ "$release_DISTRO" == "" ]]; then
			text_test=`echo "$text_test" | awk 'BEGIN {FS=" Linux "} { print $1 }'`
			release_DESCRIPTION="$text_test Linux"
			text_test=`echo "$text_test" | sed 's/ //g' | tr '[:upper:]' '[:lower:]'`
			release_DISTRO="$text_test"
		fi
		text_test=`echo "$release_text" | awk 'BEGIN {FS=" "} { print $1 }'`
		if [[ "$text_test" != "" ]] && [[ "$release_DISTRO" == "" ]]; then
			release_DISTRO=`echo "$text_test" | tr '[:upper:]' '[:lower:]'`
		fi
		unset text_test

		text_test=`echo "$release_text" | grep 'release'`
		if [[ "$text_test" != "" ]] && [[ "$release_DESCRIPTION" == "" ]]; then
			text_test=`echo "$text_test" | awk 'BEGIN {FS=" release"} { print $1 }'`
			release_DESCRIPTION="$text_test"
		fi
		text_test=`echo $release_text | grep 'Linux'`
		if [[ "$text_test" != "" ]] && [[ "$release_DESCRIPTION" == "" ]]; then
			text_test=`echo "$text_test" | awk 'BEGIN {FS=" Linux"} { print $1 }'`
			release_DESCRIPTION="$text_test Linux"
		fi

		text_test=`echo "$release_text" | sed 's/ release//'`
		text_end=`expr length "$release_text"`
		text_end=`expr index "$text_test" "$release_RELEASE"`
		let "text_end=$text_end-2"
		text_test=`expr substr "$text_test" "1" "$text_end"`

		if [[ "$text_test" != "" ]] && [[ "$release_DESCRIPTION" == "" ]]; then
			release_DESCRIPTION="$text_test"
		fi

		# allow force of release file infomation
		if [ "$release_DISTRO" ] && [[ "$AUTOPACKAGE_DISTRIBUTION_ID" == "" ]]; then export AUTOPACKAGE_DISTRIBUTION_ID="$release_DISTRO"; fi;
		if [ "$release_RELEASE" ] && [[ "$AUTOPACKAGE_DISTRIBUTION_RELEASE" == "" ]]; then export AUTOPACKAGE_DISTRIBUTION_RELEASE="$release_RELEASE"; fi;
		if [ "$release_CODENAME" ] && [[ "$AUTOPACKAGE_DISTRIBUTION_CODENAME" == "" ]]; then export AUTOPACKAGE_DISTRIBUTION_CODENAME="$release_CODENAME"; fi;
		if [ "$release_DESCRIPTION" ] && [[ "$AUTOPACKAGE_DISTRIBUTION_DESCRIPTION" == "" ]]; then export AUTOPACKAGE_DISTRIBUTION_DESCRIPTION="$release_DESCRIPTION"; fi;

	fi

	# Determine distribution manager and graphical application

	# allow forcing of available applications
	DISTRIBUTION_MANAGERS="urpmi yum apt-get yast2 apt rpm"
	DISTRIBUTION_MANAGERS_GRAPHICAL=""
	if [ "$DISTRIBUTION_MANAGERS" ] && [[ "$AUTOPACKAGE_DISTRIBUTION_MANAGERS" == "" ]]; then export AUTOPACKAGE_DISTRIBUTION_MANAGERS="$DISTRIBUTION_MANAGERS"; fi;
	if [ "$DISTRIBUTION_MANAGERS_GRAPHICAL" ] && [[ "$AUTOPACKAGE_DISTRIBUTION_MANAGERS_GRAPHICAL" == "" ]]; then export AUTOPACKAGE_DISTRIBUTION_MANAGER_GRAPHICAL="$DISTRIBUTION_MANAGERS_GRAPHICAL"; fi;

	for P in $AUTOPACKAGE_DISTRIBUTION_MANAGERS; do
		locateCommand "$P" && DISTRIBUTION_MANAGER="$P" && DISTRIBUTION_MANAGER_GRAPHICAL="$P" && break;
	done

	# allow forcing
	if [ "$DISTRIBUTION_MANAGER" ] && [[ "$AUTOPACKAGE_DISTRIBUTION_MANAGER" == "" ]]; then export AUTOPACKAGE_DISTRIBUTION_MANAGER="$DISTRIBUTION_MANAGER"; fi;
	if [ "$DISTRIBUTION_MANAGER_GRAPHICAL" ] && [[ "$AUTOPACKAGE_DISTRIBUTION_MANAGER_GRAPHICAL" == "" ]]; then export AUTOPACKAGE_DISTRIBUTION_MANAGER_GRAPHICAL="$DISTRIBUTION_MANAGER_GRAPHICAL"; fi;

	trace AUTOPACKAGE_LSB_VERSION=\"$AUTOPACKAGE_LSB_VERSION\"
	trace AUTOPACKAGE_DISTRIBUTION_ID=\"$AUTOPACKAGE_DISTRIBUTION_ID\"
	trace AUTOPACKAGE_DISTRIBUTION_RELEASE=\"$AUTOPACKAGE_DISTRIBUTION_RELEASE\"
	trace AUTOPACKAGE_DISTRIBUTION_CODENAME=\"$AUTOPACKAGE_DISTRIBUTION_CODENAME\"
	trace AUTOPACKAGE_DISTRIBUTION_DESCRIPTION=\"$AUTOPACKAGE_DISTRIBUTION_DESCRIPTION\"
	trace AUTOPACKAGE_DISTRIBUTION_MANAGER=\"$AUTOPACKAGE_DISTRIBUTION_MANAGER\"
	trace AUTOPACKAGE_DISTRIBUTION_MANAGER_GRAPHICAL=\"$AUTOPACKAGE_DISTRIBUTION_MANAGER_GRAPHICAL\"

}


# will test the dependencies of package $1 and print the root names of the failed deps
function verifyPackage() {

    # since there is no action on the package, user can verify
    # a globally installed package - use _loadPackage instead of _resolveName
    if ! _loadPackage "$1"; then
        _packageReturnCode "1" "$1"
        return "$?"
    fi

    # execute the verifications script
    trace sourcing verification file \"$PACKAGELOCATION/verification\"
    if [ -f "$PACKAGELOCATION/verification" ]; then
        source "$PACKAGELOCATION/verification"
    else
        _packageReturnCode "4" "$1"
        return "$?"
    fi
}


##
# uninstallFromLog
#
# Process the uninstall log that was generated by the autopackage file installation functions.
# The contents of the log must be in the $log variable.
#
# Example:
# # This is part of an autopackage specfile
# [Install]
# copyFiles share/* "$PREFIX/share"
# installLib lib/*
#
# [Uninstall]
# uninstallFromLog
function uninstallFromLog() {
    trace log is:
    trace "$log"
    eval "$log"
    return 0
}

# return of 0 = uninstalled ok
# return of 1 = package not found/database corrupt
# return of 2 = completed with errors
# return of 3 = this package supports some others: listed in uninstall_result (unless $2 = force)
# return of 4 = this package is in the database but wasn't installed by autopackage
# return of 5 = this package was installed by root and you're not root, so piss off
# return of 6 = this package is in the user db, but you're running as root
function uninstallPackage() {

    trace called with $@

    # test to see if removing autopackage support code
    if [[ "$1" == "autopackage" ]]; then
        _removeAutopackage
        # no bebug added to call because the log was just deleted by the previous removeAutopackage call
        _packageReturnCode "$?" --no-debug
        return "$?"
    fi

    # ensure we have the root name while _loadPackage checks all available package databases
    local name
    if ! name=`_resolveName "$1"` && ! _loadPackage "$1"; then
        _packageReturnCode "1" "$1"
        return "$?"
    fi
    trace $1 resolved to $name
    unset name

    # restore package environment
    _loadPackageEnvironment "$autopackage_db_location/$1"

    # the name may have been resolved to a database we can't/shouldn't actually access.

    # firstly, if we are root, check that the package is in the global database. it could be in the user db if the user ran package
    # using sudo, but we don't want to touch the user db as the root user, otherwise things get complicated.
    if [[ `id -u` == "0" ]] && [ -e "$autopackage_user_db_location/$ROOTNAME/environment.en" ]; then
        _packageReturnCode "6"
        return "$?"
    fi

    # next, if we are not root and the package exists in the global db but not the user db, we can't proceed
    if [ -e "$autopackage_global_db_location/$ROOTNAME/environment.en" ] && [ ! -e "$autopackage_user_db_location/$ROOTNAME/environment.en" ] && [[ `id -u` != "0" ]]; then
        _packageReturnCode "5"
        return "$?"
    fi

    # Check we don't support anything
    root_name=`justRootName "$ROOTNAME"`
    if [[ `echo x; cat "$autopackage_db_location/$root_name/supports" 2>/dev/null` != "x" ]] && [[ "$2" == "" ]]; then
        export uninstall_result=`cat "$autopackage_db_location/$root_name/supports"`
        _packageReturnCode "3"
        return "$?"
    fi
    unset root_name

    trace checking for installation environment file
    if [ ! -e "$autopackage_db_location/$ROOTNAME/environment.en" ]; then
        _packageReturnCode "4"
        return "$?"
    fi

    # now get the script section
    trace retrieving uninstall scripts
    local script_uninstall=`cat "$autopackage_db_location/$ROOTNAME/uninstall"`
    [[ "$script_uninstall" == "" ]] && local script_uninstall=`getSection "$autopackage_db_location/$ROOTNAME"/info Script-Uninstall`

    # log for use in eval "$script_uninstall" call to uninstallFromLog function
    local log=`cat "$autopackage_db_location/$ROOTNAME/log"`

    # load package environment variables
    _loadPackageEnvironment "$autopackage_db_location/$ROOTNAME"

    trace evaluating script_uninstall
    trace "$script_uninstall"
    eval "$script_uninstall"

    # remove support entries from dependencies
    _unforgeDependencies "$ROOTNAME"

    # remove root database package directory and symlinks
    rm -f "$autopackage_db_location/$SHORTNAME"
    rm -f "$autopackage_db_location/$SHORTNAME-$SOFTWAREVERSION"
    rm -fr "$autopackage_db_location/$ROOTNAME"
    removeDir "$autopackage_db_location/$ROOTNAME"

    # check for deletion of package root directory
    if [ -e "$autopackage_db_location/$ROOTNAME" ]; then
        _packageReturnCode "4"
        return "$?"
    else
        _packageReturnCode "0"
        return "$?"
    fi

}


##
# _packageReturnCode <RETURN-CODE> [MESSAGE]
# RETURN-CODE: returned exit code to evaluate and provide output.
# MESSAGE: text that would accompany the gettext (apkg-defs) output.
#
# $uninstall_result is set as text output from the uninstallPackage command to
# give an message to the user.
#
function _packageReturnCode() {

	[[ "$2" == "--no-debug" ]] && export DEBUGLEVEL=0

	case "$1" in

		"0" )	# continuation status
			green
			out "$intl_DONE"
			normal
			;;

		"1" )	# continuation status
			red
			out "$intl_PACKAGE_NOT_FOUND" "$2"
			normal
			;;

		"2" )
			red
			out "$intl_FAILED"
			cyan
			out "$intl_ERRORS"
			normal
			out "$uninstall_result"
			;;

		"3" )
			red
			out "$intl_FAILED"
			normal
			out "$intl_UNINSTALLING_WOULD_BREAK"
			out "$uninstall_result"
			out
			out "$intl_UNINSTALL_DO_IT_ANYWAY"
			out
			;;

		"4" )	# continuation status
			red
			out "$intl_PACKAGE_NOT_AUTOPACKAGE"
			normal
			;;

		"5" )	# continuation status
			red
			out "$intl_UNINSTALL_MUST_BE_ROOT"
			normal
			;;

		"6" )	# continuation status
			red
			out "$intl_UNINSTALL_NO_SUDO"
			normal
			;;

		"7" )
			red
			outn "$intl_FAIL"
			normal
			out "$intl_PACKAGE_SPECIFY"
			;;

		"10" )
			red
			outn "$intl_FAIL"
			normal
			out "$intl_FILE_NOT_READABLE" "$2"
			;;

		"12" )
			out "$intl_INSTALL_SUCCESS" "$2"
			;;

		"13" )
			red
			outn "$intl_FAIL"
			normal
			out "$intl_INSTALL_ERROR" "$2"
			;;

		"15" )
			red
			outn "$intl_FAIL"
			normal
			out "$intl_PACKAGE_UNKNOWN_COMMAND" "$2"
			;;

		* )
			assertNotReached
			;;

	esac
	return "$1"
}


function checkConfigVersion() {
    if [[ "$autopackage_config_version" != "1" ]]; then
	red; outn "$intl_FAIL"; normal;
	out "$intl_BAD_CONFIG_VERSION";
	return 1;
    fi
    return 0;
}

# variable that holds all the package specfile keys that are available
# keep SOFTWAREVERSION first in list such that ROOTNAME or other variables can use its value
specKeys="AUTOPACKAGETARGET \
	CPUARCHITECTURES \
	DISPLAYNAME \
	INTERFACEVERSION \
	LICENSE \
	MAINTAINER \
	PACKAGER \
	PACKAGEVERSION \
	ROOTINSTALLONLY \
	ROOTNAME \
	SHORTNAME \
	SOFTWAREVERSION \
	SUMMARY \
	URL \
"

# variable that holds all the package specfile keys that can be localized
intlKeys="DISPLAYNAME \
	SUMMARY \
"

# variable that holds all the package build keys that are available
buildKeys="BUILDHOST \
	EXPANDSIZE \
	FILETOTAL \
	PACKAGELANGUAGES \
	TIMESTAMPBUILD \
	TIMESTAMPBUILDDISPLAY \
"

# variable that holds all the package installation keys that are available
installKeys="BACKUP \
	CPUARCHITECTURE \
	DATABASE \
	DATASIZE \
	DISTRIBUTIONCODENAME \
	DISTRIBUTIONDESCRIPTION \
	DISTRIBUTIONID \
	DISTRIBUTIONMANAGER \
	DISTRIBUTIONMANAGERGRAPHICAL \
	DISTRIBUTIONRELEASE \
	LSBVERSION \
	MD5 \
	METASIZE \
	TIMESTAMPINSTALL \
	TIMESTAMPINSTALLDISPLAY \
"


function _resetKeys() {

	local key keys
	
	keys="$specKeys $buildKeys $installKeys DESCRIPTION PACKAGELOCATION"

	oIFS="$IFS"
	IFS=$' \t\n'

	for k in $keys; do
		unset $k
	done

	IFS="$oIFS"
	return 0

}


##
# _launchFE
#
# Launch a frontend. This function checks whether X and/or a console is available.
# It launches the terminal frontend or the GUI frontend, depending on the results
# of the those checks.
#
# If the environment variable $AUTOPACKAGE_FRONTEND is set, then that will be used
# as frontend instead. X/console availability will not be checked.
function _launchFE()
{
        trace launching frontend
	local xerr

	# try to find xdpyinfo - if not found guess and add path
	locateCommand -l xdpyinfo &>/dev/null
	if [[ "$lc_location" == "" ]]; then
		# Slackware not in path
		[ -e "/usr/X11R6/bin/xdpyinfo" ] && lc_location="/usr/X11R6/bin/xdpyinfo"
	fi

	if [[ "$AUTOPACKAGE_FRONTEND" != "" ]]; then
		if ! "$AUTOPACKAGE_FRONTEND" "$@"; then
		    red; outn "$intl_FAIL"; normal; out "$intl_FE_TERMINATED_ABNORMALLY";
		fi
	elif [[ "$DISPLAY" != "" ]] && xerr=`LANG=us_US LC_MESSAGES=us_US LC_ALL=us_US $lc_location &>/dev/null`; then
		# we have X, so let's use our spiffy gui FE
		if locateCommand autopackage-frontend-qt; then
			# Use the QT frontend when available
			trace booting qtfe
			autopackage-frontend-qt "$@"
		elif locateCommand autopackage-frontend-gtk; then
			# Use the GTK+ frontend when available
			trace booting gtkfe
			autopackage-frontend-gtk "$@"
		elif tty -s; then
		        # we have a terminal, but no GTK front end, so let's just fall back to the terminal
			trace no gtkfe, booting ttyfe
		        "$autopackage_prefix/share/autopackage/apkg-ttyfe" "$@"
		else
			# no terminal, but we do have X, so try to launch ttyfe in a new terminal.
			trace no gtkfe, no terminal, do have X: attempting to open ttyfe in new terminal
			launchInTerminal --title "Installing software..." /bin/bash -c "\"$autopackage_prefix/share/autopackage/apkg-ttyfe\" \"$@\"; echo 'Press ENTER to exit.'; read" 2>/dev/null
			# If that didn't work...
			[[ $? != 0 ]] && "$autopackage_prefix/share/autopackage/apkg-ttyfe" "$@"
		fi
	else
		if [[ "$xerr" != "" ]]; then
			# $DISPLAY is not empty, but we can't launch xdpyinfo.
			red
			echo -n "WARNING: "
			normal

			if echo "$xerr" | grep -q 'not authorized'; then
				echo -n "you (`whoami`) do not have authorization to conenct to the X display server. "
			else
				echo -n "unable to connect to the X display server. "
			fi
			echo "The graphical frontend will not be launched, and the console frontend will be used instead."
		fi

		# no X, let's use the terminal
		"$autopackage_prefix/share/autopackage/apkg-ttyfe" "$@"
	fi
}


##
# _installAutopackage
#
# Installs autopackage support tools within downloader.
## START INSTALLAUTOPACKAGE
## Function is substituted from apkg-funclib.
function _installAutopackage() {

	local retval
	local oldpath="$PATH"

	_autosuCommand -m apkg-install autopackage/install --silent
	retval="$?"

	# remove expanded autopackage support code package
	rm -fr "autopackage"

	if [[ "$retval" != "0" ]]; then
		_finishWindow
		return "$retval"
	fi

	# load installed autopackage support code
	[ -e /etc/autopackage/config ] && source /etc/autopackage/config;
	[ -e ${XDG_CONFIG_HOME:-~/.config}/autopackage/config ] && source ${XDG_CONFIG_HOME:-~/.config}/autopackage/config;
	if [[ "$autopackage_prefix" = "" ]]; then
		out " "
		red
		out "$intl_SETUP_CANT_FIND_CONFIG"
		normal
		out " "
		_finishWindow
		return 1
	fi
	source "$autopackage_prefix/share/autopackage/apkg-funclib"

	out " "
	out "autopackage support code setup complete. "

	out " "
	out "$intl_SETUP_THANKYOU"
	out " "

	# we do this here so it appears after the packages have been installed on first run
	if ! isInList "$autopackage_prefix/bin" "$oldpath"; then
		updateEnv PATH "$autopackage_prefix/bin"
		out " "
		out "$intl_SETUP_RUN_EXEC_BASH"
		out " "
	fi

	_finishWindow
	return 0

}
## END INSTALLAUTOPACKAGE


##
# _removeAutopackage
#
# Determines how autopackage support code is installed and removes support code.
function _removeAutopackage() {

	trace called
	local r

	# check for installed RPM and remove if present
	if locateCommand rpm; then
		"$lc_location" -q --quiet autopackage
		r="$?"
		if [[ "$r" == "0" ]]; then
			trace removing autopackage rpm package
			rpm -e --quiet autopackage
			return "$?"
		fi
	fi

	# test to see if support code is from a package
	if [ -O "$autopackage_prefix/share/autopackage/remove" ]; then
		trace executing "$autopackage_prefix/share/autopackage/remove" --silent
		"$autopackage_prefix/share/autopackage/remove" --silent;
		return "$?"

	# test to see if support code is from CVS
	elif [ -L "$autopackage_prefix/share/autopackage" ]; then
		locateCommand package
		apkg_main_dir=`ls -la "$lc_location"`
		apkg_main_dir=`echo  "$apkg_main_dir" | awk 'BEGIN { FS=" -> " } { print $2 }'`
		apkg_main_dir=`dirname "$apkg_main_dir"`
		[[ "$apkg_main_dir" == "." ]] && apkg_main_dir="$lc_location"
		if [ -e "$apkg_main_dir/unsetup" ]; then
			trace executing "$apkg_main_dir/unsetup" --silent
			"$apkg_main_dir/unsetup" --silent;
			return "$?"
		fi
	else
		# autopackage must be installed since we exist, so it must not be available to
		# be removed - return code for _packageReturnCode function
		return 5
	fi

}


##
# _installGTKFE
#
# Determines if autopackage gtk front end application needs to be downloaded/upgraded/installed.
function _installGTKFE() {

	trace called

	local retval

	# if manually called from install script
	if [[ "$executing_from_directory" == "" ]]; then
		executing_from_directory=`pwd`
		executing_from_directory=`dirname "$executing_from_directory"`
	fi
	[[ "$required_version" == "" ]] && required_version="$autopackage_version"

	if testForLib libgtk-x11-2.0.so && testForLib libglade-2.0.so; then

		[ ! "$autopackage_silent" ] && out "$intl_SETUP_YOU_HAVE_GTK";

		if locateCommand autopackage-launcher-gtk; then
			apkg_gtk_version=`"$lc_location" --version | awk 'BEGIN {FS=" version "} { print $2 }'`
		fi

		trace found GTKFE version $apkg_gtk_version
		if [[ "$apkg_gtk_version" != "" ]]; then
			trace removing GTKFE $apkg_gtk_version
			PATH="$PATH":~/.local/bin package remove autopackage-gtk
		fi

		#if ( ( compareVersions "$required_version" "$apkg_gtk_version" ) && [[ "$apkg_gtk_version" != "" ]] ) || ( ! locateCommand "autopackage-launcher-gtk" ); then
			# check in sealed installer packages directory
			if [ -e "$meta_dir/packages/autopackage-gtk-$required_version.x86.package" ]; then
				filename="$meta_dir/packages/autopackage-gtk-$required_version.x86.package"
			# check in executed from directory
			elif [ -e "$executed_from_directory/autopackage-gtk-$required_version.x86.package" ]; then
				filename="$executed_from_directory/autopackage-gtk-$required_version.x86.package"
			fi
			trace trying to locate GTKFE package "$filename"
			if [[ "$filename" != "" ]]; then
				[ ! "$autopackage_silent" ] && out " "
				out "Installing graphical interface, please wait... "
				chmod +x "$filename"
				"$filename"
				retval="$?"
				if [[ "$retval" != "0" ]]; then
					_finishWindow
					return "$retval"
				fi
			else
				trace trying to download GTKFE package "http://autopackage.org/downloads/latest/autopackage-gtk-latest.x86.package"
				if [[ "$yesno_suppress" != "1" ]]; then
					yesNo "OK to download graphical interface now? (Y/n): "
					retval="$?"
					if [[ "$retval" != "0" ]]; then
						return "$retval"
					fi
				fi
				download "http://autopackage.org/downloads/latest/autopackage-gtk-latest.x86.package"

				filename="`pwd`/autopackage-gtk-latest.x86.package"
				chmod +x "$filename"
				[ ! "$autopackage_silent" ] && out "Installing graphical interface, please wait... "
				"$filename"
				retval="$?"
				if [[ "$retval" != "0" ]]; then
					_finishWindow
					return "$retval"
				fi
				rm "$filename"

			fi

			[ ! "$autopackage_silent" ] && out " "
		#fi
	fi

	return 0

}


##
# _installApbuild
#
# Upgrade/install apbuild.
function _installApbuild() {

	trace called
	keep_apbuild=false

	if locateCommand apgcc; then
		# Only upgrade if the apbuild on the system is different
		if ! diff --brief "$lc_location" "$apkg_main_dir/../apbuild/apgcc" &> /dev/null; then
			keep_apbuild=false
			# check for CVS directory apbuild
			if [ ! -e "$apkg_main_dir/../apbuild" ]; then
				err "Need to have CVS directory autopackage/apbuild available"
				err "so that it can be installed for use."
				return 1
			fi
			cd "$apkg_main_dir/../apbuild"
                        
			[ ! "$autopackage_silent" ] && out
			[ ! "$autopackage_silent" ] && out "Need to remove CVS directory apbuild's apgcc executable... "
			if [ ! "$autopackage_silent" ]; then
			    make uninstall
			else
			    make uninstall > /dev/null 2>&1
			fi
		else
			keep_apbuild=true
			[[ ! "$autopackage_silent" && "$1" != "-q" ]] && out
			[[ ! "$autopackage_silent" && "$1" != "-q" ]] && out "Skipping installation of CVS directory apbuild's apgcc executable... "
		fi
	fi

	if ! $keep_apbuild; then
		[ ! "$autopackage_silent" ] && out
		[ ! "$autopackage_silent" ] && out "Installing CVS directory apbuild's apgcc executable... "
		cd "$apkg_main_dir/../apbuild"
                
		[ ! "$autopackage_silent" ] && out
		[ ! "$autopackage_silent" ] && out "Need to install CVS directory apbuild's apgcc executable... "
		if [ ! "$autopackage_silent" ]; then
		    make install
		else
		    make install > /dev/null 2>&1
		fi

		# add uninstall commands to log
		logCommand "oPWD=\`pwd\`; cd `escapeFilename "${apkg_main_dir}/../apbuild"`; make uninstall; cd \"\$oPWD\";"
	fi
}

## START AUTOSUCOMMAND
## Function is substituted from apkg-funclib.
function _autosuCommand() {

	local status_message

	# autosu error codes
	#   0  Success
	#  11  User clicked cancel
	#  12  User doesn't have a password
	#  13  su exited abnormally
	#  14  User typed incorrect password 3 times
	#  15  System error

	# Don't use autosu if we're already root, or if $autopackage_no_autosu is set.
	# If /etc/autopackage/config was not found, then that means the user
	# installed autopackage itself as non-root. In that case, never ask
	# for the root password, because root will not be able to find the
	# autopackage support libraries.

	if [[ `id -u` == 0 || ( ! -f /etc/autopackage/config && -f ${XDG_CONFIG_HOME:-~/.config}/autopackage/config ) || ("$autopackage_no_autosu" == "true" && "$1" != "--root-only") ]]; then
		# Filter out autosu arguments
		while [[ "${1:0:1}" == "-" ]]; do
			if [[ "$1" == '--root-only' ]]; then
				shift
			elif [[ "$1" == '-m' ]]; then
				shift
				shift
			else
				break
			fi
		done
		"$@"
		return "$?"
	fi

	local cmdret
	local r
	local autosu_component

	cmdret="$TMP/autosu.$RANDOM$$"

	# define autosu component and location to execute autosu command

	# check for X and GTK2
	if [[ "$DISPLAY" == "" ]] || ! xdpyinfo &>/dev/null || [[ "$AUTOPACKAGE_FRONTEND" == "apkg-ttyfe" ]] || ! testForLib libgtk-x11-2.0.so || ! testForLib libglade-2.0.so ; then
		# No X and/or GTK2, so use tui (could be a headless script)
		autosu_component="autosu-tui"
	else
		autosu_component="autosu-gtk"
	fi

	# autopackage support code installation location
	if [ -x "$autopackage_prefix/libexec/autopackage/$autosu_component" ]; then
		"$autopackage_prefix/libexec/autopackage/$autosu_component" "$@" 5>"$cmdret"
		r="$?"
		cmdret=`cat "$cmdret"; rm "$cmdret"`

	# autopackage support code package location
	elif [ -x "autopackage/libexec/$autosu_component" ]; then
		"autopackage/libexec/$autosu_component" "$@" 5>"$cmdret"
		r="$?"
		cmdret=`cat "$cmdret"; rm "$cmdret"`
	fi

	# user clicked cancel or entered the wrong password 3 times
	if [[ "$r" == "11" || "$r" == "14" ]]; then
		return 13

	# user does not have a root password
	elif [[ "$r" == "12" ]]; then
		# Filter out autosu arguments
		while [[ "${1:0:1}" == "-" ]]; do
			shift
			shift
		done
		"$@"
		return "$?"

	# for all other errors fail
	elif [[ "$r" != "0" ]]; then
		return 15
	fi

	return 0

}
## END AUTOSUCOMMAND


##
# _checkVersionRequirements
#
# Determines minimum levels of acceptable versions for certain commands
function _checkVersionRequirements() {

	trace funclib: sanity version checks starting

	#locateCommand file "--version"
	#current_version=`echo "$lc_output" | grep -e 'file-' | sed 's/file-//'`
	#if ! compareVersions "3.30" "$current_version"; then
	#	out "$intl_SETUP_VERSION_REQUIREMENT" "file" "3.30"
	#	exit 1
	#fi

	locateCommand wc "--version"
	# There's a difference between GNU textutils's wc and coreutils's wc
	if echo "$lc_output" | grep -q '^wc (textutils)'; then
		current_version=`echo "$lc_output" | grep -e 'wc ' | sed 's/wc (textutils) //'`
		if ! compareVersions "2.0.14" "$current_version"; then
			out "$intl_SETUP_VERSION_REQUIREMENT" "wc" "2.0.14"
			exit 1
		fi
	#else
	#	current_version=`echo "$lc_output" | grep -e 'wc ' | sed 's/wc (coreutils) //'`
	#	if ! compareVersions "4.5" "$current_version"; then
	#		out "$intl_SETUP_VERSION_REQUIREMENT" "wc" "4.5"
	#		exit 1
	#	fi
	fi

	# test for glib-2.0 requirement
	if ! testForLib libglib-2.0.so; then
		out "$intl_SETUP_VERSION_REQUIREMENT" "glib" "2.0"
		exit 1
	fi

	trace funclib: sanity version checks completed

}


function _processPackageArguments() {
	# process the CLI arguments, step 2
	trace called with $@
	while [[ "$1" != "" ]]; do
	    case `echo $1 | sed 's/=.*//'` in
		"-p" | "--prefix") export prefix=`chewArgument $@`; shift; shift;
		                   trace using prefix $prefix
				   if [[ "$prefix" == "" ]]; then red; outn "$intl_FAIL"; normal; out "$intl_PREFIX_NOT_SPECIFIED"; exit 1; fi;
				   ;;
	        "-f" | "--force") force="true"; shift;
				  ;;
		"-h" | "--help") shift; out "$intl_INSTALLER_HELP"; rm -rf "$working_dir"; exit 0;;
		"-g" | "--gtkfe") shift; export AUTOPACKAGE_FRONTEND="autopackage-frontend-gtk"; shift;;
		"-t" | "--ttyfe") shift; export AUTOPACKAGE_FRONTEND="apkg-ttyfe"; shift;;
		*)  red; outn "$intl_FAIL"; normal; out "$intl_UNKNOWN_OPTION" "$1"; shift;
		    shift; exit 1;
		    ;;
	    esac
	done
}


function _genSummary() {
	{
		echo "DISPLAY-SUMMARY"
		echo "install"
		echo "success"
		echo "$SHORTNAME"
		if [ -e "$working_dir/display-names" ]; then
			echo `cat "$working_dir/display-names" | wc -l`
			cat "$working_dir/display-names"
		else
			echo "0"
		fi
		if [ -e "$working_dir/desktop-files" ]; then
			echo `cat "$working_dir/desktop-files" | wc -l`
			cat "$working_dir/desktop-files"
		else
			echo 0
		fi
		if [ -e "$working_dir/install-sizes" ]; then
			# stream sum total - count is always 1
			echo "1"
			while read; do
				line=`echo "$REPLY"`
				[[ "$line" != "" ]] && let "total = $total + $line"
			done <"$working_dir/install-sizes"
			echo "$total"
		else
			echo "0"
		fi
		if [ -e "$working_dir/failed-recommends" ]; then
			echo `cat "$working_dir/failed-recommends" | wc -l`
			cat "$working_dir/failed-recommends"
		else
			echo "0"
		fi

	} > "$autopackage_pipe"
	cat "$autopackage_pipe" >/dev/null # sloppy but i'm tired -m
}


##
# getLanguages
#
# Returns a list of user languages like 'fr_CA fr en'.
# Example: language_list=`getLanguages`
function getLanguages() {

	trace called
	local language_list
	local language_match_list

	# if AUTOPACKAGE_LANGUAGE is used then the user is forcing
	if [ "$AUTOPACKAGE_LANGUAGE" ]; then
		language_list="$AUTOPACKAGE_LANGUAGE"
		trace using AUTOPACKAGE_LANGUAGE=$AUTOPACKAGE_LANGUAGE

	else

		# order and structure defined by The Open Group Base Specifications Issue 6
		# use LANGUAGE if it exist because it is used by GNU gettext
		# LANGUAGE=en_US:en
		if [[ "$LANGUAGE" != "" && "$LANGUAGE" != "C" ]]; then
			language_list="$LANGUAGE"
			trace using LANGUAGE=$LANGUAGE

		# LC_ALL is used to default LC_* environment variables
		# LC_ALL=en_US
		elif [[ "$LC_ALL" != "" && "$LC_ALL" != "C" ]]; then
			language_list="$LC_ALL"
			trace using LC_ALL=$LC_ALL

		# use LANG if LC_ALL is not present
		# LANG=en_US
		elif [[ "$LANG" != "" && "$LANG" != "C" ]]; then
			language_list="$LANG"
			trace using LANG=$LANG

		# define default language
		else
			language_list="en"
			trace using default as language_list=$language_list
		fi

	fi

	# filter for LANGUAGE information syntax
	language_list=`echo "$language_list" | sed 's/:/ /g'`

	# breakdown country_locale entries and add country to language_list if it does not exist
	# cycle through and collect a match list from language list like en_US --> match_list=en
	for language_item in $language_list; do
		language_element="${language_item/_*/}"
		if [[ "$language_item" != "$language_element" ]]; then
			language_match_list=`echo "$language_match_list $language_element"`
		fi
	done

	# cycle through match_list to see if it does not exist already in language_list
	for language_match_item in $language_match_list; do
		unset language_match
		language_match=`echo "$language_list" | grep -cw "$language_match_item"`
		if [[ "$language_match" == "0" ]]; then
			trace adding $language_match_item to language_list
			language_list=`echo "$language_list $language_match_item"`
		fi
	done

	# add default language `en' if not present or derived
	language_match=`echo "$language_list" | grep -c "en"`
	if [[ "$language_match" == "0" ]]; then
		trace adding en as default to language_list
		language_list=`echo "$language_list en"`
	fi

	trace language_list=$language_list
	echo "$language_list"
	return 0

}


##
# _loadPackageEnvironment <DIRECTORY>
# DIRECTORY: base directory in which to look for environment files
#
# Loads package environment file and description file from the DIRECTORY.
# The users language setting is determined and the representative environment
# file is loaded. The environment file enables the system to give localized
# package information. If any information is not localized, then it will be
# have been retrieved from the en language setting. The environment files can
# be either processed files (environment.en) or non-processed
# (apkg-environment.en) files.
# <pre>
# Process:
#   Looks for environment file to match user languages
#     fr --> apkg-environment.fr     de --> apkg-environment.de
#   If files are named environment then the files have already been copied
#     into the package database and load the representative file instead
#   If no localized environment file exists then load apkg-environment.en
#   Create files to copy into package database
#     fr --> environment.fr     de --> environment.de
# </pre>
# Example:
#   _loadPackageEnvironment "$autopackage_db_location/$1"
#
function _loadPackageEnvironment() {

    trace called with "$1"
    local location="$1"
    local language
    unset language_selected

    # get list of user languages if not defined by _initializeAutopackage - this is used
    # during initial autosu through _autosuCommand() for installation authorization
    if [[ "$language_list" == "" ]]; then
        language_list=`getLanguages`
    else
        trace language_list=$language_list
    fi

    # go through language list and match the first language from order of preference user listing
    for language in $language_list; do

        if [ -e "$location/environment.${language}" ]; then
            trace loading package environment from "$location/environment.${language}"
            source "$location/environment.${language}"
            [ -e "$location/description.${language}" ] && export DESCRIPTION=`cat "$location/description.${language}"`;
            language_selected="$language"
            break
        elif [ -e "$location/apkg-environment.${language}" ]; then
            trace loading package environment from "$location/apkg-environment.${language}"
            source "$location/apkg-environment.${language}"
            [ -e "$location/apkg-description.${language}" ] && export DESCRIPTION=`cat "$location/apkg-description.${language}"`;
            language_selected="$language"
            break
        fi

    done

    if [ ! "$language_selected" ]; then
        trace requested user language not found, falling back to en or database package location
        language_selected="en"
        if [ -e "$location/environment.${language_selected}" ]; then
            trace loading package environment from "$location/environment.${language_selected}"
            source "$location/environment.${language_selected}"
            [ -e "$location/description.${language_selected}" ] && export DESCRIPTION=`cat "$location/description.${language_selected}"`;
        elif [ -e "$location/apkg-environment.${language_selected}" ]; then
            trace loading database package environment from "$location/apkg-environment.${language_selected}"
            source "$location/apkg-environment.${language_selected}"
            [ -e "$location/apkg-description.${language_selected}" ] && export DESCRIPTION=`cat "$location/apkg-description.${language_selected}"`;
        fi
    fi

    # set variable for location for other functions that call _loadPackageEnvironment
    export PACKAGELOCATION="$location"
    
    # set variable for the language that was selected for display from getLanguages $language_list
    export language_selected="$language_selected"

    # change UTC *DISPLAY variables to locale text
    TIMESTAMPBUILDDISPLAY=`LC_ALL="$language_selected" LC_MESSAGES=en_US date --date="$TIMESTAMPBUILDDISPLAY" +%c`
    TIMESTAMPINSTALLDISPLAY=`LC_ALL="$language_selected" LC_MESSAGES=en_US date --date="$TIMESTAMPINSTALLDISPLAY" +%c`
    
    trace ROOTNAME=$ROOTNAME
    trace SHORTNAME=$SHORTNAME
    trace DISPLAYNAME=$DISPLAYNAME

    if [[ "$meta_dir" = "" ]]; then
        local meta_dir=$1
    fi
    export apkg_logfile="$meta_dir/log"
    export apkg_filelist="$meta_dir/filelist"

}


##
# _createPackageEnvironmentFiles <DIRECTORY>
# DIRECTORY: base directory to create environment files.
#
# Loads package environment file and description file from the DIRECTORY.
# The users language setting is determined and the representative environment
# file is loaded. Processes for each package language, the environment and
# description files to be prepared for copying in package installation database.
# Add runtime installation variables to environment files.
# <pre>
# Process:
#   Create files to copy into package database within _createDBEntry function.
#     fr --> environment.fr     de --> environment.de
# </pre>
# Example:
#   _createPackageEnvironmentFiles "$meta_dir"
#
function _createPackageEnvironmentFiles() {

    trace called with "$1"
    local location="$1"
    local language

    # Load and use package environment file during package file creation
    _loadPackageEnvironment "$location"

    # Create package environment file for use in _createDBEntry function if not created yet
    if [ ! -e "$location/environment.en" ]; then

        # Determine install package variables for package environment file
        if [[ `id -u` == "0" ]]; then
            DATABASE="Global"
        else
            DATABASE="User"
        fi
        BACKUP="$ROOTNAME/backup"

        # generate UTC timestamp to use with locale
        TIMESTAMPINSTALL="`LC_ALL=en_US LC_MESSAGES=en_US date --utc --iso-8601=seconds | cut -b -19`Z"
        TIMESTAMPINSTALLDISPLAY=`LC_ALL="en" LC_MESSAGES=en_US date --utc`

        # go through language list and create package environment files and add runtime install variables
        for language in $PACKAGELANGUAGES; do

            trace creating package environment from "$location/apkg-environment.${language}"
            cp -f "$location/apkg-description.${language}" "$location/description.${language}"
            cp -f "$location/apkg-environment.${language}" "$location/environment.${language}"
            echo "" >> "$location/environment.${language}"
            echo "# Package install information" >> "$location/environment.${language}"
            echo "export BACKUP=\"$BACKUP\"" >> "$location/environment.${language}"
            echo "export CPUARCHITECTURE=\"$cpu_architecture\"" >> "$location/environment.${language}"
            echo "export DATABASE=\"$DATABASE\"" >> "$location/environment.${language}"
            echo "export DATASIZE=\"$dataSize\"" >> "$location/environment.${language}"
            echo "export DISTRIBUTIONCODENAME=\"$AUTOPACKAGE_DISTRIBUTION_CODENAME\"" >> "$location/environment.${language}"
            echo "export DISTRIBUTIONDESCRIPTION=\"$AUTOPACKAGE_DISTRIBUTION_DESCRIPTION\"" >> "$location/environment.${language}"
            echo "export DISTRIBUTIONID=\"$AUTOPACKAGE_DISTRIBUTION_ID\"" >> "$location/environment.${language}"
            echo "export DISTRIBUTIONMANAGER=\"$AUTOPACKAGE_DISTRIBUTION_MANAGER\"" >> "$location/environment.${language}"
            echo "export DISTRIBUTIONMANAGERGRAPHICAL=\"$AUTOPACKAGE_DISTRIBUTION_MANAGER_GRAPHICAL\"" >> "$location/environment.${language}"
            echo "export DISTRIBUTIONRELEASE=\"$AUTOPACKAGE_DISTRIBUTION_RELEASE\"" >> "$location/environment.${language}"
            echo "export LSBVERSION=\"$AUTOPACKAGE_LSB_VERSION\"" >> "$location/environment.${language}"
            echo "export MD5=\"$MD5\"" >> "$location/environment.${language}"
            echo "export METASIZE=\"$metaSize\"" >> "$location/environment.${language}"
            echo "export PREFIX=\"$PREFIX\"" >> "$location/environment.${language}"
            echo "export TIMESTAMPINSTALL=\"$TIMESTAMPINSTALL\"" >> "$location/environment.${language}"
            echo "export TIMESTAMPINSTALLDISPLAY=\"$TIMESTAMPINSTALLDISPLAY\"" >> "$location/environment.${language}"

        done

    fi

}


##
# _dumpPackageEnvironment <IDENTIFY>
# IDENTIFY: text to identify the location of the breakpoint
#
# Place _dumpPackageEnvironment in some logic to trace all of the package variables.
# Add extra variables to trace by including a APKG_DUMP_VARIABLES.
#
# Example:
#   export AUTOPACKAGE_DUMP_VARIABLES="meta_dir working_dir"
#   _dumpPackageEnvironment first package to arrive
function _dumpPackageEnvironment() {

	local apkg_variables
	local apkg_variable
	trace called with $@
	# if AUTOPACKAGE_DUMP_VARIABLES is used then the user is adding variables to output
	if [ "$AUTOPACKAGE_DUMP_VARIABLES" ]; then
		apkg_variables="$specKeys $buildKeys $installKeys $AUTOPACKAGE_DUMP_VARIABLES"
	else
		apkg_variables="$specKeys $buildKeys $installKeys"
	fi
	for apkg_variable in $apkg_variables; do
		a="${apkg_variable}"
		trace "$apkg_variable=\"${!a}\""
	done

}


##
# _packageInfo <SHORTNAME>
# SHORTNAME: name which declares package.
#
# Output package information of a given package.
function _packageInfo() {

    trace called with "$1"

    if ! _loadPackage "$1"; then
        _packageReturnCode "1" "$1"
        return "$?"
    fi

    out "$intl_PACKAGE_INFO_SHORTNAME" "$SHORTNAME"
    out "$intl_PACKAGE_INFO_DISPLAYNAME" "$DISPLAYNAME"
    out "$intl_PACKAGE_INFO_ROOTNAME" "$ROOTNAME"
    out "$intl_PACKAGE_INFO_SOFTWAREVERSION" "$SOFTWAREVERSION"
    out "$intl_PACKAGE_INFO_INTERFACEVERSION" "$INTERFACEVERSION"
    out "$intl_PACKAGE_INFO_PACKAGEVERSION" "$PACKAGEVERSION"
    out "$intl_PACKAGE_INFO_MAINTAINER" "$MAINTAINER"
    out "$intl_PACKAGE_INFO_LICENSE" "$LICENSE"
    out "$intl_PACKAGE_INFO_ROOTINSTALLONLY" "$ROOTINSTALLONLY"
    [[ "$DATABASE" == "Global" ]] && out "$intl_PACKAGE_INFO_DATABASE" "$intl_PACKAGE_INFO_DATABASE_GLOBAL";
    [[ "$DATABASE" == "User" ]] && out "$intl_PACKAGE_INFO_DATABASE" "$intl_PACKAGE_INFO_DATABASE_USER";
    out "$intl_PACKAGE_INFO_BUILDHOST" "$BUILDHOST"
    out "$intl_PACKAGE_INFO_TIMESTAMPBUILD" "$TIMESTAMPBUILDDISPLAY"
    out "$intl_PACKAGE_INFO_TIMESTAMPINSTALL" "$TIMESTAMPINSTALLDISPLAY"
    out "$intl_PACKAGE_INFO_SIZE" "$INSTALLSIZE"
    out "$intl_PACKAGE_INFO_MD5" "$MD5"
    out "$intl_PACKAGE_INFO_PACKAGER" "$PACKAGER"
    out "$intl_PACKAGE_INFO_URL" "$URL"
    out "$intl_PACKAGE_INFO_SUMMARY" "$SUMMARY"
    out "$intl_PACKAGE_INFO_DESCRIPTION" "$DESCRIPTION"
    echo

}

##
# _apkgPrefix
#
# Determine the prefix to use for installing autopackage support code to.
# If the user is root, this is /usr. If the user is not root,
# it is $HOME/.local. The result is output on stdout.
#
# This is an internal function used only while setting up the autopackage
# support code. Never use this function.
function _apkgPrefix() {
	local prefix
	if [[ `id -u` != "0" ]]; then
	    prefix="$HOME/.local"
	else
	    prefix="/usr"
	fi

	trace prefix="$prefix"
	echo "$prefix"
}

##
# _userPrefix
#
# Determine prefix to install software to. This can be overriden
# by the autopackage config file. When root, the result is by default
# /usr, when non-root ~/.local, however this may change on a per-package
# basis depending on the system configuration.
#
# This is an internal function used to set $PREFIX (if $PREFIX isn't already
# explicitly set by an argument). Do not use this function, use $PREFIX instead.
function _userPrefix() {
	local prefix
	trace called
	if [[ "$autopackage_default_prefix" != "" ]] || [ ! -d "$autopackage_default_prefix" ]; then
		prefix=`eval echo $autopackage_default_prefix`
		if [[ `id -u` != "0" ]]; then
			if ! haveWriteAccess "$prefix"; then
				prefix="$HOME/.local"
			fi
		fi
	else
		if [[ `id -u` != "0" ]]; then
			prefix="$HOME/.local"
		else
			prefix="/usr/local"
		fi
	fi
	trace prefix="$prefix"
	echo "$prefix"

}


##
# _userConfig
# Outputs: a directory name.
#
# Determine the folder in which configuration files are stored.
# If root then the directory is /etc or /etc/xdg [XDG]. If user then the directory
# is $HOME/.config or $XDG_CONFIG_HOME/config [XDG].
#
# This is an internal function used only while setting up the autopackage support code.
# It's not encouraged that you use this function unless you have a very good reason to do so.
function _userConfig() {
	local etc_dir

	if [[ `id -u` != "0" ]]; then
		if [[ "$XDG_CONFIG_HOME" != "" ]]; then
			etc_dir="$XDG_CONFIG_HOME/config"
		else
			etc_dir="$HOME/.config"
		fi
	else
		if [[ "$XDG_CONFIG_DIRS" != "" ]] || [[ "$XDG_DATA_DIRS" != "" ]]; then
			etc_dir="/etc/xdg"
		else
			etc_dir="/etc"
		fi
	fi
	trace etc_dir="$etc_dir"
	echo "$etc_dir"

}


# The reason that this is so hard to understand is because we have to start from the
# bottom of the payload tree and work up. A payload may depend on its dependencies
# being fully installed first, so we have to walk the tree in the opposite direction
# to processing the prep scripts -mike 27/04/2003
function processInstallPayloads() {
	# read the first
	local p
	local oIFS="$IFS"

	# for some reason, aliases don't work here (bug in bash?)
	(( DEBUGLEVEL >= 3 )) && _trace -f$FUNCNAME " $1";

	IFS=$'\n'
	if [ -e "$working_dir/meta/$1/payloads" ]; then
		for p in `cat "$working_dir/meta/$1/payloads"`; do
			# recurse into them
			(( DEBUGLEVEL >= 3 )) && _trace -f$FUNCNAME " --> recursing into $p, here we go!"
			meta_dir="$working_dir/meta/$p" processInstallPayloads "$p" || return $?
			(( DEBUGLEVEL >= 3 )) && _trace -f$FUNCNAME " <-- processed OK, recursing out of $p"
		done
	fi
	IFS="$oIFS"

	# does the payload exist? if not, we need to download it first
	if [ ! -d "$working_dir/payload/$1" ]; then
		(( DEBUGLEVEL >= 3 )) && _trace -f$FUNCNAME " payload $1 is registered but non-existant locally, retrieving from network"
		_retrievePayloadFromNet $1 || return 2
	fi

	pushd "$working_dir/payload/$1" >/dev/null
	# FIXME: should we do meta_dir here too?
	payload_dir="$working_dir/payload/$1"
	# restore environment
	_loadPackageEnvironment "$working_dir/meta/$1"
	# execute the install script
	(( _cur_series_pos++ ))
	"$working_dir/meta/$1/apkg-install-script" || {
		popd >/dev/null
		local err=`outn "$intl_INSTALL_ERROR" "$DISPLAYNAME"`
		outputFail "$err"
		return 1
	}
	popd >/dev/null
	return 0
}


# **************************************************************
#   Firstly, we check for the presence of the autopackage tools. If not
#   present, then we fork to another script that offers to download
#   and install it - easy for the user no? If it is present, then
#   we proceed with the installation process, using named pipes to
#   communicate with the "front end" module. Installations should
#   have the ability to proceed with NO user interaction whatsoever,
#   this might mean being able to read settings from an external file
#   or simply always having sensible defaults.
#
# **************************************************************

# Called when the entire installation is done. Don't confuse this with
# _installScriptFinished, which is called every time an install script has finished.
#
# Put stuff that always needs to be done on exit (whether clean or not) here.
# Exit code (optional) is given in $1
function _installerFinish() {
    # exit global session
    trace called
    if [[ "$autopackage_pipe" != "" ]]; then terminateFE; fi

    rm -rf "$working_dir"

    # if error code then leave the session file behind for reporting/debugging
    # session file removed next time through bashlib
    if (( DEBUGLEVEL == 0 )) && ( [[ "$1" == "" ]] || [[ "$1" == "0" ]] ); then
        rm -f "$_AUTOPACKAGE_SESSION"
    else
        exit $1
    fi
}

function _installer() {
        trace starting up
                        
	# need to process arguments first before allowing the package meta data to be loaded
	# _loadPackageEnvironment sources and writes environment files to database during first run
	_processPackageArguments "$@"

	# initialize variables
	_initializeAutopackage

	if [[ "$first_autosu" == "" ]]; then
                # this [sorta hack] is about preventing recursive authentication attempts
                # it should probably be combined with we_are_the_first - see below
		export first_autosu="true" 

                local tmp
                local this_arch
                local needed_archs
                tmp=$( _loadPackageEnvironment "$meta_dir"; echo "$CPUARCHITECTURES"; echo "$ROOTINSTALLONLY"; echo "$DISPLAYNAME"; )

                # check CPU arch is OK before we run any native code
                needed_archs=$( echo "$tmp" | sed -n '1p' )
                local found=false
                for a in $needed_archs; do
                    if [[ "$a" == "$cpu_architecture" ]]; then found=true; fi
                done
                
                if ! $found; then
                    echo
                    out "$intl_UNSUPPORTED_CPU_ARCH" "$needed_archs" "$this_arch"
                    echo
                    return 1
                fi

                trace passed cpu arch test
                
		ROOTINSTALLONLY=$( echo "$tmp" | sed -n '2p' )
		DISPLAYNAME=$( echo "$tmp" | sed -n '3p' )
                unset tmp
                
		export AUTOSU_DISPLAYNAME="$DISPLAYNAME"

                # recurse
		if [[ "$ROOTINSTALLONLY" == "Yes" ]]; then
			_autosuCommand --root-only "$meta_dir/apkg-installer" "$@"
		else
			_autosuCommand "$meta_dir/apkg-installer" "$@"
		fi
		retval=$?
                trace "autosu retval=$retval"

		rm -rf "$working_dir"
		return $retval
	fi

	# load and create package environment variables
	_createPackageEnvironmentFiles "$meta_dir"

	if [[ "$we_are_the_first" == "" ]]; then
		export we_are_the_first="true"
	fi  # otherwise it must be false

	boot_frontend="false"
	if [[ "$autopackage_pipe" == "" ]]; then
		export autopackage_pipe="${TMP}/apkg-fifo$$"
		rm -f "$autopackage_pipe" # in case we get an old crashed pid
		trace creating fifo at $autopackage_pipe
		mkfifo "$autopackage_pipe" || {
                    err failed to create fifo
                    rm -rf "$working_dir"
                    exit 1
                }
		boot_frontend="true"
	fi

	# touch the payloads file into existance
	touch "$meta_dir/payloads"

	# start the install process
	if $we_are_the_first; then
		(
			# create a "global" session, so that we don't quit in the time between the end of the
			# prep scripts and start of the install scripts
			trace waiting for frontend
			if ! waitForHELLO; then
				outputFail "$intl_PROTOCOL_MISMATCH";
                                _installerFinish 1
			fi

			# check for user lock
			if $autopackage_deny_user; then
				outputFail "$intl_ACCESS_DENIED"
                                _installerFinish 1
			fi

			# check to see if we are already installed..... for now just check the autopackage db
                        # this should be replaced by an actual file check post 1.0
			# dependencies don't do this check because if the dependency check failed, we assume that
			# even when the package is apparently installed, parts of it must be missing
			if isNameKnown "$SHORTNAME"; then
			        # HACK HACK HACK should be going via the frontend
				outn "$intl_PACKAGE_ALREADY_INSTALLED ... "
				# needs to be in subshell to protect the package environment
				( uninstallPackage "$SHORTNAME"; exit $?; )
				if [[ "$?" != "0" ]]; then
                                    _installerFinish 1
				fi
			fi

			if ! checkDiskSpace "$EXPANDSIZE" "$PREFIX"; then
				outputFail "$intl_NO_DISK_SPACE" "$SHORTNAME" "$PREFIX" "$EXPANDSIZE";
                                _installerFinish 1
			fi

			# process the prep scripts - why do we set we_are_the_first here?
			we_are_the_first="false" "$meta_dir/apkg-prep-install-script"
			if [[ "$?" == "0" ]]; then
				trace proceeding with installation

				# start a series on the GUI
				if [ -e "$working_dir/global-payloads" ]; then
					_total_payloads=$( cat "$working_dir/global-payloads" | wc -l )
					# for the current package, which won't be registered
					(( _total_payloads++ ))
					startSeries $_total_payloads
					unset _total_payloads
				else
					startSeries 1
				fi
				export _cur_series_pos=0

				processInstallPayloads "$ROOTNAME" # process the payloads
				local ret="$?"
				if [[ "$ret" == "0" ]]; then
					# we made it! praise be!
					_genSummary
				else
					# if payloads were not installed because of a failure in the package scripts
					# then rollback installation. if the return code is 2 that means something went
					# wrong with unpacking or retrieving the payloads
					_sessionRollback
					_installerFinish "$ret"
				fi # assume we output some FAIL message to explain why we didn't install correctly
			elif [[ "$?" == "3" ]]; then
				local err=`outn "$intl_PREP_ROOTINSTALLONLY" "$DISPLAYNAME"`
				outputFail "$err"
			else
				local err=`outn "$intl_PREP_ERROR" "$DISPLAYNAME"`
				outputFail "$err"
			fi # assume we output some FAIL message to explain why we didn't prepare correctly

			_installerFinish 0

		) &

	else
		(
			"$meta_dir/apkg-prep-install-script" # just process the prep scripts here, payloads will be recursed into in the correct order by the first process
			if [[ "$?" == "0" ]]; then
				if ! checkDiskSpace "$EXPANDSIZE" "$PREFIX"; then # recheck disk space
					outputFail "$intl_NO_DISK_SPACE" "$SHORTNAME" "$PREFIX" "$EXPANDSIZE"
				fi
				trace subprep went OK
				exit 0
			elif [[ "$?" == "3" ]]; then
				warn subprep failed on ROOTINSTALLONLY check
				exit 3
			else
				warn subprep failed
				exit 1
			fi
		) &
	fi

	if $boot_frontend; then
		# now start the front end.
		# we do this here so the front end gets hold of stdin/stdout
		unset boot_frontend
		( # run as subshell, so it can exit in the middle of the install
                  # do we still have to do this?
			_launchFE "$autopackage_pipe"
		);
		fe_result=$?;

		trace deleting fifo $autopackage_pipe
		rm -f "$autopackage_pipe"

		exit $fe_result;
	else
		wait $!
		exit $?
	fi
}

##
# _sessionRollback
#
# Process the session log that was generated by the autopackage file
# installation functions. Function requires the variable $_AUTOPACKAGE_SESSION
# that is set in bashlib autopackage logging framework.
function _sessionRollback() {

	out "$intl_SESSION_ROLLBACK"
	trace called with _AUTOPACKAGE_SESSION=$_AUTOPACKAGE_SESSION
	local log

	if [ -e "$_AUTOPACKAGE_SESSION" ]; then
		log=`tac "$_AUTOPACKAGE_SESSION"`
                trace executing: "$log"
		eval "$log"
		return 0
	fi

	err Session rollback failed because it requires the session file $_AUTOPACKAGE_SESSION.
	return 1

}


##
# _loadPackage <NAME>
# NAME: SHORTNAME or unversioned ROOTNAME that defines package.
# RETURNS: 0 if successful.<br />1 if not available.
#
# Load package information that matches NAME and makes package
# information available to system.
#
# See also: _loadPackageEnvironment().
#
# Example:
#   if ! _loadPackage "$1"; then
#       _packageReturnCode "1" "$1"
#       return "$?"
#   fi
# # All package environment variables are now available
# # including PACKAGELOCATION which gives directory location of package.
#
function _loadPackage() {

    trace called with $@
    local p r

    for p in `_listPackagesDB`; do
        # do not compare basenames - load package environment
        # and check SHORTNAME to SHORTNAME or unverioned ROOTNAME to unverioned ROOTNAME
        trace matching $1 $p
        _loadPackageEnvironment "$p"
        r=`justRootName "${ROOTNAME}"`
        if [[ "${1}" == "${SHORTNAME}" ]]; then
            trace matches ${1} ${SHORTNAME}
            return 0
            break
        elif [[ "${1}" == "${r}" ]]; then
            trace matches ${1} ${r}
            return 0
            break
        fi
    done

    return 1

}


##
# _listPackages
#
# List package information that is available to the user.
function _listPackages() {

    trace called

    for p in `_listPackagesDB`; do
        _loadPackageEnvironment "$p"
        out "$SHORTNAME: $DISPLAYNAME"
    done
    return 0

}


##
# _listPackagesDB
#
# List package filenames that is available from user package database.
function _listPackagesDB() {

    trace called
    local package_list package_list_shortnames package_list_final
    local package_dir
    local package_match=false

    if [[ `id -u` != "0" ]]; then
        if [ -d "$autopackage_user_db_location" ]; then
            package_list=`_listPackagesDBDir "$autopackage_user_db_location"`
        else
            trace User package directory does not exist: $autopackage_user_db_location
        fi
    fi

    if [ -d "$autopackage_global_db_location" ]; then
        package_list=`echo -n "$package_list "; _listPackagesDBDir "$autopackage_global_db_location"`
    else
        trace Global package directory does not exist: $autopackage_global_db_location
    fi

    # multiple listings of the same package could exist because of root and
    # non-root installations so remove duplicate $SHORTNAMES which means
    # user package database will supercede the global package database
    # and then sort results
    for f in $package_list; do
        #trace checking $f
        if [ -e "$f/environment.en" ]; then
            _loadPackageEnvironment "$f"
            for package_dir in $package_list_shortnames; do
                #trace matching $SHORTNAME $package_dir
                if [[ "$SHORTNAME" == "$package_dir" ]]; then
                    #trace matches $SHORTNAME $package_dir
                    package_match=true
                    break
                fi
            done
            if ! $package_match; then
                #trace adding $PWD/$SHORTNAME
                package_list_final=`echo "$package_list_final"; escapeFilename "$f"`
                package_list_shortnames=`echo "$package_list_shortnames"; echo "$SHORTNAME"`
            fi
            package_match=false
        fi
    done
    trace package_list=$package_list_final
    echo "$package_list_final"
    return 0

}


##
# _listPackagesDBDir <DIRECTORY>
# RETURNS: 0 if successful.<br />1 if DIRECTORY does not exist.
#
# List package filenames from available database directory.
#
# Example:
#   package_list=`_listPackagesDBDir "$autopackage_user_db_location"`
#
function _listPackagesDBDir() {

    trace called with $1
    local package_list package_list_shortnames
    local package_shortname
    local package_match=false

    if [ ! -d "$1" ]; then
        warn Package database directory does not exist: $1
        echo ""
        return 1
    fi
    local oPWD=`pwd`
    cd "$1"
    local PWD=`pwd`
    for f in `ls -1`; do
        #trace checking $f
        if [ -e "$f/environment.en" ]; then
            _loadPackageEnvironment "$f"
            # multiple listings of the same package will exist because
            # of symlinks so remove duplicate $SHORTNAMES
            for package_shortname in $package_list_shortnames; do
                #trace matching $SHORTNAME $package_shortname
                if [[ "$SHORTNAME" == "$package_shortname" ]]; then
                    #trace matches $SHORTNAME $package_shortname
                    package_match=true
                    break
                fi
            done
            if ! $package_match; then
                #trace adding $PWD/$SHORTNAME
                package_list=`echo "$package_list"; escapeFilename "$PWD/$SHORTNAME"`
                package_list_shortnames=`echo "$package_list_shortnames"; echo "$SHORTNAME"`
            fi
            package_match=false
        fi
    done
    cd "$oPWD"
    echo "$package_list"
    return 0

}


##
# _listPackageFiles <SHORTNAME>
# RETURNS: 0 if successful.<br />1 if error code was returned.
#
# List package installed files from user available database.
function _listPackageFiles() {

    trace called with $@
    local list_filename

    if [[ "$1" == "" ]]; then
        _packageReturnCode "7"
        return "$?"
    fi

    if ! _loadPackage "$1"; then
        _packageReturnCode "1" "$1"
        return "$?"
    fi

    if [ -f "$PACKAGELOCATION/files" ]; then
        list_filename="$PACKAGELOCATION/files"
    else
        _packageReturnCode "1" "$1"
        return "$?"
    fi

    cat "$list_filename" | awk 'BEGIN { FS="  " } { print $1 }' | sort
    return 0

}


##
# _listPackageLog <SHORTNAME>
# RETURNS: 0 if successful.<br />1 if error code was returned.
#
# List package log from user available database.
function _listPackageLog() {

    trace called with $@
    local log_filename
    local log_text
    local uninstall_filename
    local output

    if [[ "$1" == "" ]]; then
        _packageReturnCode "7"
        return "$?"
    fi

    if ! _loadPackage "$1"; then
        _packageReturnCode "1" "$1"
        return "$?"
    fi

    if [ -f "$PACKAGELOCATION/uninstall" ] && [ -f "$PACKAGELOCATION/log" ]; then
        uninstall_filename="$PACKAGELOCATION/uninstall"
        log_filename="$PACKAGELOCATION/log"
    elif [ -f "$PACKAGELOCATION/uninstall" ] || [ -f "$PACKAGELOCATION/log" ]; then
        _packageReturnCode "4" "$1"
        return "$?"
    else
        _packageReturnCode "1" "$1"
        return "$?"
    fi

    log_text=`cat "$log_filename"`

    while read; do
        line=`echo "$REPLY"`
        match=`echo "$line" | grep -e "^uninstallFromLog"`
        if [[ "$match" != "" ]]; then
            if [[ "$output" != "" ]]; then
                output=`echo "$output"; echo "$log_text";`
            else
                output=`echo "$log_text";`
            fi
        elif [[ "$line" != "" ]] ; then
            if [[ "$output" != "" ]]; then
                output=`echo "$output"; echo "$line";`
            else
                output=`echo "$line";`
            fi
        fi
    done <"$uninstall_filename"
    output=`stripComments "$output"`
    output=`stripBlankLines "$output"`
    echo "$output"
    return 0

}


# Used in backend.template to clean files on exit.
function __cleanup_backend() {
	trace called
	terminateFE
	[ -e "$apkg_logfile" ]  && rm -f "$apkg_logfile"
	[ -e "$apkg_filelist" ] && rm -f "$apkg_filelist"
	[ -e "$apkg_uninstalldirs" ] && rm -f "$apkg_uninstalldirs"
}


### START DOWNLOADAUTOPACKAGEINFO
### Function is substituted from apkg-funclib.
function _downloadAutopackageInfo() {
	cat <<EOF

The installation of this software requires some additional support
code to be installed.

A] If the support code is found in a local directory, it will be used.
   The file containing the support code will be called:

      "autopackage-$required_version.tar.bz2"

 or

B] If there is an active Internet connection, the support code will be
   downloaded from:

      "http://autopackage.org/downloads/latest/autopackage-latest.tar.bz2"

   Proxy users should ensure the http_proxy environment variable is
   set, otherwise the download may fail.


EOF
}
### END DOWNLOADAUTOPACKAGEINFO


# Used in downloader.template to close terminal window.
### START FINISHWINDOW
### Function is substituted from apkg-funclib.
function _finishWindow() {
	if [[ "$usingX" == "yes" ]]; then
		echo
		echo Press Enter to close this window.
		read junk;
	fi
}
### END FINISHWINDOW


##
# setVariables <KEY> <VALUE> ...
#
# Save package variables into the environment files which will make the variables
# available for prep, install, and uninstall functions.
#
# Example: setVariables "Test" "false"
function setVariables() {
	while [ $# -gt 0 ]
	do

		# go through language list and add variables to each package environment file
		for language in $PACKAGELANGUAGES; do
			echo "export $1=\"$2\"" >> "$meta_dir/environment.${language}"
		done
		shift 2
	done
}


##
# _checkFile [OPTIONS] <FILENAME>
# FILENAME: file to check information from.
# --perms: permission block of file.
# --links: links to file.
# --uid: user id of file.
# --gid: groud id of file.
# --mtime: last modified time in seconds of file.
# --name: name of file.
# --md5: generated MD5 checksum of file.
# --all: process all availible checks.
#
# Method will do defined checks on FILENAME in the baseline file.
#
# Example:
#   _checkFile --uid --gid --md5 "/lib/libfoo.so.1.1.2"
#   _checkFile --all "/lib/libfoo.so.1.1.2"
#
function _checkFile() {

    local baseline_info
    local file_info
    local file
    local count

    # grab last argument
    declare -a args
    args=("$@")
    count=${#args[@]}

    # last argument is the filename
    b="${count}"
    file=`echo "${!b}"`

    # check for existance
    if [ ! -e "$file" ]; then
        err "File $file does not exist."
        return 1
    fi

    trace checking \"$file\"

    # decrement count and use it to parse over arguments
    (( count-- ))
    i=0
    while (( "$i" < count )); do

        case "$1" in

            "--perms" )
                        file_info=`getFile --perms "$file"`
                        baseline_info=`getBaseline --perms "$file"`
                        ;;

            "--uid" )
                        file_info=`getFile --uid "$file"`
                        baseline_info=`getBaseline --uid "$file"`
                        ;;

            "--gid" )
                        file_info=`getFile --gid "$file"`
                        baseline_info=`getBaseline --gid "$file"`
                        ;;

            "--size" )
                        file_info=`getFile --size "$file"`
                        baseline_info=`getBaseline --size "$file"`
                        ;;

            "--mtime" )
                        file_info=`getFile --mtime "$file"`
                        baseline_info=`getBaseline --mtime "$file"`
                        ;;

            "--md5" )
                        file_info=`getFile --md5 "$file"`
                        baseline_info=`getBaseline --md5 "$file"`
                        ;;

            "--all" )
                        # recurse to run all tests
                        #_checkFile --perms --uid --gid --size --md5 "$file"
                        _checkFile --md5 "$file"
                        # set values to pass the check outside the case
                        file_info="1"
                        baseline_info="1"
                        ;;

            "*" )
                        ;;

        esac

        (( i++ ))

        if [[ "$file_info" == "$baseline_info" ]]; then
            shift
        else
            err validation failure running \"$1\" on \"$file\"
	    err \"$file_info\" does not match \"$baseline_info\"
            return 1
        fi

    done

    return 0

}


##
# _checkBaselineFiles [OPTIONS]
# --perms: permission block of file.
# --links: links to file.
# --uid: user id of file.
# --gid: groud id of file.
# --mtime: last modified time in seconds of file.
# --md5: generated MD5 checksum of file.
# --all: process all availible checks.
#
# Method will parse and do defined checks on every entry in the baseline file.
#
# See also: _checkFile().
#
# Example:
#   _checkBaselineFiles --uid --gid --md5
#   _checkBaselineFiles --all
#
function _checkBaselineFiles() {

    local file
    local line

    while read; do
        line=`echo "$REPLY"`
        file=`echo "$line" | awk '{ print $6 }'`
        if [ -e "$file" ]; then
            _checkFile "$@" "$file"
            local r="$?"
            if [[ "$r" == "0" ]]; then
                continue
            else
                err running \"$1\" on \"$file\"
                return "$r"
            fi
        else
            err "File does not exist $file"
            return 1
        fi
    done <"$autopackage_db_location/$ROOTNAME/baseline"

}

function _xmlSoftwareEntry() {

    trace called with $1 $2

    local output outfile
    local filename="$1"
    local uri="$2"
    local language

    local xml_uri xml_md5sum xml_size xml_builddate xml_rootname
    
    [ ! -f "$filename" ] && err "$filename does not exist."
    if (( PACKAGEVERSION > 1 )); then
        outfile="$SHORTNAME-$SOFTWAREVERSION.r$PACKAGEVERSION.package"
    else
        outfile="$SHORTNAME-$SOFTWAREVERSION.package"
    fi
    if [[ "$uri" != "" ]];then
        xml_uri="$uri/$outfile"
    else
        xml_uri="http://ftp.sunsite.dk/projects/autopackage/$autopackage_version/$outfile"
    fi

    xml_md5sum=`getFile --md5 "$filename"`
    trace xml_md5sum=$xml_md5sum
    
    xml_size=`getFile --size "$filename"`
    trace xml_size=$xml_size

    xml_builddate=`echo "$TIMESTAMPBUILD" | cut -c -10`
    trace xml_builddate=$xml_builddate

    xml_rootname=`justRootName "$ROOTNAME"`
    trace xml_rootname=$xml_rootname

    XML_SOFTWARE_ENTRY_1="	<program-info id=\"${xml_rootname}\">"

    XML_SOFTWARE_ENTRY_2="

	</program-info>

	<software version=\"${SOFTWAREVERSION}\">
		<date>${xml_builddate}</date>
		<interface version=\"${INTERFACEVERSION}\" />
		<keyword>UNSTABLE</keyword>"

    XML_SOFTWARE_ENTRY_3="

		<package type=\"autopackage\"
		         size=\"${xml_size}\"
		         md5=\"${xml_md5sum}\">
			${xml_uri}
		</package>
	</software>
"

    unset XML_SOFTWARE_ENTRY_1_2
    unset XML_SOFTWARE_ENTRY_2_3

    # set just for en language ... need to get luau to handle multiple languages with lang:<language> arguments
    local PACKAGELANGUAGES="en"

    for language in $PACKAGELANGUAGES; do

	# source package environment file
	source "$metadata_dir/apkg-environment.${language}"

		# convert some data for xml presentation - need a more complete routine for all package data
		PACKAGER=`echo "$PACKAGER" | sed 's/</\&lt;/g; s/>/\&gt;/g'`
		MAINTAINER=`echo "$MAINTAINER" | sed 's/</\&lt;/g; s/>/\&gt;/g'`

		XML_SOFTWARE_ENTRY_1_2=`echo "$XML_SOFTWARE_ENTRY_1_2"; echo "
		<shortname>${SHORTNAME}</shortname>
		<fullname>${DISPLAYNAME}</fullname>
		<desc>${SUMMARY}</desc>

"`
		XML_SOFTWARE_ENTRY_2_3=`echo "$XML_SOFTWARE_ENTRY_2_3"; echo "
		<short>Short declarative statement(s) about release for language ${language}.</short>
		<long>
			Paragraphs describing the release for language ${language}.
		</long>

"`

    done

    XML_SOFTWARE_ENTRY="$XML_SOFTWARE_ENTRY_1 $XML_SOFTWARE_ENTRY_1_2 $XML_SOFTWARE_ENTRY_2 $XML_SOFTWARE_ENTRY_2_3 $XML_SOFTWARE_ENTRY_3"
    echo "$XML_SOFTWARE_ENTRY"

}

