#!/bin/sh
##############################################################################
#
# FILE NAME  : install-package.sh
#
# DESCRIPTION: Application package installation script to be run on TARGET
#
# ----------------------------------------------------------------------------
# Copyright (C) 2008-2019, Axis Communications AB, LUND, SWEDEN
##############################################################################

INSTALLDIR=/usr/local/packages
ADPPACKCFG=package.conf
ADPPACKPARAMCFG=param.conf
DEFRUNLEVELSSTART=3
DEFRUNLEVELSSTOP="0 1 2 4 5 6"
PHC="parhandclient --nocgi --nolog"
LIMITED_POSTINSTALL=no

information() {
	printf "%s\n" "$*" >&1
}

warning() {
	printf "%s\n" "$*" >&2
}

error() {
	warning "$*\n"
	[ "$is_reinstall" ] || uninstall
	exit 1
}

. /usr/html/axis-cgi/lib/acap_handle_files.sh

. /usr/html/axis-cgi/lib/preserve.sh

__pkgconf_unset(){
	unset \
	APPGRP APPID APPMAJORVERSION APPMINORVERSION APPNAME APPOPTS APPTYPE \
	APPUSR LICENSENAME LICENSEPAGE LUAFILES LUAFILESENCRYPTED MENUNAME OTHERFILES \
	PACKAGENAME POSTINSTALLSCRIPT PREUPGRADESCRIPT REQEMBDEVVERSION \
	SETTINGSPAGEFILE SETTINGSPAGETEXT STARTMODE VENDOR VENDORHOMEPAGELINK
}

__pkgconf_unset
[ -r $ADPPACKCFG ] || {
	warning "Failed to read $ADPPACKCFG"
	exit 1
}
. ./$ADPPACKCFG || {
	warning "Failed to source $ADPPACKCFG"
	exit 1
}

[ "$DIRNAME" ] || DIRNAME=$APPNAME
[ "$DIRNAME" ] || {
	warning "Failed to read DIRNAME"
	exit 1
}

if [ "$APPTYPE" = lua ]; then
	DIRNAME=${APPNAME%.*}
	XMLCONFFILE=$INSTALLDIR/$DIRNAME/$APPNAME
	APPNAME=$DIRNAME
	APPUSR=ruleengined
	APPGRP=ruleengined
fi

ETC_HTTPD_CONF=/etc/apache2
ETC_VHOSTS_ALL=$ETC_HTTPD_CONF/conf.d/vhosts/all
ACAP_DOC_ROOT=/usr/html/local
ETC_TRANSFER_CONF=$ETC_HTTPD_CONF/transfer
ETC_MIME_CONF=$ETC_HTTPD_CONF/mime
ABSAPPNAME=$INSTALLDIR/$DIRNAME/$APPNAME
PKG_CONFDIR=$INSTALLDIR/$DIRNAME/conf
RUNSTATE_CONF=$PKG_CONFDIR/runstate.conf
GROUPNAME=$(r=${APPNAME#?};f=${APPNAME%$r};echo $(echo $f | tr [:lower:] [:upper:])$r)
ETC_DYN=/etc/dynamic
ETC_DYN_APP_CONF=$ETC_DYN/$APPNAME.conf
PKG_ETC_DYN_APP_CONF=$PKG_CONFDIR/$APPNAME.conf
ETC_DYN_PARAM=$ETC_DYN/param
ETC_DYN_PARAM_APP_CONF=$ETC_DYN_PARAM/$APPNAME.conf
PKG_ETC_DYN_PARAM_APP_CONF=$PKG_CONFDIR/param_$APPNAME.conf
WEB_DIR=/usr/html/local
DBUS_DIR=/etc/dbus-1/system.d
DBUS_FILE=$DBUS_DIR/$APPNAME.conf
PKG_DBUS_FILE=$PKG_CONFDIR/dbus_$APPNAME.conf
DATA_DIR=$INSTALLDIR/$DIRNAME/localdata
BAK_DIR=$INSTALLDIR/$DIRNAME/configuration.bak
HTTP_VAR_RUN=/var/run/http
HTTPD_CONF_LOCAL=httpd.conf.local.$APPNAME
HTTPD_MIME_LOCAL=mime.types.local.$APPNAME
ETC_INIT_D_APPNAME=/etc/init.d/sdk$APPNAME
PKG_ETC_INIT_D_APPNAME=$PKG_CONFDIR/sdk$APPNAME
SYSTEMD_SERVICE_FILENAME=sdk$APPNAME.service
ETC_SYSTEMD_DIR=/etc/systemd/system
ETC_SYSTEMD_APPNAME=$ETC_SYSTEMD_DIR/$SYSTEMD_SERVICE_FILENAME
PREUPGRADE_SERVICE=preupgrade$APPNAME
PREUPGRADE_SERVICE_FILENAME=$PREUPGRADE_SERVICE.service
PREUPGRADE_LOG=$INSTALLDIR/$APPNAME/preupgrade.log
POSTINSTALL_SERVICE=postinstall$APPNAME
POSTINSTALL_SERVICE_FILENAME=$POSTINSTALL_SERVICE.service
POSTINSTALL_LOG=$INSTALLDIR/$APPNAME/postinstall.log

LOGINFOAPPNAME="logger -p INFO -t $APPNAME[0]"

create_initscript() {
	local respawn=$1

	cat <<-EOF > $PKG_ETC_INIT_D_APPNAME.tmp
		#! /bin/sh -e

		. /etc/init.d/functions.sh
		trap 'end \$?' EXIT

		sdkkillall() {
			local appname pid thispid binexe

			[ "\$1" ] && [ "\$2" ] || return 2
			appname=\${2##*/}
			pid=\$(pidof \$appname) || return 0
			if [ "\$pid" ]; then
				for thispid in \$pid ; do
					binexe=\$(readlink /proc/\${thispid}/exe) || return 1
					if eval \$(echo -n "\$binexe" | grep -q "\$INSTALLDIR" ) ; then
						[ "\$1" = 0 ] ||
							$LOGINFOAPPNAME "$0: kill -\$1 \$thispid" || :
						kill -\$1 \$thispid || return 1
					fi
				done
			fi
		}


		start_d() {
			elflibcheck.sh $ABSAPPNAME || {
				$LOGINFOAPPNAME "elflibcheck failed $APPNAME"
				return 1
			}


			start-package-allowed.sh $ABSAPPNAME > /dev/null 2>&1 || {
				return 1
			}
			$LOGINFOAPPNAME "starting $APPNAME"
			/sbin/start-stop-daemon --start --background \
				-c $APPUSR:$APPGRP --exec \
				"$ABSAPPNAME" -- $APPOPTS || {
				$LOGINFOAPPNAME "start-stop-daemon \
					\"$ABSAPPNAME\" $APPOPTS failed!" || {
						return 1
					}
			}
EOF
	if [ "$respawn" ]; then
		cat <<-EOF >> $PKG_ETC_INIT_D_APPNAME.tmp
			respawn-on-n -c $APPUSR -g $APPGRP "$ABSAPPNAME" $APPOPTS ||
				$LOGINFOAPPNAME "respawn-on-n -c $APPUSR -g $APPGRP \"$ABSAPPNAME\" $APPOPTS failed!" || :
EOF
	fi
	cat <<-EOF >> $PKG_ETC_INIT_D_APPNAME.tmp
		}


		stop_d() {
EOF
	if [ "$respawn" ]; then
		cat <<-EOF >> $PKG_ETC_INIT_D_APPNAME.tmp
			respawn-off "$ABSAPPNAME" $APPOPTS ||
				$LOGINFOAPPNAME "respawn-off \"$ABSAPPNAME\" $APPOPTS failed!" || :
EOF
	fi
	cat <<-EOF >> $PKG_ETC_INIT_D_APPNAME.tmp
			$LOGINFOAPPNAME "stopping $APPNAME"
			stop_daemon $ABSAPPNAME ||
				$LOGINFOAPPNAME "stop_daemon $APPNAME failed"

			! sdkkillall 0 $ABSAPPNAME ||
				sdkkillall SIGKILL $ABSAPPNAME || :
		}

		case \$1 in
			start)
				begin "Starting $APPNAME"
				start_d
				;
			stop)
				begin "Stopping $APPNAME"
				stop_d
				;
			restart)
				begin "Restarting $APPNAME"
				stop_d ; start_d
				;
			*)
				error "Usage: \$0 start|stop|restart"
				;
		esac
EOF
	chmod 755 $PKG_ETC_INIT_D_APPNAME.tmp ||
		error "Failed to chmod $PKG_ETC_INIT_D_APPNAME.tmp."
	fsynced_write_or_cleanup $PKG_ETC_INIT_D_APPNAME.tmp $PKG_ETC_INIT_D_APPNAME
}

create_lua_service() {
	luaappname=${APPNAME%.*}
	if [ $STARTMODE = auto ]; then
		startcmd=start
	else
		startcmd=add
	fi
	cat <<-EOF > $ETC_SYSTEMD_APPNAME.tmp
[Unit]
Description=$luaappname
After=ruleengined.service
Requires=ruleengined.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/libexec/rc-ruleengine-acap $startcmd $luaappname
ExecStop=/usr/libexec/rc-ruleengine-acap remove $luaappname
EOF
	chmod 644 $ETC_SYSTEMD_APPNAME.tmp ||
		error "Failed to chmod $ETC_SYSTEMD_APPNAME.tmp."
	chown root:root $ETC_SYSTEMD_APPNAME.tmp ||
		error "Failed to chown $ETC_SYSTEMD_APPNAME.tmp."
	fsynced_write_or_cleanup $ETC_SYSTEMD_APPNAME.tmp $ETC_SYSTEMD_APPNAME
}

create_initwrap_service() {
	local respawn=$1

	cat <<-EOF > $ETC_SYSTEMD_APPNAME.tmp
[Unit]
Description=$APPNAME
After=acap-pre.target
Requires=acap-pre.target
EOF
	if [ "$respawn" ]; then
		cat <<-EOF >> $ETC_SYSTEMD_APPNAME.tmp
After=respawnd.service
Requires=respawnd.service
EOF
	fi
	cat <<-EOF >> $ETC_SYSTEMD_APPNAME.tmp
[Service]
Slice=extension-acap.slice
Type=oneshot
RemainAfterExit=yes
ExecStart=$ETC_INIT_D_APPNAME start
ExecStop=$ETC_INIT_D_APPNAME stop
[Install]
WantedBy=acap.target
EOF
	chmod 644 $ETC_SYSTEMD_APPNAME.tmp ||
		error "Failed to chmod $ETC_SYSTEMD_APPNAME.tmp."
	chown root:root $ETC_SYSTEMD_APPNAME.tmp ||
		error "Failed to chown $ETC_SYSTEMD_APPNAME.tmp."
	fsynced_write_or_cleanup $ETC_SYSTEMD_APPNAME.tmp $ETC_SYSTEMD_APPNAME
}

setup_legacy_webserver_config() {
	local line transfer_conf transfer_link mime_conf mime_link

	if [ -r "$HTTPD_CONF_LOCAL" ]; then


		transfer_conf=$PKG_CONFDIR/$HTTPD_CONF_LOCAL
		transfer_link=$ETC_TRANSFER_CONF/legacy_transfer_$APPNAME.conf

		if [ -h $transfer_link ]; then
			rm -f $transfer_link || error "Failed to remove link: $transfer_link"
		fi

		echo "# $APPNAME config" > $transfer_conf.tmp
		while read -r line; do
			case $line in
				Transfer[[:blank:]]*)
					transfer=${line#Transfer[[:blank:]]}
					echo "TransferProxy $transfer"
					;
				TransferMethod[[:blank:]]*)
					transfer=${line#TransferMethod[[:blank:]]}
					echo "TransferMethodProxy $transfer"
					;
			esac
		done < "$HTTPD_CONF_LOCAL" > $transfer_conf.tmp
		chmod 644 $transfer_conf.tmp
		chown www:www $transfer_conf.tmp

		fsynced_write_or_cleanup $transfer_conf.tmp $transfer_conf

		ln -sf $transfer_conf $transfer_link ||
			error "Failed to create link: $transfer_link"
		chown -h www:www $transfer_link
	fi

	if [ -r "$HTTPD_MIME_LOCAL" ]; then


		mime_conf=$PKG_CONFDIR/$HTTPD_MIME_LOCAL
		mime_link=$ETC_MIME_CONF/legacy_mime_$APPNAME.conf

		if [ -h $mime_link ]; then
			rm -f $mime_link || error "Failed to remove link: $mime_link"
		fi

		echo "# $APPNAME types" > $mime_conf.tmp
		while read -r line; do
			[ -z "$line" ] || printf "AddType $line\n"
		done < "$HTTPD_MIME_LOCAL" > $mime_conf.tmp
		chmod 644 $mime_conf.tmp
		chown www:www $mime_conf.tmp

		fsynced_write_or_cleanup $mime_conf.tmp $mime_conf

		ln -sf $mime_conf $mime_link ||
			error "Failed to create link: $mime_link"
		chown -h www:www $mime_link
	fi
}

create_config_links() {
	local tmp_file owner cgi_path cgi_path_dir cgi_path_file lic_file
	local chown_lic_file=no
	local path_validation_expr='^\(/\([-./_~]\|[[:alnum:]]\|%[[:xdigit:]]\{2\}\)\+[^/]\)*$'

	if [ "$APPTYPE" != lua ] && [ ! -h $ETC_INIT_D_APPNAME ]; then
               ln -sf $PKG_ETC_INIT_D_APPNAME $ETC_INIT_D_APPNAME ||
                       error "Failed to create link: $ETC_INIT_D_APPNAME"
	fi

	if [ ! -h $WEB_DIR/$APPNAME ] && [ -d $INSTALLDIR/$DIRNAME/html ]; then
		ln -sfn $INSTALLDIR/$DIRNAME/html $WEB_DIR/$APPNAME ||
			error "Failed to create link: $WEB_DIR/$APPNAME"
	fi

	setup_legacy_webserver_config

	if [ "$HTTPCGIPATHS" ]; then
		if [ ! -r $HTTPCGIPATHS ]; then
			error "Failed to read $HTTPCGIPATHS, file is read protected"
		fi

		tmp_file=$PKG_CONFDIR/$HTTPCGIPATHS.tmp


		while read owner cgi_path; do
			[ "$cgi_path" ] || continue

			printf "%s" "$cgi_path" | grep -q $path_validation_expr ||
				error "Failed to verify path: $cgi_path"

			echo "TransferMethodProxy /local/$APPNAME$cgi_path /var/run/http/$APPNAME/http"

		done<$HTTPCGIPATHS>$tmp_file

		chmod 644 $tmp_file || error "Failed to chmod: $tmp_file"

		fsynced_write_or_cleanup $tmp_file $PKG_CONFDIR/$HTTPCGIPATHS

		ln -sf $PKG_CONFDIR/$HTTPCGIPATHS $ETC_TRANSFER_CONF/transfer_$APPNAME.conf ||
			error "Failed to create link: $ETC_TRANSFER_CONF/transfer_$APPNAME.conf"

		while read owner cgi_path; do
			[ "$cgi_path" ] || continue

			case $owner in
				administrator)
					owner=admin
					;
				operator|viewer)
					;
				*)
					error "Not a vaild owner: $owner"
					;
			esac

			cgi_path_dir=$INSTALLDIR/$DIRNAME/html/$(dirname $cgi_path) ||
				error "Failed to dirname: $cgi_path"

			cgi_path_file=$cgi_path_dir/$(basename $cgi_path) ||
				error "Failed to basename: $cgi_path"

			mkdir -p $cgi_path_dir ||
				error "Failed to mkdir: $cgi_path_dir"

			find $cgi_path_dir -type d | xargs chown sdk:sdk ||
				error "Failed to chown: $cgi_path_dir"

			>$cgi_path_file.tmp ||
				error "Failed to create: $cgi_path_file.tmp"

			chgrp $owner $cgi_path_file.tmp ||
				error "Failed to chgrp: $owner $cgi_path_file.tmp"

			chmod 0750 $cgi_path_file.tmp ||
				error "Failed to chmod: $cgi_path_file.tmp"

			fsynced_write_or_cleanup  $cgi_path_file.tmp $cgi_path_file
		done<$HTTPCGIPATHS
	fi

	if [ "$LICENSENAME" ] && [ -d $INSTALLDIR/$DIRNAME/html ]; then
		lic_file=$INSTALLDIR/$DIRNAME/LICENSE

		[ -r $lic_file ] ||
			error "No LICENSE file for $DIRNAME"

		chown_lic_file=yes

		chmod 0640 $lic_file ||
			error "Failed to set file permissions for the LICENSE file"

		ln -sf $lic_file $INSTALLDIR/$DIRNAME/html/LICENSE >/dev/null 2>&1 ||
			error "Failed to expose license - could not create symlink"
	fi

	if [ -d $INSTALLDIR/$DIRNAME/html ]; then
		for dir in $(find $INSTALLDIR/$DIRNAME/html -type d); do
			chmod 751 $dir || error "Failed to set permissions html"
		done

		install_urls $APPNAME $INSTALLDIR/$DIRNAME/html ||
			error "Failed to create install urls"

		chown $APPUSR:www $INSTALLDIR/$DIRNAME/html ||
			error "Failed to change ownership html"
	fi

	if [ "$chown_lic_file" = yes ]; then
		chown $APPUSR:www $lic_file ||
			error "Failed to set ownership of the LICENSE file for $DIRNAME"
	fi

	if [ ! -h $ETC_DYN_APP_CONF ] && [ -r $PKG_ETC_DYN_APP_CONF ]; then
		ln -sf $PKG_ETC_DYN_APP_CONF $ETC_DYN_APP_CONF ||
			error "Failed to create link: $ETC_DYN_APP_CONF"
	fi
	if [ ! -h $ETC_DYN_PARAM_APP_CONF ] &&
	   [ -r $PKG_ETC_DYN_PARAM_APP_CONF ]; then
		ln -sf $PKG_ETC_DYN_PARAM_APP_CONF $ETC_DYN_PARAM_APP_CONF ||
			error "Failed to create link: $ETC_DYN_PARAM_APP_CONF"
	fi

	if [ "$APPTYPE" != lua ] && [ ! -h $DBUS_FILE ]; then
		ln -sf $PKG_DBUS_FILE $DBUS_FILE ||
			error "Failed to create link: $DBUS_FILE"
	fi
}

reload_configs() {
	dbus-send --system --type=method_call --dest=org.freedesktop.DBus / \
		org.freedesktop.DBus.ReloadConfig ||
	error "Failed to reload DBus configuration."

	if [ -r "$ETC_DYN_PARAM_APP_CONF" ]; then
		$PHC readgroupfile $ETC_DYN_PARAM_APP_CONF ||
			error "Failed to read group file ($ETC_DYN_PARAM_APP_CONF)."
	fi
}

set_up_certificates() {
	if [ "$CERTSETNAME" ]; then
		case $CERTSETACTOR in
			client|server)
				;
			*)
				error "Failed to create certificate set: CERTSETACTOR"\
				      "should be 'client' or 'server'"
				;
		esac
		[ "$CERTSETPROTOCOL" ] ||
			error "Failed to create certificate set: empty CERTSETPROTOCOL"
		gdbus call -y -d com.axis.PolicyKitCert \
			-o /com/axis/PolicyKitCert \
			-m com.axis.PolicyKitCert.CertSetCreate \
			"$CERTSETNAME" "$APPNAME" "$CERTSETACTOR" \
			"$CERTSETPROTOCOL" $(id -u $APPUSR) ||
			error "Failed to create certificate set"
	fi
}

clean_up_certificates() {
	if [ "$CERTSETNAME" ]; then
		local _continue=ok

		case $CERTSETACTOR in
			client|server)
				;
			*)
				_continue=
				warning "Failed to clean up certificate set: CERTSETACTOR"\
				      "should be 'client' or 'server'"
				;
		esac
		[ "$CERTSETPROTOCOL" ] || {
			_continue=
			warning "Failed to delete certificate sets: empty CERTSETPROTOCOL"
		}
		[ -z "$_continue" ] ||
			gdbus call -y -d com.axis.PolicyKitCert \
			-o /com/axis/PolicyKitCert \
			-m com.axis.PolicyKitCert.CertSetDeleteAll \
			"$APPNAME" "$CERTSETACTOR" "$CERTSETPROTOCOL" ||
			error "Failed to delete certificate sets"
	fi
}


binary_specific_install() {
	local line entry type param

	chmod 755 $ABSAPPNAME || error "Failed to change permissions on $ABSAPPNAME"


	case $STARTMODE in
		once|never)
			create_initscript
			;
		respawn)
			create_initscript respawn
			;
	esac
	create_initwrap_service respawn

	if [ "$is_reinstall" != yes ]; then

	mkdir -p $DATA_DIR || error "Failed to create dir $DATA_DIR"

	chown $APPUSR:$APPGRP $DATA_DIR ||
		error "Failed to set file ownership on $DATA_DIR."

	mkdir -p $ETC_DYN_PARAM || error "Failed to create dir $ETC_DYN_PARAM"
	mkdir -p $ETC_DYN || error "Failed to create dir $ETC_DYN"

	cat <<-EOF > $PKG_ETC_DYN_PARAM_APP_CONF.tmp
		group $GROUPNAME {
			parser = Standard2parser
			file = "$ETC_DYN_APP_CONF"
			dbus = "--system --dest=com.axis.Param.$APPNAME /com/axis/Param/$APPNAME com.axis.Param.ChangeNotification string:'\$NAME' string:'\$VALUE'"
			accessControl = "admin:3;$APPGRP:3;operator:1;viewer:1"
EOF

	echo "[$GROUPNAME]" > $PKG_ETC_DYN_APP_CONF.tmp
	if [ -r $ADPPACKPARAMCFG ]; then
		while read -r line; do
			entry=$(echo $line | sed -rne 's/^[[:space:]]*([[:alnum:]]*)[[:space:]]*=[[:space:]]*"?([^"]*)"?.*/\1="\2"/p')
			if [ "$entry" ]; then
				type=$(echo $line | sed -rne 's/.*type[[:space:]]*=[[:space:]]*"([^"]*)"[[:space:]]*$/\1/p')
				[ "$type" ] || type=string
				param=${entry%%=*}
				cat <<-EOF >> $PKG_ETC_DYN_PARAM_APP_CONF.tmp
					param $param {
						mount = "Standard2{$GROUPNAME}{$param}"
						type = "$type"
					}
EOF
				echo $entry >> $PKG_ETC_DYN_APP_CONF.tmp
			fi
		done < $ADPPACKPARAMCFG
	fi
	echo "}" >> $PKG_ETC_DYN_PARAM_APP_CONF.tmp

	chown $APPUSR:$APPGRP $PKG_ETC_DYN_APP_CONF.tmp ||
		error "Failed to chown on $PKG_ETC_DYN_APP_CONF.tmp."

	chown $APPUSR:$APPGRP $PKG_ETC_DYN_PARAM_APP_CONF.tmp ||
		error "Failed to chown on $PKG_ETC_DYN_PARAM_APP_CONF.tmp."

	fsynced_write_or_cleanup $PKG_ETC_DYN_APP_CONF.tmp $PKG_ETC_DYN_APP_CONF
	fsynced_write_or_cleanup $PKG_ETC_DYN_PARAM_APP_CONF.tmp $PKG_ETC_DYN_PARAM_APP_CONF

	cat <<-EOF > $PKG_DBUS_FILE.tmp
		<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
		 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
		<busconfig>
			<!-- Only root or user $APPUSR can own the $APPNAME service. -->
			<policy user="$APPUSR">
				<allow own="com.axis.Param.$APPNAME"/>
				<allow send_destination="com.axis.Param.$APPNAME"/>
				<allow receive_sender="com.axis.Param.$APPNAME"/>
			</policy>
			<policy user="root">
				<allow own="com.axis.Param.$APPNAME"/>
				<allow send_destination="com.axis.Param.$APPNAME"/>
				<allow receive_sender="com.axis.Param.$APPNAME"/>
			</policy>
			<policy context="default">
				<allow send_destination="com.axis.Param.$APPNAME"/>
				<allow receive_sender="com.axis.Param.$APPNAME"/>
			</policy>
		</busconfig>
EOF
	chmod 644 $PKG_DBUS_FILE.tmp || error "Failed to chmod on $PKG_DBUS_FIL.tmp"
	fsynced_write_or_cleanup $PKG_DBUS_FILE.tmp $PKG_DBUS_FILE
	fi
}

add_file_to_url_conf() {
	local url_conf_file url_group url_file url_base_file

	[ $# -eq 2 ] || error "Wrong number of arguments"
	[ "$1" ] && url_conf_file=$1 || error "Configuration file not specified"
	[ "$2" ] && url_file=$2 || error "Failed to read file (file not found)"

	unset IFS

	# This function will always be called with the path to a directory first
	# and then additional calls are made with the paths to the files in the
	# directory. We simply ignore the directories.
	[ ! -d $url_file ] || return 0

	url_group=$(stat -c "%G" $url_file)
	[ "$url_group" = 'admin' ] || [ "$url_group" = 'operator' ] || \
		[ "$url_group" = 'viewer' ] || url_group='admin'

	url_base_file=$(basename $url_file)

	echo "	<Files \"$url_base_file\">
		Require axis-group $url_group
	"  >> $url_conf_file || error "Failed add config for '$url_base_file' in '$url_conf_file'"
	[ "$url_file" != "$INSTALLDIR/$DIRNAME/html/LICENSE" ] || \
		echo "	Header set Content-Type \"text/plain; charset=utf-8\"
	"  >> $url_conf_file || error "Failed add Content-Type config for '$url_base_file' in '$url_conf_file'"

	echo "</Files>" >> $url_conf_file || error "Failed end config for '$url_base_file' in '$url_conf_file'"

	cmd="chmod g+r $url_file"
	$cmd || warning "'$cmd' failed"

	cmd="chgrp www $url_file"
	$cmd || warning "'$cmd' failed"
}

gen_url_conf() {
	local url_conf_file dir files file

	[ $# -eq 2 ] || error "Wrong number of arguments"
	[ "$1" ] && url_conf_file=$1 ||
			error "Failed to complete, missing argument url_conf_file"
	[ "$2" ] && dir=$2 || error "Failed to complete, missing argument dir"

	files=$(ls -A $dir)
	if [ "$files" ]; then
		for file in $files; do
			add_file_to_url_conf $url_conf_file $dir/$file
		done
	fi
}

install_urls() {
	local acap_name dir dirs subdir url_conf_tmpfile url_conf_file url_dir

	[ $# -eq 2 ] || error "Wrong number of arguments"
	[ "$1" ] && acap_name=$1 || error "Failed to complete, missing argument acap_name"
	[ "$2" ] && dir=$2 || error "Failed to complete, missing argument dir"

	url_conf_tmpfile=$ETC_VHOSTS_ALL/urls_$acap_name.conf.tmp
	url_conf_file=$ETC_VHOSTS_ALL/urls_$acap_name.conf
	rm -f $url_conf_file 1>/dev/null 2>&1
	rm -f $url_conf_tmpfile 1>/dev/null 2>&1
	dirs=$(find $dir -type d)

	for subdir in $dirs; do

		if [ "$dir" = "$subdir" ]; then
			url_dir=$ACAP_DOC_ROOT/$acap_name
		else
			url_dir=$ACAP_DOC_ROOT/$acap_name/$(basename $subdir)
		fi
		echo "<Directory \"$url_dir\">" >> \
				$url_conf_tmpfile ||
				error "Failed to write begining to '$url_conf_tmpfile'"

		gen_url_conf $url_conf_tmpfile $subdir

		echo "</Directory>" >> $url_conf_tmpfile ||
				error "Failed to write end to '$url_conf_tmpfile'"

	done

	fsynced_write_or_cleanup $url_conf_tmpfile $url_conf_file
}

install() {
	local dir=

	if [ "$is_reinstall" != yes ]; then
		information "Installing $APPNAME in $INSTALLDIR/$DIRNAME"
	else
		information "Re-installing $APPNAME in $INSTALLDIR/$DIRNAME"
		[ ! -d "$BAK_DIR" ] || rm -rf $BAK_DIR
	fi

	handle_eventdecl -d $INSTALLDIR/$DIRNAME/declarations -n $APPNAME -a ||
		error "Failed to handle_eventdecl illegal declaration template"

	mkdir -p $PKG_CONFDIR || error "Failed to mkdir -p $PKG_CONFDIR"

	chmod 755 $PKG_CONFDIR || error "Failed to change permissions on $PKG_CONFDIR"

	if [ "$is_reinstall" != yes ]; then
		echo ENABLED=no > $RUNSTATE_CONF.tmp || error "Failed to write to $RUNSTATE_CONF.tmp"
		chmod 644 $RUNSTATE_CONF.tmp || error "Failed to change permissions on $RUNSTATE_CONF.tmp"
		fsynced_write_or_cleanup $RUNSTATE_CONF.tmp $RUNSTATE_CONF
	fi

	chown -Rh $APPUSR:admin $INSTALLDIR/$DIRNAME ||
		error "Failed to chown -R $APPUSR:admin '$INSTALLDIR/$DIRNAME'"

	if [ "$HTTPCGIPATHS" ] || [ "$LICENSENAME" ] && [ ! -d $INSTALLDIR/$DIRNAME/html ]; then
		mkdir -p $INSTALLDIR/$DIRNAME/html ||
		error "Failed to create directory: $INSTALLDIR/$DIRNAME/html"
	fi

	if [ "$APPTYPE" != lua ]; then
		binary_specific_install
	else
		create_lua_service
	fi

	if [ -d "$BAK_DIR" ]; then
		if __restore_app $INSTALLDIR/$DIRNAME $BAK_DIR; then
			information "Restored config for '$APPNAME'"
		else
			warning "Failed to restore config for '$APPNAME'"
		fi
		rm -rf "$BAK_DIR"
	fi

	chmod 644 $INSTALLDIR/$DIRNAME/$ADPPACKCFG || {
		warning "Failed to make $ADPPACKCFG readable for $APPNAME"
	}
}

create_preupgrade_service() {
	information "Preupgrade script $2 executed as user $1"
	printf "\
[Unit]
Description=%s

[Service]
User=%s
Type=oneshot
ExecStart=/bin/sh %s
WorkingDirectory=%s/%s
" $PREUPGRADE_SERVICE $1 $2 $INSTALLDIR $APPNAME > $ETC_SYSTEMD_DIR/$PREUPGRADE_SERVICE_FILENAME

}

remove_preupgrade_service() {
	rm $ETC_SYSTEMD_DIR/$PREUPGRADE_SERVICE_FILENAME ||
		warning "Failed to remove $ETC_SYSTEMD_DIR/$PREUPGRADE_SERVICE_FILENAME"
}

run_pre_upgrade() {
	[ $# -eq 1 ] || {
		warning "Missing argument to perform preupgrade. Aborting"
		return 0
	}

	[ -r $1 ] || {
		warning "Failed to read the preupgrade script provided by $APPNAME"
		return 0
	}

	information "Executing preupgrade script"

	create_preupgrade_service $APPUSR $1

	systemctl start $PREUPGRADE_SERVICE >/dev/null 2>&1 || {
		warning "Preupgrade script provided by $APPNAME returned error code $?"
		systemctl reset-failed $PREUPGRADE_SERVICE > /dev/null 2>&1 ||
			warning "Failed to reset failed service $PREUPGRADE_SERVICE with error code $?"
	}
	remove_preupgrade_service
}

create_postinstall_service() {
	information "Run $APPNAME/$POSTINSTALLSCRIPT as $1"
	printf "\
[Unit]
Description=%s

[Service]
User=%s
Type=oneshot
ExecStart=/bin/sh %s/%s/%s
WorkingDirectory=%s/%s
" $POSTINSTALL_SERVICE $1 $INSTALLDIR $APPNAME $POSTINSTALLSCRIPT $INSTALLDIR $APPNAME > $ETC_SYSTEMD_DIR/$POSTINSTALL_SERVICE_FILENAME

}

remove_postinstall_service() {
	rm $ETC_SYSTEMD_DIR/$POSTINSTALL_SERVICE_FILENAME ||
		warning "Failed to remove $ETC_SYSTEMD_DIR/$POSTINSTALL_SERVICE_FILENAME"
}

run_post_install() {
	[ "$POSTINSTALLSCRIPT" ] || return 0
	[ -r "$POSTINSTALLSCRIPT" ] || {
		warning "Failed to read $POSTINSTALLSCRIPT"
		return 0
	}

	information "Run $PACKAGENAME post install script $POSTINSTALLSCRIPT"
	if [ $LIMITED_POSTINSTALL = yes ]; then
		create_postinstall_service $APPUSR
	else
		create_postinstall_service root
	fi

	systemctl --quiet status $POSTINSTALL_SERVICE >/dev/null 2>&1 ||
		[ $? != 4 ] || systemctl --quiet daemon-reload >/dev/null 2>&1

	systemctl start $POSTINSTALL_SERVICE >/dev/null 2>&1 || {
		warning "Failed to run $POSTINSTALLSCRIPT"
		systemctl reset-failed $POSTINSTALL_SERVICE > /dev/null 2>&1 ||
			warning "Failed to reset failed service $POSTINSTALL_SERVICE with error code $?"
	}
	remove_postinstall_service

	chmod 644 $INSTALLDIR/$DIRNAME/$ADPPACKCFG || {
		warning "Failed to make $ADPPACKCFG readable for $APPNAME"
	}
}


binary_specific_uninstall() {
	rm -f $ETC_TRANSFER_CONF/transfer_$APPNAME.conf
	rm -f $ETC_TRANSFER_CONF/legacy_transfer_$APPNAME.conf
	rm -f $ETC_MIME_CONF/legacy_mime_$APPNAME.conf
	rm -rf $HTTP_VAR_RUN/$APPNAME

	rm -f $ETC_DYN_PARAM_APP_CONF
	rm -f $ETC_DYN_APP_CONF
	$PHC deletegroup $GROUPNAME >/dev/null 2>&1 || :
}

remove_package_dir() {
 rm -rf $INSTALLDIR/$DIRNAME
}


read_enabled() {
	local enb=no var= val= IFS==

	if [ -r $RUNSTATE_CONF ]; then
		while read var val; do
			case $var in
				ENABLED)
					eval enb=$val
					;
				*)
					$log_info "unknown runstate $var for $APPNAME"
					;
			esac
		done < $RUNSTATE_CONF
	else
		$log_info "no runstate for $APPNAME"
	fi
	echo $enb
}

keep_runstate() {
	# first check that this acap uses systemd
	[ -r $ETC_SYSTEMD_APPNAME ] || return 0

	enabled=$(read_enabled)
	if [ $STARTMODE != never ] && [ $enabled = yes ]; then
		systemctl enable $SYSTEMD_SERVICE_FILENAME ||
			warning "Failed to enable $SYSTEMD_SERVICE_FILENAME"
	fi
	if [ $STARTMODE = never ] && [ $enabled = yes ]; then
		echo ENABLED=no >$RUNSTATE_CONF ||
		 warning "Failed to set runstate for $RUNSTATE_CONF"
	fi
}

uninstall() {
	local runlevel

	[ "$APPTYPE" = lua ] || binary_specific_uninstall

	handle_eventdecl -d $INSTALLDIR/$DIRNAME/declarations -n $APPNAME -r

	rm -rf $WEB_DIR/$APPNAME

	if [ "$APPTYPE" != lua ]; then
		rm -f $ETC_INIT_D_APPNAME
	fi
	rm -f $ETC_SYSTEMD_APPNAME
	rm -f $DBUS_FILE
}


case $2 in
	yes)
		information "Limited access rights for $APPNAME"
		LIMITED_POSTINSTALL=yes
		;
	*)
esac

case $1 in
	backup)
		backup
		;
	preupgrade)
		run_pre_upgrade $2
		information "$APPNAME has been successfully pre upgraded (OK)"
		;
	install)
		install
		create_config_links
		set_up_certificates
		reload_configs
		run_post_install
		information "$APPNAME has been successfully installed (OK)"
		;
	reinstall|reinstall-forced)
		is_reinstall=yes
		install
		keep_runstate
		create_config_links
		set_up_certificates
		reload_configs
		run_post_install
		information "$APPNAME has been successfully re-installed (OK)"
		;
	uninstall)
		clean_up_certificates
		uninstall
		remove_package_dir
		reload_configs
		;
	*)
		information "usage: $0 backup|preupgrade|install|reinstall|uninstall"
		exit 1
		;
esac