#!/bin/sh -e
#
# (C) Copyright 2015-2018 Axis Communications AB, LUND, SWEDEN

. /usr/lib/addon-common
. /usr/lib/addon-apache-config

LOG_TAG="addon-setup"

[ $# -le 3 ] && [ "$1" ] && [ "$2" ] || {
	echo "This is a setup script for add-on package.

Usage: ${0##*/} <package filename> <signed package 0:1> <optional: first_boot_mode>"
	return 1
}

# Declare global variables
OPKGNAME=$(get_package_name $1) || {
	syslog_err $LOG_TAG "addon-setup: Failed to get package name from $1"
	exit 1
}

# Declare signed package status used to determine if devmode needs to be checked
[ "$2" -eq 1 ] && SIGNED_PACKAGE=1 || SIGNED_PACKAGE=0

if [ $# -eq 3 ]; then
	if [ "$3" ]; then
		FIRST_BOOT_MODE="$3"
	else
		syslog_err $LOG_TAG "addon-setup: Failed to get pre-install mode from $3"
		exit 1
	fi
fi


is_package_name_valid "$OPKGNAME" result ||
	fail_errorcode $ERR_INVALID_PKG_NAME 		"Failed to validate package name: $OPKGNAME"

[ $result -eq $TRUE ] || fail_errorcode $ERR_INVALID_PKG_NAME 	"Package name $OPKGNAME contains illegal characters only " 	"[a-z0-9.+-] is allowed"

#Declare variables for folders access rights
# Current addon access rights
#
# <addon dir>:           $OPKGNAME:addon 701 (exec required by Apache)
# /usr:                  $OPKGNAME:addon 701 (exec required by Apache)
# /usr/bin/*:            $OPKGNAME:addon 700
# <web folder>:          $OPKGNAME:www   750 (exec required by Apache)
# <web folder>/<dirs>:   $OPKGNAME:www   750 (exec required by Apache)
# <web folder>/<files>:  $OPKGNAME:www   640
# License file:          $OPKGNAME:www   640

PERM_EXECDIR=701
PERM_OTHERDIR=700
PERM_BINFILES=700
PERM_WEBDIR=750
PERM_WEBFILES=640
PERM_LICFILE=640
PERM_OTHER=600

# Make sure package is installed
is_package_installed $OPKGNAME result || fail_errorcode $ERR_INSTALL_ERROR 	"Failed to check if Add-on package $OPKGNAME is installed"

[ $result -eq $TRUE ] || fail_errorcode $ERR_ADDON_NOT_FOUND 	"Add-on $pkgname is not installed"

OPKGFILES=$($OPKG files $OPKGNAME | tail +2) || {
	syslog_err $LOG_TAG 		"addon-setup: Failed to get list of installed files for $OPKGNAME"
	exit 1
}

MANIFESTFILE=$MANIFEST_PATH/${OPKGNAME}_manifest.xml
[ -f "$MANIFESTFILE" ] || {
	syslog_err $LOG_TAG "addon-setup: $MANIFESTFILE does not exist"
	exit 1
}

revert_and_fail() {
	local errorcode

	rm -f $SERVICE_PATH/$OPKGNAME.service
	rm -f $WEB_ROOT$OPKGNAME
	remove_apac_grant $OPKGNAME || :
	remove_addon_configuration $OPKGNAME || :

	# If an error code was specified used it, otherwise default to install error
	if [ $# -gt 1 ]; then
		errorcode=$1
		shift
	else
		errorcode=$ERR_INSTALL_ERROR
	fi

	fail_errorcode $errorcode "$@"
}

get_schema_location() {
# Check which version of the schema is requested
# Validate that this version is available.
# $1 - The manifest containing the version
# $2 - Output parameter indicating the schema to use
	local manifest_chk schema_location
	# Schema install path
	local SCHEMAPATH="usr/share/addon/schema"
	manifest_chk="$1"

	major=$(xmllint --xpath "string(//Manifest/@Major)" $manifest_chk) ||
		revert_and_fail $ERR_INSTALL_ERROR 			"Internal Error when parsing manifest version"
	minor=$(xmllint --xpath "string(//Manifest/@Minor)" $manifest_chk) ||
		revert_and_fail $ERR_INSTALL_ERROR 			"Internal Error when parsing manifest version"

	[ "$major" ] && [ "$minor" ] || revert_and_fail $ERR_INSTALL_ERROR 		"Schema version: Major or Minor is missing"

	[ -d $SDKTARGETSYSROOT/$SCHEMAPATH/$major/$minor ] || {
		revert_and_fail $ERR_INSTALL_ERROR 			"Requested schema version not available"
	}

	schema_location=$SDKTARGETSYSROOT/$SCHEMAPATH/$major/$minor/unrestricted_manifest.xsd

	eval $2=\$schema_location
}

get_schema_location $MANIFESTFILE SCHEMAFILE

[ -f "$SCHEMAFILE" ] || {
	syslog_err $LOG_TAG "addon-setup: $SCHEMAFILE does not exist"
	exit 1
}

WEB_FOLDER=
FCGI_SOCK=
LINUX_CAPS=
ADDON_CB_BUSNAME=

[ -d $SERVICE_PATH ] || {
	syslog_err $LOG_TAG "addon-setup: $SERVICE_PATH does not exist"
	exit 1
}

# Prints the opkg path that ends with $1
# Return error if not found
get_path() {
	local f

	f=$(echo "$OPKGFILES" | grep -E "/$1/?$")
	[ "$f" ] || return 1

	echo "$f"
	return 0
}

INSTALL_DIR=$(get_path $OPKGNAME) || {
	syslog_err $LOG_TAG "addon-setup: Failed to get install dir for $OPKGNAME"
	exit 1
}

[ -d "$INSTALL_DIR" ] || {
	syslog_err $LOG_TAG "addon-setup: No install directory found for $OPKGNAME"
	exit 1
}

# Strip trailing '/'
INSTALL_DIR=${INSTALL_DIR%/}

get_manifest_xpath() {
	[ ${#MANIFEST} -ne 0 ] || return 1
	[ $1 ] || return 1

	echo $MANIFEST | xmllint --xpath "$1" -
}

extract_manifest_basic_data() {
	# Validate the xml format according to the DTD (currently part of the xml
	# file) should be added as a system file in both the product and the sdk.
	# alternatively a schema could be added to do validaton against.
	MANIFEST=$(xmllint --schema $SCHEMAFILE $MANIFESTFILE) > /dev/null 2>&1 ||
		revert_and_fail $ERR_MANIFEST "Invalid manifest"
	# Check if license exists
	license=$(get_manifest_xpath 'string(//License)') ||
			revert_and_fail $ERR_MANIFEST 				"Internal error when trying to: get license"

	[ -n "$license" ] || revert_and_fail $ERR_NO_LICENSE 							"No license in manifest"
}

generate_dbus_access_file() {
	local busname tmp_busname count_iface m type i=0 m=0

	# Clear old APAC grants if available
	syslog_notice $LOG_TAG "Remove grants for user $OPKGNAME "
	remove_apac_grant $OPKGNAME

	count_iface=$(get_manifest_xpath 'count(//DbusInterface)') ||
		revert_and_fail $ERR_MANIFEST 			'Fail to extract required data from manifest'


	if [ "$count_iface" -le 0 ]; then
		return 0;
	fi

	# Grant user access required APIs
	while [ $i -lt $count_iface ]; do
		i=$(($i + 1))

		busname=$(get_manifest_xpath "string(//DbusInterface[$i]/@Name)") ||
			revert_and_fail $ERR_MANIFEST 				'Fail to extract requirement name from manifest'

		# Count number of methods the interface has and handle them.
		count_method=$(get_manifest_xpath "count(//DbusInterface[$i]/Method)") ||
			revert_and_fail $ERR_MANIFEST 			'Fail to extract required data from manifest'

		while [ $m -lt $count_method ]; do
			m=$(($m + 1))
			method=$(get_manifest_xpath 				"string(//DbusInterface[$i]/Method[$m])") ||
				revert_and_fail $ERR_MANIFEST 				'Fail to extract requirement name from manifest'
			tmp_busname="$busname.$method"
			# Convert the Dbus interface and method name to a APAC
			# action id. If not possible, fail.
			syslog_notice $LOG_TAG "Grant access for user $OPKGNAME, $tmp_busname"
			apac-update grant $OPKGNAME "$tmp_busname" > /dev/null 2>&1 ||
				revert_and_fail $ERR_API_GRANT_FAILED 				"Cannot grant access to $tmp_busname"
			# If the API supports CB then we need to add symlinks to the
			# configurations.
			enable_dbus_conf_for_cb $OPKGNAME

		done
		m=0
	done
}

get_secondary_groups() {
	local count groups type name i=0

	count=$(get_manifest_xpath 'count(//Uses/Requires/LinuxGroup)') ||
		fail 'Fail to extract data from manifest'

	while [ $i -lt $count ]; do
		i=$(($i + 1))
		name=$(get_manifest_xpath "string(//Uses/Requires/LinuxGroup[$i])") ||
			fail 'Fail to extract requirement busname from manifest'
		[ -e /usr/share/addon/group/$name ] ||
			revert_and_fail $ERR_INVALID_REQUIREMENT 				"$name is not a valid addon group"

		if [ "$groups" ]; then
			groups="$groups, '$name'"
		else
			groups="'$name'"
		fi
	done
	echo "$groups"
}

verify_dbus_dependencies() {
	local count type busname user ownablebusname devmode_allowed_apis i=0

	count=$(get_manifest_xpath 'count(//DbusInterface)') ||
		revert_and_fail $ERR_MANIFEST 			'Fail to extract requirement data from manifest'

	devmode_allowed_apis=$(get_devmode_allowed_apis)

	while [ $i -lt $count ]; do
		i=$(($i + 1))
		busname=$(get_manifest_xpath 			"string(//DbusInterface[$i]/@Name)") ||
			revert_and_fail $ERR_MANIFEST 				'Fail to extract requirement busname from manifest'
		minor_version=$(get_manifest_xpath 				"string(//DbusInterface[$i]/@Minor)") ||
			revert_and_fail $ERR_MANIFEST 				'Fail to extract minor version from DbusInterface'

		# Method name not included so we only use the interface since the
		# API check is only done on interface level

		# Check if the API exist
		is_api_available $busname $minor_version 			result user > /dev/null 2>&1 ||
			revert_and_fail $ERR_INSTALL_ERROR 					"Failed to check API $busname" 					"$minor_version is available"

		# The addon is not signed and we're in devmode but not in 'allow all' mode.
		# Check if we're allowed to use it
		if [ $SIGNED_PACKAGE -eq 0 ] && [ "$devmode_allowed_apis" ]; then
			is_api_allowed $devmode_allowed_apis "$DEVMODE_ALLOW_ALL_VALUE" ||
				is_api_allowed $devmode_allowed_apis $busname ||
					revert_and_fail $ERR_INSTALL_ERROR 						"API $busname is not allowed in developer mode"

		fi


		if [ $result -eq $TRUE ]; then
			[ -z $user ] || {
				# Check whether a user was returned.
				# This means that the API supports cb and that
				# a .conf file needs to be generated.
				ownablebusname=$(echo "$OPKGNAME" | sed "s/-/_/g")
				generate_dbus_conf_for_cb $OPKGNAME $user $busname
				ADDON_CB_BUSNAME="com.axis.callbacks.$ownablebusname"
			}
		else
			revert_and_fail $ERR_INVALID_REQUIREMENT 			"D-Bus name $busname ver $minor_version not available"
		fi
	done
}

configure_linux_cap() {
	# Read LinuxCapability tags from manifest and create a string
	# that is suitable for use in systemd service file.

	local count linux_cap temp_caps i=0
	local cap_xpath=//Uses/Requires/LinuxCapability

	count=$(get_manifest_xpath "count($cap_xpath)") ||
		revert_and_fail $ERR_MANIFEST "Invalid manifest"

	while [ $i -lt $count ]; do
		i=$(($i + 1))
		linux_cap=$(get_manifest_xpath "string($cap_xpath[$i])") ||
			revert_and_fail $ERR_MANIFEST "Invalid manifest"
		temp_caps="$temp_caps $linux_cap"
	done

	LINUX_CAPS="CapabilityBoundingSet=$temp_caps
AmbientCapabilities=$temp_caps"

}

extract_systemd_service_options()
{
	# Extract systemD service field options from the manifest
	# and use them in the creation of the systemd service file.
	local optionvalue optioncount temp optioncommand i=0
	local option_xpath=//Configuration/SystemdServiceFileOption

	# $1 - The service file being generated
	local servicefile="$1"
	addon_path="$OPKG_DEST/$OPKGNAME"
	addon_bin_path="$addon_path/usr/bin"

	optioncount=$(get_manifest_xpath "count($option_xpath)") ||
		revert_and_fail $ERR_INSTALL_ERROR "Internal error"

	while [ $i -lt $optioncount ]; do
		i=$(($i + 1))
		temp=$(get_manifest_xpath "string($option_xpath[$i])") ||
			revert_and_fail $ERR_MANIFEST "Invalid manifest"
		[ -n "$temp" ] ||
			revert_and_fail $ERR_MANIFEST "Empty SystemdServiceFileOption"

	optionvalue=${temp##*=}
	optioncommand=${temp%=*}

	optionvalue=$(echo $optionvalue | sed "s#\%ADDON_HOME\%#$addon_path#g")

	optionvalue=$(echo $optionvalue | sed "s#\%ADDON_BIN\%#$addon_bin_path#g")
	echo "$optioncommand=$optionvalue" >> $servicefile

	done
}

generate_services_file() {
	local servicefile tmp_file
	local start_execfile full_start_exec_path start_exec_option start_args
	local stop_execfile full_stop_exec_path stop_exec_option stop_args
	local remain_value remain_option
	local fcgis_count
	local env_option
	local cb_busname_option
	local dropdownfolder dropdownfile tmpdropdownfile

	# Set the environment variable for passing the Add-ons FCGI socket if it
	# manifests to use FCGI
	fcgis_count=$(get_manifest_xpath 'count(//Fcgis)') ||
		revert_and_fail $ERR_MANIFEST "Failed to get Fcgis"
	if [ $fcgis_count -eq 1 ]; then
		env_option="Environment=FCGI_SOCKET_NAME=$FCGI_SOCK"
	fi

	if [ -n "$ADDON_CB_BUSNAME" ]; then
		cb_busname_option="Environment=ADDON_CB_BUSNAME=$ADDON_CB_BUSNAME"
	fi

	servicefile=$SERVICE_PATH/"$OPKGNAME".service
	tmp_file=$servicefile.tmp

	rm -f $tmp_file

	if [ -f $servicefile ]; then
		# The service file is being re-generated, the saved state should
		# reflect the state in the previous service file.
		# With new systemd changes, systemctl stop can not be call directly.
		systemctl enable $OPKGNAME > /dev/null 2>&1 ||
		syslog_err $LOG_TAG 			"generate_services_file: Failed to enable service $OPKGNAME"
		systemctl stop $OPKGNAME > /dev/null 2>&1 ||
		syslog_err $LOG_TAG 			"generate_services_file: Failed to stop service $OPKGNAME"
		systemctl disable $OPKGNAME > /dev/null 2>&1 ||
		syslog_err $LOG_TAG 			"generate_services_file: Failed to disable service $OPKGNAME"
		remove_service $OPKGNAME
	fi

	echo "[Unit]
Description=Addon $OPKGNAME
[Service]
$LINUX_CAPS
User=$OPKGNAME
RuntimeDirectory=$OPKGNAME
WorkingDirectory=$OPKG_DEST/$OPKGNAME
Restart=on-failure
RuntimeDirectoryMode=0700
Slice=extension-addon.slice" >$tmp_file || revert_and_fail $ERR_FILE_SYSTEM 	"Failed to create service for $OPKGNAME"

	extract_systemd_service_options $tmp_file
	echo "
$env_option
$cb_busname_option
[Install]
WantedBy=multi-user.target" >>$tmp_file || revert_and_fail $ERR_FILE_SYSTEM 	"Failed to create service for $OPKGNAME"

	chmod 644 $tmp_file

	fsynced_write_or_cleanup $tmp_file $servicefile

	# Create the systemd service file dropdown folder
	dropdownfolder=$servicefile.d
	mkdir -p $dropdownfolder || revert_and_fail "Could not create dir: $dropdownfolder"

	# Create the network access capability settings file
	dropdownfile=$dropdownfolder/50-axis.conf
	tmpdropdownfile=$dropdownfile.tmp
	rm -f $tmpdropdownfile

	echo "[Service]
PrivateNetwork=no
CapabilityBoundingSet=~" >$tmpdropdownfile || revert_and_fail $ERR_FILE_SYSTEM 	"Failed to create systemd conf file for $OPKGNAME"

	chmod 644 $tmpdropdownfile
	fsynced_write_or_cleanup $tmpdropdownfile $dropdownfile
}

configure_addon_access() {
	# Sets all files in the addon to be owned by the addon user and to be apart
	# of the addon group.

	# Initially only the owner can access to addon files. If files needs other
	# permissions they should be set explicitly e.g. WEB_FOLDER, /usr/bin and
	# etc
	chown $OPKGNAME:addon -R $INSTALL_DIR ||
		revert_and_fail $ERR_FILE_SYSTEM 			"Failed to change owner of the addon to $OPKGNAME"
	chmod -R $PERM_OTHERDIR $INSTALL_DIR ||
		revert_and_fail $ERR_FILE_SYSTEM 			"Failed to set file permission for addon directory and its content"

	for addon_sub_dir in $(find -H $INSTALL_DIR -type f); do
		chmod $PERM_OTHER $addon_sub_dir
	done

	# Apache needs executable permissions for all directories in the full
	# path to $WEB_FOLDER and the $WEB_FOLDER subdirectories
	chmod $PERM_EXECDIR $INSTALL_DIR ||
		revert_and_fail $ERR_FILE_SYSTEM 			"Failed to set executable permission for $INSTALL_DIR"

	chmod $PERM_EXECDIR $INSTALL_DIR/usr ||
		revert_and_fail $ERR_FILE_SYSTEM 			"Failed to set executable permission for $INSTALL_DIR/usr"

	# Systemd will execute the addon service as the addon user, so only the
	# addon user should have permission to execute the addon binaries
	chmod -R $PERM_BINFILES $INSTALL_DIR/usr/bin/* ||
		revert_and_fail $ERR_FILE_SYSTEM 			"Failed to set file permission for addon binaries"
}

configure_layered_addon_access() {
	# Sets all files in the addon to be owned by the addon user and to be apart
	# of the addon group.

	# Initially only the owner can access to addon files. If files needs other
	# permissions they should be set explicitly e.g. WEB_FOLDER, /usr/bin and
	# etc
	local addon_sub_file addon_sub_file

	chown $OPKGNAME:addon $INSTALL_DIR ||
		revert_and_fail $ERR_FILE_SYSTEM "Failed to change owner of the addon to $OPKGNAME"

	for addon_sub_file in $(find -H $INSTALL_DIR -type f); do
		addon_sub_dir=${addon_sub_file%/*}
		if [ $addon_sub_dir != $INSTALL_DIR/usr/lib ];then
		     chown $OPKGNAME:addon $addon_sub_file
		     chown $OPKGNAME:addon $addon_sub_dir
		     chmod $PERM_OTHER $addon_sub_file
		fi
	done

	# Apache needs executable permissions for all directories in the full
	# path to $WEB_FOLDER and the $WEB_FOLDER subdirectories
	chmod $PERM_EXECDIR $INSTALL_DIR ||
		revert_and_fail $ERR_FILE_SYSTEM "Failed to set executable permission for $INSTALL_DIR"

	chmod $PERM_EXECDIR $INSTALL_DIR/usr ||
		revert_and_fail $ERR_FILE_SYSTEM "Failed to set executable permission for $INSTALL_DIR/usr"

	# Systemd will execute the addon service as the addon user, so only the
	# addon user should have permission to execute the addon binaries
	chmod -R $PERM_BINFILES $INSTALL_DIR/usr/bin/* ||
		revert_and_fail $ERR_FILE_SYSTEM "Failed to set file permission for addon binaries"

}

configure_web_folder() {
	# Expose folder http to web server
	# Create it if user addon do not supply it
	WEB_FOLDER=$INSTALL_DIR/usr/http
	mkdir -p $WEB_FOLDER || revert_and_fail "Could not create dir: $WEB_FOLDER"

	# Create web_folder configuration dir
	HTTP_CONF_DIR=$INSTALL_DIR/usr/conf
	mkdir -p $HTTP_CONF_DIR || revert_and_fail 		"Could not create dir: $HTTP_CONF_DIR"

	ln -sfn $WEB_FOLDER $WEB_ROOT$OPKGNAME > /dev/null 2>&1 ||
		revert_and_fail $ERR_FILE_SYSTEM 			"Failed to configure web server for $OPKGNAME"
}

configure_license() {
	local lic_file urls_list

	[ $# -eq 1 ] || revert_and_fail $ERR_FILE_SYSTEM 		'Missing url list while configuring license'

	urls_list=$1

	# Expose the LICENSE file to web server
	lic_file=$(get_path $OPKGNAME/LICENSE) || revert_and_fail 'No license file'

	# The license file should be owned by the addon user but be part of the
	# www group so Apache can read it
	chown $OPKGNAME:www $lic_file ||
		revert_and_fail $ERR_FILE_SYSTEM 			'Failed to set ownership of the license file'

	# Set permission 640 for license file so Apache can read it from the www
	# group
	chmod $PERM_LICFILE $lic_file ||
		revert_and_fail $ERR_FILE_SYSTEM 			'Failed to file permissions for the license file'

	ln -sf $lic_file $WEB_FOLDER/LICENSE > /dev/null 2>&1 ||
		revert_and_fail $ERR_FILE_SYSTEM 'Failed to expose license'

	urls_list=$(append_addon_url_configuration LICENSE viewer "$urls_list")

	echo "$urls_list"
}

create_rewrite_webroot_conf_file() {
	# Will take create conf file that contain rewrite rule
	# to make mainPage as webRoot.
	#
	# $1 MainPage file
	#

	local rewrite_file=$HTTP_CONF_DIR/$ADDON_MAIN_REWRITE_FILE
	local tmp_file=$rewrite_file.tmp

	rm -f $tmp_file

	echo "RewriteCond \"%{REQUEST_URI}\" !^/admin/?
RewriteRule \"^/$\" \"/local/$OPKGNAME/$1\" [L]" 	>$tmp_file ||
		revert_and_fail $ERR_FILE_SYSTEM 			"Could not create file: $ADDON_MAIN_REWRITE_FILE"

	fsynced_write_or_cleanup $tmp_file $rewrite_file
}

create_rewrite_alt_root_conf_file() {
	# Will create second configuration file
	# which contains alternative webroots. Meaning
	# other URLs will point to the main addon webroot and addon server-root.
	#

	local alternative_webroot=//Supplies/WebContent/AlternativeRoot i=0
	local main_webpage=//MainPage count=0 url_to_redirect main_webpage_file
	local alt_webroot_conf_file=$HTTP_CONF_DIR/40_addon_webroot_alt_$OPKGNAME.conf
	local tmp_file=$alt_webroot_conf_file.tmp

	main_webpage_file=$(get_manifest_xpath "string($main_webpage)") ||
		revert_and_fail 'Fail to extract main webpage file from manifest'

	main_webpage_file=${main_webpage_file##*/}

	count=$(get_manifest_xpath "count($alternative_webroot)") ||
		revert_and_fail $ERR_MANIFEST 			'Fail to extract alternativeWebroot from manifest'

	# Strip away local (ip/local/addon) if either of the files are or to be created.

	rm -f $tmp_file

	[ ! -f $ADDON_MAIN_REWRITE_FILE ] && [ $count -lt 1 ] || {
		echo 			"RewriteRule ^/$OPKGNAME/?\$ /local/$OPKGNAME/$main_webpage_file [L] 
RewriteRule ^/$OPKGNAME/(.*)\$ /local/$OPKGNAME/\$1 [N] " 			>$tmp_file || revert_and_fail $ERR_FILE_SYSTEM 				"Could not create file: $tmp_file"
        }

	while [ $i -lt $count ]; do
		i=$(($i + 1))

		url_to_redirect=$(get_manifest_xpath 			"string($alternative_webroot[$i])") ||
			revert_and_fail $ERR_MANIFEST 				'Fail to extract AlternativeRoot name from manifest'

		echo 			"RewriteRule ^$url_to_redirect/?\$ /local/$OPKGNAME/$main_webpage_file [L] 
RewriteRule ^$url_to_redirect/(.*)\$ /local/$OPKGNAME/\$1 [N]" 		>>$tmp_file ||
			revert_and_fail $ERR_FILE_SYSTEM 				"Could not append to file: $tmp_file"
	done

	[ -f $tmp_file ] &&
		fsynced_write_or_cleanup $tmp_file $alt_webroot_conf_file

	# Create the symbolic links.
	create_rewrites_symlinks $OPKGNAME
}

configure_fcgis() {
	local fcgiUrl=//Supplies/Fcgis/Url count i=0 fcgi_file aliasurl aliasconf 		aliasconf_tmp fcgis_list fcgis_handlers_list

	[ -d "$WEB_FOLDER" ] ||
		revert_and_fail "Web folder $WEB_FOLDER doesn't exist"

	FCGI_SOCK=$WEB_FOLDER/${OPKGNAME}_fcgi.socket
	touch $FCGI_SOCK || revert_and_fail $ERR_FILE_SYSTEM 		"Failed to create fastcgi socket"

	count=$(get_manifest_xpath "count($fcgiUrl)") ||
		revert_and_fail $ERR_MANIFEST 'Fail to extract fcgi data from manifest'

	# In case of upgrade, remove previous alias and create new
	remove_addon_url_alias $OPKGNAME || revert_and_fail $ERR_FILE_SYSTEM 		"Failed to delete previous alias file"

	aliasconf=$ALIAS_CONF_DIR/$OPKGNAME.conf
	aliasconf_tmp=$aliasconf.tmp

	while [ $i -lt $count ]; do
		i=$(($i + 1))
		fcgi_file=$(get_manifest_xpath "string($fcgiUrl[$i])") ||
			revert_and_fail $ERR_MANIFEST 				'Fail to extract fcgi file from manifest'
		# TODO: The WSDL or DTD shall check that only valid group names are used
		group=$(get_manifest_xpath "string($fcgiUrl[$i]/@AccessGroup)") ||
			revert_and_fail $ERR_MANIFEST 				'Fail to extract fcgi group from manifest'

		aliasurl=$(get_manifest_xpath "string($fcgiUrl[$i]/@AlternativeUrl)") 			|| {
			# This warning will only occur if the function failed to extract
			# the AlternativeUrl value. If the argument is not present in
			# the manifest it will exit with a zero status.
			syslog_warn $LOG_TAG "Failed to get AlternativeUrl for $fcgi_file"
		}

		touch $WEB_FOLDER/$fcgi_file || revert_and_fail $ERR_FILE_SYSTEM 			"Failed to create fast CGI alias $fcgi_file"

		[ -z "$aliasurl" ] || echo "Alias $aliasurl 			$WEB_DOCUMENT_ROOT/local/$OPKGNAME/$fcgi_file" >> $aliasconf_tmp

		fcgi_file=${fcgi_file##*/}

		fcgis_handlers_list=$(append_addon_fcgi_handler_configuration $fcgi_file 			$FCGI_SOCK "$fcgis_handlers_list") || revert_and_fail $ERR_CREATE_FCGI 			"Missing arguments"
		fcgis_list=$(append_addon_fcgi_configuration $fcgi_file $group 			"$fcgis_list") || revert_and_fail $ERR_CREATE_FCGI "Missing arguments"
	done
	[ "$fcgis_list" ] && [ "$fcgis_handlers_list" ] && {
		create_addon_fcgis_handlers_configuration $OPKGNAME 			"$fcgis_handlers_list" || revert_and_fail $ERR_CREATE_FCGI 			'Failed to create FCGI handlers configuration'
		create_addon_fcgis_configuration $OPKGNAME "$fcgis_list" ||
			revert_and_fail $ERR_CREATE_FCGI 			'Failed to create FCGI configuration'
	}
	# If needed, move alias tmp config file to real config file.
	# Reload of Apache HTTPD will be done in the end of the installation
	[ ! -f $aliasconf_tmp ] || {
		mv $aliasconf_tmp $aliasconf || revert_and_fail $ERR_CREATE_FCGI 			'Failed to move configuration file'
	}
}

configure_main_webpage() {
	local main_webpage=//MainPage main_webpage_file group urls_list is_webroot i=0

	[ "$1" ] || revert_and_fail $ERR_FILE_SYSTEM 		'Missing url list while configuring main webpage'
	urls_list=$1

	count=$(get_manifest_xpath "count(//$main_webpage)") ||
		revert_and_fail 'Fail to extract webpages data from manifest'

	if [ $count -eq 1 ]; then
		main_webpage_file=$(get_manifest_xpath "string($main_webpage)") ||
			revert_and_fail 'Fail to extract main webpage file from manifest'

		[ -f "$WEB_FOLDER/$main_webpage_file" ] ||
			revert_and_fail "$WEB_FOLDER/$main_webpage_file doesn't exist"

		main_webpage_file=${main_webpage_file##*/}

		is_webroot=$(get_manifest_xpath "boolean($main_webpage/@WebRoot)")
		[ "$is_webroot" != true ] ||
			create_rewrite_webroot_conf_file $main_webpage_file

		group=$(get_manifest_xpath "string($main_webpage/@AccessGroup)") ||
			revert_and_fail 'Fail to extract main_webpage group from manifest'

		urls_list=$(append_addon_url_configuration $main_webpage_file $group 			"$urls_list") || revert_and_fail $ERR_CREATE_URL 			"Failed to append url entry for main webpage '$main_webpage_file'"

	fi

	echo "$urls_list"
}

configure_webpages() {
	local webpage=//Page count webpage_file group i=0 urls_list

	[ "$1" ] || revert_and_fail $ERR_FILE_SYSTEM 		"Missing url list while configuring main webpage"
	urls_list=$1

	count=$(get_manifest_xpath "count($webpage)") ||
		revert_and_fail 'Fail to extract webpages data from manifest'

	while [ $i -lt $count ]; do
		i=$(($i + 1))
		webpage_file=$(get_manifest_xpath "string($webpage[$i])") ||
			revert_and_fail 'Fail to extract webpage file from manifest'

		[ -f "$WEB_FOLDER/$webpage_file" ] ||
			revert_and_fail "$WEB_FOLDER/$webpage_file doesn't exist"
		webpage_file=${webpage_file##*/}

		group=$(get_manifest_xpath "string($webpage[$i]/@AccessGroup)") ||
			revert_and_fail 'Fail to extract webpage group from manifest'

		urls_list=$(append_addon_url_configuration $webpage_file $group 			"$urls_list") ||
			revert_and_fail $ERR_CREATE_URL 				"Failed to add url entry for file '$webpage_file'"

	done

	echo "$urls_list"
}

configure_urls() {
	local urls_list

	configure_fcgis
	urls_list=$(configure_license "$urls_list")
	urls_list=$(configure_main_webpage "$urls_list")
	urls_list=$(configure_webpages "$urls_list")
	create_addon_urls_configuration $OPKGNAME "$urls_list" ||
		revert_and_fail $ERR_CREATE_URL 'Failed to create URLS configuration'
}

clear_addon_configuration() {
  remove_addon_configuration $OPKGNAME || :
}

configure_web_access() {
	local web_sub_dir
	# Sets all the access rights required for Apache to access the web folder
	# and its content

	# Change so WEB_FOLDER and its files are apart of the www group and is
	# readable by the group.
	chown -R $OPKGNAME:www $WEB_FOLDER ||
		revert_and_fail $ERR_FILE_SYSTEM 			"Failed to change owner for $WEB_FOLDER and its content"

	chmod -R $PERM_WEBFILES $WEB_FOLDER ||
		revert_and_fail $ERR_FILE_SYSTEM 			"Failed to set permission for $WEB_FOLDER and its content"

	chmod $PERM_WEBDIR $WEB_FOLDER ||
		revert_and_fail $ERR_FILE_SYSTEM 			"Failed to set permission for $WEB_FOLDER and its content"

	for web_sub_dir in $(find -H $WEB_FOLDER -type d); do
		chmod $PERM_WEBDIR $web_sub_dir || revert_and_fail $ERR_FILE_SYSTEM 			"Failed to set permissions for $WEB_FOLDER sub directories"
	done
}

# Mount the layers
mount_layers() {
	# If the addon has layers defined
	# Find each layer described in the layer tar of the addon
	# and apply them in correct order.
	local layer_tars upperdir workdir mergeddir lowerdir layer layer_dir
	local lower_layer= layers_dir=/opt/layers tmp_dir layer_tar
	local lower_tmp diff_tmp

	tmp_dir=$(mktemp -d) || revert_and_fail "$ERR_INSTALL_ERROR" "Failed to create tmp_dir"

	mkdir -p $layers_dir || revert_and_fail "$ERR_INSTALL_ERROR" "Failed to create $layers_dir"
	tar -C $tmp_dir -xf /opt/$OPKGNAME/usr/misc/layer/oci_layers.tar ||
		revert_and_fail "$ERR_INSTALL_ERROR" "Layers file is missing"

	layer_tars=$(sed -e 's/.*"Layers":\[\([^]]*\)\].*/\1/' -e 's/,/ /g' -e 's/"//g' 		$tmp_dir/manifest.json)

	# Support any amount of layers
	for layer_tar in $layer_tars; do
		layer=${layer_tar%/layer.tar}
		layer_dir=$layers_dir/$layer
		if [ ! -d $layer_dir ]; then
			mkdir -p $layer_dir/ref ||
				revert_and_fail "$ERR_INSTALL_ERROR" "Failed to create $layer_dir/ref"

			mkdir -p $layer_dir/work ||
				revert_and_fail "$ERR_INSTALL_ERROR" "Failed to create $layer_dir/work"

			[ -z $lower_layer ] || {
				lower_tmp=$layer_dir/lower.tmp
				rm -f $lower_tmp
				[ ! -f $layer_dir/lower ] || cat $layer_dir/lower >$lower_tmp ||
					revert_and_fail "$ERR_INSTALL_ERROR" "Failed to write to $lower_tmp"

				echo "$layers_dir/$lower_layer" >>$lower_tmp ||
					revert_and_fail "$ERR_INSTALL_ERROR" "Failed to append to $lower_tmp"

				fsynced_write_or_cleanup $lower_tmp $layer_dir/lower
			}

			diff_tmp=$layer_dir/diff.tmp
			[ ! -d $layer_dir/diff ] || rm -rf $layer_dir/diff 2>&1
			rm -rf $diff_tmp 2>&1

			mkdir -p $diff_tmp ||
				revert_and_fail "$ERR_INSTALL_ERROR" "Failed to create $diff_tmp"

			tar -C $diff_tmp -xf $tmp_dir/$layer_tar

			sync

			mv $diff_tmp $layer_dir/diff || {
				rm -rf $diff_tmp 2>&1
				revert_and_fail "$ERR_INSTALL_ERROR" "Failed to mv tmp to $layer_dir/diff"
			}

			fsync $layer_dir || {
				rm -rf $diff_tmp 2>&1
				revert_and_fail "$ERR_INSTALL_ERROR" "Failed to fsync $layer_dir"
			}
		fi
		[ -z $lower_layer ] || >$layers_dir/$lower_layer/ref/$layer
		lower_layer=$layer
	done

	rm -rf $tmp_dir

	upperdir=$layer_dir/diff
	workdir=$layer_dir/work
	mergeddir=/opt/$OPKGNAME

	while [ -f $layer_dir/lower ]; do
		[ -r $layer_dir/lower ] ||
			revert_and_fail $ERR_INSTALL_ERROR "Cannot mount addon layers"
		read layer_dir <$layer_dir/lower
		lowerdir=${lowerdir:+$lowerdir:}$layer_dir/diff
	done

	# If there is only one layer
	lowerdir=${lowerdir:-$upperdir}

	rm -rf $mergeddir/*
	local mount_options="lowerdir=$lowerdir,upperdir=$upperdir,workdir=$workdir $mergeddir"
	mount -t overlay overlay -o $mount_options ||
		revert_and_fail "$ERR_INSTALL_ERROR" "Mounting of filesystem failed"

	sed -i '$ a overlay '$mergeddir' overlay '"$mount_options"' 0 0' /etc/fstab
	fsync /etc/fstab
	# Mark addon as layered
	echo "${upperdir%/diff}" >>"$mergeddir/.layered"
}


extract_manifest_basic_data
verify_dbus_dependencies

# Check if add-on user exists
get_uid_for_user $OPKGNAME result || revert_and_fail $ERR_INSTALL_ERROR 	"Failed to check if Add-on user $OPKGNAME exists"

sec_groups=$(get_secondary_groups)
if [ $result -eq -1 ]; then
	# If the add-on user doesn't exist create it
	syslog_notice $LOG_TAG 		"Add-on $OPKGNAME does not exist - create addon user"
	create_addon_user $OPKGNAME "$sec_groups" || revert_and_fail 		$ERR_INSTALL_ADDON_USER "Failed to create user $OPKGNAME"
elif [ $result -ge 500 ]; then
	# If the user exists and is not permanent, it needs to be updated
	# with correct groups in case requirements have changed.
	syslog_notice $LOG_TAG 		"Add-on $OPKGNAME exist - update addon user groups - $sec_groups"
	update_addon_user_groups $OPKGNAME "$sec_groups" || revert_and_fail 		$ERR_INSTALL_ADDON_USER "Failed to update user $OPKGNAME"
fi

# Mount layers
if [ -d /opt/$OPKGNAME/usr/misc/layer/ ]; then
	mount_layers
	# Configure required resources
	generate_dbus_access_file
	# Configures access rights for the addon files
	configure_layered_addon_access
else
	generate_dbus_access_file
	# Configures access rights for the addon files
	configure_addon_access
fi

# Create web content and configure access rights
configure_web_folder
clear_addon_configuration
configure_urls
create_rewrite_alt_root_conf_file
configure_web_access
configure_linux_cap
reload_httpd

# Systemd service files
generate_services_file