#!/bin/bash

PP_AGENT_BIN_PATH=/opt/vzagent/bin
PP_CONFIG_DIR=/etc/opt/pva/pp
PP_DATA_DIR=/var/opt/pva/pp
PP_INSTALL_DIR=/opt/pva/pp
PP_SERVICE=/etc/rc.d/init.d/pvapp
pvappcon=$PP_INSTALL_DIR/libexec/pvappcon
xsldir=$PP_DATA_DIR/xsl

if [ -e /etc/SuSE-release ]; then 
	HTTPD_CONF=/etc/apache2/httpd.conf
	HTTPD_CONFD=/etc/apache2/vhosts.d
	SSL_CERT_ROOT=/etc/apache2
	HTTPD=rcapache2
else 
	HTTPD_CONF=/etc/httpd/conf/httpd.conf
	HTTPD_CONFD=/etc/httpd/conf.d
	SSL_CERT_ROOT=/etc/httpd/conf
	HTTPD=/etc/init.d/httpd
fi
HTTPD_PP_CONF_PREFIX=$HTTPD_CONFD/z.pva.pp
HTTPD_PP_CONF=$HTTPD_PP_CONF_PREFIX.10.conf
HTTPD_SSL_CONF=$HTTPD_CONFD/ssl.conf


PP_VE_PRIVATE=$PP_DATA_DIR/sve/
PP_VEID=1


function generate_ssl_certificate() {
	if [ ! -e $SSL_CERT_ROOT/ssl.crt/server.crt -o ! -e $SSL_CERT_ROOT/ssl.key/server.crt ]; then
	(
		echo ""
		echo "# Generating SSL certificates"

		pushd /tmp
		openssl req -new -batch -out server.csr -passout pass:1q2w3e -subj "/CN=`hostname -f`/O=Parallels, Inc./OU=Herndon/emailAddress=info@parallels.com/L=Herndon/C=US/ST=VA/STREET=13755 Sunrise Valley Drive Suite 600" || abort $? "openssl req call failed"
		openssl rsa -in privkey.pem -out server.key -passin pass:1q2w3e || abort $? "openssl rsa call failed"
		openssl x509 -in server.csr -out server.crt -req -signkey server.key -days 365  -passin pass:1q2w3e || abort $? "openssl x509 call failed"
	
		rm privkey.pem
		rm server.csr

		mkdir -p $SSL_CERT_ROOT/ssl.crt || abort $? "'mkdir -p $SSL_CERT_ROOT/ssl.crt' failed"
		mkdir -p $SSL_CERT_ROOT/ssl.key || abort $? "'mkdir -p $SSL_CERT_ROOT/ssl.key' failed"

		mv -f server.key $SSL_CERT_ROOT/ssl.key || abort $? "'mv -f server.key $SSL_CERT_ROOT/ssl.key' failed"
		mv -f server.crt $SSL_CERT_ROOT/ssl.crt || abort $? "'mv -f server.crt $SSL_CERT_ROOT/ssl.crt' failed"

		popd
	) || abort $? "Failed to generate SSL certificate"
	fi
}


# Echo error
function error()
{
	echo "[ERROR] " $* >&2
}

function abort() {
	code=$1
	shift 1
	echo "[ERROR $code] " $* >&2
	exit $code
}

function store_old_config(){
	echo "# Locating old configuration file..."
	if [ -e /etc/vz/vz.conf ]; then
		( 
			set -e
			VEID=1
			. /etc/vz/vz.conf
			if [ -e $VE_ROOT/etc/vzcp/vzcpcon.conf ]; then
				echo "VZCP 4.0 config file found at $VE_ROOT/etc/vzcp/vzcpcon.conf"
				cp $VE_ROOT/etc/vzcp/vzcpcon.conf /tmp/pvapp.conf.old 
			elif [ -e /etc/opt/pva/pp/pvapp.conf ]; then
				echo "PVA Power Panel config file found at /etc/opt/pva/pp/pvapp.conf"
				cp /etc/opt/pva/pp/pvapp.conf /tmp/pvapp.conf.old 
			else
				echo "Old config in not found."
				return 1
			fi
		)
	elif [ -e /etc/opt/pva/pp/pvapp.conf ]; then
		echo "PVA Power Panel config file found at /etc/opt/pva/pp/pvapp.conf"
		cp /etc/opt/pva/pp/pvapp.conf /tmp/pvapp.conf.old 
	else
		echo "Old config in not found."
		return 1
	fi
}

function import_config() {
	old_config="$1"

	echo "# Trying to import old configuration file"

	if [ -z "${old_config}" ]; then
		old_config=/tmp/pvapp.conf.old 
	fi
	if [ ! -e "${old_config}" ]; then
		echo "Old configuration file was not found at ${old_config}"
		return 1
	fi
	echo "Importing existing configuration file ${old_config}"
	cp $old_config ${PP_CONFIG_DIR}/pvapp.conf.old
	pushd ${PP_CONFIG_DIR}
	$pvappcon -n -f ${PP_CONFIG_DIR}/pvapp.conf -x ${xsldir}/utils/merge-configs.xsl ${old_config}
	if [ $? -ne 0 ]; then
		popd
		error "Failed to merge configuration files using $pvappcon utility." 
		return 1
	else
		popd
		# XXX: vap@ hardcoded pvacc.conf.merged to be the output of merge-configs.xsl
		mv ${PP_CONFIG_DIR}/pvacc.conf.merged ${PP_CONFIG_DIR}/pvapp.conf 
	fi
}

function disablePort80OnBaremetal() {
	if [ -e /etc/redhat-release ]; then
		if [ ! -z "`cat /etc/redhat-release | grep Parallels`" ]; then
			echo "# Disabling default httpd listener on port 80"
			cp $HTTPD_CONF $HTTPD_CONF.old
			cat $HTTPD_CONF.old | sed -e 's/Listen 80/#Listen 80/' > $HTTPD_CONF
		fi
	fi
}

function hideApacheVer() {
	echo "Setting ServerTokens ProductOnly"
	cp $HTTPD_CONF $HTTPD_CONF.old
	cat $HTTPD_CONF.old | sed -e 's/ServerTokens .*/ServerTokens ProductOnly/' > $HTTPD_CONF
}

function fix413CSS() {
	echo "Fix 413 Error HTTP Request Method Cross-Site Scripting"
	cp $HTTPD_CONF $HTTPD_CONF.old
	cat $HTTPD_CONF.old | sed -e 's/#    ErrorDocument 413 \/error\/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var/ErrorDocument 413 "\&quot;Error 413 - Request Entity Too Large\&quot;"/' > $HTTPD_CONF
}

function disableSSLVhost() {
	echo "# Disabling SSL VirtualHost record"
	if [ -e /etc/SuSE-release ]; then
		rm -f /etc/apache2/vhosts.d/vhost-ssl.conf
	else
		cp $HTTPD_SSL_CONF $HTTPD_SSL_CONF.old
		cat $HTTPD_SSL_CONF.old | awk 'BEGIN{matches=0;}{if (match($0, "^[[:space:]]*<VirtualHost.+:443\\s*>")) {matches = 1;}if (matches != 0) {print "#", $0;} else {print;}if (match($0, "^[[:space:]]*</VirtualHost>")) {matches = 0;}}' > $HTTPD_SSL_CONF
	fi
}

function disableSSL() {
	echo "# Disabling SSL"
	if [ -e /etc/SuSE-release ]; then
		yast2 http-server modules disable="ssl"
	else
		cp $HTTPD_PP_CONF $HTTPD_PP_CONF.old
		cat $HTTPD_PP_CONF.old | awk 'BEGIN{matches=0;}{if (match($0, "^[[:space:]]<IfModule mod_ssl.c>*")) {matches = 1;}if (matches != 0) {print "#", $0;} else {print;}if (match($0, "^[[:space:]]*</IfModule>")) {matches = 0;}}' > $HTTPD_PP_CONF
	fi
}

function enableSSL() {
	echo "# Enabling SSL"
	if [ -e /etc/SuSE-release ]; then
		yast2 http-server modules enable="ssl"
	else 
		cp $HTTPD_PP_CONF $HTTPD_PP_CONF.old
		cat $HTTPD_PP_CONF.old | awk 'BEGIN{matches=0;}{if (match($0, "^#[[:space:]]*<IfModule mod_ssl.c>\\s*")) {matches = 1;}if (matches != 0) {print substr($0, 2);} else {print;}if (match($0, "^#[[:space:]]*</IfModule>")) {matches = 0;}}' > $HTTPD_PP_CONF
	fi
}

function registerService() {
	if [ -e /etc/init.d ]; then
		echo "#Registering pvapp service"
		[ -e /etc/init.d/pvapp ] || ln -sf $PP_SERVICE /etc/init.d/pvapp
		[ -e /sbin/chkconfig ] && /sbin/chkconfig --add pvapp && /sbin/chkconfig pvapp on
	fi
}

function unregisterService() {
	echo "#Unregistering pvapp service"
	if [ -e /sbin/chkconfig ]; then 
		/sbin/chkconfig --list pvapp 1>/dev/null 2>&1 && /sbin/chkconfig --del pvapp
	fi
	if [ -h /etc/init.d/pvapp ]; then
		rm -f /etc/init.d/pvapp
	fi
}

# same function is used for postupgrade, too.
function postinstall() {
	/sbin/ldconfig
	
	echo "# Stopping $HTTPD"
	$HTTPD stop

	if [ -e /etc/SuSE-release ]; then
		a2enmod headers
		a2enmod rewrite
		groupadd apache
		groupmod -A wwwrun apache
		chgrp -R apache $PP_DATA_DIR
	fi

	sed "s#\$\$ssl_cert_root#${SSL_CERT_ROOT}#" < /etc/opt/pva/pp/plugins/httpd/include.ssl.conf > /tmp/include.ssl.conf
	mv /tmp/include.ssl.conf /etc/opt/pva/pp/plugins/httpd/include.ssl.conf

	generate_ssl_certificate || abort $? "Failed to generate SSL certificate"

	import_config

	disablePort80OnBaremetal || abort $? "Failed to disable default listener on port 80"

	hideApacheVer || abort $? "Failed to set ServerTokens"
	fix413CSS || abort $? "Failed to Fix 413 Error HTTP Request Method Cross-Site Scripting"
	
	disableSSLVhost || abort $? "Failed to disable default mod_ssl VirtualHost"

	registerService

	echo "# Configurating $PP_SERVICE"
	$PP_SERVICE reconfigure || abort $? "Failed to configure $PP_SERVICE service"

	if [ "$1" == "--nossl" ]
	then
		disableSSL || abort $? "Failed to disable SSL"
	else
		enableSSL || abort $? "Failed to enable SSL"
	fi

	if [ -e /etc/SuSE-release ]; then
		# rm -f ${HTTPD_CONFD}/yast2_vhosts.conf TODO - check if this is required
		yast2 http-server modules enable="rewrite,proxy,proxy_connect,proxy_http"
	fi
	
	echo "# Starting $PP_SERVICE"
	$PP_SERVICE start || abort $? "Failed to start $PP_SERVICE service"
}

function postuninstall() {
	rm -f $HTTPD_PP_CONF_PREFIX.*
	rm -f $HTTPD_CONFD/0.pp.conf
	rm -f $HTTPD_CONFD/pva.soap.conf
	if [ ! -e /tmp/no-pva-httpd ]; then 
	    $HTTPD start
	else
	    rm /tmp/no-pva-httpd
	fi
	rm -rf $PP_CONFIG_DIR
	rm -rf $PP_DATA_DIR
	rm -rf $PP_INSTALL_DIR
}

function preinstall() {
	vzlist 1 && abort 1 "Container with CTID 1 already exists, please remove it or change CTID and launch PVA installation again"
	store_old_config || echo ""

	echo "# Removing old httpd configuration files..."
	rm -f /$HTTPD_CONFD/{vzcp*,pim*,plesk,pva*,$HTTPD_PP_CONF_PREFIX.*}.conf

	rpm -q --qf "%{release}" httpd | grep centos4
	if [ $? -eq 0 ]; then
		echo "# Removing unsupported httpd packages"
		rpm -e httpd httpd-suexec
	fi
}

function preupgrade() {
	if [ -e $PP_SERVICE ]; then
	    echo "Stopping $PP_SERVICE..."
	    $PP_SERVICE stop
	fi
	$HTTPD stop

	echo "# Removing old httpd configuration files..."
	rm -f /$HTTPD_CONFD/{vzcp*,pim*,plesk,pva*,$HTTPD_PP_CONF_PREFIX.*}.conf

	store_old_config || abort $? "Failed to locate old config file"
	unregisterService
}

function preuninstall() {
	$HTTPD status || touch /tmp/no-pva-httpd

	if [ -e $PP_SERVICE ]; then
	    echo "# Stopping $PP_SERVICE service..."
	    $PP_SERVICE stop
	fi
	$HTTPD stop
	unregisterService
}

function auto_assign_sve_address()
{
	local addr=""
	while /bin/true; do
		let "i=($RANDOM%250)+2"
		let "j=($RANDOM%250)+2"
		addr="192.168.$i.$j"
		ip addr show | grep -q $addr
		[ $? -eq 0 ] || break
	done
	echo $addr
}

