#!/bin/bash

export LANG=en_US.UTF-8

PPA_VERSION="PPA_11.1.0"
PRODUCT_NAME="Parallels Plesk Automation"
BASE_REPOSITORY_URL="http://autoinstall.plesk.com/$PPA_VERSION/"
SUPPORTED_OS='\(CentOS-5.*-.*\|RedHat.*-5.*-.*\)'
SUPPORTED_LANG="en_US de_DE fr_FR es_ES ru_RU zh_TW it_IT ja_JP nl_NL zh_CN pt_BR"
DEFAULT_LANG="en_US"
I18N_LOCALE_FILE="/etc/sysconfig/i18n"

PWD_PATH=`pwd`
PPA_PATH="/usr/local/ppa"
PPA_LOG_DIR="$PPA_PATH/log"
PPA_TMP_DIR="$PPA_PATH/tmp"
PPA_BIN_DIR="$PPA_PATH/bin"
PPA_DOWNLOAD_DIR="$PPA_TMP_DIR/build"
PPA_INSTALLATION_STEPS_DIR="$PPA_TMP_DIR/install"
PPA_INSTALLATION_LOG="/tmp/ppa_install.log"

AI_BUILD="$PPA_DOWNLOAD_DIR/ai"
AI_PATH="$AI_BUILD/autoinstaller"
UI_CHANGES_DIR="$PPA_DOWNLOAD_DIR/ui_changes"
WIN32_FILES_DIR="$PPA_DOWNLOAD_DIR/win32"
INIT_D="/etc/init.d"

YUM_UTIL="yum"
WGET_UTIL="wget"
WGET_PARAMS="-nHv -l 100"
CURL_UTIL="curl"
SELINUX_UTIL="getenforce"

###POA section
POA_BUILD="$PPA_DOWNLOAD_DIR/poa"
POA_ROOT_PATH="/usr/local/pem"
POA_SW_CONFIG=/etc/sw-cp-server/applications.d/msp.conf
POA_UI_PATH="$POA_ROOT_PATH/ui"
POSTGRESQL_DEFAULT_PORT=5432
POSTGRESQL_DB_DATA="/var/lib/pgsql/9.0/data"

###Plesk section
PLESK_ROOT_PATH="/usr/local/psa"
VHOST_SKELETON_DIR="$PPA_DOWNLOAD_DIR/skeleton"
AI_VERSION="latest"
PLESK_REPOSITORY="${BASE_REPOSITORY_URL}Plesk"
#PLESK_COMPONENTS="common psa-autoinstaller sitebuilder postfix proftpd web-hosting horde webalizer atmail awstats phpgroup mod_fcgid mod_perl mod_python mod-bw drweb spamassassin"
PLESK_COMPONENTS="common psa-autoinstaller sitebuilder postfix proftpd web-hosting horde webalizer atmail awstats phpgroup mod_fcgid mod_perl mod_python apache-sni"
PLESK_PANEL_CONFIG="$PLESK_ROOT_PATH/admin/conf/panel.ini"
PLESK_VHOST="/var/www/vhosts/"

###APSMail section
APS_MAIL_PACKAGE_URL="$BASE_REPOSITORY_URL/APS"
APS_MAIL_PACKAGE_NAME="RemotePostfix-0.2-4.zip"
APS_DIR='APS'

###PPA section
PPA_ROOT_PATH="/usr/local/ppa"
# PPA_SESSION_TTL measured in minutes
PPA_SESSION_TTL=120
DNS_RESTART_INTERVAL=10

DNS_RESOURCE_NAME="DNS"
DNS_RESOURCE_CLASS="DNS Hosting"
BRANDING_HOSTING_RESOURCE_NAME="Branding Hosting"
BRANDING_HOSTING_RESOURCE_CLASS="pleskweb_hosting"
BRANDING_RESOURCE_TYPES=();
BRANDING_RESOURCE_TYPES_LIMITS=();
BRANDING_NONROOT_RESOURCE_TYPES=();
BRANDING_NONROOT_RESOURCE_TYPES_LIMITS=();
HOSTING_ACTIVATION_PARAMETERS_NAMES=();
HOSTING_ACTIVATION_PARAMETERS_VALUES=();
LOCAL_NODE_ATTRIBUTE="Management Node"

APACHE_ROLE_CODE="PPA_APACHE"
BACKUP_ROLE_CODE="PPA_BACKUP"
POSTFIX_ROLE_CODE="PPA_POSTFIX"
IIS_ROLE_CODE="PPA_IIS"
DNS_ROLE_CODE="PPA_DNS"
APACHE_POSTFIX_ROLE_CODE="PPA_APACHE_POSTFIX"
APACHE_POSTFIX_DNS_ROLE_CODE="PPA_APACHE_POSTFIX_DNS"
APACHE_DNS_ROLE_CODE="PPA_APACHE_DNS"
POSTFIX_DNS_ROLE_CODE="PPA_POSTFIX_DNS"
HSPHERE_APACHE_ROLE_CODE="PPA_HS_APACHE"
MYSQL_ROLE_CODE="PPA_MYSQL"
POSTGRESQL_ROLE_CODE="PPA_POSTGRESQL"
APACHE_MYSQL_ROLE_CODE="PPA_APACHE_MYSQL"
APACHE_POSTGRESQL_ROLE_CODE="PPA_APACHE_POSTGRESQL"

ADMIN_CONTACT_INFO_COUNTRY="US"
ADMIN_CONTACT_INFO_STATE="Alaska"
ADMIN_CONTACT_INFO_CITY="Willow"
ADMIN_CONTACT_INFO_COMPANY="Neverhood"
ADMIN_CONTACT_INFO_ZIP="99688"

MN_IP=`/sbin/ifconfig | sed -n "/^[A-Za-z0-9]/ {N;/dr:/{;s/.*dr://;s/ .*//;p;}}" | grep -v "127.0.0.1"`
MN_IP_BY_HOSTNAME=`hostname -i`
MN_HOSTNAME=`hostname -f`

MN_ALLOWED_USERS="root pemuser"

logError()
{
    local msg=`echo $* | sed "s/$password/********/"`
    echo "["`date +"%c"`"][ERROR]" "$msg" | tee -a $PPA_INSTALLATION_LOG
    exit 1;
}

logInfo()
{
    local msg=$1;
    local not_log_to_stdout=$2;

    msg=`echo "$msg" | sed "s/$password/********/"`

    if [ X"$not_log_to_stdout" = "X" ]; then
        echo "["`date +"%c"`"][INFO]" "$msg" | tee -a $PPA_INSTALLATION_LOG
    else
        echo "["`date +"%c"`"][INFO]" "$msg" >> $PPA_INSTALLATION_LOG
    fi;

}

init()
{
    mkdir -p $PPA_LOG_DIR
    mkdir -p $PPA_TMP_DIR
    mkdir -p $PPA_DOWNLOAD_DIR
    mkdir -p $PPA_INSTALLATION_STEPS_DIR

    touch $PPA_INSTALLATION_LOG

    chmod 700 $PPA_LOG_DIR
    chmod 600 $PPA_INSTALLATION_LOG
}

isRootPrivileges()
{
    if [ `id -u` -ne 0 ]; then
        echo "You should have superuser privileges to install $PRODUCT_NAME"
        exit 1;
    fi
}

checkRequirements()
{
    checkHostname;
    checkOs;
    checkYUM;
    checkSystemTools;
    checkSystemLocale;
    checkSelinux;
    checkDiskSpace;
    checkHttpd;
    checkIsUpgrade;
}

checkOs()
{
    logInfo "Checking requirements...";

    osArch=$(uname -m)
    if [ "$osArch" != "x86_64" -a "${SKIP_ARCH_CHECK}x" = "x" ]; then
        logError "This operating system architecture '$osArch' is not supported. $PRODUCT_NAME can be installed on x86_64 OS only."
    fi;

    lsb_release_path=$(which lsb_release 2> /dev/null)
    if [ "${lsb_release_path}x" != "x" ]; then
        osName=$(${lsb_release_path} -i | cut -d ':' -f2 | sed 's/\t *//g')
        osVersion=$(${lsb_release_path} -r | cut -d ':' -f2 | sed 's/\t *//g')
    elif [ -f /etc/redhat-release ]; then
        if [ "$(cat /etc/redhat-release | grep -i 'Red Hat')x" != "x" ]; then
            osName='RedHat'
        else
            osName=$(cat /etc/redhat-release | cut -d ' ' -f1)
        fi
        osVersion=$(cat /etc/redhat-release | sed 's/.*release\ //' | sed 's/\ .*//' )
    else
        logError "This operating system is not supported. $PRODUCT_NAME can be installed to 'RedHat / CentOS 5.x' only."
    fi

    local os="$osName-$osVersion-$osArch";

    if echo $os|grep -e $SUPPORTED_OS>/dev/null; then
        logInfo "OS: $os";
    else
        logError "This operating system '$os' is not supported. $PRODUCT_NAME can be installed to 'RedHat / CentOS 5.x' only."
    fi;
}

checkSelinux()
{
    logInfo "Checking that SELinux is switched off..."

    local selinux=`$SELINUX_UTIL 2>/dev/null`
    local selinuxConfigurationFile="/etc/selinux/config";

    if [ -z "${selinux}" ]; then
        selinux=$(awk -F= '/^SELINUX=/{print $2; exit}' 2>/dev/null < ${selinuxConfigurationFile})
    fi

    if [ "$selinux" = "Enforcing" ]; then
        runCmd "setenforce 0" "Turn off SELinux policy" "Unable to turn off SELinux policy"
        if  [ -f ${selinuxConfigurationFile} ]; then
            runCmd "sed -i.original -e s/^\\s*SELINUX\\s*=\\s*\\S\\+\\s*$/SELINUX=disabled/g ${selinuxConfigurationFile}" "Disable selinux in config" "Unable to disable selinux in config";
        fi;
    fi;
}

checkDiskSpace()
{
    logInfo "Checking free disk space...";

    #
    # All sizes are in megabytes

    local DIST_SIZE=2048;
    local INSTALLED_SIZE=2560;
    local TOTAL_SIZE=$((DIST_SIZE + INSTALLED_SIZE))

    local INSTALL_DIR=/usr/local;
    local DOWNLOAD_DIR=$POA_BUILD;
    [ -z "$DOWNLOAD_DIR" ] && DOWNLOAD_DIR=$(pwd)
    [ -d "$DOWNLOAD_DIR" ] || mkdir -p $DOWNLOAD_DIR

    declare local download_dir_free_space
    declare local download_fs

    eval $(df --portability --block-size=1M $DOWNLOAD_DIR | awk '/\// { printf "download_fs=%s; download_dir_free_space=%s\n", $1, $4; exit }');

    if [ $download_dir_free_space -lt $DIST_SIZE ]; then
        logError "Unable to download $PRODUCT_NAME installation packages: Not enough free disk space on $(readlink -f $DOWNLOAD_DIR) (${download_fs}) (${download_dir_free_space}MB). ${DIST_SIZE}MB required."
    fi

    declare local install_dir_free_space
    declare local install_fs

    eval $(df --portability --block-size=1M $DOWNLOAD_DIR | awk '/\// { printf "install_fs=%s; install_dir_free_space=%s\n", $1, $4; exit }');

    if [ $install_dir_free_space -lt $INSTALLED_SIZE ]; then
        logError "Unable to install $PRODUCT_NAME: Not enough free disk space on $(readlink -f $INSTALL_DIR) (${install_fs}) (${install_dir_free_space}MB). ${INSTALLED_SIZE}MB required."
    fi

    #
    # Check if $DOWNLOAD_DIR and $INSTALL_DIR are located on same device

    if [ $(df --portability --block-size=1M $DOWNLOAD_DIR $INSTALL_DIR | awk '/\// { print $1 }' | uniq | wc -l) -eq 1 ]; then
        if [ $install_dir_free_space -lt $TOTAL_SIZE ]; then
            logError "Unable to install $PRODUCT_NAME: Not enough free disk space on ${install_fs} (${install_dir_free_space}MB). ${TOTAL_SIZE}MB required."
        fi
    fi
}

checkSystemTools()
{
    local SYSTEM_UTILS="$WGET_UTIL $CURL_UTIL $SELINUX_UTIL"

    logInfo "Checking that required system tools are installed in system..."
    for util in $SYSTEM_UTILS; do
        runCmd "which $util" "Checking $util..." "Unable to find the utility '$util'. Please install it before running $PRODUCT_NAME installation"
        logInfo "'$util' is installed - OK"
    done;
}

checkSystemLocale()
{
    logInfo "Checking system locale..."

    if [ ! -s "$I18N_LOCALE_FILE" ]; then
        logInfo "System locale is not set. Configuring system default as en_US.UTF-8..."

        cat <<EOT > $I18N_LOCALE_FILE
LANG="en_US.UTF-8"
SYSFONT="latarcyrheb-sun16"
EOT
    fi;

    local CURLANG=$LANG
    source $I18N_LOCALE_FILE
    local SYSLANG=$LANG
    LANG=$CURLANG

    local systemLocale=`echo $SYSLANG | awk '{print tolower($0)}'`
    if [ "$systemLocale" != "en_us.utf8" ] && [ "$systemLocale" != "en_us.utf-8" ]; then
        logError "Current system locale '$SYSLANG' is not supported. Please switch system locale to 'en_US.UTF-8' and run installation again"
    fi;
}

checkYUM()
{
    runCmd "which $YUM_UTIL" "Checking YUM..." "YUM package manager is not installed. Please install it and run install"
}

checkHttpd()
{
    logInfo "Checking httpd..."

    if [ ! -f "$INIT_D/httpd" ] && [ ! -f "$INIT_D/apache" ] && [ ! -f "$INIT_D/apache2" ]; then
        runCmd "$YUM_UTIL -y install httpd" "Installing Apache Web Server" "Unable to install Apache Web Server"
        if [ ! -f "$INIT_D/httpd" ] && [ ! -f "$INIT_D/apache" ] && [ ! -f "$INIT_D/apache2" ]; then
            logError "Unable to install Apache Web Server through YUM package manager. Need to make sure that YUM is configured correctly and after that run command '$YUM_UTIL -y install httpd' again."
        fi;
    fi;
}

checkHostname()
{
    if [ ! -n "$MN_HOSTNAME" ]; then
        logError "The hostname is not defined. It should point to IP address '$MN_IP'."
    fi;

    if [ "$MN_HOSTNAME" == "localhost" ] || [ "$MN_HOSTNAME" == "localhost.localdomain" ]; then
        logError "The hostname points to loopback interface '127.0.0.1'. It should point to IP address '$MN_IP'."
    fi;

    if isIP "$MN_HOSTNAME"; then
        logError "The hostname '$MN_HOSTNAME' set in your system does not meet PPA requirements: The hostname must not contain the host's IP address. Please change the hostname and run installation again."
    fi;

    if [ ! -n "$MN_IP_BY_HOSTNAME" ]; then
        logError "Unable to resolve IP address by hostname '$MN_HOSTNAME'. Please check that hostname is defined and points to IP address '$MN_IP'."
    fi;

    local isIpAddressExist=`/sbin/ifconfig -a | grep $MN_IP_BY_HOSTNAME`
    if [ ! -n "$isIpAddressExist" ]; then
        logError "The hostname '$MN_HOSTNAME' points to non-existent IP '$MN_IP_BY_HOSTNAME'. It should point to IP address '$MN_IP'."
    fi;

    if [ "$MN_IP_BY_HOSTNAME" != "$MN_IP" ]; then
        logError "The hostname '$MN_HOSTNAME' points to wrong IP '$MN_IP_BY_HOSTNAME'. It should point to IP address '$MN_IP' that you specified during installation."
    fi;
}

checkRPMS()
{
    local rpms_installed
    for i in `grep rpms_install_nodeps $POA_BUILD/install | sed -n 's/.*\[\(.*\)\].*/\1/p' | tr -d ",'"`; 
    do 
	if rpm -qi --quiet $i
	then  
	    # 'uniq' in case of two installed packages (i386/x86_64)
	    local ins_ver=$(rpm -q $i --queryformat="%{NAME}-%{VERSION}-%{RELEASE}\n" | uniq)
	    local poa_ver=$(ls -1 $POA_BUILD/os/RHEL/5/RPMS/$i-[[:digit:]]*.rpm 2>/dev/null | awk '{ print gensub(".*/(.+)\\.[[:alpha:]].*\\.rpm$", "\\1", ""); }' | tail -n 1)
        
	    [[ -n "$poa_ver" && "$ins_ver" != "$poa_ver" ]] && rpms_installed+="$ins_ver "
	fi
    done

    if [ -n "$rpms_installed" ]; then
        logInfo "The list of packages installed in the system which conflict with $PRODUCT_NAME: $rpms_installed"
        if [ ! -e /usr/bin/yum ]; then
            logError "Unable to resolve conflicts automatically: Yum package manager is not installed. Please install yum or remove conflict packages manually before running $PRODUCT_NAME installation."
        fi;
        #runCmd "/usr/bin/yum -y remove $rpms_installed" "Remove conflict packages" "Unable to remove conflict packages"
    fi

    #
    # POA libwsman1 dependance
    #installThirdPartyForced curl.i386 libidn.i386
}

isx64()
{
    uname -m | grep -i "x86_64" >/dev/null
}

installAdditionalTools()
{
    local packetName="ppa-external-tools"
    local repoFileName="$packetName.repo"
    local repoURL="$BASE_REPOSITORY_URL/external-tools/$repoFileName"
    local repoPath="/etc/yum.repos.d/$repoFileName" 
    local ppaVersionPath="$PPA_ROOT_PATH/version"
    
    step "Installing Additional tools, please wait..."
    local cmd="$WGET_UTIL --quiet $repoURL --output-document=$repoPath"
    runCmd "$cmd" "Downloading $PRODUCT_NAME .repo file" "Unable to download $PRODUCT_NAME .repo file from '$repoURL'"
    
    cmd="$YUM_UTIL -y makecache"
    runCmd "$cmd" "Generating the yum metadata cache" "Unable to generate the yum metadata cache"
    
    cmd="$YUM_UTIL -y install $packetName" 
    runCmd "$cmd" "Installing rpm packages" "Unable to install Additional tools"

}

parseOptions()
{
    login="admin"
    install_billing=1
    pg_port=$POSTGRESQL_DEFAULT_PORT

    while [ "$#" -gt "0" ]
    do
        case $1 in
            -h|--help)
                helpUsage;
                ;;
            --ppa_source)
                shift
                BASE_REPOSITORY_URL=$1
                ;;
            --password)
                shift
                password=$1
                ;;
            --admin_email)
                shift
                admin_email=$1
                ;;
            --poa_source)
                shift
                POA_BUILD=$1
                ;;
            --ip)
                shift
                input_ip=$1
                ;;
            --communication_ip)
                shift
                input_communication_ip=$1
                ;;
            --set_default_lang)
                shift
                DEFAULT_LANG=$1
                ;;
#            --pg_port)
#                shift
#                pg_port=$1
#                ;;
            *)
                ;;
        esac
        shift
    done
}

validateOptions()
{
    if [ ! X"$help" = "X" ]; then
        helpUsage;
    fi;

    if [ X"$password" = "X" ]; then
        echo "Missing an Administrator's password. Try the --help option for more information."
        helpUsage;
    fi;

    if expr match "${password}" '.*'${login}'.*' >/dev/null
    then
        echo "Administrator password can't contain '$login' as a substring"
        helpUsage;
    fi;

    if [ X"$admin_email" = "X" ]; then
        echo "Missing an Administrator's e-mail address. Try the --help option for more information."
        helpUsage;
    fi;

    #Check that option "--ip" is specified in case when we have several IP addresses in the system
    local countIpAddr=`echo $MN_IP | wc -w`;
    if [ $countIpAddr -gt 1 ] && [ X"$input_ip" = "X" ]; then
        logError "Please specify the primary IP address for Management Node. There are several IP addresses in the system and you need to choose one of them. List of IPs:
$MN_IP";
    fi;

    if [ ! X"$input_ip" = "X" ]; then
        local isExistsIPAddress=`/sbin/ifconfig -a | grep $input_ip`
        if [ X"$isExistsIPAddress" = "X" ]; then
            logError "You are specified the wrong IP address '$input_ip'"
        fi;
        MN_IP=$input_ip;
    fi;

    MN_COMMUNICATION_IP=$MN_IP

    if [ ! X"$input_communication_ip" = "X" ]; then
        local isExistsIPAddress=`/sbin/ifconfig -a | grep $input_communication_ip`
        if [ X"$isExistsIPAddress" = "X" ]; then
            logError "You are specified the wrong communication IP address '$input_communication_ip'"
        fi;
        MN_COMMUNICATION_IP=$input_communication_ip;
    fi;

    #checkPostgreSQLPort
    checkPassword $password
    checkEmail $admin_email

    is_valid_lnd_code=0;
	for LANG_CODE in $SUPPORTED_LANG; do
        if [ "$DEFAULT_LANG" = "$LANG_CODE" ]; then
            is_valid_lnd_code=1;
        fi;
	done

	if [ $is_valid_lnd_code -eq 0 ]; then
        logError "You are specified the wrong language code '$DEFAULT_LANG'. The list of allowed locales are $SUPPORTED_LANG"
	fi;
}

checkPostgreSQLPort() 
{
    if [ -z "$pg_port" ]; then
        echo "PostgreSQL port is not set. Please, specify port using --pg_port option"
        helpUsage;
    fi;

    local used=`netstat --listening --numeric-ports --tcp | grep -w ":${pg_port}[:space:]*"`
    if [ -n "$used" ] && [ ! -d $POA_ROOT_PATH ]; then
        echo "PostgreSQL port '$pg_port' is already in use. Please, specify another port using --pg_port option"
	helpUsage;
    fi;
}

helpUsage()
{
    echo ""
    echo "Usage: $0 --password <password> --admin_email <email> [--set_default_lang <lang_code> ] [--ip <primary_ip_address> ] [--communication_ip <communication_ip_address> ]"
    echo ""
    echo "Options: "
    echo "--password,           Sets an administrator's password"
    echo "--admin_email,        Sets an administrator's e-mail address"
    echo "--set_default_lang,   Sets the default language. The list of supported languages are '$SUPPORTED_LANG'"
    echo "--ip,                 Sets the main PPA IP address. All users will use this address to log in to PPA. You should explicitly specify this parameter if there is more than one IP address on your server."
    echo "--communication_ip,   (Optional) Sets the communication IP address. The management node will use this address for communicating with service nodes. If there is more than one IP address on your server, we recommend that you use one of them only for node-to-node communication"
    echo "--help,               Displays this help"
    echo ""
    exit 1;
}

runInstallation()
{
    cleanYumCache;
    getAIAndPoaUrlPath;

    download;
    install;
}

runConfiguration()
{
    execOnce "configurePOA";
    execOnce "configurePlesk";
	
	if [ $install_billing -eq 1 ]; then
        execOnce "configureBilling";
    fi
}

cleanYumCache()
{
    runCmd "$YUM_UTIL clean all" "Clean YUM cache" "Unable to clean YUM cache"
}

download()
{
    step "Downloading $PRODUCT_NAME installation packages...";

    execOnce "downloadAI";
    downloadPOA;
    execOnce "downloadWin32Files";
    execOnce "downloadVhostTemplate";
    execOnce "downloadUIChanges";
}

install()
{
    #step "Checking for installed RPM packages...";
    #checkRPMS;

    step "Running $PRODUCT_NAME installation...";
    execOnce "fixPOAdist" libarchive.i386 libarchive.x86_64 expat-1.95.8.i386 expat-1.95.8.x86_64 libacl.i386 libacl.x86_64 acl.x86_64;
    execOnce "installPOA";
    execOnce "installWin32Files";

    isx64 && installThirdParty libarchive
    execOnce "installPlesk";
}

downloadAI()
{
    mkdir -p $AI_BUILD
    rm -f "$AI_PATH" >/dev/null 2>&1

    local cmd="$WGET_UTIL $WGET_PARAMS $aiUrl -O $AI_PATH"
    runCmd "$cmd" "Downloading Parallels installer" "Unable to download Parallels installer from '$aiUrl'"
}

downloadPOA()
{
    if [ -f "$POA_BUILD/install" ]; then
        logInfo "POA installation packages are already downloaded. Skipping the step..."
        return;
    fi;

    if [ -f "$POA_BUILD/$basePOAPath/install" ]; then
        POA_BUILD="$POA_BUILD/$basePOAPath"
        logInfo "POA installation packages are already downloaded. Skipping the step..."
        return;
    fi;

    mkdir -p $POA_BUILD

    local cmd="$WGET_UTIL -r $WGET_PARAMS --cut-dirs=2 --no-parent --reject "index.html*" $poaUrl -P $POA_BUILD"
    runCmd "$cmd" "Downloading POA installation packages" "Unable to download POA installation packages from '$poaUrl'"

    POA_BUILD="$POA_BUILD/$basePOAPath"
}

downloadVhostTemplate()
{
    local vhostTemplateUrl="$BASE_REPOSITORY_URL/skeleton/"

    mkdir -p $VHOST_SKELETON_DIR
    mkdir -p $VHOST_SKELETON_DIR/images

    $WGET_UTIL -r $WGET_PARAMS --reject "index.html*" --cut-dirs=5 --no-parent $vhostTemplateUrl/default/images/ -P $VHOST_SKELETON_DIR
    $WGET_UTIL $WGET_PARAMS --reject "index.html*" --cut-dirs=4 --no-parent $vhostTemplateUrl/default/style.css -P $VHOST_SKELETON_DIR
    $WGET_UTIL $WGET_PARAMS --cut-dirs=4 --no-parent $vhostTemplateUrl/default/index.html -P $VHOST_SKELETON_DIR
}

downloadUIChanges()
{
    local uiChangesUrl="$BASE_REPOSITORY_URL/ui_changes/"

    mkdir -p $UI_CHANGES_DIR

    local cmd="$WGET_UTIL -r $WGET_PARAMS --cut-dirs=3 --no-parent --reject "index.html*" $uiChangesUrl -P $UI_CHANGES_DIR"
    runCmd "$cmd" "Download UI changes" "Unable to download UI changes from '$uiChangesUrl'"
}

downloadWin32Files()
{
    local poaWin32Url="$BASE_REPOSITORY_URL/POA/Win32/"

    local cmd="$WGET_UTIL -r $WGET_PARAMS --cut-dirs=4 --no-parent --reject "index.html*" $poaWin32Url -P $WIN32_FILES_DIR"
    runCmd "$cmd" "Download Win32 POA files..." "Unable to download Win32 POA files from '$poaWin32Url'."
}

# BUGFIX #95248
# NOTE: we doanload and put everything requested into any required dists ignoring arch for simplicity
#       (ex.: x86_64 version will be put into x86 dist)
fixPOAdist()
{
    logInfo "Downloading packages... $*"

    declare -r local THIRDPARTY_URL=$BASE_REPOSITORY_URL/thirdparty/
    declare local pkg_url_list
    declare local REQUIRED_OS_DIST='\(CentOS-5.*-.*\/os\/.*\/5\/RPMS$\|RedHat.*-el5.*-.*\/os\/.*\/5\/RPMS$\)'

    until [ -z "$1" ] 
    do
	local pkg_name=$(expr match "$1" '\(.*\)\..*$')
	local pkg_arch=$(expr match "$1" '.*\.\(.*\)$')

	[ -n "$pkg_name" ] || pkg_name=$1
	[ -n "$pkg_arch" ] ||  
	{
	    isx64 && pkg_arch="x86_64" || pkg_arch="i386" 
	}

	local pkg_rpm=$(curl -s $THIRDPARTY_URL | sed -n 's/.*"\('${pkg_name}'.*'${pkg_arch}'.rpm\)".*/\1/p' | tail -n 1)
	[ -n "$pkg_rpm" ] && pkg_url_list+="${THIRDPARTY_URL}/$pkg_rpm " || logError "Unable to download a package '${pkg_name}.${pkg_arch}' from '${THIRDPARTY_URL}'"
	shift
    done

    if [ -n "$pkg_url_list" ]; 
    then
        logInfo "Required RPM packages:"
	for i in $pkg_url_list; do logInfo "- $i"; done

	for i in $(find $PPA_DOWNLOAD_DIR -type d | grep -e $REQUIRED_OS_DIST); do
	    $WGET_UTIL $pkg_url_list -P $i
	done
    fi
}

installPOA()
{
    #Install package "simplejson"
    rpm -Uhv $BASE_REPOSITORY_URL/thirdparty/python-simplejson-2.0.9-8.el5.i386.rpm --force

    #Backup existing PGSQL default db if present
    if [ -s "$POSTGRESQL_DB_DATA/PG_VERSION" ]; then
        service postgresql-9.0 stop
        logInfo "Backing up existing postgresql DB..."
        ts=`date +%s`
        mv $POSTGRESQL_DB_DATA $POSTGRESQL_DB_DATA.$ts
    fi;

    chmod +x "${POA_BUILD}/install"

    setPOAConfigFile;

    local cmd="python $POA_BUILD/install --config $POA_BUILD/poa_config --batch --reinstall"
    runCmd "$cmd" "Installing POA" "Unable to install POA"

    if [ -f "/etc/hosts.pemsave" ]; then
        mv /etc/hosts.pemsave /etc/hosts
    fi
}

installWin32Files()
{
    cp -r -f ${WIN32_FILES_DIR}/pem/* ${POA_ROOT_PATH}
    chown pemuser:pemgroup ${POA_ROOT_PATH}/install/tarballs/Win32Bin

    local cmd="${POA_ROOT_PATH}/bin/ppm_ctl add pkg ${WIN32_FILES_DIR}/other-Win32-5.2-i386-pleskd-1.2.pdl.asc"
    runCmd "$cmd" "Installing Win32 pleskd package..." "Unable to install Win32 pleskd package."
}

installPlesk()
{
    chmod +x "$AI_PATH"

    runCmd "$AI_PATH --set-feedback-product ppa-mn" "Set option '--set-feedback-product ppa-mn' to report product errors" "Unable to set option '--set-feedback-product ppa-mn' to report product errors"
    runCmd "$AI_PATH --enable-feedback" "Set option '--enable-feedback' to enable reporting product errors" "Unable to set option '--enable-feedback' to enable reporting product errors"

    local aiCmd="$AI_PATH --source $PLESK_REPOSITORY --select-product-id=plesk --select-release-latest --skip-branch-filter"
    if [ $upgrade_mode -eq 1 ]; then
        runCmd "${aiCmd} --upgrade-installed-components --ignore-key-errors" "Upgrading packages..." "Unable to upgrade packages"
    fi;

    #Skip CBM installation if option "no-billing" is not specified
    if [ $install_billing -eq 1 ]; then
        PLESK_COMPONENTS="${PLESK_COMPONENTS} billing"
    fi

    for aiComponent in $PLESK_COMPONENTS; do
        local aiCmd="${aiCmd} --install-component ${aiComponent}"
    done;

    local cmd="$aiCmd"
    runCmd "$cmd" "Installing Plesk" "Unable to install Plesk."
}

checkIsUpgrade()
{
    if [ -f $PPA_ROOT_PATH/version ]; then
        upgrade_mode=0;
    else
        #local installed=$(rpm -qa | grep plesk-billing)
        #if [ -n "$installed" ]; then
        #     logError "Plesk Panel is installed on your system. We don't support yet installation of $PRODUCT_NAME over Plesk Panel. You should install $PRODUCT_NAME to clean node."
        #fi;
        if [ -d $PLESK_ROOT_PATH ]; then
            logError "Plesk Panel is installed on your system. We don't support yet installation of $PRODUCT_NAME over Plesk Panel. You should install $PRODUCT_NAME to clean node."
            upgrade_mode=1;
        else
            upgrade_mode=0;
        fi;
    fi;
}

configurePOA()
{
    configureLibSwKey;
    writePOASWCPServerConfig;
    enablePOAOpenAPIHTTPAuthentification;
    enablePOANotificationEvents;
    updatePOATimeouts;
    setTaskRunnersCount;
    
    service pem restart;
}

writePOASWCPServerConfig()
{
    logInfo "Enabling POA HTTPS...";
    
    echo 'server.modules += ("mod_rewrite", "mod_proxy")' > $POA_SW_CONFIG
    echo '$SERVER["socket"] == ":8443" {' >> $POA_SW_CONFIG
    echo '  url.rewrite-once += (' >> $POA_SW_CONFIG
    echo '      "^/$" => "/servlet/Turbine/",' >> $POA_SW_CONFIG
    echo '      "^/plesk-hosting/$" => "/index.php",' >> $POA_SW_CONFIG
    echo '      "^/plesk-hosting/(.+)$" => "/$1",' >> $POA_SW_CONFIG
    echo '  )' >> $POA_SW_CONFIG
    echo '  $HTTP["url"] =~ "^/(servlet\/|single.html|workspace.html|static\/|pem\/|webgate\/)" {' >> $POA_SW_CONFIG
    echo '      proxy.server = ( "" => ( ( "host" => "127.0.0.1", "port" => 8080 ) ) )' >> $POA_SW_CONFIG
    echo '  }' >> $POA_SW_CONFIG
    echo '}' >> $POA_SW_CONFIG
    echo '$SERVER["socket"] == ":8880" {' >> $POA_SW_CONFIG
    echo '  url.rewrite-once += (' >> $POA_SW_CONFIG
    echo '      "^/plesk-hosting/$" => "/index.php",' >> $POA_SW_CONFIG
    echo '      "^/plesk-hosting/(.+)$" => "/$1",' >> $POA_SW_CONFIG
    echo '  )' >> $POA_SW_CONFIG
    echo '}' >> $POA_SW_CONFIG
    chmod 644 $POA_SW_CONFIG
    
    service sw-cp-server restart;
}

registerRoles()
{
    execOnce "registerApacheRole";
    execOnce "registerPostfixRole";
    execOnce "registerApachePostfixRole";
    execOnce "registerApachePostfixDNSRole";
    execOnce "registerApacheDNSRole";
    execOnce "registerPostfixDNSRole";
    execOnce "registerIISRole";
    execOnce "registerDNSRole";
    #execOnce "registerHsphereApacheRole";
    execOnce "registerMySqlRole";
    execOnce "registerPostgreSqlRole";
    execOnce "registerApacheMysqlRole"
    execOnce "registerApachePostgresqlRole"
}

enablePOAOpenAPIHTTPAuthentification()
{
    logInfo "Enabling POA openAPI authentication...";
    runPOADBQuery "update openapi_config set require_auth = 'y', use_ssl = 'y'";

    runPOADBQuery "SELECT rule_id FROM openapi_hosts WHERE ip_address='$MN_IP'";
    if [ X"$queryResult" = "X" ]; then
        local netmask=`/sbin/ifconfig -a | grep $MN_IP | awk '{ print $5 }' | sed -n "s/Mask://p"`;
        if [ X"$netmask" = "X" ]; then
            netmask=`/sbin/ifconfig -a | grep $MN_IP | awk '{ print $4 }' | sed -n "s/Mask://p"`;
        fi;
        runPOADBQuery "INSERT INTO openapi_hosts (ip_address, netmask) VALUES ('$MN_IP', '$netmask')";
    fi;

    runPOADBQuery "SELECT rule_id FROM openapi_hosts WHERE ip_address='$MN_COMMUNICATION_IP'";
    if [ X"$queryResult" = "X" ]; then
        local netmask=`/sbin/ifconfig -a | grep $MN_COMMUNICATION_IP | awk '{ print $5 }' | sed -n "s/Mask://p"`;
        if [ X"$netmask" = "X" ]; then
            netmask=`/sbin/ifconfig -a | grep $MN_COMMUNICATION_IP | awk '{ print $4 }' | sed -n "s/Mask://p"`;
        fi;
        runPOADBQuery "INSERT INTO openapi_hosts (ip_address, netmask) VALUES ('$MN_COMMUNICATION_IP', '$netmask')";
    fi;
}

enablePOANotificationEvents()
{
    logInfo "Enabling POA notification events...";
    runPOADBQuery "SELECT transport_id FROM transports WHERE transport_type='HTTPMessenger'";
    local httpTransportId=$queryResult;
    runPOADBQuery "DELETE FROM routes WHERE transport_id = ${httpTransportId}";
    runPOADBQuery "INSERT INTO routes (transport_id, dst, user_id) VALUES (${httpTransportId}, 1, 1)";
    runPOADBQuery "SELECT route_id FROM routes WHERE transport_id=${httpTransportId}";
    local httpTransportRouteId=$queryResult;
    runPOADBQuery "INSERT INTO subs (message_type_id, route_id) SELECT message_type_id, ${httpTransportRouteId} FROM message_types";
}

updatePOATimeouts()
{
    # Set timeouts to 3 hours, see http://kb.parallels.com/en/8138
    runPOADBQuery "UPDATE property_values SET value='10800' WHERE value_id IN (SELECT value_id FROM component_properties WHERE prop_id IN (SELECT prop_id FROM properties WHERE name='tm.default.timeout'));"
    runPOADBQuery "UPDATE property_values SET value='10800' WHERE value_id IN (SELECT value_id FROM component_properties WHERE prop_id IN (SELECT prop_id FROM properties WHERE name='hcl.timeout'));"

    # Interval between sc monitoring cycles
    runPOADBQuery "UPDATE property_values SET value = 10 WHERE value_id IN (SELECT pv.value_id FROM component_properties cp JOIN property_values pv ON cp.value_id = pv.value_id JOIN properties p ON cp.prop_id = p.prop_id JOIN components c ON cp.component_id = c.component_id JOIN packages pkg ON c.pkg_id = pkg.pkg_id WHERE c.host_id = 1 AND pkg.name='pleskd' AND p.name='host_service_manager.worker.timeout');"
}

setTaskRunnersCount()
{
    local runners=5
    logInfo "Setting ${runners} runners in POA TM..."

    runPOADBQuery "UPDATE tm_config SET num_runners = ${runners}"
}

runPOADBQuery()
{
    local query=$1;

    queryResult=`su postgres -c "cd ~;psql plesk  -qtA -c \"${query}\""`
}

runPleskQuery()
{
    local query=$1;

    queryResult=`mysql psa -uadmin -p\`cat /etc/psa/.psa.shadow\` -e "$query"`
}

runBillingQuery()
{
	local query=$1;

    queryResult=`mysql billing -uadmin -p\`cat /etc/psa/.psa.shadow\` -e "$query"`
}

configurePlesk()
{
    #turnOnAPC;
    removeDailyMaintenanceFromCron;
    
    runPleskQuery "select val from misc where param='psa_configured';"
    if [[ "$queryResult" == *true* ]]; then
        local init_mode="update";
    else
        local init_mode="init"
    fi;    

    local cmdAdminSetup="$PLESK_ROOT_PATH/bin/init_conf --$init_mode -name $login -passwd $password \
        -email $admin_email \
        -city $ADMIN_CONTACT_INFO_CITY \
        -state $ADMIN_CONTACT_INFO_STATE \
        -zip $ADMIN_CONTACT_INFO_ZIP \
        -country $ADMIN_CONTACT_INFO_COUNTRY \
        -address $ADMIN_CONTACT_INFO_CITY \
        -company $ADMIN_CONTACT_INFO_COMPANY \
        -license_agreed true -ip-type shared"
        
    runCmd "$cmdAdminSetup" "Configuring Parallels Plesk Panel" "Unable to configure Parallels Plesk Panel."
    
    runPleskQuery "replace misc values \
        (\"business_type\", \"hosting\"),\
        (\"power_user_panel\", \"false\"),\
        (\"simple_panel\", \"false\"),\
        (\"classic_panel\", \"false\"),\
        (\"simple_panel_lock\", \"false\")"

    putOptionToPleskConf "url.rootBase"     "/plesk-hosting/"
    putOptionToPleskConf "url.loginUrl"     "/servlet/Turbine"
    putOptionToPleskConf "sso.ui"           "server"
    putOptionToPleskConf "sso.spApiBaseUrl" "https://$MN_IP:8443/sso"
    putOptionToPleskConf "sso.spRootUrl"    "https://$MN_IP:8443/plesk-hosting/"
    putOptionToPleskConf "serviceNodes.enabled" "1"
}

configureBilling()
{
	runBillingQuery "insert into settings values \
		(null, \"security_UsernameMinimalLength\", 0),\
		(null, \"security_PasswordMinimalLength\", 0),\
		(null, \"security_PasswordAlphanumericEnable\", 0)"
}

removeDailyMaintenanceFromCron()
{
	rm -f /etc/cron.daily/50plesk-daily
	rm -f /etc/cron.weekly/50plesk-weekly
	rm -f /etc/cron.monthly/50plesk-monthly
}

turnOnAPC()
{
    sed -i -e /apc.enabled/s/0/1/ /usr/local/psa/admin/conf/php.ini
}

putOptionToPleskConf()
{
    local name=$1;
    local value=$2;

    if [ ! -f "${PLESK_PANEL_CONFIG}" ]; then
        touch "${PLESK_PANEL_CONFIG}"
    fi;

    mv -f "${PLESK_PANEL_CONFIG}" "${PLESK_PANEL_CONFIG}.original";
    grep -v -e "^\s*${name}\s*=.*\$" "${PLESK_PANEL_CONFIG}.original" > "${PLESK_PANEL_CONFIG}"
    echo "${name}=${value}" >> "${PLESK_PANEL_CONFIG}";
}

getAIAndPoaUrlPath()
{
    if isx64; then
        local arch="x86_64";
    else
        local arch="i386";
    fi;

    local osName=`awk '{print $1}' /etc/redhat-release`
    local osVersion=`head -1 /etc/redhat-release | sed -e 's/[^0-9.]*\([0-9.]*\).*/\1/g'`
    local osVersion=`echo $osVersion | awk -F'.' '{print $1}'`

    case $osName$osVersion$arch in
        CentOS*) osVersion=`echo $osVersion | awk -F'.' '{print $1}'` ;;
        Red*)
          osName="RedHat";
          osVersion="el`echo $osVersion | awk -F'.' '{print $1}'`" ;;
        *) die "Unknown OS: $osName-$osVersion-$arch" ;;
    esac

    aiUrl="${PLESK_REPOSITORY}/Autoinstaller_${AI_VERSION}/${osName}-${osVersion}-${arch}"
    logInfo "AI repository url = ${aiUrl}"

    basePOAPath="POA/${osName}-${osVersion}-${arch}";

    poaUrl="${BASE_REPOSITORY_URL}/$basePOAPath/"
    logInfo "POA repository url = ${poaUrl}"
}

setPOAConfigFile()
{
    step "Generating the POA configuration file..."
    
    rm -f ${POA_BUILD}/poa_config >/dev/null 2>&1

    local netmask=`/sbin/ifconfig -a | grep $MN_IP | awk '{ print $5 }' | sed -n "s/Mask://p"`;
    if [ X"$netmask" = "X" ]; then
        netmask=`/sbin/ifconfig -a | grep $MN_IP | awk '{ print $4 }' | sed -n "s/Mask://p"`;
    fi;
    if [ X"$netmask" = "X" ]; then
        logError "Unable to detect a network mask for the IP: '$MN_IP'"
    fi;
    local interface=`ip addr show | grep inet\ $MN_IP | awk '{print $NF}'`;
    if [ X"$interface" = "X" ]; then
        logError "Unable to detect network interface for Panel IP: '$MN_IP'"
    fi;

    local communication_netmask=`/sbin/ifconfig -a | grep $MN_COMMUNICATION_IP | awk '{ print $5 }' | sed -n "s/Mask://p"`;
    if [ X"$communication_netmask" = "X" ]; then
        communication_netmask=`/sbin/ifconfig -a | grep $MN_COMMUNICATION_IP | awk '{ print $4 }' | sed -n "s/Mask://p"`;
    fi;
    if [ X"$communication_netmask" = "X" ]; then
        logError "Unable to detect a network mask for communication IP: '$MN_COMMUNICATION_IP'"
    fi;
    local communication_interface=`ip addr show | grep inet\ $MN_COMMUNICATION_IP | awk '{print $NF}'`;
    if [ X"$communication_interface" = "X" ]; then
        logError "Unable to detect network interface for communication IP: '$MN_COMMUNICATION_IP'"
    fi;

    logInfo "Config options:"

    putOptionToPoaConfig "communication_ip=$MN_COMMUNICATION_IP"
    putOptionToPoaConfig "communication_netiface_name=$communication_interface"
    putOptionToPoaConfig "communication_netmask=$communication_netmask"
    putOptionToPoaConfig "db=plesk"
    putOptionToPoaConfig "db_hostname=$MN_COMMUNICATION_IP"
    putOptionToPoaConfig "db_port=$pg_port"
    putOptionToPoaConfig "dsn=plesk"
    putOptionToPoaConfig "dsn_login=plesk"
    putOptionToPoaConfig "dsn_passwd="
    putOptionToPoaConfig "email=${admin_email}"
    putOptionToPoaConfig "external_ip=$MN_IP"
    putOptionToPoaConfig "external_netiface_name=$interface"
    putOptionToPoaConfig "external_netmask=$netmask"
    putOptionToPoaConfig "hostname=$MN_HOSTNAME"
    putOptionToPoaConfig "kernel_endpoint_port=8354"
    putOptionToPoaConfig "modules=MSP"
    putOptionToPoaConfig "password=$password"
    putOptionToPoaConfig "pleskd_endpoint_port=8352"
    putOptionToPoaConfig "rootpath=$POA_ROOT_PATH"
    putOptionToPoaConfig "sc-MailMessenger:messenger_mail.from=${admin_email}"
    putOptionToPoaConfig "sc-MailMessenger:messenger_mail.smtphost=$MN_HOSTNAME"
    putOptionToPoaConfig "source_dir=$POA_BUILD"
    putOptionToPoaConfig "sysgroup=pemgroup"
    putOptionToPoaConfig "sysuser=pemuser"
    putOptionToPoaConfig "username=$login"

    logInfo "The path to the POA configuration file: ${POA_BUILD}/poa_config"
}

callOpenAPI()
{
    local xml=$1;
    local returnValueName=$2;
    local returnValueVar=$3;

    local openAPIUrl="https://$MN_IP:8440/RPC2"
    local openAPIMethod=`echo "$xml"|sed -n -e 's/.*<methodName>\([^<]*\)<\/methodName>.*/\1/p'`

    logInfo "POA API method: $openAPIMethod"
    logInfo "POA API request: $xml" "not_log_to_stdout"

    openAPIResponse=`curl $openAPIUrl -u${login}:${password} -s -k -d "$xml" | tee -a $PPA_INSTALLATION_LOG | tr -d '\n'`
    if [ "$openAPIResponse" == "" ]; then
        logError "System error is occurred: OpenAPI response is empty. System log is here /var/log/poa.log";
    fi;

    logInfo "POA API response: $openAPIResponse" "not_log_to_stdout"
    local openAPIResult=${PIPESTATUS[0]}
    if [ "${openAPIResult}" -ne 0 ]; then
        logError "System error is occurred: ${openAPIResult}";
    fi;

    local openAPIFault=`echo $openAPIResponse|sed -n -e 's/.*<fault>.*<name>[^<]*faultString[^<]*<\/name>[^<]*<value>[^<]*<string>\(.*\)<\/string>.*/\1/p'`
    if [ -n "${openAPIFault}" ]; then
        logError "POA API raised the error: ${openAPIFault}";
    fi;

    local openAPIStatus=`echo $openAPIResponse|sed -n -e 's/.*<name>[^<]*status[^<]*<\/name>[^<]*<value>[^<]*<i4>\(.*\)<\/i4>.*/\1/p'`

    if [ "${openAPIStatus}" -ne 0 ]; then
        local openAPIError=`echo $openAPIResponse|sed -n -e 's/.*<name>[^<]*error_message[^<]*<\/name>[^<]*<value>[^<]*<string>\([^<]*\)<\/string>.*/\1/p'`
        logError "POA API raised the error: ${openAPIError}";
    fi;

    if [[ "$returnValueName" ]]; then
        local valueType="[^>]*"
        local value=`echo $openAPIResponse|sed -n -e "s/.*<member><name>result<\/name><value><struct><member><name>$returnValueName<\/name><value><$valueType>\([^<]*\)<\/$valueType><\/value>.*/\1/p"`
        eval $returnValueVar="'$value'"
    fi

    return $openAPIResult;
}

putOptionToPoaConfig()
{
    logInfo "Option: $1"
    echo "$1" >> ${POA_BUILD}/poa_config
}

setPleskConnection()
{
    logInfo "Register secret key in Plesk..."

    local key=`$PLESK_ROOT_PATH/bin/secret_key --create -ip-address 127.0.0.1 2>&1`
    if [ ${#key} -ne 32 ] ; then
        logError "Unable to generate secret key. Result of execution utility '$PLESK_ROOT_PATH/bin/secret_key': $key";
    fi

    logInfo "Register secret key in POA..."
    local xmlRequest="<?xml version=\"1.0\"?><methodCall><methodName>pem.pleskintegration.setPleskConnection</methodName><params><param><value><struct>"
    xmlRequest+="<member><name>auth_key</name><value><string>${key}</string></value></member>"
    xmlRequest+="</struct></value></param></params></methodCall>"

    callOpenAPI "${xmlRequest}"
}

setupSSO()
{
    step "Configuring Single Sign-On (SSO) ..."

    local spApiUrl="https://$MN_IP:8443/servlet/Turbine/frm/single/action/mspsso.SSOHandler"
    local idpApiUrl="https://$MN_IP:8443"

    #######################################################  OPEN API REQUESTS SECTION ####################################################################

    local poaRegisterRequest="<?xml version=\"1.0\"?><methodCall><methodName>pem.mspsso.registerServiceProvider</methodName><params><param><value><struct>"
          poaRegisterRequest+="<member><name>idp_api_url</name><value><string>$idpApiUrl</string></value></member>"
          poaRegisterRequest+="<member><name>sp_api_url</name><value><string>$spApiUrl</string></value></member>"
          poaRegisterRequest+="</struct></value></param></params></methodCall>"

    local poaGetConfigRequest="<?xml version=\"1.0\"?><methodCall><methodName>pem.mspsso.getConfig</methodName><params></params></methodCall>"

    local poaEnableSSORequest="<?xml version=\"1.0\"?><methodCall><methodName>pem.mspsso.enable</methodName><params></params></methodCall>"

    local poaFICreationRequest="<?xml version=\"1.0\"?><methodCall><methodName>pem.mspsso.registerGlobalAccount</methodName><params><param><value><struct>"
          poaFICreationRequest+="<member><name>fi_login</name><value><string>$login</string></value></member>"
          poaFICreationRequest+="<member><name>fi_password</name><value><string>$password</string></value></member>"
          poaFICreationRequest+="<member><name>fi_email</name><value><string>$admin_email</string></value></member>"
          poaFICreationRequest+="</struct></value></param></params></methodCall>"

    local USER_ID;
    setupSSOCreateLocalUser()
    {
        # Params:
        local user_login=$1
        local fi_id=$2
        local sp_id=$3
        local user_id=$4

        local poaUserCreationRequest="<?xml version=\"1.0\"?><methodCall><methodName>pem.mspsso.registerUser</methodName><params><param><value><struct>"
              poaUserCreationRequest+="<member><name>login</name><value><string>${user_login}</string></value></member>"
              poaUserCreationRequest+="<member><name>fi_id</name><value><string>${fi_id}</string></value></member>"
              poaUserCreationRequest+="<member><name>sp_id</name><value><string>${sp_id}</string></value></member>"
              poaUserCreationRequest+="<member><name>user_id</name><value><int>${user_id}</int></value></member>"
              poaUserCreationRequest+="</struct></value></param></params></methodCall>"

        callOpenAPI "${poaUserCreationRequest}"
	    USER_ID=`echo $openAPIResponse | sed 's/.*<name>[^<]*id[^<]*<\/name>[^<]*<value>[^<]*<string>\(.*\)<\/string>.*/\1/'`

        [ -z "$USER_ID" ] && logError "Unable to register the POA administrator account in the SSO service"
    }

    setupSSOregisterDispatcherRole()
    {
        # Params:
        local role=$1
        local sp_id=$2
        local url=$3
        local auth_key=$4

        local poaDispatcherRoleRegistration="<?xml version=\"1.0\"?><methodCall><methodName>pem.mspsso.setDispatcherConfig</methodName><params><param><value><struct>"
              poaDispatcherRoleRegistration+="<member><name>role</name><value><string>${role}</string></value></member>"
              poaDispatcherRoleRegistration+="<member><name>sp_id</name><value><string>${sp_id}</string></value></member>"
              poaDispatcherRoleRegistration+="<member><name>url</name><value><string>${url}</string></value></member>"
              poaDispatcherRoleRegistration+="</struct></value></param></params></methodCall>"

        callOpenAPI "${poaDispatcherRoleRegistration}"
    }

    #######################################################  END OF OPEN API SECTION  ####################################################################

    local setSSOHostname="$PLESK_ROOT_PATH/bin/sw-engine-pleskrun /usr/local/sso/scripts/update_hostname.php --hostname $MN_IP"
    runCmd "$setSSOHostname" "Setting the SSO hostname" "Unable to set the SSO hostname.";

    local ssoConfigurationFile="/etc/sso/sso_config.ini"
    local ssoApplicationConfigFile="/etc/sw-cp-server/applications.d/sso.socket.sh"

    #
    # POA registration on SSO

    logInfo "Registering POA in SSO..."

    callOpenAPI "${poaGetConfigRequest}"
    local SPID=`echo $openAPIResponse| sed 's/.*<name>[^<]*sp_id[^<]*<\/name>[^<]*<value>[^<]*<string>\(.*\)<\/string>.*/\1/'`

    if [ -z "$SPID" ];
    then
        callOpenAPI "$poaRegisterRequest"

        callOpenAPI "${poaGetConfigRequest}"
        SPID=`echo $openAPIResponse | sed 's/.*<name>[^<]*sp_id[^<]*<\/name>[^<]*<value>[^<]*<string>\(.*\)<\/string>.*/\1/'`

        [ -z "$SPID" ] && logError "Unable to register POA in SSO service"
    fi

    setupSSOregisterDispatcherRole "system" "${SPID}" "https://${MN_IP}:8443/servlet/Turbine/?dispatcherRole=system"

    #
    # Creating SSO Global Account for admins (FI)

    logInfo "Registering the SSO global account..."
    callOpenAPI "$poaFICreationRequest"

    local FI_ID=`echo $openAPIResponse| sed 's/.*<name>[^<]*id[^<]*<\/name>[^<]*<value>[^<]*<string>\(.*\)<\/string>.*/\1/'`
    [ -z "$FI_ID" ] && logError "Unable to register federal identity"

    #
    # Creating local POA admin on SSO

    logInfo "Linking the local POA administrator with the SSO global account..."
    setupSSOCreateLocalUser ${login} ${FI_ID} ${SPID} 1

    #
    # POA => 'Privileged SP'

    grep -q 'privileged_sp_id' $ssoConfigurationFile;
    if [ $? -eq 0 ]; then
        mv -f --backup=numbered "${ssoConfigurationFile}" "${ssoConfigurationFile}.original";
        cat "${ssoConfigurationFile}.original" | sed -e "s/^\s*privileged_sp_id\s*=.*\$/privileged_sp_id=${SPID}/" > "${ssoConfigurationFile}";
    else
        echo "" >> $ssoConfigurationFile;
        echo "; Master SP id" >> $ssoConfigurationFile;
        echo "privileged_sp_id = ${SPID}" >> $ssoConfigurationFile;
    fi;

    #
    # Plesk registration

    logInfo "Registering Parallels Plesk Panel in SSO..."
    if $PLESK_ROOT_PATH/bin/sso -s -url https://localhost:8443/ -server https://localhost:8443/ > /dev/null
    then
        local PLESK_SPID=`$PLESK_ROOT_PATH/bin/sso -g | sed -n 's/.*Application ID:[[:space:]]*\(.*\)/\1/p'`

        logInfo "Linking the Plesk Panel administrator with the SSO global account..."
        setupSSOCreateLocalUser admin ${FI_ID} ${PLESK_SPID} 0

        logInfo "Registering Parallels Plesk Panel as a default Hosting Panel..."
        setupSSOregisterDispatcherRole "hosting" "${PLESK_SPID}" "https://${MN_IP}:8443/plesk-hosting/"

        runCmd "$PLESK_ROOT_PATH/bin/sso -e" "Enabling SSO service..." "Unable to start SSO service"
    else
        logError "Unable to register Parallels Plesk Panel as a default Hosting Panel."
    fi

    #
    # CBM registration
    logInfo "Registering CBM in SSO..."

    local cbmResponse=`/usr/share/plesk-billing/integration \
                            --command=install \
                            --user=$login \
                            --password=$password \
                            --country=$ADMIN_CONTACT_INFO_COUNTRY \
                            --city=$ADMIN_CONTACT_INFO_CITY \
                            --company=$ADMIN_CONTACT_INFO_COMPANY \
                            --ui-url=https://${MN_IP}:8443/servlet/Turbine/ \
                            --email=$admin_email \
                            --api-url=https://localhost:8440/RPC2 \
                            --sso-url=https://localhost:8443 \
                            --xml | tr -d '\n'`;

    local cbmStatus=`echo $cbmResponse | sed 's/.*<status>\(.*\)<\/status>.*/\1/'`
    [ "$cbmStatus" != "ok" ] && logError "Unable to register CBM: `echo $cbmResponse | sed 's/.*<error><!\[CDATA\[\(.*\)\]\]><\/error>.*/\1/'`"

    local CBM_ADMIN_SPID=`echo $cbmResponse | sed 's/.*<admin_sp_id>\(.*\)<\/admin_sp_id>.*/\1/'`
    local CBM_CUSTOMER_SPID=`echo $cbmResponse | sed 's/.*<customer_sp_id>\(.*\)<\/customer_sp_id>.*/\1/'`

    [[ -z "$CBM_ADMIN_SPID" || -z "$CBM_CUSTOMER_SPID" ]] && logError "Unexpected CBM response (empty sp_ids)"

    logInfo "Linking CBM admin with global account..."
    ## TODO: Get admin user_id from db    
    setupSSOCreateLocalUser ${login} ${FI_ID} ${CBM_ADMIN_SPID} 0

    setupSSOregisterDispatcherRole "billing-admin" "${CBM_ADMIN_SPID}" "https://${MN_IP}:8443/plesk-billing/admin/"
    setupSSOregisterDispatcherRole "billing-client" "${CBM_CUSTOMER_SPID}" "https://${MN_IP}:8443/plesk-billing/client/"

    logInfo "Disabling CBM..."
    cbmResponse=`/usr/share/plesk-billing/integration --command=disable --xml | tr -d '\n'`
    cbmStatus=`echo $cbmResponse | sed 's/.*<status>\(.*\)<\/status>.*/\1/'`
    [ "$cbmStatus" != "ok" ] && logError "Unable to disable CBM: `echo $cbmResponse | sed 's/.*<error><!\[CDATA\[\(.*\)\]\]><\/error>.*/\1/'`"

    #
    # Finalize

    logInfo "Updating the SSO configuration..."
    grep -q '\^/ui\$' $ssoApplicationConfigFile;
    if [ $? -ne 0 ]; then
        mv -f --backup=numbered "${ssoApplicationConfigFile}" "${ssoApplicationConfigFile}.original";
        cat "${ssoApplicationConfigFile}.original" | sed '/\^\/meta\$/a\\t"^/ui$" => "/sso-site/sso_main.php",' > "${ssoApplicationConfigFile}"
        chmod 755 "${ssoApplicationConfigFile}"
        service sw-cp-server restart;
    fi;

    logInfo "Activating SSO..."
    callOpenAPI "${poaEnableSSORequest}"
}

exportPOAManagementNodeIdToPlesk()
{
    step "Setting up Plesk Panel external-id for the management node..."
    
    runPOADBQuery "select host_id from hosts order by host_id limit 1;"
    local external_id=$queryResult;
    
    local xml='<service-node>';
    xml+='<set>';
    xml+='<filter>';
    xml+='<ip-address>local</ip-address>';
    xml+='</filter>';
    xml+='<values>';
    xml+='<external-id>';
    xml+=$external_id;
    xml+='</external-id>';        
    xml+='</values>';
    xml+='</set>';
    xml+='</service-node>';

    callPleskAPI "$xml";
}

registerApacheRole()
{
    step "Configuring $APACHE_ROLE_CODE role..."

    webRolePackages="<member>";
    webRolePackages+="<name>packages</name>";
    webRolePackages+="<value><array><data><value><struct>";
    webRolePackages+=`getMember "name" "ppa_apache"`;
    webRolePackages+=`getMember "type" "service"`;
    webRolePackages+="</struct></value></data></array></value>";
    webRolePackages+="</member>";

    registerRole "$APACHE_ROLE_CODE" "addLinux" "LINUX_GENERIC" "$webRolePackages";

    deregisterRole "LINUX_GENERIC";
}

registerHsphereApacheRole()
{
    step "Configuring $HSPHERE_APACHE_ROLE_CODE role..."

    local role="<member>";
    role+="<name>packages</name>";
    role+="<value><array><data><value><struct>";
    role+=`getMember "name" "plesk_hsphere_apache"`;
    role+=`getMember "type" "other"`;
    role+="</struct></value></data></array></value>";
    role+="</member>";

    registerRole "$HSPHERE_APACHE_ROLE_CODE" "addLinux" "LINUX_GENERIC" "$role";
}

registerDNSRole()
{
    step "Configuring $DNS_ROLE_CODE role..."

    dnsRolePackages="<member>";
    dnsRolePackages+="<name>packages</name>";
    dnsRolePackages+="<value><array><data><value><struct>";
    dnsRolePackages+=`getMember "name" "bind9"`;
    dnsRolePackages+=`getMember "type" "service"`;
    dnsRolePackages+="</struct></value></data></array></value>";
    dnsRolePackages+="</member>";

    registerRole "$DNS_ROLE_CODE" "addLinux" "LINUX_GENERIC" "$dnsRolePackages";
}

registerPostfixRole()
{
    step "Configuring $POSTFIX_ROLE_CODE role..."

    local role="<member>";
    role+="<name>packages</name>";
    role+="<value><array><data>";

    role+="<value><struct>";
    role+=`getMember "name" "ppa_postfix"`;
    role+=`getMember "type" "service"`;
    role+="</struct></value>";

    role+="</data></array></value>";
    role+="</member>";

    registerRole "$POSTFIX_ROLE_CODE" "addLinux" "LINUX_GENERIC" "$role";
}

registerApachePostfixRole()
{
    step "Configuring $APACHE_POSTFIX_ROLE_CODE role..."

    local role="<member>";
    role+="<name>packages</name>";
    role+="<value><array><data>";

    role+="<value><struct>";
    role+=`getMember "name" "ppa_apache"`;
    role+=`getMember "type" "service"`;
    role+="</struct></value>";

    role+="<value><struct>";
    role+=`getMember "name" "ppa_postfix"`;
    role+=`getMember "type" "service"`;
    role+="</struct></value>";

    role+="</data></array></value>";
    role+="</member>";

    registerRole "$APACHE_POSTFIX_ROLE_CODE" "addLinux" "LINUX_GENERIC" "$role";
}

registerApachePostfixDNSRole()
{
    step "Configuring $APACHE_POSTFIX_DNS_ROLE_CODE role..."

    local role="<member>";
    role+="<name>packages</name>";
    role+="<value><array><data>";

    role+="<value><struct>";
    role+=`getMember "name" "ppa_apache"`;
    role+=`getMember "type" "service"`;
    role+="</struct></value>";

    role+="<value><struct>";
    role+=`getMember "name" "ppa_postfix"`;
    role+=`getMember "type" "service"`;
    role+="</struct></value>";

    role+="<value><struct>";
    role+=`getMember "name" "bind9"`;
    role+=`getMember "type" "service"`;
    role+="</struct></value>";

    role+="</data></array></value>";
    role+="</member>";

    registerRole "$APACHE_POSTFIX_DNS_ROLE_CODE" "addLinux" "LINUX_GENERIC" "$role";
}

registerApacheDNSRole()
{
    step "Configuring $APACHE_DNS_ROLE_CODE role..."

    local role="<member>";
    role+="<name>packages</name>";
    role+="<value><array><data>";

    role+="<value><struct>";
    role+=`getMember "name" "ppa_apache"`;
    role+=`getMember "type" "service"`;
    role+="</struct></value>";

    role+="<value><struct>";
    role+=`getMember "name" "bind9"`;
    role+=`getMember "type" "service"`;
    role+="</struct></value>";

    role+="</data></array></value>";
    role+="</member>";

    registerRole "$APACHE_DNS_ROLE_CODE" "addLinux" "LINUX_GENERIC" "$role";
}

registerPostfixDNSRole()
{
    step "Configuring $POSTFIX_DNS_ROLE_CODE role..."

    local role="<member>";
    role+="<name>packages</name>";
    role+="<value><array><data>";

    role+="<value><struct>";
    role+=`getMember "name" "ppa_postfix"`;
    role+=`getMember "type" "service"`;
    role+="</struct></value>";

    role+="<value><struct>";
    role+=`getMember "name" "bind9"`;
    role+=`getMember "type" "service"`;
    role+="</struct></value>";

    role+="</data></array></value>";
    role+="</member>";

    registerRole "$POSTFIX_DNS_ROLE_CODE" "addLinux" "LINUX_GENERIC" "$role";
}

registerIISRole()
{
    step "Configuring $IIS_ROLE_CODE role..."

    registerRoleScript "UninstallPOAAgent.vbs" "Uninstalls POA Agent"
    local uninstallAgentScript=$?

    registerRoleScript "Ensure-PrimaryDNSSuffix-Empty.vbs" "Ensures that 'Primary DNS Suffix' is empty"
    local checkDNSSuffixScript=$?

    params="<member>";
    params+="<name>packages</name>";
    params+="<value><array><data><value><struct>";
    params+=`getMember "name" "ppa_iis"`;
    params+=`getMember "type" "service"`;
    params+="</struct></value></data></array></value>";
    params+="</member>";

    params+="<member>";
    params+="<name>scripts</name>";
    params+="<value><array><data>"
    params+="<value><struct>";
    params+=`getLong "script_id" "$uninstallAgentScript"`;
    params+=`getLong "weight" 0`;
    params+="</struct></value>"
    params+="<value><struct>";
    params+=`getLong "script_id" "$checkDNSSuffixScript"`;
    params+=`getLong "weight" 0`;
    params+="</struct></value>"
    params+="</data></array></value>";
    params+="</member>";

    registerRole "$IIS_ROLE_CODE" "addWindows" "" "$params";

    deregisterRole "PDC";
    deregisterRole "SDC";
    deregisterRole "WIN_GENERIC";
    deregisterRole "MPS";
    deregisterRole "REG_PDC";
    deregisterRole "IIS_7_5";
}

registerMySqlRole()
{
    step "Configuring $MYSQL_ROLE_CODE role..."

    webRolePackages="<member>";
    webRolePackages+="<name>packages</name>";
    webRolePackages+="<value><array><data><value><struct>";
    webRolePackages+=`getMember "name" "ppa_mysql"`;
    webRolePackages+=`getMember "type" "service"`;
    webRolePackages+="</struct></value></data></array></value>";
    webRolePackages+="</member>";

    registerRole "$MYSQL_ROLE_CODE" "addLinux" "LINUX_GENERIC" "$webRolePackages";
}

registerPostgreSqlRole()
{
    step "Configuring $POSTGRESQL_ROLE_CODE role..."

    webRolePackages="<member>";
    webRolePackages+="<name>packages</name>";
    webRolePackages+="<value><array><data><value><struct>";
    webRolePackages+=`getMember "name" "ppa_pgsql"`;
    webRolePackages+=`getMember "type" "service"`;
    webRolePackages+="</struct></value></data></array></value>";
    webRolePackages+="</member>";

    registerRole "$POSTGRESQL_ROLE_CODE" "addLinux" "LINUX_GENERIC" "$webRolePackages";
}

registerApacheMysqlRole()
{
    step "Configuring $APACHE_MYSQL_ROLE_CODE role..."

    local role="<member>";
    role+="<name>packages</name>";
    role+="<value><array><data>";

    role+="<value><struct>";
    role+=`getMember "name" "ppa_apache"`;
    role+=`getMember "type" "service"`;
    role+="</struct></value>";

    role+="<value><struct>";
    role+=`getMember "name" "ppa_mysql"`;
    role+=`getMember "type" "service"`;
    role+="</struct></value>";

    role+="</data></array></value>";
    role+="</member>";

    registerRole "$APACHE_MYSQL_ROLE_CODE" "addLinux" "LINUX_GENERIC" "$role";
}

registerApachePostgresqlRole()
{
    step "Configuring $APACHE_POSTGRESQL_ROLE_CODE role..."

    local role="<member>";
    role+="<name>packages</name>";
    role+="<value><array><data>";

    role+="<value><struct>";
    role+=`getMember "name" "ppa_apache"`;
    role+=`getMember "type" "service"`;
    role+="</struct></value>";

    role+="<value><struct>";
    role+=`getMember "name" "ppa_pgsql"`;
    role+=`getMember "type" "service"`;
    role+="</struct></value>";

    role+="</data></array></value>";
    role+="</member>";

    registerRole "$APACHE_POSTGRESQL_ROLE_CODE" "addLinux" "LINUX_GENERIC" "$role";
}

registerRoleScript()
{
    local path_to_script=$1;
    local description=$2;
    local invocation_line=$3;

    local xml='<?xml version="1.0"?>'
    xml+="<methodCall><methodName>pem.registerScript</methodName>";
    xml+="<params><param><value><struct>"
    xml+=`getMember "path_to_script" "$path_to_script"`;
    xml+=`getMember "description" "$description"`;
    xml+=`getMember "invocation_line" "$invocation_line"`;
    xml+=`getBoolean "network_access" true`;
    xml+=`getBoolean "reboot_check" false`;
    xml+=`getMember "interpreter" ""`;
    xml+="</struct></value></param></params>"
    xml+="</methodCall>"

    logInfo "Registering role script '$path_to_script'...";

    local script_id="";
    callOpenAPI "$xml" "script_id" script_id
    return $script_id
}

registerRole()
{
    roleName=$1;
    wizardType=$2;
    baseName=$3
    customParam=$4;

    local xml='<?xml version="1.0"?>'
    xml+="<methodCall><methodName>pem.registerRole</methodName>";
    xml+="<params><param><value><struct>"
    xml+=`getMember "name" "$roleName"`;
    xml+=`getMember "description" ""`;
    xml+=`getMember "add_wizard_type" "$wizardType"`;
    xml+=`getMember "base_name" "$baseName"`;
    xml+=$customParam;
    xml+="</struct></value></param></params>"
    xml+="</methodCall>"

    logInfo "Registering the '$roleName' service node role"
    callOpenAPI "$xml"
}

deregisterRole()
{
    roleName=$1;

    local xml='<?xml version="1.0"?>'
    xml+="<methodCall><methodName>pem.deregisterRole</methodName>";
    xml+="<params><param><value><struct>"
    xml+=`getMember "name" "$roleName"`;
    xml+="</struct></value></param></params>"
    xml+="</methodCall>"

    logInfo "Deregistering the '$roleName' service node role..."
    callOpenAPI "$xml"
}

setupDNSHosting()
{
    step "Configuring DNS..."

    ### Set Management Node As Ready To Provide DNS hosting
    xml='<?xml version="1.0"?>'
    xml+="<methodCall><methodName>pem.setHostReadyToProvide</methodName>";
    xml+="<params><param><value><struct>"
    xml+=`getInt "host_id" "1"`;
    xml+=`getBoolean "ready_to_provide" "1"`;
    xml+="</struct></value></param></params>";
    xml+="</methodCall>";
    logInfo "Setting the management node as Ready To Provide..."
    callOpenAPI "$xml"

    ### Add resource type "DNS"
    xml='<?xml version="1.0"?>'
    xml+="<methodCall><methodName>pem.addResourceType</methodName>";
    xml+="<params><param><value><struct>"
    xml+=`getString "resclass_name" "$DNS_RESOURCE_CLASS"`;
    xml+=`getString "name" "$DNS_RESOURCE_NAME"`;
    xml+=`getString "descr" "DNS hosting"`;
    xml+="<member>";
    xml+="<name>act_params</name>";
    xml+="<value><array><data>";
    xml+="<value><struct>";
    xml+=`getMember "var_name" "auto_host_domains"`;
    xml+=`getMember "var_value" "yes"`;
    xml+="</struct></value>";
    xml+="<value><struct>";
    xml+=`getMember "var_name" "configuration_id"`;
    xml+=`getMember "var_value" "1"`;
    xml+="</struct></value>";
    xml+="</data></array></value>";
    xml+="</member>";
    xml+="</struct></value></param></params>";
    xml+="</methodCall>";
    logInfo "Add Resource Type with name '$DNS_RESOURCE_NAME'..."
    callOpenAPI "$xml"
	
	logInfo "Set up nameserver for resource type '$DNS_RESOURCE_NAME'..."
    runPOADBQuery "update dns_hostings set ns1 = (select dns_service_id from dns_services order by dns_service_id limit 1) where hosting_id=1;"
}

setOwnDNSZonesForSubdomains()
{
    runPleskQuery "REPLACE into misc values('subdomain_own_zones', 'true')"
}

tunePleskSettings()
{
    step "Enable pipe logs for Apache Web Server..."
    runPleskQuery "REPLACE into misc values('apache_pipelog', 'true')";
    rebuildApacheConfigs;
}

addProvisioningAttribute()
{
    local name=$1
    local description=$2

    xml='<?xml version="1.0"?>'
    xml+="<methodCall><methodName>pem.addProvisioningAttributes</methodName>";
    xml+="<params><param><value><struct>"
    xml+="<member>";
    xml+="<name>attrs</name>";
    xml+="<value><array><data>";
    xml+="<value><struct>";
    xml+=`getString "name" "$name"`;
    xml+=`getString "descr" "$description"`;
    xml+="</struct></value>";
    xml+="</data></array></value>";
    xml+="</member>";
    xml+="</struct></value></param></params>";
    xml+="</methodCall>";
    logInfo "Adding provisioning attribute '$name'..."
    callOpenAPI "$xml"
}

assignProvisioningAttributes()
{
    step "Assigning provisioning attributes..."

    addProvisioningAttribute "$LOCAL_NODE_ATTRIBUTE" "Apache and postfix hosting on management node"
    addProvisioningAttribute "Apache" "Apache web hosting"
    addProvisioningAttribute "IIS" "IIS web hosting"
    addProvisioningAttribute "Postfix" "Postix mail hosting"
#    addProvisioningAttribute "HSphere Apache" "H-Sphere apache hosting"

    runPOADBQuery "select host_id from hosts order by host_id limit 1";
    local localNodeId=$queryResult;

    ### Set host attributes
    local xml='<?xml version="1.0"?>'
    xml+="<methodCall><methodName>pem.setHostAttributes</methodName>";
    xml+="<params><param><value><struct>"
    xml+=`getInt "host_id" "$localNodeId"`;
    xml+="<member>";
    xml+="<name>attr</name>";
    xml+="<value><array><data>";
    xml+="<value><string>$LOCAL_NODE_ATTRIBUTE</string></value>";
    xml+="</data></array></value>";
    xml+="</member>";
    xml+="</struct></value></param></params>";
    xml+="</methodCall>";
    logInfo "Assigning the '$LOCAL_NODE_ATTRIBUTE' attribute to the host with the '$localNodeId' ID..."
    callOpenAPI "$xml"
}

createDBResourceType()
{
    local name=$1
    local dbType=$2
    local attribute=$3

    xml='<?xml version="1.0"?>'
    xml+="<methodCall><methodName>pem.addResourceType</methodName>";
    xml+="<params><param><value><struct>"
    xml+=`getString "resclass_name" "plesk_db_hosting"`;
    xml+=`getString "name" "$name"`;
    xml+=`getString "descr" ""`;

    xml+="<member>";
    xml+="<name>attrs</name>";
    xml+="<value><array><data><value>";
    xml+="<string>$attribute</string>";
    xml+="</value></data></array></value></member>";

    xml+="<member>";
    xml+="<name>act_params</name>";
    xml+="<value><array><data>";
    xml+="<value><struct>";
    xml+=`getString "var_name" "plesk_db_hosting.type"`;
    xml+=`getString "var_value" "$dbType"`;
    xml+="</struct></value>";
    xml+="<value><struct>";
    xml+=`getString "var_name" "plesk_db_hosting.port"`;
    xml+=`getString "var_value" ""`;
    xml+="</struct></value>";
    xml+="<value><struct>";
    xml+=`getString "var_name" "plesk_db_hosting.ip"`;
    xml+=`getString "var_value" ""`;
    xml+="</struct></value>";
    xml+="</data></array></value></member>";

    xml+="</struct></value></param></params>";
    xml+="</methodCall>";
    logInfo "Addding DB resource type '$name'..."

    callOpenAPI "$xml"
}

createDBResourceTypes()
{
    addProvisioningAttribute "MySQL" "MySQL server";
    addProvisioningAttribute "PostgreSQL" "PostgreSQL server";
    addProvisioningAttribute "Microsoft SQL" "Microsoft SQL server";
    addProvisioningAttribute "WebHost" "Database located at web hosting server";

    createDBResourceType "MySQL database" "mysql" "MySQL"
    createDBResourceType "MySQL database at web server" "mysql" "WebHost"
    
    createDBResourceType "PostgreSQL database" "postgresql" "PostgreSQL"
    createDBResourceType "PostgreSQL database at web server" "postgresql" "WebHost"
    
    createDBResourceType "Microsoft SQL database" "mssql" "Microsoft SQL"
    createDBResourceType "Microsoft SQL database at web server" "mssql" "WebHost"
}

createHostingResourceTypeForBranding()
{
    generateNeededActivationParameters

    xml='<?xml version="1.0"?>'
    xml+="<methodCall><methodName>pem.addResourceType</methodName>";
    xml+="<params><param><value><struct>"
    xml+=`getString "resclass_name" "$BRANDING_HOSTING_RESOURCE_CLASS"`;
    xml+=`getString "name" "$BRANDING_HOSTING_RESOURCE_NAME"`;
    xml+=`getString "descr" "Apache webspace for branding domain"`;
    xml+="<member>";
    xml+="<name>attrs</name>";
    xml+="<value><array><data><value>";
    xml+="<string>$LOCAL_NODE_ATTRIBUTE</string>";
    xml+="</value></data></array></value></member>";
    xml+="<member>";
    xml+="<name>act_params</name>";
    xml+="<value><array><data>";

    local length=${#HOSTING_ACTIVATION_PARAMETERS_NAMES[@]};
    for ((i = 0; i < length; i++)) 
    do
       xml+="<value><struct>";
       xml+=`getString "var_name" "${HOSTING_ACTIVATION_PARAMETERS_NAMES[i]}"`;
       xml+=`getString "var_value" "${HOSTING_ACTIVATION_PARAMETERS_VALUES[i]}"`;
       xml+="</struct></value>";
    done

    xml+="</data></array></value></member>";
    xml+="</struct></value></param></params>";
    xml+="</methodCall>";
    logInfo "Add Resource Type with name '$BRANDING_HOSTING_RESOURCE_NAME'..."

    callOpenAPI "$xml"
}

generateNeededActivationParameters() 
{
    local i=0;    
 
    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.hosting_type";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="vrt_hst";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.ssl";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="true";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.webstat_type";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="awstats";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.shell";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="/bin/false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.scripting.cgi";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.scripting.perl";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.scripting.python";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.scripting.ssi";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.scripting.web_users";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.scripting.php.type";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="none";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.scripting.php.safe_mode";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.scripting.fastcgi";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.scripting.asp";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.custom_error_docs";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.hosting_management";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.manage_php_settings";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.anonftp_management";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.scheduler_management";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.local_backup";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="true";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.ftp_backup";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="true";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.logrot_management";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="true";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.dom_create";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.subdomain_management";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.domalias_management";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.additional_ftp_management";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="true";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.java_management";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.perfomance_management";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.quota_management";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    HOSTING_ACTIVATION_PARAMETERS_NAMES[i]="pleskweb.permission.catalog_access";
    HOSTING_ACTIVATION_PARAMETERS_VALUES[i]="false";
    let i=$i+1;

    #log rotation settings will be default. Option logrotation_management is on
}

createBrandingServiceTemplate() 
{
    getNeededResourceTypes 
 
    local serviceTemplateId;
    local serviceTemplateName="Branding";
    local serviceTemplateDescription="Default service template for reseller branding subscription";
    createServiceTemplate "$serviceTemplateName" "$serviceTemplateDescription" serviceTemplateId

    setResourceTypesLimits $serviceTemplateId

    activateServiceTemplate $serviceTemplateId
}

getNeededResourceTypes() 
{
    local diskQouta;
    let diskQuota=$[256 * 1024]; #in POA limits in KB
    local i=0;
    local j=0;

    #DNS resource type
    runPOADBQuery "select rt_id from resource_types inner join resource_classes on resource_types.class_id = resource_classes.class_id where resource_types.owner_id=1 and resource_types.restype_name='$DNS_RESOURCE_NAME' and resource_classes.name='$DNS_RESOURCE_CLASS';"
    BRANDING_RESOURCE_TYPES[i]=$queryResult;
    BRANDING_RESOURCE_TYPES_LIMITS[i]=-1;
    let i=$i+1;

    runPOADBQuery "select rt_id from resource_types where resource_types.owner_id=1 and resource_types.restype_name='DNS management' and resource_types.parent_id='${BRANDING_RESOURCE_TYPES[$[i-1]]}';"
    BRANDING_NONROOT_RESOURCE_TYPES[j]=$queryResult;
    BRANDING_NONROOT_RESOURCE_TYPES_LIMITS[j]=-1;
    let j=$j+1;

    #Subscription resource type
    runPOADBQuery "select rt_id from resource_types inner join resource_classes on resource_types.class_id = resource_classes.class_id where resource_types.owner_id=1 and resource_types.restype_name='Subscription' and resource_classes.name='plesk_integration';"
    BRANDING_RESOURCE_TYPES[i]=$queryResult;
    BRANDING_RESOURCE_TYPES_LIMITS[i]=1;
    let i=$i+1;

    runPOADBQuery "select rt_id from resource_types rt inner join resource_classes rc on rt.class_id = rc.class_id where rt.owner_id=1 and rc.name='plesk_integration.domains_number' and rt.parent_id='${BRANDING_RESOURCE_TYPES[$[i-1]]}';"
    BRANDING_NONROOT_RESOURCE_TYPES[j]=$queryResult;
    BRANDING_NONROOT_RESOURCE_TYPES_LIMITS[j]=1;
    let j=$j+1;

    #Diskspace
    runPOADBQuery "select rt_id from resource_types inner join resource_classes on resource_types.class_id = resource_classes.class_id where resource_types.owner_id=1 and resource_types.restype_name='Diskspace' and resource_classes.name='disc_space';"
    BRANDING_RESOURCE_TYPES[i]=$queryResult;
    BRANDING_RESOURCE_TYPES_LIMITS[i]=$diskQuota;
    let i=$i+1;

    #Traffic
    runPOADBQuery "select rt_id from resource_types inner join resource_classes on resource_types.class_id = resource_classes.class_id where resource_types.owner_id=1 and resource_types.restype_name='Traffic' and resource_classes.name='traffic';"
    BRANDING_RESOURCE_TYPES[i]=$queryResult;
    BRANDING_RESOURCE_TYPES_LIMITS[i]=-1;
    let i=$i+1;

    #IPv4 addresses
    runPOADBQuery "select rt_id from resource_types inner join resource_classes on resource_types.class_id = resource_classes.class_id where resource_types.owner_id=1 and resource_types.restype_name='IP addresses' and resource_classes.name='ips';"
    BRANDING_RESOURCE_TYPES[i]=$queryResult;
    BRANDING_RESOURCE_TYPES_LIMITS[i]=0;
    let i=$i+1;

    #IPv6 addresses
    runPOADBQuery "select rt_id from resource_types inner join resource_classes on resource_types.class_id = resource_classes.class_id where resource_types.owner_id=1 and resource_types.restype_name='IPv6 addresses' and resource_classes.name='ipv6_addresses';"
    BRANDING_RESOURCE_TYPES[i]=$queryResult;
    BRANDING_RESOURCE_TYPES_LIMITS[i]=0;
    let i=$i+1;

    #Branding access points
    runPOADBQuery "select rt_id from resource_types inner join resource_classes on resource_types.class_id = resource_classes.class_id where resource_types.owner_id=1 and resource_types.restype_name='Branding access points' and resource_classes.name='rt.branding.access_points';"
    BRANDING_RESOURCE_TYPES[i]=$queryResult;
    BRANDING_RESOURCE_TYPES_LIMITS[i]=1;
    let i=$i+1;

    #Branding hosting
    runPOADBQuery "select rt_id from resource_types inner join resource_classes on resource_types.class_id = resource_classes.class_id where resource_types.owner_id=1 and resource_types.restype_name='$BRANDING_HOSTING_RESOURCE_NAME' and resource_classes.name='$BRANDING_HOSTING_RESOURCE_CLASS';"
    BRANDING_RESOURCE_TYPES[i]=$queryResult;
    BRANDING_RESOURCE_TYPES_LIMITS[i]=1;
    let i=$i+1;

    runPOADBQuery "select rt_id from resource_types rt inner join resource_classes rc on rt.class_id = rc.class_id where rt.owner_id=1 and rc.name='pleskweb.webuser_number' and rt.parent_id='${BRANDING_RESOURCE_TYPES[$[i-1]]}';"
    BRANDING_NONROOT_RESOURCE_TYPES[j]=$queryResult;
    BRANDING_NONROOT_RESOURCE_TYPES_LIMITS[j]=0;
    let j=$j+1;

    runPOADBQuery "select rt_id from resource_types rt inner join resource_classes rc on rt.class_id = rc.class_id where rt.owner_id=1 and rc.name='pleskweb.java_apps_number' and rt.parent_id='${BRANDING_RESOURCE_TYPES[$[i-1]]}';"
    BRANDING_NONROOT_RESOURCE_TYPES[j]=$queryResult;
    BRANDING_NONROOT_RESOURCE_TYPES_LIMITS[j]=0;
    let j=$j+1;

    runPOADBQuery "select rt_id from resource_types rt inner join resource_classes rc on rt.class_id = rc.class_id where rt.owner_id=1 and rc.name='pleskweb.hard_quota' and rt.parent_id='${BRANDING_RESOURCE_TYPES[$[i-1]]}';"
    BRANDING_NONROOT_RESOURCE_TYPES[j]=$queryResult;
    BRANDING_NONROOT_RESOURCE_TYPES_LIMITS[j]=$diskQuota;
    let j=$j+1;

    runPOADBQuery "select rt_id from resource_types rt inner join resource_classes rc on rt.class_id = rc.class_id where rt.owner_id=1 and rc.name='pleskweb.connections_limit' and rt.parent_id='${BRANDING_RESOURCE_TYPES[$[i-1]]}';"
    BRANDING_NONROOT_RESOURCE_TYPES[j]=$queryResult;
    BRANDING_NONROOT_RESOURCE_TYPES_LIMITS[j]=-1;
    let j=$j+1;

    runPOADBQuery "select rt_id from resource_types rt inner join resource_classes rc on rt.class_id = rc.class_id where rt.owner_id=1 and rc.name='pleskweb.bandwidth_limit' and rt.parent_id='${BRANDING_RESOURCE_TYPES[$[i-1]]}';"
    BRANDING_NONROOT_RESOURCE_TYPES[j]=$queryResult;
    BRANDING_NONROOT_RESOURCE_TYPES_LIMITS[j]=-1;
    let j=$j+1;

    runPOADBQuery "select rt_id from resource_types rt inner join resource_classes rc on rt.class_id = rc.class_id where rt.owner_id=1 and rc.name='pleskweb.ftp.accounts_number' and rt.parent_id='${BRANDING_RESOURCE_TYPES[$[i-1]]}';"
    BRANDING_NONROOT_RESOURCE_TYPES[j]=$queryResult;
    BRANDING_NONROOT_RESOURCE_TYPES_LIMITS[j]=0;
    let j=$j+1;

    runPOADBQuery "select rt_id from resource_types rt inner join resource_classes rc on rt.class_id = rc.class_id where rt.owner_id=1 and rc.name='pleskweb.mysql.db_number' and rt.parent_id='${BRANDING_RESOURCE_TYPES[$[i-1]]}';"
    BRANDING_NONROOT_RESOURCE_TYPES[j]=$queryResult;
    BRANDING_NONROOT_RESOURCE_TYPES_LIMITS[j]=0;
    let j=$j+1;

    runPOADBQuery "select rt_id from resource_types rt inner join resource_classes rc on rt.class_id = rc.class_id where rt.owner_id=1 and rc.name='pleskweb.pgsql.db_number' and rt.parent_id='${BRANDING_RESOURCE_TYPES[$[i-1]]}';"
    BRANDING_NONROOT_RESOURCE_TYPES[j]=$queryResult;
    BRANDING_NONROOT_RESOURCE_TYPES_LIMITS[j]=0;
    let j=$j+1;

    runPOADBQuery "select rt_id from resource_types rt inner join resource_classes rc on rt.class_id = rc.class_id where rt.owner_id=1 and rc.name='pleskweb.mssql.db_number' and rt.parent_id='${BRANDING_RESOURCE_TYPES[$[i-1]]}';"
    BRANDING_NONROOT_RESOURCE_TYPES[j]=$queryResult;
    BRANDING_NONROOT_RESOURCE_TYPES_LIMITS[j]=0;
    let j=$j+1;

    runPOADBQuery "select rt_id from resource_types rt inner join resource_classes rc on rt.class_id = rc.class_id where rt.owner_id=1 and rc.name='pleskweb.sb_sites_number' and rt.parent_id='${BRANDING_RESOURCE_TYPES[$[i-1]]}';"
    BRANDING_NONROOT_RESOURCE_TYPES[j]=$queryResult;
    BRANDING_NONROOT_RESOURCE_TYPES_LIMITS[j]=0;
    let j=$j+1;
}

createServiceTemplate() 
{
    local serviceTemplateName="$1";
    local description="$2";
    local resourcesLength=${#BRANDING_RESOURCE_TYPES[@]};

    local xml='<?xml version="1.0"?>';
    xml+="<methodCall><methodName>pem.addServiceTemplate</methodName>";
    xml+="<params><param><value><struct>";

    xml+=`getInt "owner_id" "1"`;
    xml+=`getString "name" "$serviceTemplateName"`;
    xml+=`getString "descr" "$description"`;
    xml+=`getString "category" "msp.shared_hosting"`;

    xml+="<member><name>resources</name><value>";
    xml+="<array><data>";
    
    for ((i = 0; i < resourcesLength; i++)) 
    do
       xml+="<value><struct>";
       xml+=`getInt "resource_type_id" "${BRANDING_RESOURCE_TYPES[i]}"`;
       xml+="</struct></value>";
    done
     
    xml+="</data></array>";
    xml+="</value></member>";

    xml+="</struct></value></param></params>";
    xml+="</methodCall>";

    logInfo "Create '$serviceTemplateName' service template"
    local id=$3;
    callOpenAPI "$xml" "st_id" $id
}

setResourceTypesLimits() 
{
    local serviceTemplateID=$1;

    local xml='<?xml version="1.0"?>';
    xml+="<methodCall><methodName>pem.setSTRTLimits</methodName>";
    xml+="<params>";
    xml+="<param><value><struct>";
    xml+=`getInt "st_id" "$serviceTemplateId"`;
    xml+="<member>";
    xml+="<name>limits</name>";
    xml+="<value><array><data>";

    local length=${#BRANDING_RESOURCE_TYPES[@]};
    for ((i = 0; i < length; i++)) 
    do
       xml+="<value><struct>";
       xml+=`getInt "resource_id" "${BRANDING_RESOURCE_TYPES[i]}"`;
       xml+=`getInt "resource_limit" "${BRANDING_RESOURCE_TYPES_LIMITS[i]}"`;
       xml+="</struct></value>";
    done

    local length=${#BRANDING_NONROOT_RESOURCE_TYPES[@]};
    for ((i = 0; i < length; i++)) 
    do
       xml+="<value><struct>";
       xml+=`getInt "resource_id" "${BRANDING_NONROOT_RESOURCE_TYPES[i]}"`;
       xml+=`getInt "resource_limit" "${BRANDING_NONROOT_RESOURCE_TYPES_LIMITS[i]}"`;
       xml+="</struct></value>";
    done

    xml+="</data></array></value></member>";
    xml+="</struct></value></param>";
    xml+="</params>";
    xml+="</methodCall>";

    callOpenAPI "$xml"
}

activateServiceTemplate() 
{
    local serviceTemplateId="$1";

    local xml='<?xml version="1.0"?>';
    xml+="<methodCall><methodName>pem.activateST</methodName>";
    xml+="<params><param><value><struct>";
    xml+=`getInt "st_id" "$serviceTemplateId"`;
    xml+="</struct></value></param></params>";
    xml+="</methodCall>";

    logInfo "Activating service template with id = '$serviceTemplateId'... "
    callOpenAPI "$xml" 
}

getMember()
{
    echo "<member><name>$1</name><value><string>$2</string></value></member>";
}

getString()
{
    echo "<member><name>$1</name><value><string>$2</string></value></member>";
}

getInt()
{
    echo "<member><name>$1</name><value><int>$2</int></value></member>";
}

getLong()
{
    echo "<member><name>$1</name><value><i4>$2</i4></value></member>";
}

getBoolean()
{
    echo "<member><name>$1</name><value><boolean>$2</boolean></value></member>";
}

setPOAConnection()
{
    local xml='<server>';
    xml+='<set-poa-connection>';
    xml+='<connection>';
    xml+="<poa-api-url>https://$MN_IP:8440/RPC2</poa-api-url>";
    xml+="<poa-api-login>$login</poa-api-login>";
    xml+="<poa-api-password>$password</poa-api-password>";
    xml+='</connection>';
    xml+='</set-poa-connection>';
    xml+='</server>';

    callPleskAPI "$xml";
}

callPleskAPI()
{
    logInfo "Sending the API request to Plesk Panel..."

    local packet="<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
    packet+="<packet version=\"1.6.4.0\">";
    packet+="$1";
    packet+="</packet>";

    pleskUrl="https://$MN_IP:8443/enterprise/control/agent.php"
    logInfo "Plesk API request: $packet" "not_log_to_stdout"
    openAPIResponse=`curl $pleskUrl -s -d "$packet" -H "HTTP_AUTH_LOGIN: admin" -H "HTTP_AUTH_PASSWD: $password" -H "Content-Type: text/xml" --insecure | tee -a $PPA_INSTALLATION_LOG | tr -d '\n'`
    logInfo "$openAPIResponse";

    local openAPIResult=${PIPESTATUS[0]}
    if [ "${openAPIResult}" -ne 0 ]; then
        logError "Unable to perform API request: ${openAPIResult}";
    fi;

    local openAPIStatus=`echo $openAPIResponse|sed -n -e 's/.*<status>\(.*\)<\/status>.*/\1/p'`

    if [[ "$openAPIStatus" == *error* ]]; then
        logError "Plesk API raised the error: ${openAPIResponse}";
    fi;
}

checkPassword()
{
    local result=`echo $1 | egrep "[a-zA-Z0-9]{5,}"`

    if [ X"$result" = "X" ]; then
        logError "The password does not meet policy requirements. It must contain at least five alphanumeric characters.";
    fi;
}

isIP()
{
    echo $1 | egrep "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" > /dev/null
}

checkEmail()
{
    local result=`echo $1 | egrep "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$"`

    if [ X"$result" = "X" ]; then
        logError "Email address '$1' is invalid."
    fi
}

runCmd()
{
    local cmd=$1;
    local stepInfo=$2;
    local msgErr=$3;

    logInfo "${stepInfo}..."
    logInfo "$cmd"

    $cmd 2>&1 | tee -a $PPA_INSTALLATION_LOG

    local status=${PIPESTATUS[0]}
    if [ "${status}" -ne 0 ]; then
        logError "$msgErr";
    fi;
}

step()
{
    echo ""
    logInfo $1;
}

#
# The function installs the specified packages (if they do not exist) from third-party url
# Arguments must be provided with the following syntax: 
#   installThirdParty pkg_name1[.arch] pkg_name2[.arch] ... pkg_nameN[.arch]
# All packages will be installed in a single rpm call. If 'arch' is not explicitly specified,
# current machine architecture will be used. 
#
# In addition, the behavior of the function is affected by the environment variable:
# __FORCE_PKG_INSTALL__ = 0 /* Install if not installed, 'force' mode off */
# __FORCE_PKG_INSTALL__ = 1 /* Install if not installed, 'force' mode on  */
# __FORCE_PKG_INSTALL__ = 2 /* Install unconditionally,  'force' mode on  */
#
# Examples: 
#   installThirdParty curl libarchive.i386
#   installThirdPartyForced curl.i386
#   replaceThirdParty libarchive.x86_64
# 

installThirdParty()
{
    logInfo "Installing third-party packages... $*"

    declare -r local THIRDPARTY_URL=$BASE_REPOSITORY_URL/thirdparty/
    declare local pkg_url_list

    until [ -z "$1" ] 
    do
	local pkg_name=$(expr match "$1" '\(.*\)\..*$')
	local pkg_arch=$(expr match "$1" '.*\.\(.*\)$')

	[ -n "$pkg_name" ] || pkg_name=$1
	[ -n "$pkg_arch" ] ||  
	{
	    isx64 && pkg_arch="x86_64" || pkg_arch="i386" 
	}

	if [[ "$__FORCE_PKG_INSTALL__" -eq 2 ]] || ! rpm -qi --quiet "${pkg_name}.${pkg_arch}"
	then
	    local pkg_rpm=$(curl -s $THIRDPARTY_URL | sed -n 's/.*\('${pkg_name}'.*'${pkg_arch}'.rpm\).*/\1/p' | tail -n 1)
	    [ -n "$pkg_rpm" ] && pkg_url_list+="${THIRDPARTY_URL}/$pkg_rpm " || logError "Unable to download a third-party package '${pkg_name}.${pkg_arch}' from '${THIRDPARTY_URL}'"
	fi
	shift
    done

    if [ -n "$pkg_url_list" ]; 
    then
        logInfo "Required RPM packages:"
	for i in $pkg_url_list; do logInfo "- $i"; done

	local force_args
	[[ "$__FORCE_PKG_INSTALL__" -ge 1 ]] && force_args="--force"

	rpm -ivh --ignorearch $force_args $pkg_url_list
    fi
}

installThirdPartyForced()
{
    __FORCE_PKG_INSTALL__=1
    installThirdParty $*
    __FORCE_PKG_INSTALL__=0
}

replaceThirdParty()
{
    __FORCE_PKG_INSTALL__=2
    installThirdParty $*
    __FORCE_PKG_INSTALL__=0
}

downloadAPSMail()
{
    mkdir -p $APS_DIR
    local cmd="$WGET_UTIL $WGET_PARAMS $APS_MAIL_PACKAGE_URL/$APS_MAIL_PACKAGE_NAME -O $APS_DIR/$APS_MAIL_PACKAGE_NAME"
    runCmd "$cmd" "Downloading APSMail package" "Unable to download APSMail package from '$APS_MAIL_PACKAGE_URL'"
}

importAPSMail()
{
    downloadAPSMail;
    logInfo "Import APSMail package to Plesk Panel: ${APS_MAIL_PACKAGE_NAME}"

    local cmd="$PPA_PATH/bin/apsmail -i $APS_DIR/${APS_MAIL_PACKAGE_NAME} --default"
    runCmd "$cmd" "Importing APSMail package to Plesk Panel: ${APS_MAIL_PACKAGE_NAME}" "Unable to import APSMail package from file '$APS_DIR/$APS_MAIL_PACKAGE_NAME'"
}

disablePleskMailNotifications()
{
	logInfo "Disable Plesk Mail Notifications"
	runPleskQuery "replace into misc values('disable_mail_notifications', 'true')"
}

turnOnFeaturedApps()
{
	logInfo "Turn on Featured Apps"
	runPleskQuery "replace into misc values('show_commercial_apps', 'true')"
}

applyVhostTemplateChanges()
{
    step "Applying the default virtual host template..."

    cp -r -f $VHOST_SKELETON_DIR/* $PLESK_VHOST/default/htdocs/
    cp -r -f $VHOST_SKELETON_DIR/* $PLESK_VHOST/default/httpsdocs/
    cp -r -f $VHOST_SKELETON_DIR/* $PLESK_VHOST/.skel/0/httpdocs/
}

applyUIChanges()
{
    step "Applying UI changes..."
    cp -r -f ${UI_CHANGES_DIR}/* ${POA_UI_PATH}
    #export PEM_SKIN_VERSION=2
}

enableApacheModules()
{
    step "Enabling modules mod_rewrite and mod_proxy for Apache..."
    runCmd "$PLESK_ROOT_PATH/admin/sbin/httpd_modules_ctl -e rewrite" "Trying to enable mod_rewrite" "Unable to enable mod_rewrite"
    sleep 5s
    runCmd "$PLESK_ROOT_PATH/admin/sbin/httpd_modules_ctl -e proxy" "Trying to enable mod_proxy" "Unable to enable mod_proxy"
}

rebuildApacheConfigs()
{
    runCmd "$PLESK_ROOT_PATH/admin/sbin/httpdmng --reconfigure-all" "Rebuild apache configs..." "Unable to rebuild apache configs"
}

setDNSRestartInterval()
{
    step "Set DNS restart interval..."
    runCmd "$PPA_BIN_DIR/dns_restart_interval -i $DNS_RESTART_INTERVAL"
}

updateMNConfigurationInPlesk()
{
    local setSharedIP="$PLESK_ROOT_PATH/bin/ipmanage --update $MN_IP -type shared"
    runCmd "$setSharedIP" "Setting the IP address $MN_IP as shared" "Unable to change type of the IP: $MN_IP"

    exportPOAManagementNodeIdToPlesk
}

setPPASessionTimeout()
{
    step "Setting PPA UI session timeout: $PPA_SESSION_TTL minutes..."
    ${PPA_ROOT_PATH}/bin/session_timeout -t $PPA_SESSION_TTL --password=$password
    if [ "$?" -ne 0 ]; then
        logError "Unable to set PPA UI session timeout: $PPA_SESSION_TTL minutes";
    fi;
}

configureLibSwKey()
{
	echo "sw-key-repository-2.0" > /etc/sw/keys/info
	rm -f /etc/sw/keys/keys/plesk-default-key.xml
}

createPPALogs() 
{
    step "Creating PPA logs..."

    pushd $PPA_LOG_DIR > /dev/null

    ln -s $PPA_INSTALLATION_LOG install.log
    ln -s /var/log/poa.log poa.log
    ln -s /var/log/poa-ui.log poa-ui.log
    ln -s /var/log/poa.debug.log poa.debug.log
    ln -s /var/log/sso/sso.log sso.log
    ln -s /var/log/sw-cp-server/error_log plesk.log
    ln -s /usr/local/psa/var/log/maillog mail.log
    ln -s /usr/local/psa/admin/logs/sitebuilder.log sitebuilder.log
    ln -s /usr/local/psa/admin/logs/httpsd_access_log plesk_access.log

    popd > /dev/null
}

createPPAMNCertificates()
{
    runCmd "$PPA_BIN_DIR/agent_certmng -c -type ca" "Creating MN CA..." "Failed to create MN CA"
    runCmd "$PPA_BIN_DIR/agent_certmng -c -type mn" "Creating MN certificate..." "Failed to create MN certificate"
}

setPPASourceUrl()
{
    step "Update PleskIntegration SC properties..."

    runPOADBQuery "select value_id from v_props where name='ppa.plesk.repo.url';"
    local valId=$queryResult;
    local fixedRepoUrl=`echo ${BASE_REPOSITORY_URL} | sed -e "s/\/*$//"`
    runPOADBQuery "update property_values set value='$fixedRepoUrl' where value_id=$queryResult;"
}

registerService()
{
    step "Register services..."

    /sbin/chkconfig --add "ppa"
    /sbin/chkconfig "ppa" on
}

congratulation()
{

echo "
======================================================================
CONGRATULATIONS!
$PRODUCT_NAME was successfully installed.
To complete system configuration, please proceed to URL: https://${MN_IP}:8443/

Use the 'admin' username and the password you specified during the installation.

======================================================================
"  | tee -a $PPA_INSTALLATION_LOG;

}

execOnce()
{
    local command="$1";
    shift

    local lockFile="$PPA_INSTALLATION_STEPS_DIR/$command"
    if [ -f $lockFile ]; then
        logInfo "Skip step '$command'..."
    else
        $command $*;
        touch "${lockFile}";
    fi;
}

enableOwnerModule()
{
    local test_chain="ppa_test"
    iptables -N $test_chain 2> /dev/null
    iptables -A $test_chain -p tcp --dport 8352 -m owner --uid-owner 0 -j ACCEPT 2> /dev/null
    local ret=$?
	if [ $ret -eq 0 ]; then
	    iptables -F $test_chain 2> /dev/null
	fi
	iptables -X $test_chain 2> /dev/null
	return $ret
}

isRulesConfigured()
{
	iptables -L "ppa_rules" 2> /dev/null
}

configureIptables()
{
	runCmd "chkconfig iptables on" "Enabling iptables service" "Failed to enable iptables service"
	if enableOwnerModule; then
		if isRulesConfigured; then
			runCmd "iptables -F ppa_rules" "Flush rules for ppa_rules chain" "Unable to flush rules for ppa_rules chain"
		else
			runCmd "iptables -N ppa_rules" "Create chain ppa_rules" "Unable to create ppa_rules chain"
			runCmd "iptables -I OUTPUT 1 -j ppa_rules" "Insert ppa_rules chain into OUTPUT chain" "Unable to insert ppa_rules chain into OUTPUT chain"
		fi;

		for user in $MN_ALLOWED_USERS; do
			local user_id=`id -u ${user}`
			runCmd "iptables -A ppa_rules -p tcp --dport 8352 -m owner --uid-owner ${user_id} -j ACCEPT" "Configure firewall rule for user '${user}'" "Unable to configure firewall rule for user '${user}'"
			runCmd "iptables -A ppa_rules -p tcp --dport 8354 -m owner --uid-owner ${user_id} -j ACCEPT" "Configure firewall rule for user '${user}'" "Unable to configure firewall rule for user '${user}'"
		done;
		runCmd "iptables -A ppa_rules -p tcp --dport 8352 -j DROP" "Configure firewall rule for outgoing connections to port 8352" "Unable to configure firewall rule for outgoing connections to port 8352"
		runCmd "iptables -A ppa_rules -p tcp --dport 8354 -j DROP" "Configure firewall rule for outgoing connections to port 8354" "Unable to configure firewall rule for outgoing connections to port 8354"
		runCmd "service iptables save" "Save iptables configuration" "Unable to save iptables configuration"
	fi;
	runCmd "$PPA_BIN_DIR/sn_access_list -i" "Init Service Nodes firewall access list rules" "Unable to init Service Nodes firewall access list rules"
}

setDefaultLocale()
{
    lng_code=`echo $DEFAULT_LANG | awk -F"_" '{print $1}'`
    lng_country=`echo $DEFAULT_LANG | awk -F"_" '{print $2}'`

    runPOADBQuery "UPDATE users SET l_language_code='$lng_code', l_country_code='$lng_country'"
}

configurePleskAutoinstaller()
{
	step "Set default repository for Plesk Autoinstaller"
	AI_CONFIG_FILE_NAME="/root/.autoinstallerrc"
	touch "$AI_CONFIG_FILE_NAME"
	NEW_FILE=`mktemp`
	grep -v SOURCE $AI_CONFIG_FILE_NAME > $NEW_FILE
	echo "SOURCE=$PLESK_REPOSITORY" >> $NEW_FILE
	mv -f $NEW_FILE $AI_CONFIG_FILE_NAME
}

installUpdates()
{
    runCmd "$PPA_BIN_DIR/ppa_update --install-updates --no-banner" "Installing updates" "Failed to install updates"
}

removeCbmCronTask()
{
    rm -f /etc/cron.d/billing-task-manager
}

isRootPrivileges;
init;

parseOptions $@;
validateOptions;

logInfo "Running PPA installation..."
checkRequirements;

execOnce "configurePleskAutoinstaller"
execOnce "runInstallation";
execOnce "setPPASourceUrl";
execOnce "runConfiguration";
execOnce "setPOAConnection";
execOnce "setPleskConnection";
execOnce "registerRoles";
execOnce "setupDNSHosting";
execOnce "setOwnDNSZonesForSubdomains";
execOnce "assignProvisioningAttributes";
execOnce "createHostingResourceTypeForBranding";
execOnce "createBrandingServiceTemplate";
execOnce "createDBResourceTypes";
execOnce "setupSSO";
execOnce "importAPSMail";
execOnce "disablePleskMailNotifications";
execOnce "turnOnFeaturedApps"
execOnce "enableApacheModules"
execOnce "updateMNConfigurationInPlesk"
execOnce "tunePleskSettings"
execOnce "setDNSRestartInterval"
execOnce "applyVhostTemplateChanges";
execOnce "applyUIChanges";
execOnce "createPPALogs"
execOnce "registerService"
execOnce "createPPAMNCertificates"
execOnce "configureIptables"
execOnce "setDefaultLocale";
# setPPASessionTimeout will restart pemui service.
execOnce "setPPASessionTimeout";
execOnce "installAdditionalTools";
execOnce "installUpdates";
execOnce "removeCbmCronTask";

congratulation;
