#!/usr/bin/env bash

ENCRYPTION_KEY_PARAM_NAME="encryption-key"
READ_ONLY_MODE_PARAM_NAME="read-only-mode"

. "/opt/MXB/sbin/proxy_settings_utils-fp.sh"
. "/opt/MXB/sbin/common_utils-fp.sh"

GENERAL_PARAMS=(
    user
    password
    $ENCRYPTION_KEY_PARAM_NAME
)

GENERAL_PARAMS_DESC=(
    "Device name"
    "Password"
    "Security code"
)

GENERAL_PARAMS_DESC_LONG=(
    ""
    ""
    "Your files are sent and stored encrypted, so they are unreadable and
useless to anybody, except to you. You can even think up your own
security code. Please note that you should use a key that you will be
able to recall later on. NO ONE has access to your data without this
security code."
)

NO_BANNER_MODE=0
NO_RESTART_MODE=0
WAIT_FOR_FP_MODE=0
MINIMAL_INTERACTION_MODE=0

banner()
{
    cat <<EOT
Functional Process configuration tool, version 26.7.0.26244
Copyright (c) © 2026 N-able Technologies Ltd.

EOT
}

usage() # errCode
{
    usageArg()
    {
        printf "  %-25s  %s\n" "$1" "$2"
    }

    local errCode=$1
    shift

    [ $errCode -ne 0 ] && echo ""
    echo "usage: $(basename "$0") [options]"
    echo "       $(basename "$0") (with no options, in interactive mode)"
    echo ""
    echo "General options:"
    for ((i = 0; i < ${#GENERAL_PARAMS[@]}; i++)); do
        usageArg "--${GENERAL_PARAMS[$i]}" "${GENERAL_PARAMS_DESC[$i]}"
    done
    echo ""
    echo "Proxy options:"
    for ((i = 0; i < ${#PROXY_PARAMS[@]}; i++)); do
        usageArg "--${PROXY_PARAMS[$i]}" "${PROXY_PARAMS_DESC[$i]}"
    done
    echo ""
    echo "Other options:"
    usageArg "-h, --help" "This help message"
    echo ""

    cleanupAndExit $errCode
}

error() # message*
{
    echo "error: $(basename "$0"): $@" >&2
}

indexByValue() #value array
{
    local value=$1
    shift
    declare -a array=("$@")
    local result="-1"

    for ((i = 0; i < ${#array[@]}; i++)); do
        if [ "$value" = "${array[$i]}" ]; then
            result=$i
            break
        fi
    done

    echo "$result"
}

waitForFpInitialization()
{
    echo ""
    echo "Initialization in progress. It can take a while..."

    while true ;  do
        fpState="$('/opt/MXB/bin/ClientTool' -machine-readable control.status.get 2>/dev/null)"
        if [ "$fpState" = "Idle" ]; then
            echo ""
            echo "Functional process initialized successfully."
            echo ""

            if grep -q '^InteractiveConfigurationRequired=1$' "/opt/MXB/etc/config.ini" >/dev/null 2>&1; then
                echo "Nonetheless, interactive configuration is still being reported as required."
                echo "You may need to consult log file or try connecting to functional process"
                echo "remotely."
                echo ""
            fi

            return 0
        fi
        echo "..."
        sleep 3
    done
}

decompileConfig()
{
    local configFile="/opt/MXB/etc/config.ini"

    # check if config.ini exists and is readable
    [ -r "$configFile" ] || return

    # parse config.ini, writing each section contents into separate file
    awk -v"tmpdir=$TMP_DIR" '
    BEGIN { section = "-" }
    {
        s = $0
        if (substr(s, 1, 1) == "[" && substr(s, length(s), 1) == "]")
        {
            section = substr(s, 2, length(s) - 2)
        }
        else
        {
            partFile = tmpdir "/config.ini." section ".part"
            print s >> partFile
        }
    }' "$configFile"
}

restoreConfigFileFromBackup()
{
    local configFile="/opt/MXB/etc/config.ini"
    [ -e "$configFile" ] && rm "$configFile"
    [ -e "$configFile~" ] && mv "$configFile~" "$configFile"
}

truncateConfigFile() #config file path
{
    local configFile="$1"

    if [ -s "$configFile" ]; then

        if [ -e "$configFile~" ] && ! rm "$configFile~"; then
            error "unable to remove previous configuration file backup"
            cleanupAndExit 1
        fi

        if ! mv "$configFile" "$configFile~"; then
            error "unable to backup configuration file"
            cleanupAndExit 1
        fi

        if ! echo -n "" > "$configFile"; then
            error "unable to create new configuration file"
            restoreConfigFileFromBackup
            cleanupAndExit 1
        fi

    fi
}

compileConfig()
{
    local configFile="/opt/MXB/etc/config.ini"

    truncateConfigFile "$configFile"

    for section in General HttpServer Logging; do
        local partFile="$TMP_DIR/config.ini.$section.part"
        [ -e "$partFile" ] || continue
        echo "[$section]" >> "$configFile"
        cat "$partFile" >> "$configFile"
    done

    [ $NO_RESTART_MODE -ne 0 ] && return 0

    # restart ProcessController (which effectively restarts FP)
    if ! $serviceCtl restart; then
        error "unable to restart process controller"
        cleanupAndExit 1
    fi

    # check if FP in idle state
    waitForFpInitialization
}

getNormalizedBool() # string to normalize
{
    if [ "$1" = "true" -o "$1" = "yes" -o "$1" = "on" -o "$1" = "1" ]; then
        echo 1
    else
        echo 0
    fi
}

validateUserParam()
{
    test -n "$1"
}
validatePasswordParam()
{
    test -n "$1"
}
validateEncryptionKeyParam()
{
    test -n "$1"
}

setConfigParam() # section, paramName, paramValue
{
    local section="$1"
    local paramName="$2"
    local paramValue="$3"
    shift 3

    # try validating param value, if possible
    local validateCallback="validate${paramName}Param"
    if declare -f "$validateCallback" > /dev/null 2>&1; then
        eval "$validateCallback \"\$paramValue\"" || return 1
    fi

    local partFile="$TMP_DIR/config.ini.$section.part"
    if [ -e "$partFile" ] && grep "^$paramName=" "$partFile" > /dev/null 2>&1; then
        sed -ie "s|^$paramName=.*$|$paramName=$paramValue|" "$partFile"
    else
        echo "$paramName=$paramValue" >> "$partFile"
    fi

    eval "CONFIG_$paramName=\"\$paramValue\""
    return 0
}

parseUnattendedInstallationParameters() # packageName
{
    local packageName="$1"
    local parameters="$(echo "$packageName" | grep -oE '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}(#[0-9]*)?(#[0-9]*)?(#[0-9]*)?')"

    if [ -z "$parameters" ]; then
        return 1
    fi

    local partnerUid="$(echo "$parameters" | awk -F'#' '{print $1}')"
    local profileId="$(echo "$parameters" | awk -F'#' '{print $2}')"
    local storageId="$(echo "$parameters" | awk -F'#' '{print $3}')"
    local productId="$(echo "$parameters" | awk -F'#' '{print $4}')"

    UNATTENDED_MODE_COMMAND_LINE_ARGUMENTS="-unattended-mode -partner-uid=$partnerUid"

    if [ -n "$profileId" ]; then
        UNATTENDED_MODE_COMMAND_LINE_ARGUMENTS="$UNATTENDED_MODE_COMMAND_LINE_ARGUMENTS -profile-id=$profileId"
    fi

    if [ -n "$storageId" ]; then
        UNATTENDED_MODE_COMMAND_LINE_ARGUMENTS="$UNATTENDED_MODE_COMMAND_LINE_ARGUMENTS -storage-id=$storageId"
    fi

    if [ -n "$productId" ]; then
        UNATTENDED_MODE_COMMAND_LINE_ARGUMENTS="$UNATTENDED_MODE_COMMAND_LINE_ARGUMENTS -product-id=$productId"
    fi

    return 0
}

validateUnattendedArgs() # args*
{
    validate_proxy_parameters "$@"
}

runUnattendedInstall() # args*
{
    validateUnattendedArgs "$@" || return $?

    local configFileDir="/opt/MXB/etc"
    local configFilePath="$configFileDir/config.ini"
    local clientTool='/opt/MXB/bin/ClientTool'
    local unattendedConfigFilePath="$configFileDir/config_unattended.ini"

    if ! "$clientTool" install -config-path="$unattendedConfigFilePath" -previous-config-path="$configFilePath" $UNATTENDED_MODE_COMMAND_LINE_ARGUMENTS $@; then
        error "invalid arguments for ClientTool: $UNATTENDED_MODE_COMMAND_LINE_ARGUMENTS $@"
        $serviceCtl start
        return 1
    fi

    if [ -e "$unattendedConfigFilePath" ]; then
        $serviceCtl stop
        truncateConfigFile "$configFilePath"
        mv -f "$unattendedConfigFilePath" "$configFilePath"
    else
        return 1
    fi

    return 0
}

configureWithPassphrase()
{
    local configFilePath="/opt/MXB/etc/config.ini"
    truncateConfigFile "$configFilePath"
    CLIENT_TOOL='/opt/MXB/bin/ClientTool'
    local params="install -config-path=$configFilePath $@"
    if ! $CLIENT_TOOL $params; then
        error "invalid arguments for ClientTool: $@"
        restoreConfigFileFromBackup
        return 1
    fi
    return 0
}

configureWithArgs() # args*
{
    decompileConfig

    setXGeneralParams

    while [ $# -gt 0 ]; do
        local arg="$1"
        shift

        [ "$arg" = "-h" -o "$arg" = "--help" ] && usage 0

        local argName="${arg%%=*}"
        local argValue="${arg#*=}"
        [ -z "$argName" ] && argName="$arg"
        if [ "${argName:0:2}" = '--' ]; then
            local cleanArgName="${argName:2}"

            if [ "$cleanArgName" = "package-name" ]; then
                continue
            fi

            local paramName=$(argToConfigParam "$cleanArgName")
            local found=0
            for i in "${GENERAL_PARAMS[@]}" "${PROXY_PARAMS[@]}"; do
                [ "$i" = "$cleanArgName" ] || continue
                setConfigParam General "$paramName" "$argValue" || break
                found=1
                break
            done
            [ $found -eq 1 ] && continue
        fi

        # if we got here, argument was not recognized or had invalid value
        error "invalid argument: '$arg'"
        cleanupAndExit 1
    done

    checkConnectionToCloud || cleanupAndExit 1

    # preconditions for security code validation
    launchFpWithMinimalConfiguration
    local launchFpResult=$?
    local encryptionKeyValidationResult=0

    if [ $launchFpResult -eq 0 ]; then
        validateEncryptionKeyNonInteractively
        encryptionKeyValidationResult=$?
    else
        encryptionKeyValidationResult=1 #indicating validation failure
    fi

    if [ $encryptionKeyValidationResult -eq 0 ]; then
        setEncryptionKeyConfigParam
    fi

    $serviceCtl stop

    if [ $encryptionKeyValidationResult -eq 0 ]; then
        setConfigParam General "InteractiveConfigurationRequired" "0"
        compileConfig
    else
        restoreConfigFileFromBackup
    fi

    return $encryptionKeyValidationResult
}

enterGeneralParamByIndex() # param index in "GENERAL" array, -no-long-desc to disable longDesc
{
    local i
    local disableLongDesc=0

    while [ $# -gt 0 ]; do
        case "$1" in
        -index)
            shift
            i="$1"
            ;;
        -no-long-desc)
            disableLongDesc=1
            ;;
        esac
        shift
    done

    local argName="${GENERAL_PARAMS[$i]}"
    local paramName=$(argToConfigParam "$argName")

    local paramValue xParamValue
    eval "paramValue=\"\$CONFIG_$paramName\""
    eval "xParamValue=\"\$X_CONFIG_$paramName\""

    if [ $MINIMAL_INTERACTION_MODE -ne 0 ]; then
        setConfigParam General "$paramName" "${paramValue:-$xParamValue}" && return 1
    fi

    local longDesc="${GENERAL_PARAMS_DESC_LONG[$i]}"
    if [ -n "$longDesc" -a $disableLongDesc -eq 0 ]; then
        echo ""
        echo "$longDesc"
        echo ""
    fi

    while true; do
        local oldValueHint="${xParamValue/?*/(previously configured value)}"
        local valueHint="${paramValue:-$oldValueHint}"
        echo -n "${GENERAL_PARAMS_DESC[$i]} [${valueHint}]: "
        read x
        [ "$x" = "" -a -n "$paramValue$xParamValue" ] && return 1
        setConfigParam General "$paramName" "$x" && return 0
    done
}

enterProxyParamByIndex() # param index in "PROXY" array, -no-long-desc to disable longDesc
{
    local i
    local disableLongDesc=0

    while [ $# -gt 0 ]; do
        case "$1" in
        -index)
            shift
            i="$1"
            ;;
        -no-long-desc)
            disableLongDesc=1
            ;;
        esac
        shift
    done

    local argName="${PROXY_PARAMS[$i]}"
    local paramName=$(argToConfigParam "$argName")

    local paramValue xParamValue
    eval "paramValue=\"\$CONFIG_$paramName\""
    eval "xParamValue=\"\$X_CONFIG_$paramName\""

    if [ $MINIMAL_INTERACTION_MODE -ne 0 ]; then
        setConfigParam General "$paramName" "${paramValue:-$xParamValue}" && return 1
    fi

    local longDesc="${PROXY_PARAMS_DESC_LONG[$i]}"
    if [ -n "$longDesc" -a $disableLongDesc -eq 0 ]; then
        echo ""
        echo "$longDesc"
        echo ""
    fi

    while true; do
        local oldValueHint
        [ "$argName" = "proxy-password" ] && \
            oldValueHint="${xParamValue/?*/(previously configured value)}" || \
            oldValueHint="$xParamValue"

        local valueHint="${paramValue:-${oldValueHint:-${PROXY_PARAMS_IMPLICIT_DEFAULTS[$i]}}}"
        echo -n "${PROXY_PARAMS_DESC[$i]} [$valueHint]: "
        read x
        [ "$x" = "" -a -n "$paramValue$xParamValue" ] && return 1
        [ -z "$x" ] && x="${PROXY_PARAMS_IMPLICIT_DEFAULTS[$i]}"
        setConfigParam General "$paramName" "$x" && return 0
    done
}

ENCRYPTION_KEY_PARAM_INDEX="$(indexByValue "${ENCRYPTION_KEY_PARAM_NAME}" "${GENERAL_PARAMS[@]}")"

declare -a PARTIAL_SETTINGS_ARRAY

buildPartialSettings() #input partial settings, parameters array
{
    declare -a parameterArray=("$@")

    for ((i = 0; i < ${#parameterArray[@]}; i++)); do

        local parameterName="$(argToConfigParam ${parameterArray[$i]})"
        local parameterValue="$(eval "echo \"\${CONFIG_$parameterName:-\$X_CONFIG_$parameterName}\"")"

        if [ -z "$parameterValue" ]; then
            continue
        fi

        PARTIAL_SETTINGS_ARRAY=("${PARTIAL_SETTINGS_ARRAY[@]}" "-name")
        PARTIAL_SETTINGS_ARRAY=("${PARTIAL_SETTINGS_ARRAY[@]}" "$parameterName")
        PARTIAL_SETTINGS_ARRAY=("${PARTIAL_SETTINGS_ARRAY[@]}" "-value")
        PARTIAL_SETTINGS_ARRAY=("${PARTIAL_SETTINGS_ARRAY[@]}" "$parameterValue")
    done
}

buildSetConfigCommandParameters()
{
    local useProxyNormalizedFlag=$(getNormalizedBool "$CONFIG_UseProxy")

    if [ $useProxyNormalizedFlag -eq 1 ]; then
        PARTIAL_SETTINGS_ARRAY=(control.setting.modify)
        buildPartialSettings "${PROXY_PARAMS[@]}"
    fi
}

compileMinimalConfig()
{
    local configFile="/opt/MXB/etc/config.ini"
    truncateConfigFile "$configFile"

    local username="${CONFIG_User:-$X_CONFIG_User}"
    local password="${CONFIG_Password:-$X_CONFIG_Password}"
    local pathToLocalStorage="$X_CONFIG_PathToLocalStorage"

    echo '[General]'>>"$configFile"
    echo "User=$username">>"$configFile"
    echo "Password=$password">>"$configFile"
    echo "ReadOnlyMode=1">>"$configFile"
    [ -n "$pathToLocalStorage" ] && echo "PathToLocalStorage=$pathToLocalStorage">>"$configFile"
}

displayRerunConfigMessage() # message
{
    echo ""
    error "$@"
    echo ""

    cat >&2 <<-END
Try running configuration script
    /opt/MXB/sbin/configure-fp.sh
again or uninstall application using script
    /opt/MXB/sbin/uninstall-fp.sh
END
}

waitForFpSuspendedState()
{
    while true ;  do
        fpState="$('/opt/MXB/bin/ClientTool' -machine-readable control.status.get 2>/dev/null)"
        if [ "$fpState" = "Suspended" ]; then
            return 0
        fi
        sleep 1
    done
}

launchFpWithMinimalConfiguration()
{
    echo "Initializing"

    setConfigParam General "$(argToConfigParam $READ_ONLY_MODE_PARAM_NAME)" "0"
    compileMinimalConfig

    $serviceCtl restart
    waitForFpSuspendedState > "/dev/null"

    buildSetConfigCommandParameters
    if [ ${#PARTIAL_SETTINGS_ARRAY[@]} -ne 0 ]; then
        "/opt/MXB/bin/ClientTool" "${PARTIAL_SETTINGS_ARRAY[@]}" > "/dev/null"
        if [ $? -ne 0 ]; then
            displayRerunConfigMessage "Unable to set functional process parameters"
            return 1
        fi
    fi

    return 0
}

checkConnectionToCloud()
{
    echo "Checking connection to the cloud service..."

    declare -a params=(-machine-readable connection.check -account "${CONFIG_User:-$X_CONFIG_User}" -password "${CONFIG_Password:-$X_CONFIG_Password}")

    for ((i = 0; i < ${#PROXY_PARAMS[@]}; i++)); do
        local argName="${PROXY_PARAMS[$i]}"
        local paramName=$(argToConfigParam "$argName")

        local paramValue="$(eval "echo \"\${CONFIG_$paramName:-\$X_CONFIG_$paramName}\"")"
        [ -z "$paramValue" ] && continue

        params=("${params[@]}" "-$argName" "$paramValue")
    done

    "/opt/MXB/bin/ClientTool" "${params[@]}" > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        displayRerunConfigMessage "Failed to connect to the cloud service."
        return 1
    fi

    return 0
}

validateEncryptionKeyNonInteractively()
{
    echo "Validating security code"

    local setEncryptionKeyOutput
    setEncryptionKeyOutput="$("/opt/MXB/bin/ClientTool" \
        -machine-readable encryption-key.set -encryption-key \
        "${CONFIG_EncryptionKey:-$X_CONFIG_EncryptionKey}" -force-key)"
    local setEncryptionKeyResult=$?

    if [ "$setEncryptionKeyOutput" = "invalidKey" ]; then
        displayRerunConfigMessage "Invalid security code."
        return 1
    elif [ $setEncryptionKeyResult -ne 0 ]; then
        displayRerunConfigMessage "Failed to validate security code."
    fi

    return $setEncryptionKeyResult
}

validateEncryptionKey()
{
    echo "Validating security code"

    local readOnlyModeState=0
    local forceEncryptionKeySetting=0

    while true ; do

        declare -a validateEncryptionKeyCommandParameters=(-machine-readable encryption-key.set -encryption-key)
        validateEncryptionKeyCommandParameters=("${validateEncryptionKeyCommandParameters[@]}" "${CONFIG_EncryptionKey:-$X_CONFIG_EncryptionKey}")
        [ $forceEncryptionKeySetting -eq 1 ] && validateEncryptionKeyCommandParameters=("${validateEncryptionKeyCommandParameters[@]}" "-force-key")

        local encryptionKeySettingResult="$("/opt/MXB/bin/ClientTool" "${validateEncryptionKeyCommandParameters[@]}")"

        case "$encryptionKeySettingResult" in
        "contractUsed")
            while true ; do
                echo ""
                echo "This contract is already in use."
                echo 'You can either use this contract, abort configuration or'
                echo -n 'install application in restore only mode [u/a/R]: '
                read x

                case "$x" in
                [Aa])
                    displayRerunConfigMessage "Configuration process aborted."
                    return 1
                    ;;
                [Uu])
                    forceEncryptionKeySetting=1
                    break
                    ;;
                [Rr] | "")
                    forceEncryptionKeySetting=1
                    readOnlyModeState=1
                    break
                    ;;
                *)
                    echo "Invalid input. Try again."
                    ;;
                esac
            done
            ;;
        "invalidKey")
            echo "Invalid security code entered. Try again."
            MINIMAL_INTERACTION_MODE=0 enterGeneralParamByIndex -index $ENCRYPTION_KEY_PARAM_INDEX -no-long-desc
            ;;
        "")
            echo "Security code successfully set."
            break
            ;;
        *)
            displayRerunConfigMessage "$encryptionKeySettingResult"
            return 1
            ;;
        esac
    done

    setConfigParam General "$(argToConfigParam $READ_ONLY_MODE_PARAM_NAME)" "$readOnlyModeState"

    return 0
}

setXGeneralParams()
{
    if [ -f "$TMP_DIR/config.ini.General.part" ]; then
        while read line; do
            echo "$line" | grep "^[a-zA-Z]\+=" > /dev/null 2>&1 || continue
            eval "X_CONFIG_$line"
        done < "$TMP_DIR/config.ini.General.part"
    fi
}

setEncryptionKeyConfigParam()
{
    # Wait 10 seconds until the encryption key is written to the configuration file

    local configFilePath="/opt/MXB/etc/config.ini"

    for i in $(seq 1 10); do
        local encriptionKey="$(grep "EncryptionKey" "$configFilePath" | awk -F'=' '{print $2}')"
        if [ -n "$encriptionKey" ]; then
            setConfigParam General "$(argToConfigParam $ENCRYPTION_KEY_PARAM_NAME)" "$encriptionKey"
            break
        fi
        sleep 1
    done
}

configureInteractively()
{
    decompileConfig

    setXGeneralParams

    local generalParamsChanged=0
    for ((i = 0; i < ${#GENERAL_PARAMS[@]}; i++)); do
        if enterGeneralParamByIndex -index $i; then
            generalParamsChanged=1
        fi
    done

    if [ $MINIMAL_INTERACTION_MODE -ne 0 -a $generalParamsChanged -eq 0 ]; then
        return 0
    fi

    local proxyParamsChanged=0
    for ((i = 0; i < ${#PROXY_PARAMS[@]}; i++)); do
        if enterProxyParamByIndex -index $i; then
            proxyParamsChanged=1
        fi

        # proxy configuration may be terminated at 2 points
        [ "${PROXY_PARAMS[$i]}" = "use-proxy" ] && \
            [ $(getNormalizedBool "${CONFIG_UseProxy-$X_CONFIG_UseProxy}") -eq 0 ] && break
        [ "${PROXY_PARAMS[$i]}" = "use-proxy-authorization" ] && \
            [ $(getNormalizedBool "${CONFIG_UseProxyAuthorization-$X_CONFIG_UseProxyAuthorization}") -eq 0 ] && break
    done

    if [ $generalParamsChanged -eq 0 -a $proxyParamsChanged -eq 0 ]; then
        return 0
    fi

    checkConnectionToCloud || cleanupAndExit 1

    # preconditions for security code validation
    launchFpWithMinimalConfiguration
    local launchFpResult=$?
    local encryptionKeyValidationResult=0

    if [ $launchFpResult -eq 0 ]; then
        if [ $generalParamsChanged -eq 0 ]; then
            encryptionKeyValidationResult=-1
        else
            validateEncryptionKey
            encryptionKeyValidationResult=$?
        fi
    else
        encryptionKeyValidationResult=1 #indicating validation failure
    fi

    if [ $encryptionKeyValidationResult -eq 0 ]; then
        setEncryptionKeyConfigParam
    fi

    $serviceCtl stop

    if [ $encryptionKeyValidationResult -le 0 ]; then
        compileConfig
    else
        restoreConfigFileFromBackup
    fi

    return $encryptionKeyValidationResult
}

cleanupAndExit() # errCode
{
    local errCode=$1
    shift

    rm -rf "$TMP_DIR"
    exit $errCode
}

serviceCtlLinuxSystemV() # action
{
    /etc/init.d/ProcessController $1 >/dev/null 2>&1
}

serviceCtlLinuxSystemD() # action
{
    systemctl $1 ProcessController >/dev/null 2>&1
}

main() # args*
{
    trap "cleanupAndExit 1" INT TERM

    TMP_DIR="$(mktemp -d --tmpdir="${TMPDIR:-/opt/MXB/var/tmp}" configure.XXXXXXXX)"

    while [ $# -gt 0 ]; do
        case "$1" in
        --no-banner)
            NO_BANNER_MODE=1
            ;;
        --no-restart)
            NO_RESTART_MODE=1
            ;;
        --wait-for-fp)
            WAIT_FOR_FP_MODE=1
            ;;
        --minimal-interaction)
            MINIMAL_INTERACTION_MODE=1
            ;;
        *)
            break
            ;;
        esac
        shift
    done

    [ $NO_BANNER_MODE -eq 0 ] && banner

    if [ "$(id -u)" != "0" ]; then
        error "this script should be run by root (which you are not)"
        cleanupAndExit 1
    fi

    local packageName="$(echo "$@" | grep -e "--package-name" | sed -r 's|.*--package-name=([^ ]*).*|\1|g')"
    local parametersWithoutPackageName="$(echo $@ | sed -E 's|--package-name=[^ ]* ?||g')"

    if [ $WAIT_FOR_FP_MODE -ne 0 ]; then
        waitForFpInitialization
    elif [ -n "$packageName" ] && parseUnattendedInstallationParameters "$packageName"; then
        runUnattendedInstall $parametersWithoutPackageName
    else
        if [ -n "$parametersWithoutPackageName" ]; then
            if [ -n "$(echo "$@" | grep -e "--passphrase")" ]; then
                configureWithPassphrase "$parametersWithoutPackageName"
            else
                configureWithArgs "$@"
            fi
        elif [ ${INSIDE_AUTOMATIC_UPDATE:-0} -eq 0 ]; then
            configureInteractively
        fi
    fi

    cleanupAndExit $?
}

SN="$(uname -s | tr A-Z a-z)"
case "$SN" in
linux)
    if is_rescue_environment; then
        serviceCtl=service_in_rescue_environment
    else
        sd_booted && serviceCtl=serviceCtlLinuxSystemD \
                  || serviceCtl=serviceCtlLinuxSystemV
    fi
    ;;
*)
    error "Unsupported platform: $SN"
    exit 1
esac

main "$@"
