#!/bin/sh

CLEANUP=1

PACKAGE_DIRECTORY=/usr/local/packages
HTML_FILE=${HTTP_REFERER#http*//*/}
if [ -z "$HTML_FILE" ]; then
	HTML_FILE=/devtools.shtml
else
	HTML_FILE=/${HTML_FILE%%\?*}
fi

information() {
	logger -t ${0##*/} -p INFO -- "$*"
}

warning() {
	logger -t ${0##*/} -p WARNING -- "$*"
}

error() {
	logger -t ${0##*/} -p CRIT -- "$*"
}

. /usr/html/axis-cgi/lib/acap_handle_files.sh
. /lib/rcscripts/sh/cmpversions.sh
. /etc/init.d/functions.sh

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

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





ADPPACKCFG=package.conf
ELFCHECK=elflibcheck.sh
LICDIR=/var/lib/adptools
BAKDIR=configuration.bak
LICFILENAME=lic.xml
LICNAME=LICENSE
INSTLOG=install.log
LICFILEPATH=$LICDIR/$LICFILENAME
VAR_RUN_DIR=/var/run/adptools
VAR_LOCK_DIR=/var/lock
LOCKFILENAME=upload.lock
LOCKFILEPATH=$VAR_LOCK_DIR/$LOCKFILENAME
ACAP_TARGET_WANTS=/etc/systemd/system/acap.target.wants
ADP_LISTCMD_ERROR_TYPE="Internal error"
ADP_LISTCMD_ERROR_MSG_UNKNOWN="Unknown error"
ADP_LISTCMD_ERROR_MSG_MKTEMP_FILE="Error creating temporary file"
ADP_LISTCMD_ERROR_MSG_CONFIG="Error reading configuration file"
ADP_LISTCMD_ERROR_MSG_STATUS="Error getting running status"
ADP_LISTCMD_ERROR_MSG_LICENSE_STATUS="Error reading license status"
ADP_LISTCMD_ERROR_MSG_LICENSE_NAME="Error reading license name"
APACHE_VHOSTS_ALL=/etc/apache2/conf.d/vhosts/all

INSTALLER=install-package.sh
PHC="parhandclient --nocgi"
DBUS_REQ_GET_APP_STATUS="dbus-send --system --print-reply --dest=com.axis.RuleEngine /com/axis/RuleEngine com.axis.RuleEngine.GetApplicationStatus"
HTTPD_CONF_LOCAL_STR=httpd.conf.local

__error() {
	local error_nbr=$1 pack=$2 exit_status=1 fwurl=

	[ "$error_nbr" ] || {
		error "function __error() needs 1 parameter"
		exit $exit_status
	}

	if [ "$RELOAD_PAGE" = yes ]; then
		fwurl="$HTML_FILE?error=$error_nbr"
		[ -z "$pack" ] || fwurl="$fwurl&app=$pack"
		forwardurl "$fwurl"
	else
		__cgi_hdgen yes
		printf "Error: $error_nbr"
	fi


	exit $exit_status
}

__logfile2error() {
	local line

	[ $# -eq 1 ] || error "Wrong number of arguments"
	[ -r $1 ] || error "$1 not readable"

	while read line; do
		error "$line"
	done <$1
}

__send_action_resp() {
	local return_page pack=$3

	return_page=$2

	if [ "$return_page" ]; then
		forwardurl "$return_page" 0
	elif [ "$RELOAD_PAGE" = yes ]; then
		local fwurl=$HTML_FILE
		case $1 in
			upload)
				fwurl="$fwurl?package_uploaded=yes"
				;
			remove)
				fwurl="$fwurl?package_removed=yes"
				;
			start)
				fwurl="$fwurl?package_started=yes"
				;
			stop)
				fwurl="$fwurl?package_stopped=yes"
				;
			*)
				[ -z "$pack" ] || fwurl="$fwurl?app=$pack"
				;
		esac
		forwardurl "$fwurl" 0
	else
		__cgi_errhd 200 OK
	fi
}

__lua_application_is_running() {
	local xmlfile=$1

	[ "$xmlfile" ] ||	{
		error "__lua_application_is_running needs para"
		echo ""
	}

	if [ "$(dbus-send --system --print-reply --dest=com.axis.RuleEngine /com/axis/RuleEngine com.axis.RuleEngine.GetApplicationStatus string:$PACKAGE_DIRECTORY/$APPNAME/$xmlfile 2>/dev/null)" ]; then
		echo lua
	fi
}

__is_supported_apptype() {
	local arch= apptype= retval=

	[ "$1" ] || {
		warning "acap apptype validation skipped (apptype value unset)"
		return 0
	}
	apptype="$1"
	arch=$($PHC get properties.System.Architecture 2>&1) || {
		warning "acap apptype validation skipped (failed to read system architecture parameter)"
		return 0
	}
	eval arch=$arch

	retval=0
	case $apptype in
		ARTPEC-4 | ARTPEC-5 | artpec-4 | artpec-5 | mipsisa32r2el | mipsisa32r2el-axis-linux-gnu)
			[ "$arch" = mips ] || retval=1
			;
		AMBARELLA-A5S | ambarella-a5s | armv6 | armv6-axis-linux-gnueabi)
			[ "$arch" = armv6l ] || retval=1
			;
		AMBARELLA-S2 | ambarella-s2 | armv7 | armv7-axis-linux-gnueabi)
			[ "$arch" = armv7l ] || retval=1
			;
		AMBARELLA-S2L | ARTPEC-6 | ambarella-s2l | artpec-6 | armv7hf | armv7-axis-linux-gnueabihf)
			[ "$arch" = armv7hf ] || retval=1
			;
		*)
			[ "$arch" = $apptype ] || retval=1
			;
	esac

	[ "$retval" = 0 ] || warning "Unsupported acap apptype $apptype (architecture $arch)"
	return $retval
}

__read_runstate() {
	local file=$1 enb=no var= val= IFS==

	[ -r $file ] || return 0
	while read var val; do
		case $var in
			ENABLED)
				eval enb=$val
				;
			*)
				information "unknown runstate  $var"
				;
		esac
	done < $file
	eval $2=\$enb
}

__set_runstate() {
	#cmd=$1 app=$2 mode=$3
	local name= service= runstate_conf=runstate.conf _is_enabled state

	[ $# -eq 3 ] || error "Wrong number of arguments"
	[ "$2" ] && name=$2 || error "Name not specified"
	[ "$3" ] || error "Mode not specified"

	service=sdk$name.service
	state=$(systemctl is-active $service 2>/dev/null) ||:
	case $1 in
		stop)
			_is_enabled=no
			if [ "$state" = active ]; then
				systemctl stop $service || warning "Failed to stop $service"
				systemctl disable $service || warning "Failed to disable $service"
			fi
			;
		start)
			_is_enabled=yes
			systemctl enable $service || warning "Failed to enable $service"
			if [ $3 = never ]; then
				_is_enabled=no
				systemctl disable $service || warning "Failed to disable $service"
			fi
			systemctl restart $service || warning "Failed to restart $service"
			;
		*)
			error "Unsupported argument $1"
			;
	esac
	echo ENABLED=$_is_enabled >$PACKAGE_DIRECTORY/$2/conf/$runstate_conf.tmp ||
		 warning "Failed to set runstate for $2"
	fsynced_write_or_cleanup $PACKAGE_DIRECTORY/$2/conf/$runstate_conf.tmp $PACKAGE_DIRECTORY/$2/conf/$runstate_conf
}

__need_web_reload() {
	if [ "$HTTPCGIPATHS" ] || [ "$LICENSENAME" ] || [ -r $HTTPD_CONF_LOCAL_STR.$APPNAME ]; then
		information "Web server reload will be required."
		return 0
	fi
	return 1
}

__webserver_reload() {
	information "Reloading the web server."
	systemctl reload httpd ||
		warning "Failed to reload the web server, some settings might not take effect."
}

__upload_adp_package() {
	local tmp_file tmp_file_general pid= action=upload
	local oldpwd=$PWD xmlfile=
	local _eap_path= _tmpbakdir= _is_reinstall= _tmppostlog= realms=
	local reload_web=no _started=no limited_postinstall=no dirs=

	[ $# -eq 1 ] || __error 4

	tmp_file=$(file_upload -S $CONTENT_LENGTH -n 204800 \
		--allowed-realms=$realms --allowed-dirs=$dirs 2>&1) || {
			error "Upload failed: '$tmp_file'"
			__error 3
	}

	[ "$tmp_file" ] || {
		warning "No file uploaded."
		__error 10
	}

	[ -r "$tmp_file" ] || {
		error "Cannot find readable file '$tmp_file'"
		[ $CLEANUP -eq 0 ] || rm -f $tmp_file
		__error 3
	}

	tmp_file_general=$(mktemp /tmp/upload.XXXXXXXXX)
	mv $tmp_file $tmp_file_general || {
		error "Failed to rename uploaded $tmp_file to $tmp_file_general"
		[ $CLEANUP -eq 0 ] || rm -f $tmp_file
		__error 3
	}

	information "Uploaded $tmp_file as $tmp_file_general; size:$CONTENT_LENGTH"
	eval $1=\$tmp_file_general
}

__install_eap_file() {
	local oldpwd=$PWD tmp_ld res dest_dir tmp_package ret=0 embdevversion
	local _exec_as_root=no

	[ $# -eq 2 ] && [ $1 ] && [ $2 ] || {
		error "Wrong number of arguments for installation of ACAP package."
		return 2
	}
	tmp_package=$1

	! __run_as_root "$tmp_package" || _exec_as_root=yes

	if __root_prohibited && ! __is_whitelisted "$tmp_package"; then
		[ $_exec_as_root != yes ] || {
			warning "Limited access: root access prohibited for uploaded applications."
			return 5
		}
		limited_postinstall=yes
	fi

	__pkgconf_get_var $tmp_package REQEMBDEVVERSION || :
	__pkgconf_get_var $tmp_package APPNAME || :
	embdevversion=$($PHC get properties.EmbeddedDevelopment.Version 2>&1) || {
		warning "$PHC get properties.EmbeddedDevelopment.Version returned: $embdevversion"
		embdevversion=
	}
	[ $embdevversion ] || {
		warning "Failed to get embedded development version to check compatibility with application \"$APPNAME\". Defaulting to 1.0."
		embdevversion="1.0"
	}
	[ $REQEMBDEVVERSION ] || REQEMBDEVVERSION="1.0"
	compare_vers $REQEMBDEVVERSION le $embdevversion || {
		error "Invalid embedded development version $embdevversion. \"$APPNAME\" require at least version $REQEMBDEVVERSION."
		return 5
	}

	tmp_ld=$(mktemp -d /tmp/pack.XXXXXX 2>&1) || {
		error "failed: mktemp -d /tmp/pack.XXXXXX $tmp_ld"
		return 3
	}

	res=$(tar -xzf $tmp_package -C $tmp_ld 2>&1) || {
		local res2
		res2=$(tar -xf $tmp_package -C $tmp_ld 2>&1) || {
			error "Failed to unpack: ($res) ($res2)"
			[ $CLEANUP -eq 0 ] || rm -fr $tmp_ld
			return 1
		}
	}
	if [ -r "$tmp_ld/$ADPPACKCFG" ]; then
		if ! __source_if_sourceable "$tmp_ld/$ADPPACKCFG" ; then
			[ $CLEANUP -eq 0 ] || rm -fr $tmp_ld
			return 2
		fi
	else
		warning "Could not source (1) '$ADPPACKCFG'"
		[ $CLEANUP -eq 0 ] || rm -fr $tmp_ld
		return 2
	fi
	information "$PACKAGENAME EAP package unpacked"

	[ "$APPNAME" ] && [ "$APPNAME" = "$(printf "%s" $APPNAME | sed -e 's/[^[:alnum:]._-]//g')" ] || {
		error "Invalid APPNAME \"$APPNAME\" (Valid characters are: a-zA-Z0-9 '.' '_' '-' -Start with a letter)"
		[ $CLEANUP -eq 0 ] || rm -fr $tmp_ld
		return 29
	}
	[ -z "$(echo $APPID | sed -e 's/[0-9]//g')" ] || {
		error "Invalid APPID (use only 0-9)"
		[ $CLEANUP -eq 0 ] || rm -fr $tmp_ld
		return 29
	}
	[ -n "$APPMAJORVERSION" ] && [ -z "$(echo $APPMAJORVERSION | sed -e 's/[0-9]//g')" ] || {
		error "Invalid MAJOR (use only 0-9)"
		[ $CLEANUP -eq 0 ] || rm -fr $tmp_ld
		return 29
	}
	[ -n "$APPMINORVERSION" ] && [ -z "$(echo $APPMINORVERSION | sed -e 's/[0-9]//g')" ] || {
		error "Invalid MINOR (use only 0-9)"
		[ $CLEANUP -eq 0 ] || rm -fr $tmp_ld
		return 29
	}

	if [ "$APPTYPE" = lua ]; then
		xmlfile=$APPNAME
		APPNAME=${APPNAME%.*}
		handle_xml_conf_duplication -l "XML duplicate application" -s "$tmp_ld/$APPNAME.xml" \
					    -d "/tmp/$APPNAME.xml"
		if [ -e /tmp/$APPNAME.xml ]; then
			mv /tmp/$APPNAME.xml $tmp_ld/$APPNAME.xml
		fi
	else
		if [ -x $tmp_ld/$APPNAME ]; then
			__is_supported_apptype $APPTYPE || {
				[ $CLEANUP -eq 0 ] || rm -fr $tmp_ld
				return 5
			}
			res=$($ELFCHECK $tmp_ld/$APPNAME 2>&1) || {
				[ $CLEANUP -eq 0 ] || rm -fr $tmp_ld
				read res <<-EOF
					$res
				EOF
				error "elflibcheck failed: $res"
				return 5
			}
		else
			error "'$APPNAME' not found or not executable"
			[ $CLEANUP -eq 0 ] || rm -fr $tmp_ld
			return 2
		fi
	fi

	[ -d $PACKAGE_DIRECTORY ] || {
		res=$(mkdir $PACKAGE_DIRECTORY 2>&1) || {
			error "$res"
			[ $CLEANUP -eq 0 ] || rm -fr $tmp_ld
			return 3
		}
		res=$(chmod 775 $PACKAGE_DIRECTORY 2>&1) || {
			error "$res"
			[ $CLEANUP -eq 0 ] || rm -fr $tmp_ld
			return 3
		}
	}

	dest_dir=$PACKAGE_DIRECTORY/$APPNAME

	if [ -d $dest_dir ]; then
		local preupgrade_res=
		_is_reinstall=y


		_tmpbakdir=$(mktemp -d /tmp/$APPNAME.XXXXXX 2>&1) || {
			_tmpbakdir=
			warning "Failed to create temp dir for application parameters"
		}

		[ -z "$_tmpbakdir" ] || __preserve_app_runstate $dest_dir $_tmpbakdir

		__set_runstate stop "$APPNAME" "$STARTMODE"  ||
			information "Application $APPNAME can not be stopped"

		[ "$PREUPGRADESCRIPT" ] && [ -r $tmp_ld/$PREUPGRADESCRIPT ] && {
			[ $_exec_as_root = yes ] || {
				preupgrade_res=$(chmod 755 $tmp_ld 2>&1) ||
					warning "$preupgrade_res, upgrade script will not be run"
			}
			[ $preupgrade_res ] || {
				cd $dest_dir
				res=$(eval $(__rootpath) $INSTALLER preupgrade \
					$tmp_ld/$PREUPGRADESCRIPT 2>&1) || warning "$res"
				cd $oldpwd || :
			}
		}

		[ ! $_tmpbakdir ] || __preserve_app_conf $dest_dir $_tmpbakdir

		cd $dest_dir
		res=$(eval $(__rootpath) $INSTALLER uninstall) || warning "$res"
		__need_web_reload && reload_web=yes || :
		cd $oldpwd || :
		rm -rf $dest_dir
	fi


	if ! __fsynced_write_or_cleanup_dir $tmp_ld $dest_dir; then
		error "Failed to move $tmp_ld to $dest_dir"
		[ $CLEANUP -eq 0 ] || rm -fr $tmp_ld $dest_dir $_tmpbakdir
		return 3
	fi

	res=$(chmod 775 $dest_dir 2>&1) || {
		error "$res"
		[ $CLEANUP -eq 0 ] || rm -fr $dest_dir $_tmpbakdir
		return 3
	}
	if [ -d "$_tmpbakdir" ]; then
		if ! __fsynced_write_or_cleanup_dir $_tmpbakdir $dest_dir/$BAKDIR; then
			warning "Failed to restore application parameters: $res"
		fi
	fi

	rm -fr $tmp_ld $_tmpbakdir
	tmp_ld=
	_tmpbakdir=

	cd $dest_dir
	instlog=$dest_dir/$INSTLOG
	eval $(__rootpath) $INSTALLER install $limited_postinstall >$instlog.tmp 2>&1 || ret=$?
	fsynced_write_or_cleanup $instlog.tmp $instlog
	__need_web_reload && reload_web=yes || :
	cd $oldpwd

	if [ $ret -ne 0 ]; then
		error "$PACKAGENAME installation FAILED"
		__logfile2error $instlog
		[ $CLEANUP -eq 0 ] || rm -fr $dest_dir
		return 10
	fi
	information "$PACKAGENAME installation OK"

	if [ "$_is_reinstall" ] ; then
		systemctl daemon-reload
	fi
	__read_runstate $dest_dir/conf/runstate.conf _started
	if [ $_started = yes ]; then
		__set_runstate start  $APPNAME $STARTMODE ||
			warning "Failed to start $APPNAME"
	fi

	if [ "$reload_web" = yes ];then
		[ -z "$2" ] || eval "$2=$reload_web"
	fi
}

__install_adp_package () {
	local result_code eap_file reload_web

	[ $# -eq 1 ] && [ $1 ] || {
		error "Wrong number of arguments for installation of ACAP package."
		exit 2
	}
	eap_file=$1

	__install_eap_file $eap_file reload_web
	result_code=$?

	[ "$result_code" -eq 0 ] || exit $result_code

	[ "$reload_web" = yes ] && __webserver_reload || :
	information "Returning '$APPNAME'"
	echo $APPNAME
	exit 0
}

__install_license_key() {
	local pack packdir keyfile


	[ $# -eq 2 ] || {
		error "Wrong number of arguments for licensekey installation."
		return 22
	}
	pack=$1
	keyfile=$2

	packdir=$PACKAGE_DIRECTORY/$pack
	[ -d $packdir ] || {
		warning "Directory for package $pack is missing"
		return 24
	}

	local resstr

	resstr=$(cp $keyfile $packdir/$LICFILENAME 2>&1) || {
		error "$resstr"
		return 22
	}

	information "Installed '$LICFILENAME' for $pack OK"
}

__validate_license_key() {
	local old_IFS  keyfile expression licensekey=
	local applicationid= minmajorversion= minminorversion= maxmajorversion=
	local maxminorversion= expirationdate= deviceid=
	local serialnumber= expdateseconds= nowseconds=


	[ $# -eq 1 ] || {
		error "Wrong number of arguments for validation of license file."
		return 22
	}
	keyfile=$1
	[ -r $keyfile ] || return 21

	old_IFS=$IFS
	IFS=
	licensekey=$(tr -d '\n' <$keyfile |
		grep -e "<LicenseKey>.*</LicenseKey" || :)

	IFS=$old_IFS
	if [ -z "$licensekey" ]; then
		warning "License key validation failed: Malformed license key file. (1)"
		return 21
	else
		expression=$(echo $licensekey | sed -rn 's/.*<ApplicationID>([[:digit:]]*)<\/ApplicationID>.*<MinimumMajorVersion>([-[:digit:]]*)<\/MinimumMajorVersion>.*<MinimumMinorVersion>([-[:digit:]]*)<\/MinimumMinorVersion>.*<MaximumMajorVersion>([-[:digit:]]*)<\/MaximumMajorVersion>.*<MaximumMinorVersion>([-[:digit:]]*)<\/MaximumMinorVersion>.*<ExpirationDate>([-[:digit:]]*)<\/ExpirationDate>.*<DeviceID>([0-9A-Fa-f]*)<\/DeviceID>.*/applicationid=\1 minmajorversion=\2 minminorversion=\3 maxmajorversion=\4 maxminorversion=\5 expirationdate=\6 deviceid=\7/p')
		if [ ${#expression} -eq 0 ]; then
			warning "License key validation failed: Malformed license key file. (2)"
			return 21
		fi

		eval $expression || :

		if [ -z "$applicationid" ] ||
		   [ -z "$minmajorversion" ] ||
		   [ -z "$minminorversion" ] ||
		   [ -z "$maxmajorversion" ] ||
		   [ -z "$maxminorversion" ] ||
		   [ -z "$expirationdate" ]; then
			warning "License key validation failed: Failed to parse license " \
				"\"$applicationid"\" \
				"\"$minmajorversion"\" \
				"\"$minminorversion"\" \
				"\"$maxmajorversion"\" \
				"\"$maxminorversion"\" \
				"\"$expirationdate"\"
			return 21
		fi
		if [ "$applicationid" != $APPID ]; then
			warning "License key validation failed: Faulty application id."
			return 25
		fi
		if [ "$minmajorversion" -ne -1 ] &&
			[ "$APPMAJORVERSION" -lt "$minmajorversion" ]; then
			warning "License key validation failed: Wrong versions."
			return 26
		fi
		if [ "$minminorversion" -ne -1 ] &&
			[ "$APPMAJORVERSION" -eq "$minmajorversion" ] &&
			[ "$APPMINORVERSION" -lt "$minminorversion" ]; then
			warning "License key validation failed: Wrong versions."
			return 26
		fi
		if [ "$maxmajorversion" -ne -1 ] &&
			[ "$APPMAJORVERSION" -gt "$maxmajorversion" ]; then
			warning "License key validation failed: Wrong versions."
			return 26
		fi
		if [ "$maxminorversion" -ne -1 ] &&
			[ "$APPMAJORVERSION" -eq "$maxmajorversion" ] &&
			[ "$APPMINORVERSION" -gt "$maxminorversion" ]; then
			warning "License key validation failed: Wrong versions."
			return 26
		fi
		serialnumber=$($PHC get \
			properties.system.serialnumber - RAW |
			tr [:lower:] [:upper:])
		deviceid=$(echo $deviceid |tr '[:lower:]' '[:upper:]')
		[ "$serialnumber" = "$deviceid" ] || {
			warning "License key validation failed: Invalid device id."
			return 30
		}
		if [ $expirationdate != "0" ]; then
			expdateseconds=$(
				date -d $expirationdate -D%F +%s)
			nowseconds=$(date +%s)
			[ "$expdateseconds" ] && [ "$nowseconds" ] || {
				warning "License key validation failed: Failed to parse expirationdate."
				return 21
			}
			[ $expdateseconds -ge $nowseconds ] || {
				warning "License key validation failed: Date expired."
				return 31
			}
		fi
	fi
}


__install_adp_license_key() {
	local pack keyfile result_code


	[ $# -eq 2 ] || {
		error "Wrong number of arguments for installation of license file."
		exit 22
	}
	pack=$1
	keyfile=$2

	__validate_license_key $keyfile
	result_code=$?
	[ $result_code -eq 0 ] || exit $result_code

	__install_license_key $pack $keyfile
	result_code=$?
	[ $result_code -eq 0 ] || exit $result_code

	exit 0
}

__cleanup_uploaded_license_key() {
	local resstr

	[ $# -eq 1 ] || {
		error "Wrong number of arguments for cleanup of license file."
		return 0
	}

	[ -f $1 ] || {
		information "No uploaded license key file to clean out."
		return 0
	}

	resstr=$(rm $1 2>&1) || {
		error "$resstr"
	}

}

__upload_adp_license_key() {
	local pack tmp_file packdir uploaddir uploadfile
	local realms= dirs= ret=0 result_code=0


	[ $# -eq 3 ] || {
		error "Wrong number of arguments for upload of license file."
		__error 10 $pack
	}
	pack=$1
	packdir=$PACKAGE_DIRECTORY/$pack
	uploaddir=$2
	uploadfile="$2"/"$3"

	[ -d $packdir ] || {
		warning "Directory for package $pack is missing"
		__error 24 $pack
	}
	if [ -r $packdir/$ADPPACKCFG ]; then
		if ! __source_if_sourceable "$packdir/$ADPPACKCFG" ; then
			__error 24 $pack
		fi
	else
		warning "Could not source (2) '$ADPPACKCFG'"
		[ $CLEANUP -eq 0 ] || rm -fr $tmp_ld
		__error 24 $pack
	fi
	tmp_file=$(file_upload -S $CONTENT_LENGTH -n 204800 \
		--allowed-realms=$realms --allowed-dirs=$dirs 2>&1) || ret=$?
	if [ $ret -ne 0 ]; then
		error "Upload failed: '$tmp_file'"
		__error 22 $pack
	else
		[ -r "$tmp_file" ] || {
			error "Cannot find file '$tmp_file'"
			__error 22 $pack
		}

		rm -f $uploadfile
		[ -d $uploaddir ] || {
			error "Directory for upload $uploaddir is missing"
			__error 22 $pack
		}

		mv "$tmp_file" "$uploadfile" || {
			error cannot mv $tmp_file $uploadfile
			__error 22 $pack
		}
		chmod 644 $uploadfile || {
			error "Failed to set permissions on created license file"
			__error 22 $pack
		}
	fi

	__validate_license_key $uploadfile
	result_code=$?
	[ $result_code -eq 0 ] || {
		[ $result_code -ne 21 ] || rm -f $uploadfile
		__error "$result_code" $pack
	}
}

__remove_adp_package() {
	local pack=$1 action=remove pid= packdir= option=$3
	local listpack= p= xmlfile=
	local _eap_path= reload_web=no



	packdir="$PACKAGE_DIRECTORY/$pack"
	if [ -r "$packdir/$ADPPACKCFG" ]; then
		if ! __source_if_sourceable "$packdir/$ADPPACKCFG" ; then
			exit 2
		fi
		if [ "$APPTYPE" = lua ]; then
			xmlfile=$APPNAME
			APPNAME=${APPNAME%.*}
			pid=$(__lua_application_is_running $xmlfile)
		else
			pid=$(pidof $APPNAME) || :
		fi
		[ -z "$pid" ] ||
			__set_runstate stop $APPNAME $STARTMODE || {
				information "Application $APPNAME[$pid] can not be stopped"
				exit 10
			}
		cd $packdir
		eval $(__rootpath) $INSTALLER uninstall >/dev/null || {
			warning "Application $APPNAME[$pid] can not be uninstalled"
			exit 10
		}
		__need_web_reload && reload_web=yes || :
	else
		exit 4
	fi

	rm -f $APACHE_VHOSTS_ALL/urls_$APPNAME.conf
	rm -f $APACHE_VHOSTS_ALL/urls_$APPNAME.conf.tmp

	[ "$reload_web" = yes ] && __webserver_reload || :
}

__remove_adp_license_key() {
	local pack packdir resstring


	[ $# -eq 1 ] || {
		error "Wrong number of arguments for removal of license file."
		exit 10
	}
	pack=$1
	packdir=$PACKAGE_DIRECTORY/$pack

	[ -d $PACKAGE_DIRECTORY/$pack ] || {
		warning "Directory for package $pack is missing"
		exit 24
	}
	packdir=$PACKAGE_DIRECTORY/$pack
	resstring=$(rm $packdir/$LICFILENAME 2>&1) || {
		error "$resstring"
		exit 23
	}
	exit 0
}

__view_adp_license_key() {
	local pack packdir


	[ $# -eq 1 ] || {
		error "Wrong number of arguments for view of license file."
		exit 10
	}
	pack=$1
	packdir=$PACKAGE_DIRECTORY/$pack

	[ -d $packdir ] || {
		warning "Directory for package $pack is missing"
		exit 24
	}
	[ -r $packdir/$LICFILENAME ] || {
		information "No license key for $pack"
		exit 21
	}

	cat $packdir/$LICFILENAME
	exit 0
}

__read_adp_license_key() {
	local pack packdir line


	[ $# -eq 1 ] || {
		error "Wrong number of arguments for reading the license file."
		exit 10
	}
	pack=$1
	packdir=$PACKAGE_DIRECTORY/$pack

	[ -d $packdir ] || {
		warning "Directory for package $pack is missing"
		exit 24
	}
	[ -r $packdir/$LICFILENAME ] || {
		exit 0
	}

	while read line; do
		information "$line"
	done <$packdir/$LICFILENAME
	exit 0
}

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

__admin_adp_package() {
	local err= action= pack= return_page= pid= xmlfile=
	local license_status license_exp_date


	action=$1
	pack=$2
	return_page=$3
	send_response=${4:-0}

	err=4
	packdir="$PACKAGE_DIRECTORY/$pack"
	if [ -r "$packdir/$ADPPACKCFG" ]; then
		. "$packdir/$ADPPACKCFG" || :
		err=0
		if [ "$APPTYPE" = lua ]; then
			xmlfile=$APPNAME
			APPNAME=${APPNAME%.*}
			pid=$(__lua_application_is_running $xmlfile)
		else
			pid=$(pidof $APPNAME) || :
		fi
		case "$action" in
			start)
				if [ "$APPTYPE" = lua ] &&
				   [ "$LUASTANDALONE" = yes ]; then
					LICENSEFILE=lic.xml
					# Check license status
					__get_license_status "$packdir/$LICENSEFILE" license_status license_exp_date || :
					case "$license_status" in
					Missing)
						err=11
						warning "Application '$APPNAME' can not be started without license installed"
						read running_status <$packdir/is_running || :
						if [ "$running_status" = Running ]; then
							echo "Stopped" >$packdir/is_running
						fi
						;
					Valid|None|Custom)
						read running_status <$packdir/is_running || :
						if [ "$running_status" = Running ]; then
							err=6
							warning "Application '$APPNAME' is running"
						else
							echo Running >$packdir/is_running
						fi
						;
					Invalid|*)
						err=21
						warning "Invalid license. Application '$APPNAME' can not be started"
						read running_status <$packdir/is_running || :
						if [ "$running_status" = Running ]; then
							echo "Stopped" >$packdir/is_running
						fi
						;
		            esac
				elif [ "$pid" ]; then
					err=6
					information "Application '$APPNAME' is running already"
				else
					if eval $(__rootpath) start-package-allowed.sh $packdir/$APPNAME $APPTYPE >/dev/null; then
						__set_runstate start $APPNAME $STARTMODE ||
							err=8
					else
						err=9
					fi
				fi
				;
			stop)
				if [ "$APPTYPE" = lua ] &&
				   [ "$LUASTANDALONE" = yes ]; then
					read running_status <$packdir/is_running || :
					if [ "$running_status" = "Stopped" ]; then
						err=7
						information "Application '$APPNAME' is not running"
					else
						echo "Stopped" >$packdir/is_running
					fi
				elif [ "$pid" ]; then
					__set_runstate stop $APPNAME $STARTMODE || :
					if [ "$APPTYPE" = lua ]; then
						pid=$(__lua_application_is_running $xmlfile)
					else
						pid=$(pidof $APPNAME) || :
					fi
					if [ "$pid" ]; then
						warning "Application $APPNAME[$pid] can not be stopped"
						err=10
					fi
				else
					information "Application '$APPNAME' is not running"
					err=7
				fi
				;
			*)
				err=10
				;
		esac
	fi

	[ $err -eq 0 ] || exit $err

	__pkgconf_unset
	exit 0
}

__autoinstall_adp_license_key() {
	local action=autoinstalllicensekey
	local urn=/techsup/compatible_applications/api.php
	local pack= packdir= response= response_code= line=
	local old_IFS=$IFS within_xml= content= new_qs= param= err=


	pack=$1
	packdir="$PACKAGE_DIRECTORY/$pack"
	[ ! -r "$packdir/$ADPPACKCFG" ] || . "$packdir/$ADPPACKCFG" || :

	if [ -z "$APPID" ]; then
		warning "No application ID set in package.conf"
		__error 29 $pack
	fi
	if [ -z "$APPMAJORVERSION" ]; then
		warning "No major version set in package.conf"
		__error 29 $pack
	fi
	if [ -z "$APPMINORVERSION" ]; then
		warning "No minor version set in package.conf"
		__error 29 $pack
	fi

	IFS="&"
	for param in $QUERY_STRING; do
		case "${param%%=*}" in
			action|reload_page|package)
				;
			*)
				new_qs=$new_qs$param"&"
				;
		esac
	done
	IFS=$old_IFS

	urn="$urn?${new_qs}app_id=$APPID&ajor_ver=$APPMAJORVERSION&inor_ver=$APPMINORVERSION"
	response=$(curl -i -s -m 75 "http://www.axis.com:80$urn" 2>/dev/null)
	if [ -z "$response" ]; then
		information "Failed to connect to the Axis web service"
		__error 27 $pack
	fi

	response_code=$(echo $response |
		sed -rn 's/HTTP\/1\..[[:blank:]]+([[:digit:]]*).*/\1/p' ||
		response_code=)

	if [ -z "$response_code" ]; then
		error "Bad response received from the Axis web service $response"
		__error 28 $pack
	fi

	mkdir -p $LICDIR || {
		error "Failed to mkdir $LICDIR (2)"
		__error 22 $pack
	}
	chmod 700 $LICDIR || {
		error "Failed to chmod $LICDIR (2)"
		__error 22 $pack
	}

	if ! touch $LICFILEPATH >/dev/null; then
		error "Failed to create temporary license file"
		__error 28 $pack
	fi

	IFS="
"
	rm -f $LICFILEPATH.data $LICFILEPATH.raw
	for line in $response; do
		[ -z "$within_xml" ] || echo $line >>$LICFILEPATH
		echo $line >>$LICFILEPATH.raw
		echo $line >>$LICFILEPATH.data
		if [ "$line" = "<LicenseKey>" ]; then
			echo $line >$LICFILEPATH
			within_xml=1
		fi

		cr=$(printf '\r')
		if [ "$line" = "$cr" ]; then
			>$LICFILEPATH.data || :
		fi
	done
	IFS=$old_IFS

	if [ $response_code -ne 200 ]; then
		content=$(cat $LICFILEPATH.data || :)
		if [ -z "$content" ]; then
			error "Bad response received from the Axis web service(2) $response"
			__error 28 $pack
		fi
		information "Failed to retrieve license key: $content"
		err=${content%%:*}
		if [ "$(echo $err | tr -d [0-9])" ] ||
			[ $err -le 0 ] || \
			[ $err -gt 10 ]; then
			error "Failed to parse error code r=\"$response\""
			error "Failed to parse error code c=\"$content\""
			error "Failed to parse error code e=\"$err\""
			err=28
		fi
		__error $err $pack
	fi

	chmod 644 $LICFILEPATH || {
		error "Failed to set permissions on created license file"
		__error 28 $pack
	}

	__install_license_key $pack $LICFILEPATH
	result_code=$?
	rm -f $LICFILEPATH
	[ $result_code -eq 0 ] || __error "$result_code" $pack

	__send_action_resp $action "" $pack
}

__is_lua_application() {
	# Arguments
	# $1=<appname>
	local packdir

	[ $# -eq 1 ] || {
		echo "__is_lua_application: wrong number of arguments"
		return 1
	}

	[ "$1" ] || {
		echo "__is_lua_application: illegal argument"
		return 1
	}

	packdir="$PACKAGE_DIRECTORY/$1"

	[ -r "$packdir/$ADPPACKCFG" ] || {
		echo "__is_lua_application: missing package"
		return 1
	}

	. "$packdir/$ADPPACKCFG" || {
		echo "__is_lua_application: failed to read package"
		return 1
	}

	[ "$APPTYPE" ] || {
		echo "__is_lua_application: missing APPTYPE in package"
		return 1
	}

	[ "$APPTYPE" = lua ]
}


__get_application_status() {

	local dbus_resp= app_status= running_file

	if [ "$APPTYPE" = lua ]; then
		if [ "$LUASTANDALONE" = yes ]; then
			running_file=$PACKAGE_DIRECTORY/${APPNAME%.*}/is_running
			app_status=Stopped
			if [ -f $running_file ]; then
				read app_status 2>/dev/null <$running_file ||
					warning "Failed to read $running_file"
			fi
			if [ "$app_status" = "Not Running" ]; then
				app_status=Stopped
			fi
			unset LUASTANDALONE
		else
			dbus_resp=$($DBUS_REQ_GET_APP_STATUS string:$PACKAGE_DIRECTORY/${APPNAME%.*}/$APPNAME 2>/dev/null)
			dbus_resp=${dbus_resp#*string \"}
			dbus_resp=${dbus_resp%\"}
			case $dbus_resp in
				Running|Idle)
					app_status=$dbus_resp
					;
				*)
					app_status=Stopped
					;
			esac
		fi
		APPNAME=${APPNAME%.*}
	else
		if [ "$(pidof $APPNAME)" ]; then
			app_status=Running
		else
			app_status=Stopped
		fi
	fi

	eval $1=\$app_status
}

__adp_package_status() {
	local status= res= pack=

	pack=$1
	packdir="$PACKAGE_DIRECTORY/$pack"

	if [ -r "$packdir/$ADPPACKCFG" ]; then
	    . "$packdir/$ADPPACKCFG" || :
	    __get_application_status status
	else
	    res=4
	fi

	__pkgconf_unset

	printf "$status"
	exit $res
}

__licinfo_from_file() {
	local licensefile=$1 licstatus=Missing licdate= tag= ret=0

	if [ ! -f "$licensefile" ]; then
		licstatus=Missing
	elif [ ! -s "$licensefile" ]; then
		licstatus=Invalid
	elif [ -r "$licensefile" ]; then
		licstatus=$(licensekey_cli -a $APPNAME -i $APPID -m $APPMAJORVERSION -n $APPMINORVERSION) || {
		    warning "__licinfo_from_file: License verification check for $APPNAME failed."
		    return 1
		}
		tag=ExpirationDate
		while read line; do
			case $line in
				*$tag*)
					licdate=${line#<$tag>}
					licdate=${licdate%</$tag*}
					[ "$licdate" != 0 ] || licdate=
					break
					;
			esac
		done <"$licensefile"
	fi

	eval $2=\$licstatus
	eval $3=\$licdate
}

__get_license_status() {

	local license_file=$1 lic_status= lic_date=


	case $LICENSEPAGE in
		[Aa][Xx][Ii][Ss])
			__licinfo_from_file $license_file lic_status lic_date || return 1
			;
		[Cc][Uu][Ss][Tt][Oo][Mm])
			if [ "$LICENSE_CHECK_ARGS" ]; then
				lic_status=$($PACKAGE_DIRECTORY/$APPNAME/$APPNAME $LICENSE_CHECK_ARGS)
			else
				lic_status=Custom
			fi
			;
		[Nn][Oo][Nn][Ee])
			lic_status=None
			;
		*)
			# Handle faulty set LICENSEPAGE like 'Axis' for legacy reasons
			__licinfo_from_file $license_file lic_status lic_date || return 1
			;
	esac

    eval $2=\$lic_status
    eval $3=\$lic_date
}

__get_license_name() {
	local pack=$1 lic_name= packdir

	packdir=$PACKAGE_DIRECTORY/$pack

	if [ "$LICENSENAME" ]; then
		[ -r $packdir/$LICNAME ] || {
			information "No LICENSE file for $pack"
			return 1
		}
		lic_name=$LICENSENAME
	elif [ -r $packdir/$LICNAME ]; then
		information "No LICENSENAME set, use default value"
		lic_name="Available"
	fi

	eval $2=\$lic_name
}

__get_url_from_link_delim() {
        local delim= url= start= rest=

        url=$1
        delim=$2

        start=${url#*href=$delim}
        [ "$start" != "$url" ] || return 1

        rest=${start#*$delim}
        [ "$rest" != "$start" ] || return 1
        url=${start%$rest}
        url=${url%$delim}

        eval $3=\$url
}

__get_url_from_link() {
        local link=

        __get_url_from_link_delim "$1" "\'" link || {
                __get_url_from_link_delim "$1" "\"" link || {
                        eval $2=""
                        return 1
                }
        }
        eval $2=\$link
}

__list_adp_packages() {
	local listpack p single_app= found_single_app= license_name= license_status=
	local license_exp_date= status= ret_error= vendor_home_page=
	local list_resp error_msg=$ADP_LISTCMD_ERROR_MSG_UNKNOWN

	list_resp=$(mktemp $VAR_RUN_DIR/tmp_resp.XXXXXX) || {
		error_msg=$ADP_LISTCMD_ERROR_MSG_MKTEMP_FILE
		printf ' <error type="%s" message="%s" />\r\n' "$ADP_LISTCMD_ERROR_TYPE" "$error_msg"
		rm -f $list_resp
		exit 99
	}

	# Make sure that the package directory exists and list the name of the
	# subdirectories of the PACKAGE_DIRECTORY.
	if [ -d $PACKAGE_DIRECTORY ]; then
		cd $PACKAGE_DIRECTORY
		[ $# -ne 1 ] || single_app=$1

		listpack=$(echo *)
		[ "$listpack" != '*' ] || listpack=

		if [ $single_app ]; then
			for p in $listpack; do
				if [ "$p" = "$single_app" ]; then
					found_single_app=true
					listpack=$single_app
					break
				fi
			done
			[ "$found_single_app" = true ] || {
				rm -f $list_resp
				exit 0
			}
		fi

		for p in $listpack; do
			if [ -r $p/$ADPPACKCFG ]; then

				if ! __source_if_sourceable "$p/$ADPPACKCFG" ; then
					ret_error=yes
					error_msg=$ADP_LISTCMD_ERROR_MSG_CONFIG
					break
				fi

				__get_application_status status || {
					ret_error=yes
					error_msg=$ADP_LISTCMD_ERROR_MSG_STATUS
					break
				}

				__get_license_status "$p/$LICFILENAME" license_status license_exp_date || {
					ret_error=yes
					error_msg=$ADP_LISTCMD_ERROR_MSG_LICENSE_STATUS
					break
				}

				__get_license_name "$p" license_name || {
					ret_error=yes
					error_msg=$ADP_LISTCMD_ERROR_MSG_LICENSE_NAME
					break
				}

				[ -z "$VENDORHOMEPAGELINK" ] || __get_url_from_link "$VENDORHOMEPAGELINK" vendor_home_page || :

				printf ' <application Name="%s"' "$APPNAME" >> $list_resp
				[ -z "$PACKAGENAME" ]      || printf ' NiceName="%s"' "$PACKAGENAME" >> $list_resp
				[ -z "$VENDOR" ]           || printf ' Vendor="%s"' "$VENDOR" >> $list_resp
				[ -z "$APPMAJORVERSION" ]  || [ -z "$APPMINORVERSION" ]  || {
					if [ "$APPMICROVERSION" ]; then
						printf ' Version="%s"' "$APPMAJORVERSION.${APPMINORVERSION}-$APPMICROVERSION" >> $list_resp
					else
						printf ' Version="%s"' "$APPMAJORVERSION.$APPMINORVERSION" >> $list_resp
					fi
                                }
				[ -z "$APPID" ]            || printf ' ApplicationID="%s"' "$APPID" >> $list_resp
				[ -z "$license_status" ]   || printf ' License="%s"' "$license_status" >> $list_resp
				[ -z "$license_exp_date" ] || printf ' LicenseExpirationDate="%s"' "$license_exp_date" >> $list_resp
				[ -z "$status" ]           || printf ' Status="%s"' "$status" >> $list_resp
				[ -z "$SETTINGSPAGEFILE" ] || printf ' ConfigurationPage="%s"' "local/$p/$SETTINGSPAGEFILE" >> $list_resp
				[ ! -r "usr/html/local/$p/index.html" ] || printf ' MainPage="%s"' "local/$p/index.html" >> $list_resp
				[ -z "$vendor_home_page" ] || printf ' VendorHomePage="%s"' "$vendor_home_page" >> $list_resp
				[ -z "$VALIDATIONURI" ]    || printf ' ValidationResult="%s"' "$VALIDATIONURI" >> $list_resp
				[ -z "$license_name" ]     || printf ' LicenseName="%s"' "$license_name" >> $list_resp
				printf ' />\n' >> $list_resp

				APPNAME= PACKAGENAME= VENDOR= APPMAJORVERSION= APPMINORVERSION= APPMICROVERSION= APPID= license_status=
				license_exp_date= status= SETTINGSPAGEFILE= VALIDATIONURI= tag= ret_error= APPTYPE= LICENSENAME= license_name=
			fi
		done
	fi

	#__cgi_hdgen yes text/xml

	if [ "$ret_error" ]; then

		[ "$APPNAME" ] || {
			[ "$p" ] && APPNAME=$p || APPNAME=error
		}
		printf ' <error type="%s" message="%s %s" />\r\n' "$ADP_LISTCMD_ERROR_TYPE" "$APPNAME:" "$error_msg"
		rm -f $list_resp
		exit 99
	else
		while read line ; do
			printf ' %s\r\n' "$line"
		done <"$list_resp"
	fi

	rm -f $list_resp
	exit 0
}

__pkgconf2stdout() {
	local _pkg=$1

	tar -Oxf "$_pkg" $ADPPACKCFG || {
		error "Failed to extract $ADPPACKCFG from $_pkg"
		return 1
	}
}

__pkgconf_get_var(){
	local _pkg=$1 _var=$2 _sedexpr=

	eval _sedexpr='/$_var=/!d'
	_var=$(tar -Oxf "$_pkg" $ADPPACKCFG | sed "$_sedexpr" ) || {
		warning "Failed to get variable $_var from $_pkg"
		return 1
	}

	eval $_var
	[ "$2" != APPNAME ] || APPNAME=${APPNAME%.xml}
}

__pkgconf_source(){
	local _pkg=$1

	# test if package.conf is sourceable
	eval $(tar -Oxf "$_pkg" package.conf) || {
		error "Malformed $ADPPACKCFG in $_pkg"
		return 1
	}
}

__unpack_eap() {
	local _eap=$1 _dest=$2

	[ -d "$_dest" ] || mkdir -p "$_dest"
	[ -d "$_dest" ] || {
		error "failed to create directory: $_dest"
		return 1
	}

	tar zxf $_eap -C "$_dest" || {
		error "Failed to extract $_eap -> $_dest"
		return 1
	}

	chmod 775 "$_dest" 2>&1 || {
		rm -fr "$_dest"
		error "$_eap : Failed to 'chmod 775' on directory: $_dest"
		return 1
	}
}

__is_sourceable() {
	local file=$1
	if $(. "$file" 2>/dev/null) ; then
		return 0
	else
		return 1
	fi
}

__source_if_sourceable() {
	local file=$1
	if ! __is_sourceable "$file" ; then
		[ "$2" = quiet ] || warning "Could not source (1) $file"
		return 1
	fi

	. "$file"
	return 0
}

__pkgconf_compare_versions() {
	local _first= _second= _first_u= _second_u=

	[ $# -eq 6 ] && [ "$1" ] && [ "$2" ] && [ "$3" ] && [ "$4" ] && [ "$5" ] && [ "$6" ] ||
		error "Missing or empty argument(s) for __pkgconf_compare_versions"

	# check that micro tags are numerics
	_first_u=$3
	_second_u=$6
	case $3 in
		*[!0-9]*)
			_first_u=0
			;
	esac
	case $6 in
		*[!0-9]*)
			_second_u=0
			;
	esac

	_first=$(($(($1 << 32)) + $(($2 << 16)) + $_first_u))
	_second=$(($(($4 << 32)) + $(($5 << 16)) + $_second_u))

	[ $_first -le $_second ] || return 1
}