#!/bin/bash

[ "${DEBUG}" = "yes" ] || DEBUG="no"
[ -z "${DIST_UPGRADE_ENABLED}" ] && DIST_UPGRADE_ENABLED="yes"

# --------------------------------------------------------------------------
#
# Logging functions idea from
# http://www.cubicrace.com/2016/03/efficient-logging-mechnism-in-shell.html
#
# --------------------------------------------------------------------------


#LOGFILE=SystemOut.log
TMP_DIR="/tmp/support.$$"
touch "${LOGFILE}"
tmp="${0}.tmp.$$"

# User variables:
USERNAME="${1}"
[ -z "${USERNAME}" ] && USERNAME="user"
USERPASSWORD="${2}"
[ -z "${USERPASSWORD}" ] && USERPASSWORD="ChangeMe"
USERHOME="/home/${USERNAME}"



function L_LOG () {
    echo "-------------------------------------------------------------" >> "${LOGFILE}"
}

function LL_LOG () {
    echo "=============================================================" >> "${LOGFILE}"
}

function ENTRY(){
    local cfn="${FUNCNAME[1]}"
    local tstamp=$( date )
    local msg="> ${cfn} ${FUNCNAME}"
    LL_LOG
    echo -e "[${tstamp}] [DEBUG]\t${msg}" >> "${LOGFILE}"
}

function RETURN(){
    local cfn="${FUNCNAME[1]}"
    local tstamp=$( date )
    local msg="< ${cfn} ${FUNCNAME}"
    echo -e "[${tstamp}] [DEBUG]\t${msg}" >> "${LOGFILE}"
    LL_LOG
}

function INFO()
{
    local msg="${1}"
    local tstamp=$( date )
    echo -e "[${tstamp}] [INFO]\t${msg}" >> "${LOGFILE}"
}

function WARN()
{
    local msg="${1}"
    local tstamp=$( date )
    echo -e "[${tstamp}] [WARN]\t${msg}" >> "${LOGFILE}"
}

function ERROR()
{
    local msg="${1}"
    local tstamp=$( date )
    echo -e "[${tstamp}] [ERROR]\t${msg}" >> "${LOGFILE}"
}

function DEBUG()
{
    local msg="${1}"
    local tstamp=$( date )
    echo -e "[${tstamp}] [DEBUG]\t${msg}" >> ${LOGFILE}
}

# --------------------------------------------------------------
# RSB custom code
# --------------------------------------------------------------
export IP=$( ip route get 8.8.8.8 | awk '/8.8.8.8/ {print $NF}' )
export DEV=$( ip route get 8.8.8.8 | awk '/8.8.8.8/ {print $3}' )
export DATE=$( date +%Y-%m-%d:%H:%M:%S )
export DEBIAN_FRONTEND=noninteractive


function LOG_INFO()
{
    local title
    local result=""
    [ -n "${1}" ] && title="${1}" || title="${JOB_NAME}"
    [ -n "${2}" ] && result="${2}"
    INFO "${title}"
    [ ! -z "${LOG}" ] && INFO "${LOG}"
    [ ! -z "${result}" ] && INFO "${result}"
    L_LOG
    LOG=""
}

function LOG_ERROR()
{
    local title
    local result=""
    [ -n "${1}" ] && title="${1}" || title="${JOB_NAME}"
    [ -n "${2}" ] && result="${2}"
    ERROR "${title}"
    [ ! -z "${LOG}" ] && ERROR "${LOG}"
    [ ! -z "${result}" ] && ERROR "${result}"
    L_LOG
    LOG=""
}

function LOG_DEBUG()
{
    local title
    local result=""
    [ -n "${1}" ] && title="${1}" || title="${JOB_NAME}"
    [ -n "${2}" ] && result="${2}"
    DEBUG "${title}"
    [ ! -z "${LOG}" ] && DEBUG "${LOG}"
    [ ! -z "${result}" ] && DEBUG "${result}"
    L_LOG
    LOG=""
}


function LOG_RC () {
    local _rc
    _rc=${1}
    if [ ${_rc} -ne 0 ] ; then
        LOG_ERROR "${JOB_NAME}" "Failed! Rc: [${_rc}]"
    else
        LOG_INFO "${JOB_NAME}" "Success."
    fi
}


function JOB_START()
{
    local title
    [ -n "${1}" ] && title="${1}" || title="${JOB_NAME}"
    L_LOG
    INFO "${title}: Started"
    L_LOG
}

function JOB_END()
{
    local title
    [ -n "${1}" ] && title="${1}" || title="${JOB_NAME}"
    L_LOG
    INFO "${title}: Finished"
    L_LOG
}


function __run_log () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _cmd
    if [ -z "${1}" ] ; then
        ERROR "__run_log(): Argument missing!"
    else
        _cmd="${1}"
        INFO "Running command: [${_cmd}]"
        eval ${_cmd} >> "${LOGFILE}" 2>&1
        _rc=$?
        if [ ${_rc} -ne 0 ] ; then
            ERROR "Failed! Rc: [${_rc}]"
        else
            INFO "Success."
        fi
    fi
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}


function __run_nolog () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _cmd
    if [ -z "${1}" ] ; then
        ERROR "__run_nolog(): Argument missing!"
    else
        _cmd="${1}"
        eval ${_cmd} > /dev/null 2>&1
        _rc=$?
    fi
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}


function RM_FILES () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _main_rc=1
    local _rc=1
    local f
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Removing file(s)"
    JOB_START
    if [ -z "${*}" ] ; then
        ERROR "RM_FILES(): Argument missing!"
#        LOG_RC ${_main_rc}
    else
        _main_rc=0
        for f in "${@}" ; do
            INFO "Removing file: '${f}'"
            _rc=1
            if [ -e "${f}" -o -L "${f}" ] ; then
                __run_log "rm -f ${opts} \"${f}\""
                _rc=$?
                [ ${_rc} -ne 0 ] && _main_rc=${_rc}
            else
                ERROR "'${f}': file not found !"
            fi
        done
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_main_rc}
}

function RM_DIRS () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _main_rc=1
    local _rc=1
    local d
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Removing directory"
    JOB_START
    if [ -z "${*}" ] ; then
        ERROR "RM_DIRS(): Argument missing!"
    else
        _main_rc=0
        for d in "${@}" ; do
            INFO "Removing directory: '${d}'"
            if [ -d "${d}" ] ; then
                if [ "${d}" = "/" ] ; then
                    ERROR "Can not remove this directory: '${d}'"
                    _main_rc=5
                else
                    __run_log "rm -rf ${opts} \"${d}\""
                    _rc=$?
                    [ ${_rc} -ne 0 ] && _main_rc=${_rc}
                fi
            else
                ERROR "'${d}': directory does not exists."
            fi
        done
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_main_rc}
}

function APT_CLEAN () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc
    local opts="-qq"
    [ ${DEBUG} = "yes" ] && opts=""
    JOB_NAME="Perform APT Clean"
    JOB_START
    __run_log "apt-get ${opts} clean"
    _rc=$?
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function APT_UPDATE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc
    local _main_rc=0
    local opts="-qq"
    [ ${DEBUG} = "yes" ] && opts=""
    JOB_NAME="Perform APT Update"
    JOB_START
    __run_log "apt-get ${opts} update"
    _rc=$?
    [ ${_rc} -ne 0 ] && _main_rc=${_rc}
    #
    INFO "Perform APT -f install"
    __run_log "apt-get ${opts} -f install"
    _rc=$?
    [ ${_rc} -ne 0 ] && _main_rc=${_rc}
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_main_rc}
}

function APT_DIST_UPGRADE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc
    local opts="-qq"
    [ ${DEBUG} = "yes" ] && opts=""
    JOB_NAME="Perform APT Dist-Upgrade"
    JOB_START
    __run_log "apt-get ${opts} -y --force-yes dist-upgrade"
    _rc=$?
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function APT_INSTALL () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local opts="-qq"
    [ ${DEBUG} = "yes" ] && opts=""
    [ "${ALLOW_UNAUTH_PKGS}" = "yes" ] && opts="${opts} --allow-unauthenticated"
    JOB_NAME="Perform APT Install ${*}"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "APT_INSTALL(): Argument(s) missing!"
    else
        __run_log "apt-get ${opts} -y install ${*}"
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function APT_REMOVE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local opts="-qq"
    [ ${DEBUG} = "yes" ] && opts=""
    JOB_NAME="Perform APT Remove ${*}"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "APT_REMOVE(): Argument(s) missing!"
    else
        __run_log "apt-get ${opts} -y purge ${*}"
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function APT_AUTOREMOVE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc
    local opts="-qq"
    [ ${DEBUG} = "yes" ] && opts=""
    JOB_NAME="Perform APT Auto-Remove"
    JOB_START
    __run_log "apt-get ${opts} -y autoremove"
    _rc=$?
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function ADD_APT_REPO () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _repo
    JOB_NAME="Add APT Repository -> '${_repo}'"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "ADD_APT_REPO(): Argument missing!"
    else
        _repo="${1}"
        __run_log "add-apt-repository -y \"${_repo}\""
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function DEL_APT_REPO () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _repo
    JOB_NAME="Remove APT Repository -> '${_repo}'"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "DEL_APT_REPO(): Argument missing!"
    else
        _repo="${1}"
        __run_log "add-apt-repository -y -r \"${_repo}\""
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function ADD_APT_KEY_URL () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _url
    JOB_NAME="Add APT Key -> '${_url}'"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "ADD_APT_KEY_URL(): Argument missing!"
    else
        _url="${1}"
        __run_log "wget -qO - \"${_url}\" | apt-key add -"
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function ADD_APT_KEY_FILE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _file
    JOB_NAME="Add APT Key -> '${_file}'"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "ADD_APT_KEY_FILE(): Argument missing!"
    else
        _file="${1}"
        __run_log "apt-key add \"${_file}\""
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function YUM_DIST_UPGRADE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Perform YUM Dist-Upgrade"
    JOB_START
    __run_log "yum ${opts} -y update"
    _rc=$?
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function YUM_INSTALL () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    LOG=""
    JOB_NAME="Perform RPM (url) Install ${*}"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "YUM_INSTALL(): Argument(s) missing!"
    else
        if [ "${1}" = "--url" -o "${1}" = "-u" ] ; then
            if [ -z "${1}" ] ; then
                ERROR "YUM_INSTALL() URL: Argument missing!"
            else
                __run_log "rpm ${opts} -Uh \"${2}\""
                _rc=$?
            fi
        else
            __run_log "yum ${opts} -y install ${*}"
            _rc=$?
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function YUM_GROUPINSTALL () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local g
    local _main_rc=1
    local _rc
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Perform YUM Group Install ${@}"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "YUM_GROUPINSTALL(): Argument(s) missing!"
    else
        _main_rc=0
        for g in "${@}" ; do
            __run_log "yum ${opts} -y groupinstall \"${g}\""
            _rc=$?
            [ ${_rc} -ne 0 ] && _main_rc=${_rc}
        done
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_main_rc}
}

function YUM_REMOVE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Perform YUM Remove ${*}"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "YUM_REMOVE(): Argument(s) missing!"
    else
        JOB_NAME="Perform YUM Remove"
        JOB_NAME="${JOB_NAME} ${*}"
        __run_log "yum ${opts} -y remove ${*}"
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function YUM_GROUPREMOVE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local g
    local _main_rc=1
    local _rc
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Perform YUM Group Remove ${@}"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "YUM_GROUPREMOVE(): Argument(s) missing!"
    else
        _main_rc=0
        for g in "${@}" ; do
            LOG=""
            __run_log "yum ${opts} -y groupremove \"${g}\""
            _rc=$?
            [ ${_rc} -ne 0 ] && _main_rc=${_rc}
        done
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_main_rc}
}

function YUM_AUTOREMOVE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc
    local opts
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Perform YUM Auto-Remove"
    JOB_START
    LOG=""
    __run_log "yum ${opts} -y autoremove"
    _rc=$?
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function YUM_CLEAN () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Perform YUM Clean ALL"
    JOB_START
    LOG=""
    __run_log "yum ${opts} -y clean all"
    _rc=$?
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function GIT_CLONE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _url
    local _dst
    local _msg
    local opts="-q"
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Cloning repository"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "GIT_CLONE(): Argument missing!"
    else
        _url="${1}"
        _dst="${2}"
        _msg="Cloning repository: '${_url}'"
        [ ! -z "${_dst}" ] && _msg="${_msg} -> '${_dst}'"
        INFO "${s}"
        __run_log "git clone ${opts} \"${_url}\" \"${_dst}\""
        _rc=$?
    fi
    JOB_START
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function CHOWN_FILE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local f
    local _owner
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Changing owner"
    JOB_START
    if [ -z "${2}" ] ; then
        ERROR "CHOWN_FILE(): Argument(s) missing!"
    else
        _owner="${1}"
        f="${2}"
        INFO "Changing owner of '${f}' file -> '${_owner}'"
        if [ -e "${f}" ] ; then
            __run_log "chown ${opts} ${_owner} \"${f}\""
            _rc=$?
        else
            ERROR "'${f}': file does not exists."
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function CHOWN_DIR () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local d
    local _owner
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Changing owner"
    JOB_START
    if [ -z "${2}" ] ; then
        ERROR "CHOWN_DIR(): Argument(s) missing!"
    else
        _owner="${1}"
        d="${2}"
        INFO "Changing owner of '${d}' directory -> '${_owner}'"
        if [ -d "${d}" ] ; then
            __run_log "chown -R ${opts} ${_owner} \"${d}\""
            _rc=$?
        else
            ERROR "'${d}': Directory does not exists."
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function CHMOD_FILE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local f
    local _mode
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Changing mode"
    JOB_START
    if [ -z "${2}" ] ; then
        ERROR "CHMOD_FILE(): Argument(s) missing!"
    else
        _mode="${1}"
        f="${2}"
        INFO "Changing mode of '${f}' -> '${_mode}'"
        if [ -e "${f}" ] ; then
            __run_log "chmod ${opts} ${_mode} \"${f}\""
            _rc=$?
        else
            ERROR "'${f}': file does not exists."
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function CHMOD_DIR () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local d
    local _mode
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Changing mode"
    JOB_START
    if [ -z "${2}" ] ; then
        ERROR "CHMOD_DIR(): Argument(s) missing!"
    else
        _mode="${1}"
        d="${2}"
        INFO "Changing mode of '${d}' -> '${_mode}'"
        if [ -d "${d}" ] ; then
            __run_log "chmod -R ${opts} ${_mode} \"${d}\""
            _rc=$?
        else
            ERROR "'${d}': directory does not exists."
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function CP_FILE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _src
    local _dst
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Copy file"
    JOB_START
    if [ -z "${2}" ] ; then
        ERROR "CP_FILE(): Argument(s) missing!"
    else
        _src="${1}"
        _dst="${2}"
        INFO "Copying '${_src}' -> '${_dst}'"
        if [ -e "${_src}" ] ; then
            __run_log "cp -f ${opts} \"${_src}\" \"${_dst}\""
            _rc=$?
        else
            ERROR "'${_src}': file does not exists."
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function CP_DIR () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _src
    local _dst
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Copy directory"
    JOB_START
    if [ -z "${2}" ] ; then
        ERROR "CP_DIR(): Argument(s) missing!"
    else
        _src="${1}"
        _dst="${2}"
        INFO "Copying '${_src}' -> '${_dst}'"
        if [ -e "${_src}" ] ; then
            __run_log "cp -rf ${opts} \"${_src}\" \"${_dst}\""
            _rc=$?
        else
            ERROR "'${_src}': file does not exists."
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function MV () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _src
    local _dst
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Move"
    JOB_START
    if [ -z "${2}" ] ; then
        ERROR "MV(): Argument(s) missing!"
    else
        _src="${1}"
        _dst="${2}"
        INFO "Moving '${_src}' -> '${_dst}'"
        if [ -e "${_src}" ] ; then
            __run_log "mv -f ${opts} \"${_src}\" \"${_dst}\""
            _rc=$?
        else
            ERROR "'${_src}': file does not exists."
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function LN () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _tgt
    local _lnk
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Create symbolic link"
    JOB_START
    if [ -z "${2}" ] ; then
        ERROR "LN(): Argument(s) missing!"
    else
        _tgt="${1}"
        _lnk="${2}"
        INFO "Creating symbolic link: '${_lnk}' -> '${_tgt}'"
        __run_log "ln -fs ${opts} \"${_tgt}\" \"${_lnk}\""
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function SVC_ENABLE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _svc
    JOB_NAME="Enable service"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "SVC_ENABLE(): Argument missing!"
    else
        _svc="${1}"
        # Tweaks for functions.sh v1 library clients
        [ "${_svc}" = "apache2" ] && _svc="${APACHE_SVC}"
        # 
        INFO "Enabling service: '${_svc}'"
        if [ "${SVC_SYSTEM}" = "systemd" ] ; then
            __run_log "systemctl enable \"${_svc}\""
            _rc=$?
        elif [ "${SVC_SYSTEM}" = "init" ] ; then
            __run_log "chkconfig --list \"${_svc}\" > /dev/null 2>&1 \
                          || chkconfig --add \"${_svc}\" 2>&1 ; \
                             chkconfig \"${_svc}\" on 2>&1 ; \
                             chkconfig --list \"${_svc}\""
            _rc=$?
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function SVC_DISABLE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _svc
    JOB_NAME="Disable service"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "SVC_DISABLE(): Argument missing!"
    else
        _svc="${1}"
        # Tweaks for functions.sh v1 library clients
        [ "${_svc}" = "apache2" ] && _svc="${APACHE_SVC}"
        # 
        INFO "Disabling service: '${_svc}'"
        if [ "${SVC_SYSTEM}" = "systemd" ] ; then
            __run_log "systemctl disable \"${_svc}\""
            _rc=$?
        elif [ "${SVC_SYSTEM}" = "init" ] ; then
            __run_log "chkconfig \"${_svc}\" off"
            _rc=$?
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function SVC_START () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _svc
    JOB_NAME="Start service"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "SVC_START(): Argument missing!"
    else
        _svc="${1}"
        # Tweaks for functions.sh v1 library clients
        [ "${_svc}" = "apache2" ] && _svc="${APACHE_SVC}"
        # 
        INFO "Starting service: '${_svc}'"
        __run_log "/bin/bash -c \"/usr/sbin/service ${_svc} start\""
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function SVC_STOP () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _svc
    JOB_NAME="Stop service"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "SVC_STOP(): Argument missing!"
    else
        _svc="${1}"
        # Tweaks for functions.sh v1 library clients
        [ "${_svc}" = "apache2" ] && _svc="${APACHE_SVC}"
        # 
        INFO "Stopping service: '${_svc}'"
        __run_log "/bin/bash -c \"/usr/sbin/service ${_svc} stop\" 2>&1"
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function SVC_RESTART () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _svc
    JOB_NAME="Restart service"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "SVC_RESTART(): Argument missing!"
    else
        _svc="${1}"
        # Tweaks for functions.sh v1 library clients
        [ "${_svc}" = "apache2" ] && _svc="${APACHE_SVC}"
        # 
        INFO "Restarting service: '${_svc}'"
        __run_log "/bin/bash -c \"/usr/sbin/service ${_svc} restart\""
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function SYSTEMD_RELOAD () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    JOB_NAME="Reloading SystemD configuration"
    JOB_START
    LOG=""
    __run_log "systemctl daemon-reload"
    _rc=$?
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function MKDIR () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local d
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="Create directory"
    JOB_START
    if [ -z "${*}" ] ; then
        ERROR "MKDIR(): Argument missing!"
    else
        LOG=""
        d="${1}"
        _rc=0
        INFO "Creating directory: '${d}'"
        if [ ! -d "${d}" ] ; then
            __run_log "mkdir -p ${opts} \"${d}\""
            _rc=$?
        else
            ERROR "'${d}': directory already exists"
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function MKDIR_TMP () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=0
    if [ ! -d "${TMP_DIR}" ] ; then
        MKDIR "${TMP_DIR}"
        _rc=$?
    fi
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function WGET () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _url
    local opts="-nc -q --no-check-certificate"
    local path="-P ${TMP_DIR}/"
    [ ${DEBUG} = "yes" ] && opts="-nc -v -S --no-check-certificate"
    JOB_NAME="WGET"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "WGET(): Argument(s) missing!"
    else
        LOG=""
        if [ ! -z "${2}" ] ; then
            path="-O ${2}"
        fi
        _url="${1}"
        INFO "Fetching: '${_url}'"
        __run_log "wget ${opts} ${path} ${_url} 2>&1"
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function TAR_ZXF () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _tar
    local opts=""
    local path="."
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="TAR ZXF"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "TAR_ZXF(): Argument missing!"
    else
        if [ ! -z "${2}" ] ; then
            path="${2}"
        fi
        _tar="${1}"
        INFO "Extracting: '${_tar}' -> '${path}'"
        if [ ! -e "${_tar}" ] ; then
            ERROR "TAR_ZXF(): '${_tar}': file not found!"
        else
            __run_log "tar ${opts} -zxf \"${_tar}\" -C \"${path}\""
            _rc=$?
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function UNZIP () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _zip
    local path="."
    JOB_NAME="UNZIP"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "UNZIP(): Argument missing!"
    else
        if [ ! -z "${2}" ] ; then
            path="${2}"
        fi
        _zip="${1}"
        INFO "Unzipping: '${_zip}' -> '${path}'"
        if [ ! -e "${_zip}" ] ; then
            ERROR "UNZIP(): '${_zip}': file not found!"
        else
            __run_log "unzip -d \"${path}\" \"${_zip}\""
            _rc=$?
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function DPKG_CHECK () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _pkg
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-D1"
    if [ -z "${1}" ] ; then
        ERROR "DPKG_CHECK(): Argument missing!"
    else
        _pkg="${1}"
        ${__run_cmd} "dpkg ${opts} -s ${_pkg}"
        _rc=$?
    fi
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function DPKG_INSTALL () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _pkg
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-D1"
    JOB_NAME="DPKG Install"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "DPKG_INSTALL(): Argument missing!"
    else
        _pkg="${1}"
        INFO "Installing: '${_pkg}'"
        if [ ! -e "${_pkg}" ] ; then
            ERROR "'${_pkg}': file not found!"
        else
            __run_log "dpkg ${opts} -i \"${_pkg}\""
            _rc=$?
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function DPKG_REMOVE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _pkg
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-D1"
    JOB_NAME="DPKG Remove"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "DPKG_REMOVE(): Argument missing!"
    else
        _pkg="${1}"
        INFO "Removing: '${_pkg}'"
        __run_log "dpkg ${opts} --purge \"${_pkg}\""
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}


function RPM_CHECK () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _pkg
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    if [ -z "${1}" ] ; then
        ERROR "DPKG_CHECK(): Argument missing!"
    else
        _pkg="${1}"
        ${__run_cmd} "rpm ${opts} -q \"${_pkg}\""
        _rc=$?
    fi
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function RPM_INSTALL () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="RPM Install"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "RPM_INSTALL(): Argument missing!"
    else
        LOG=""
        INFO "Perform RPM Install ${*}"
        __run_log "rpm ${opts} -Uh \"${1}\""
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}


function PIP_INSTALL () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="PIP Install"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "PIP_INSTALL(): Argument(s) missing!"
    else
        INFO "Perform PIP Install: ${*}"
        __run_log "pip install ${opts} ${*}"
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function PIP_UNINSTALL () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local opts=""
    [ ${DEBUG} = "yes" ] && opts="-v"
    JOB_NAME="PIP Uninstall"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "PIP_INSTALL(): Argument(s) missing!"
    else
        INFO "Perform PIP Uninstall: ${*}"
        __run_log "pip uninstall ${opts} -y ${*}"
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function MONIT_RELOAD () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    JOB_NAME="'monit' reload"
    JOB_START
    ${__run_cmd} "service 'monit' status"
    if [ $? -ne 0 ] ; then
        ERROR "'monit' service is not active"
    else
        __run_log "monit reload"
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function RUN_LOG () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _rc=1
    local _cmd
    JOB_NAME="Run command"
    JOB_START
    if [ -z "${1}" ] ; then
        ERROR "RUN_LOG(): Argument missing!"
    else
        _cmd="${1}"
#        INFO "Running command: [${_cmd}]"
        __run_log "${_cmd}"
        _rc=$?
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function AUTOCONF_UPDATE () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _autoconf_src_path
    local _oWD
    local _rc=1

    JOB_NAME="Autoconf Update"
    JOB_START
    _oWD=$( pwd )
    while true ; do
        WGET "http://ftp.gnu.org/gnu/autoconf/autoconf-latest.tar.gz" || break
        TAR_ZXF "${TMP_DIR}/autoconf-latest.tar.gz" "${TMP_DIR}/" || break
        _autoconf_src_path=$( find "${TMP_DIR}/" -maxdepth 1 -type d -name "auto*" 2> /dev/null )
        [ -z "${_autoconf_src_path}" ] && break
        [ ! -d "${_autoconf_src_path}" ] && break
        cd "${_autoconf_src_path}"
        RUN_LOG "./configure" || break
        RUN_LOG "make" || break
        RUN_LOG "make install" || break
        _rc=0
        break
    done
    cd "${_oWD}"

    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}


function FW_OPEN_PORTS () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _main_rc=1
    local _rc
    local firewalld="no"
    local iptables="no"
    local port, proto, p

    JOB_NAME="Firewall: open ports"
    JOB_START

    if [ -z "${*}" ] ; then
        ERROR "FW_OPEN_PORTS(): Argument missing!"
        _main_rc=1
    else
        RUN_LOG "service firewalld status > /dev/null 2>&1" && firewalld="yes"
        RUN_LOG "service iptables status > /dev/null 2>&1" && iptables="yes"
        _main_rc=0
        if [ "${firewalld}" = "yes" -o "${iptables}" = "yes" ] ; then
            for p in "${@}" ; do
                INFO "Opening port: '${p}'"
                port=$(  echo "${p}" | awk -F'/' '{print $1}' )
                proto=$( echo "${p}" | awk -F'/' '{print $2}' )
                _rc=1
                if [ "${firewalld}" = "yes" ] ; then
                    RUN_LOG "firewall-cmd --zone=public --add-port=${port}/${proto} --permanent"
                elif [ "${iptables}" = "yes" ] ; then
                    RUN_LOG "iptables -I INPUT -p ${proto} -m ${proto} --dport ${port} -j ACCEPT"
                    RUN_LOG "iptables -D INPUT -j REJECT --reject-with icmp-host-prohibited" \
                        && RUN_LOG "iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited"
                    RUN_LOG "iptables -D INPUT -j LOGGING" \
                        && RUN_LOG "iptables -A INPUT -j LOGGING"
                fi
            done
            [ "${firewalld}" = "yes" ] && RUN_LOG "firewall-cmd --reload"
            [ "${iptables}" = "yes" ] && RUN_LOG "service iptables save"
        else
            WARN "Neither FirewallD nor IPTables services are active. Skipping..."
            _main_rc=1
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_main_rc}
}

function FW_REMOVE_PORTS () {
    [ "${DEBUG}" = "yes" ] && ENTRY
    local _main_rc=1
    local _rc
    local firewalld="no"
    local iptables="no"
    local port, proto, p

    JOB_NAME="Firewall: remove ports"
    JOB_START

    if [ -z "${*}" ] ; then
        ERROR "FW_REMOVE_PORTS(): Argument missing!"
        _main_rc=1
    else
        RUN_LOG "service firewalld status > /dev/null 2>&1" && firewalld="yes"
        RUN_LOG "service iptables status > /dev/null 2>&1" && iptables="yes"
        _main_rc=0
        if [ "${firewalld}" = "yes" -o "${iptables}" = "yes" ] ; then
            for p in "${@}" ; do
                INFO "Removing port: '${p}'"
                port=$(  echo "${p}" | awk -F'/' '{print $1}' )
                proto=$( echo "${p}" | awk -F'/' '{print $2}' )
                _rc=1
                if [ "${firewalld}" = "yes" ] ; then
                    RUN_LOG "firewall-cmd --zone=public --remove-port=${port}/${proto} --permanent"
                elif [ "${iptables}" = "yes" ] ; then
                    RUN_LOG "iptables -D INPUT -p ${proto} -m ${proto} --dport ${port} -j ACCEPT"
                fi
            done
            [ "${firewalld}" = "yes" ] && RUN_LOG "firewall-cmd --reload"
            [ "${iptables}" = "yes" ] && RUN_LOG "service iptables save"
        else
            WARN "Neither FirewallD nor IPTables services are active. Skipping..."
            _main_rc=1
        fi
    fi
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_main_rc}
}

function a2ensite_centos () {
    local _site
    local _rc=1
    JOB_NAME="Enable Apache2 site (${LSB_VENDOR})"
    JOB_START
    while true ; do
        if [ -z "${1}" ] ; then
            ERROR "a2ensite_centos(): Argument missing!"
            break
        else
            _site="${1}"
            INFO "Enabling site: [${_site}]"
            if [ ! -e "/etc/apache2/sites-available/${_site}" ] ; then
                if [ -e "/etc/apache2/sites-available/${_site}.conf" ] ; then
                    _site="${_site}.conf"
                else
                    ERROR "${_site}: site not found."
                    break
                fi
            fi
            LN "/etc/apache2/sites-available/${_site}" \
               "/etc/apache2/sites-enabled/${_site}"
            _rc=$?
        fi
        break
    done
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}

function a2dissite_centos () {
    local _site
    local _rc=1
    JOB_NAME="Disable Apache2 site (${LSB_VENDOR})"
    JOB_START
    while true ; do
        if [ -z "${1}" ] ; then
            ERROR "a2dissite_centos(): Argument missing!"
            break
        else
            _site="${1}"
            INFO "Disabling site: [${_site}]"
            if [ ! -e "/etc/apache2/sites-enabled/${_site}" ] ; then
                if [ -e "/etc/apache2/sites-enabled/${_site}.conf" ] ; then
                    _site="${_site}.conf"
                else
                    ERROR "${_site}: site not found."
                    break
                fi
            fi
            RM_FILES "/etc/apache2/sites-enabled/${_site}"
            _rc=$?
        fi
        break
    done
    JOB_END
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}


# ----------------------------------------------------------
# Prepare environment functions
# ----------------------------------------------------------

function _prep_env () {
    local d

    JOB_NAME="Prepare environment"
    JOB_START

    for d in \
      "Documents" \
      "Downloads" \
      "Torrents" \
      "Watch" \
      "tmp" \
      "log"
    do
        [ ! -d "/etc/skel/${d}" ] && MKDIR "/etc/skel/${d}"
    done

    # Remove obsolete scripts
    [ -d "/opt/install_scripts" ] && RM_DIRS "/opt/install_scripts"

    # Initialize global variables
    FIRST_UID=$( grep -e '^UID_MIN\s*' "/etc/login.defs" | awk '{print $2}' )

    JOB_END
}


function _create_std_user () {
    local _uid
    local _g
    local _rc
    local _main_rc=0

    JOB_NAME="Check standard user account(s)"
    JOB_START

    _uid=$( id -u "user" 2>/dev/null )
    if [ ! -z "${_uid}" ] ; then
        INFO "'user': account exists!"
    else
        # Add regular user's account
        case "${LSB_VENDOR}" in
          "CentOS")
              RUN_LOG "adduser -c 'RapidSeedbox.com User' -m user"
              CHMOD_FILE 0755 "/home/user"
              _rc=$?
              ;;
          "Debian"|"Ubuntu")
              RUN_LOG "adduser --gecos 'RapidSeedbox.com User' --disabled-password user"
              _rc=$?
              ;;
          *)
              _rc=1
              ;;
        esac
        if [ ${_rc} -ne 0 ] ; then
            _main_rc=${_rc}
        else
            # set user's password
            RUN_LOG "echo 'user:ChangeMe' | chpasswd"
            _rc=$?
            [ ${_rc} -ne 0 ] && _main_rc=${_rc}
            # Modify new user's group membership
            for _g in sudo www-data ; do
                grep -e "^${_g}:" "/etc/group" > /dev/null 2>&1
                if [ $? -eq 0 ] ; then
                    RUN_LOG "usermod -a -G ${_g} user"
                    _rc=$?
                    [ ${_rc} -ne 0 ] && _main_rc=${_rc}
                fi
            done
        fi
    fi
    JOB_END
    return ${_main_rc}
}

function _prep_ssh () {

    local sshd_restart="no"
    local f

    JOB_NAME="Configure SSHd"
    JOB_START

    # Configure sshd
    for f in \
        "users-rapidseedbox-com-ca.pub" \
        "revoked_keys"
    do
        if [ ! -f "/etc/ssh/${f}" ] ; then
            WGET "${SUPPORT}/ssh/${f}" \
                 "/etc/ssh/${f}" \
              || return 1
            if [ ! -s "/etc/ssh/${f}" -a "${f}" != "revoked_keys" ] ; then
                 ERROR "'/etc/ssh/${f}': Empty file downloaded!"
                 RM_FILES "/etc/ssh/${f}"
                 return 1
            fi
        fi
    done

    # set TrustedUserCAKeys
    ${__run_cmd} "grep -e '^TrustedUserCAKeys' '/etc/ssh/sshd_config'"
    if [ $? -eq 0 ] ; then
        ${__run_cmd} "grep -e '^TrustedUserCAKeys /etc/ssh/users-rapidseedbox-com-ca.pub' '/etc/ssh/sshd_config'"
        if [ $? -ne 0 ] ; then
            RUN_LOG "sed -i -e 's#^TrustedUserCAKeys.*#TrustedUserCAKeys /etc/ssh/users-rapidseedbox-com-ca.pub#g' '/etc/ssh/sshd_config'"
            [ $? -eq 0 ] && sshd_restart="yes"
        fi
    else
        RUN_LOG "echo 'TrustedUserCAKeys /etc/ssh/users-rapidseedbox-com-ca.pub' >> '/etc/ssh/sshd_config'"
        [ $? -eq 0 ] && sshd_restart="yes"
    fi

    # set RevokedKeys
    ${__run_cmd} "grep -e '^RevokedKeys' '/etc/ssh/sshd_config'"
    if [ $? -eq 0 ] ; then
        ${__run_cmd} "grep -e '^RevokedKeys /etc/ssh/revoked_keys' '/etc/ssh/sshd_config'"
        if [ $? -ne 0 ] ; then
            RUN_LOG "sed -i -e 's#^RevokedKeys.*#RevokedKeys /etc/ssh/revoked_keys#g' '/etc/ssh/sshd_config'"
            [ $? -eq 0 ] && sshd_restart="yes"
        fi
    else
        RUN_LOG "echo 'RevokedKeys /etc/ssh/revoked_keys' >> '/etc/ssh/sshd_config'"
        [ $? -eq 0 ] && sshd_restart="yes"
    fi

    [ "${sshd_restart}" = "yes" ] && SVC_RESTART "${SSHD_SVC}"

    JOB_END
    return 0
}


function _prep_apache2_centos() {

    local _rc=1

    JOB_NAME="Configure Apache2 (${LSB_VENDOR})"
    JOB_START

    ${PKG_CHECK} "${APACHE_SVC}"
    if [ $? -ne 0 ] ; then
        if ${PKG_INSTALL} "${APACHE_SVC}" ; then
            # Disable default welcome page:
            RUN_LOG "sed -i -e 's/^\(.*\)$/#\1/g' '/etc/httpd/conf.d/welcome.conf' 2>&1"
            # Make Debian-style config directory structure
            # -- common settings
            LN "/etc/httpd" "/etc/apache2"
            LN "/etc/httpd/conf/httpd.conf" "/etc/httpd/apache2.conf"
            # -- configurations
            MKDIR "/etc/httpd/conf-available"
            LN "/etc/httpd/conf.d" "/etc/httpd/conf-enabled"
            # -- modules
            LN "/etc/httpd/modules" "/etc/httpd/mods-available"
            if [ -d "/etc/httpd/conf.modules.d" ] ; then
                LN "/etc/httpd/conf.modules.d" "/etc/httpd/mods-enabled"
            else
                LN "/etc/httpd/modules" "/etc/httpd/mods-enabled"
            fi
            # -- sites
            MKDIR "/etc/httpd/sites-available"
            LN "/etc/httpd/conf.d" "/etc/httpd/sites-enabled"
            # -- passwords
            MKDIR "/etc/httpd/passwords-available"
            MKDIR "/etc/httpd/passwords-enabled"
            #
            # Install SSL module
            ${PKG_INSTALL} "mod_ssl"
            #
            # Symlink RSB certificate
            LN "rsb.pem" "/etc/ssl/private/apache2.pem"
            # Enable RSB certificate in Apache config
            RUN_LOG "sed -i \
                         -e 's|^SSLCertificateFile\s*.*$|SSLCertificateFile /etc/ssl/private/apache2.pem|g' \
                         '/etc/apache2/conf-enabled/ssl.conf' 2>&1"
            RUN_LOG "sed -i \
                         -e 's|^SSLCertificateKeyFile\s*.*$|SSLCertificateKeyFile /etc/ssl/private/apache2.pem|g' \
                         '/etc/apache2/conf-enabled/ssl.conf' 2>&1"
            #
            # Configure firewall
            case "${LSB_RELEASE}" in
              "6")
                  RUN_LOG "iptables -I INPUT -p tcp -m tcp --dport 443 -j ACCEPT"
                  RUN_LOG "service iptables save"
                  ;;
              "7")
                  RUN_LOG "systemctl is-active firewalld 2>&1"
                  if [ $? -eq 0 ] ; then
                      RUN_LOG "firewall-cmd --zone=public --add-port=443/tcp --permanent"
                      RUN_LOG "firewall-cmd --reload"
                  fi
                  RUN_LOG "systemctl is-active iptables 2>&1"
                  if [ $? -eq 0 ] ; then
                      RUN_LOG "iptables -I INPUT -p tcp -m tcp --dport 443 -j ACCEPT"
                      RUN_LOG "service iptables save"
                  fi
                  ;;
            esac
            #
            # Enable/Start service
            SVC_ENABLE "${APACHE_SVC}"
            SVC_RESTART "${APACHE_SVC}"
            _rc=0
        fi
    fi

    JOB_END
    return ${_rc}
}


function _prep_apache2_deb() {

    local _rc=1

    JOB_NAME="Configure Apache2 (${LSB_VENDOR})"
    JOB_START

    DPKG_CHECK "${APACHE_SVC}"
    if [ $? -ne 0 ] ; then
        APT_INSTALL "${APACHE_SVC}" "apache2-utils" || return 1
        MKDIR "/etc/apache2/userconf-enabled" || return 1
        cat <<-EOF > "/etc/apache2/sites-available/rsb.conf" 2>> "${LOGFILE}"
	<VirtualHost _default_:443>
		ServerAdmin webmaster@localhost
		DocumentRoot /var/www/html
		ErrorLog \${APACHE_LOG_DIR}/error.log
		CustomLog \${APACHE_LOG_DIR}/access.log combined
		SSLEngine on
		SSLCertificateFile /etc/ssl/private/apache2.pem
		SSLCertificateKeyFile /etc/ssl/private/apache2.pem
		<FilesMatch "\.(cgi|shtml|phtml|php)$">
			SSLOptions +StdEnvVars
		</FilesMatch>
		<Directory /usr/lib/cgi-bin>
			SSLOptions +StdEnvVars
		</Directory>

	        <IfModule mod_userdir.c>
	                UserDir /home/*
	                UserDir disabled root
	                HeaderName HEADER.html
	                ReadmeName README.html
	                <Directory /home/*>
	                        AllowOverride FileInfo AuthConfig Limit Indexes
	                        Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
	                        <Limit GET POST OPTIONS>
	                                Require all granted
	                        </Limit>
	                        <LimitExcept GET POST OPTIONS>
	                                Require all denied
	                        </LimitExcept>
	                </Directory>
	        </IfModule>

	        <IfModule mod_proxy.c>
	                 ProxyRequests off
	                 ProxyPreserveHost On
	                 RewriteEngine on
	                 RewriteRule ^/rutorrent$ /rutorrent/ [R]
	                 ProxyPass /rutorrent http://127.0.0.1:8080/
	                 ProxyPassReverse /rutorrent http://127.0.0.1:8080/
	                 IncludeOptional userconf-enabled/*.conf
	        </IfModule>
	</VirtualHost>
	EOF

        # User access file
        cat <<-EOF > "/etc/skel/.htaccess" 2>> "${LOGFILE}"
	AuthType Digest
	AuthName "apache2"
	AuthUserFile /etc/apache2/users.password
	Require user ###USERNAME###
	EOF
        CHMOD_FILE 640 "/etc/skel/.htaccess"

        if [ -d "/etc/monit/conf.d" ] ; then
            cat <<-EOF > "/etc/monit/conf.d/apache2" 2>> "${LOGFILE}"
		check process apache2 with pidfile /var/run/apache2/apache2.pid
		   group apache
		   start program = "/bin/systemctl restart apache2"
		   stop program  = "/bin/systemctl stop apache2"
		   if 5 restarts within 20 cycles then timeout
		   depend apache_bin
		   depend apache_rc

		check file apache_bin with path /usr/sbin/apache2
		   group apache
		   include /etc/monit/templates/rootbin

		check file apache_rc with path /etc/init.d/apache2
		   group apache
		   include /etc/monit/templates/rootbin
		EOF
        fi

        if [ -f "/etc/fail2ban/jail.d" ] ; then
            cat <<-EOF > "/etc/fail2ban/jail.d/apache.conf" 2>> "${LOGFILE}"
		[apache-auth]
		enabled = true

		[apache-badbots]
		enabled = true

		[apache-noscript]
		enabled = true

		[apache-overflows]
		enabled = true

		[apache-nohome]
		enabled = true

		[apache-botsearch]
		enabled = true

		[apache-fakegooglebot]
		enabled = true

		[apache-modsecurity]
		enabled = true

		[apache-shellshock]
		enabled = true
		EOF
        fi

        # Enable SSL module
        RUN_LOG "a2enmod ssl"
        # Disable default site configuration
        RUN_LOG "a2dissite 000-default"
        # Define server name
        echo -ne "ServerName $( hostname )" > "/etc/apache2/conf-available/fqdn.conf"
        RUN_LOG "a2enconf fqdn.conf"
        # RSB site configuration
        RUN_LOG "a2enmod proxy"
        RUN_LOG "a2enmod proxy_http"
        RUN_LOG "a2enmod headers"
        RUN_LOG "a2enmod rewrite"
        RUN_LOG "a2enmod auth_digest"
        RUN_LOG "a2ensite rsb.conf"
        # Symlink RSB certificate
        RUN_LOG "ln -s rsb.pem /etc/ssl/private/apache2.pem"

        # Generate selfsigned certificate
        RUN_LOG "make-ssl-cert generate-default-snakeoil --force-overwrite 2>&1"
        RUN_LOG "cat '/etc/ssl/certs/ssl-cert-snakeoil.pem' \
                     '/etc/ssl/private/ssl-cert-snakeoil.key' \
                   > '/etc/ssl/private/rsb.pem'"
        CHMOD_FILE 0600 "/etc/ssl/private/rsb.pem 2>&1"
        RM_FILES "/etc/ssl/certs/ssl-cert-snakeoil.pem" \
                 "/etc/ssl/private/ssl-cert-snakeoil.key"
        RUN_LOG "find /etc/ssl/certs -lname ssl-cert-snakeoil.pem -exec rm -v {} \; 2>&1"

        # Restart services which depends on certificates
        SVC_RESTART "${APACHE_SVC}"

        _rc=0
    fi

    JOB_END
    return ${_rc}
}



# ----------------------------------------------------------
# Script entry/exit functions
# ----------------------------------------------------------

function SCRIPTEXIT(){

    local _msg

    operation1=""
    operation2=""
    timeAndDate=$( date )
    script_name=$( basename "${0}" )

    # Auto-remove packages
    [ "${LSB_VER}" = "CentOS7" ] && ${PKG_AUTOREMOVE}

    #
    # Common tasks
    case "${LSB_VENDOR}" in
      "CentOS")
          YUM_CLEAN
          ;;
      "Debian"|"Ubuntu")
          APT_CLEAN
          ;;
    esac
    [ -e "${tmp}" ] && RM_FILES  "${tmp}"
    ${__run_cmd} "rm -rf ${TMP_DIR}"
    ${__run_cmd} "rm -f ./${LIBRARY}"

    case ${script_name} in
    install_*)
        operation1="installing"
        operation2="Installation"
        ;;
    uninstall_*)
        operation1="uninstalling"
        operation2="Uninstallation"
        ;;
    esac

    cd ~/
    _msg="${timeAndDate} :: finished ${operation1} '${APP}' for ${IP} - exit code: [${main_rc}]"
    [ ${main_rc} -ne 0 ] \
      && _msg="${timeAndDate} :: Attention - @channel - finished ${operation1} '${APP}' for ${IP} - exit code: [${main_rc}]"
    ./slackpost "rsb-installers" "${_msg}" > /dev/null 2>&1

    if [ ! -z "${main_rc}" ] ; then
        echo -e "\n\n" >> "${LOGFILE}"
        L_LOG
        JOB_NAME="${operation2} status for '${APP}'"
        LOG=""
        LOG_RC ${main_rc}
    fi

    echo -e "\n\n" >> "${LOGFILE}"
    L_LOG
    echo "${FUNCNAME}: ${script_name}" >> "${LOGFILE}"
    L_LOG
    echo -e "\n\n\n\n\n\n" >> "${LOGFILE}"

    echo "${main_rc}"
    >&2 echo "${main_rc}"
    exit ${main_rc}

}

function VALIDATE_USER() {
    USERUID=$( id -u "${USERNAME}" 2>/dev/null )
    if [ -z "${USERUID}" ] ; then
        ERROR "'${USERNAME}': account not found !"
        ERROR "Can not continue. Exiting..."
        L_LOG
        main_rc=1
        SCRIPTEXIT
    fi
}


function SCRIPTENTRY(){

    local app

    operation1=""
    timeAndDate=$( date )
    script_name=$( basename "${0}" )

    __run_cmd="__run_nolog"
    [ "${DEBUG}" = "yes" ] && __run_cmd="__run_log"

    [ -e "${LOGFILE}" ] && echo -e "\n\n\n\n" >> "${LOGFILE}"
    L_LOG
    echo "${FUNCNAME}: ${script_name}" >> "${LOGFILE}"
    L_LOG

    case ${script_name} in
    install_*)
        operation1="installing"
        ;;
    uninstall_*)
        operation1="uninstalling"
        ;;
    esac

    ./slackpost "rsb-installers" "${timeAndDate} :: started ${operation1} '${APP}' for ${IP}" > /dev/null 2>&1

    #
    # Perform common installation tasks
    #

    MKDIR_TMP
    if [ $? -ne 0 ] ; then
        main_rc=1
        SCRIPTEXIT
    fi

    ${__run_cmd} "which lsb_release 2>&1"
    if [ $? -ne 0 ] ; then
        if [ -f "/etc/redhat-release" ] ; then
            LSB_VENDOR=$( cat "/etc/redhat-release" | sed -e 's|\(.*\)\s*release\s*.*$|\1|' )
            LSB_RELEASE=$( cat "/etc/redhat-release" | awk '{print $3}' )
            LSB_CODENAME=$( cat "/etc/redhat-release" | awk '{print $4}' | tr -d "(" | tr -d ")" )
            LSB_DESCRIPTION=$( cat "/etc/redhat-release" )
        elif [ -f "/etc/lsb-release" ] ; then
            . "/etc/lsb-release"
            LSB_VENDOR="${DISTRIB_ID}"
            LSB_RELEASE="${DISTRIB_RELEASE}"
            LSB_CODENAME="${DISTRIB_CODENAME}"
            LSB_DESCRIPTION="${DISTRIB_DESCRIPTION}"
        else
            ERROR "Can not determine Linux distribution, sorry!"
            main_rc=1
            SCRIPTEXIT
        fi
    else
        LSB_VENDOR=$( lsb_release -si 2>&1 )
        LSB_RELEASE=$( lsb_release -sr )
        LSB_CODENAME=$( lsb_release -sc )
        LSB_DESCRIPTION=$( lsb_release -sd )
    fi
    LSB_VENDOR_L=$( echo "${LSB_VENDOR}" | tr '[:upper:]' '[:lower:]' )
    [ "${LSB_VENDOR}" = "CentOS" ] \
        && LSB_RELEASE=$( echo "${LSB_RELEASE}" | awk -F'.' '{print $1}' )
    LSB_VER="${LSB_VENDOR}${LSB_RELEASE}"

    case "${LSB_VENDOR}" in
      "CentOS")
          PKG_INSTALL="YUM_INSTALL"
          PKG_RAW_INSTALL="RPM_INSTALL"
          PKG_REMOVE="YUM_REMOVE"
          PKG_AUTOREMOVE="YUM_AUTOREMOVE"
          PKG_UPDATE="YUM_DIST_UPGRADE"
          DIST_UPGRADE="YUM_DIST_UPGRADE"
          PKG_CHECK="RPM_CHECK"
          SSHD_SVC="sshd"
          APACHE_SVC="httpd"
          APACHE_USER="apache"
          APACHE_GROUP="apache"
          A2ENSITE="a2ensite_centos"
          A2DISSITE="a2dissite_centos"
          REQ_PACKAGES="acl bash-completion mc monit cronie logrotate less"

          if [ "${LSB_RELEASE}" = "6" ] ; then
              SVC_SYSTEM="init"
              ${PKG_CHECK} "nux-dextop-release" || ${PKG_INSTALL} --url \
                    "http://li.nux.ro/download/nux/dextop/el6/x86_64/nux-dextop-release-0-2.el6.nux.noarch.rpm"
          elif [ "${LSB_RELEASE}" = "7" ] ; then
              SVC_SYSTEM="systemd"
              ${PKG_CHECK} "nux-dextop-release" || ${PKG_INSTALL} --url \
                    "http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm"
          fi

#          if [ "${DIST_UPGRADE_ENABLED}" = "yes" ] ; then
#              ${DIST_UPGRADE} || {
#                  ERROR "Error(s) upgrading distribution '${LSB_VER}' !"
#                  L_LOG
#                  main_rc=1
#                  SCRIPTEXIT
#              }
#          fi
          ${PKG_INSTALL} ${REQ_PACKAGES} || {
              ERROR "Error(s) installing essential packages for '${LSB_VER}' !"
              L_LOG
              main_rc=1
              SCRIPTEXIT
          }
          # Prepare environment
          _prep_env
          _create_std_user
          _prep_ssh

          ;;

      "Debian"|"Ubuntu")
          PKG_INSTALL="APT_INSTALL"
          PKG_RAW_INSTALL="DPKG_INSTALL"
          PKG_REMOVE="APT_REMOVE"
          PKG_AUTOREMOVE="APT_AUTOREMOVE"
          PKG_UPDATE="APT_UPDATE"
          DIST_UPGRADE="APT_DIST_UPGRADE"
          PKG_CHECK="DPKG_CHECK"
          SVC_SYSTEM="systemd"
          SSHD_SVC="ssh"
          APACHE_SVC="apache2"
          APACHE_USER="www-data"
          APACHE_GROUP="www-data"
          A2ENSITE="a2ensite"
          A2DISSITE="a2dissite"
          REQ_PACKAGES="acl bash-completion mc monit cron logrotate less diffutils software-properties-common"

          if [ "${LSB_VENDOR}" = "Debian" ] ; then
              REQ_PACKAGES="${REQ_PACKAGES} apt-transport-https"
          elif [ "${LSB_VENDOR}" = "Ubuntu" ] ; then
              REQ_PACKAGES="${REQ_PACKAGES} ppa-purge python-software-properties"
              case "${LSB_RELEASE}" in
                "15.04"|"15.10"|"16.04")
                     REQ_PACKAGES="${REQ_PACKAGES} apt-transport-https debconf-utils"
                     ;;
                "16.10")
                     REQ_PACKAGES="${REQ_PACKAGES} debconf"
                     ;;
              esac
          fi

          case "${LSB_VENDOR}" in
            "Debian")
                DEB_MIRROR="http://ftp.nl.debian.org/debian"
#               DEB_MIRROR="http://httpredir.debian.org/debian"
                cat <<-EOF > "${rootfs}/etc/apt/sources.list"
		deb ${DEB_MIRROR} ${LSB_CODENAME} main contrib non-free
		deb-src ${DEB_MIRROR} ${LSB_CODENAME} main contrib non-free
		deb ${DEB_MIRROR} ${LSB_CODENAME}-updates main contrib non-free
		deb-src ${DEB_MIRROR} ${LSB_CODENAME}-updates main contrib non-free
		deb http://security.debian.org/ ${LSB_CODENAME}/updates main contrib non-free
		deb-src http://security.debian.org/ ${LSB_CODENAME}/updates main contrib non-free
		deb ${DEB_MIRROR} ${LSB_CODENAME}-backports main contrib non-free
		deb-src ${DEB_MIRROR} ${LSB_CODENAME}-backports main contrib non-free
		EOF
                ;;
            "Ubuntu")
                case "${LSB_RELEASE}" in
                  "16.10")
                      cat <<-EOF > "/etc/apt/sources.list"
		deb http://archive.ubuntu.com/ubuntu ${LSB_CODENAME} main restricted universe
		deb http://archive.ubuntu.com/ubuntu ${LSB_CODENAME}-updates main restricted universe
		deb http://security.ubuntu.com/ubuntu ${LSB_CODENAME}-backports main restricted universe multiverse
		deb http://security.ubuntu.com/ubuntu ${LSB_CODENAME}-security main restricted universe multiverse
		EOF
                      ;;
                  *)
                      cat <<-EOF > "/etc/apt/sources.list"
		deb mirror://mirrors.ubuntu.com/mirrors.txt ${LSB_CODENAME} main restricted universe multiverse
		deb mirror://mirrors.ubuntu.com/mirrors.txt ${LSB_CODENAME}-updates main restricted universe multiverse
		deb mirror://mirrors.ubuntu.com/mirrors.txt ${LSB_CODENAME}-backports main restricted universe multiverse
		deb mirror://mirrors.ubuntu.com/mirrors.txt ${LSB_CODENAME}-security main restricted universe multiverse
		EOF
                     ;;
                esac
                ;;
          esac

          # Prepare environment
          _prep_env
          _create_std_user
          _prep_ssh

          # Tweaks :)
          case "${LSB_RELEASE}" in
             "15.04")
                 INFO "Workaround for '${LSB_VER}':"
                 INFO "    For details see:   https://bugs.launchpad.net/ubuntu/+source/apt/+bug/1479045"
                 RM_DIRS "/var/lib/apt/lists/partial"
                 ;;
            *)
                 ;;
          esac

          # Tweaks for various stuff :((((
          ADD_APT_KEY_URL "https://linux-packages.resilio.com/resilio-sync/key.asc"

          ${PKG_UPDATE} || {
              ERROR "Error(s) updating PKG cache for '${LSB_VER}' !"
              L_LOG
              main_rc=1
              SCRIPTEXIT
          }

          # Do not upgrade some packages
          # --- numix-gtk-theme numix-icon-theme numix-icon-theme-circle

          if [ "${DIST_UPGRADE_ENABLED}" = "yes" ] ; then
              ${DIST_UPGRADE} || {
                  ERROR "Error(s) upgrading distribution '${LSB_VER}' !"
                  L_LOG
                  main_rc=1
                  SCRIPTEXIT
              }
          fi

          ${PKG_CHECK} "mlocate"
          if [ $? -ne 0 ] ; then
              ${PKG_INSTALL} "mlocate" && RUN_LOG "updatedb"
          fi

          ${__run_cmd} "locale-gen en 2>&1"

          ${PKG_INSTALL} ${REQ_PACKAGES} || {
              ERROR "Error(s) installing essential packages for '${LSB_VER}' !"
              L_LOG
              main_rc=1
              SCRIPTEXIT
          }
          ;;
      *)
          ERROR "Unsupported distribution: '${LSB_VENDOR}'"
          L_LOG
          main_rc=1
          SCRIPTEXIT
          ;;
    esac

    # Check if Apache2 is needed
    if [ "${USE_APACHE2}" = "yes" ] ; then
        if [ "${LSB_VENDOR}" = "Debian" -o "${LSB_VENDOR}" = "Ubuntu" ] ; then
            _prep_apache2_deb
        elif [ "${LSB_VENDOR}" = "CentOS" ] ; then
            _prep_apache2_centos
        fi
        # Modify user group membership
        RUN_LOG "usermod -a -G ${APACHE_GROUP} ${USERNAME}"

        # Allow apache group to write to user's Download directory
        RUN_LOG "setfacl -Rm g:${APACHE_USER}:rwX,d:g:${APACHE_GROUP}:rwX /etc/skel/Downloads"
        RUN_LOG "setfacl -Rm g:${APACHE_USER}:rwX,d:g:${APACHE_GROUP}:rwX /home/user/Downloads"
        RUN_LOG "setfacl -Rm g:${APACHE_USER}:rwX,d:g:${APACHE_GROUP}:rwX ${USERHOME}/Downloads"
    fi

    # Update application(s)
    for app in "changeseedboxpass" "install-app" ; do
        INFO "Checking if '${app}' update available ..."
        L_LOG
        WGET "${SUPPORT}/rsb-scripts/common/${app}"
        if [ $? -eq 0 ] ; then
            if [ -s "${TMP_DIR}/${app}" ] ; then
                ${__run_cmd} "diff '${TMP_DIR}/${app}' '/usr/local/bin/${app}'"
                if [ $? -ne 0 ] ; then
                    INFO "Updating '${app}' ..."
                    MV "${TMP_DIR}/${app}" "/usr/local/bin/${app}"
                    CHOWN_FILE root:root "/usr/local/bin/${app}"
                    CHMOD_FILE 755 "/usr/local/bin/${app}"
                    LN "/usr/local/bin/${app}" "/usr/local/bin/rsb-${app}"
                else
                    INFO "'${app}' is up to date."
                fi
            fi
        fi
    done
    L_LOG
}




# ----------------------------------------------------------
# Application installation checks functions
# ----------------------------------------------------------

# Check if it safe to install/uninstall application.
# Application name is passed via $1 or determined by $APP content.
# Returns:  0     - if it is safe to install/uninstall application.
#           1     - if required parameter(s) missing.
#           111   - if app is installed and installation requested.
#           112   - if app is not installed and uninstallation was requested.
# 
function CHECK_APP_DEB () {
    [ "${DEBUG}" = "yes" ] && ENTRY

    local app
    local o_app
    local script_name
    local op
    local op_RC
    local _pkg
    local _rc

    script_name=$( basename "${0}" )
    LOG=""
    _rc=0

    case ${script_name} in
    install_*)
        op="install"
        ;;
    uninstall_*)
        op="uninstall"
        ;;
    *)
        op="${2}"
        ;;
    esac

    o_app="${1}"
    [ -z "${o_app}" ] && o_app="${APP}"
    if [ -z "${o_app}" ] ; then
        ERROR "CHECK_APP(): Argument(s) missing"
        _rc=1
        return ${_rc}
    fi

    app=$( echo "${o_app}" | tr '[:upper:]' '[:lower:]' )

    case ${app} in

    # Check dpkg package status
    "ampache"|"aria2"|"brave"|"dropbox"|"filezilla"|"firefox"|"handbrake"|"midori"|"openbox"|"pidgin"|"pyload"|"qupzilla"|"softethervpn"|"syncthing"|"uget"|"vlc"|"xrdp"|"youtube-dl")
        _rc=0
        DPKG_CHECK "${app}"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;

    # Check ${APP_DIRECTORY} existence
    "btsync"|"couchpotato"|"deluge (latest)"|"deluge 1.3.5"|"deluge 1.3.6"|"deluge 1.3.7"|"deluge 1.3.8"|"deluge 1.3.9"|"deluge 1.3.10"|"deluge 1.3.11"|"deluge 1.3.12"|"elfinder"|"flexget"|"headphones"|"nzbget"|"plexpy"|"plex trakt scrobbler"|"pydio"|"sabnzbd"|"sickbeard"|"sickrage"|"utorrent"|"vinaget"|"vnc")
        _rc=0
        if [ -z "${APP_DIRECTORY}" ] ; then
            LOG="CHECK_APP(): \$APP_DIRECTORY is not defined!"
           _rc=1
        else
            if [ -d "${APP_DIRECTORY}" ] ; then
                [ "${op}" = "install" ]   && _rc=111
            else
                [ "${op}" = "uninstall" ] && _rc=112
            fi
        fi
        ;;

    # Check "non-standard" apps :)
    "7zip")
        _rc=0
        DPKG_CHECK "p7zip-full"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "cinnamon desktop")
        _rc=0
        DPKG_CHECK "cinnamon"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "docker")
        _rc=0
        DPKG_CHECK "docker.io"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "emby server")
        _rc=0
        DPKG_CHECK "emby-server"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "fixes for cuteftp users")
        _rc=0
        ;;
    "fixes for kodi sftp connection")
        _rc=0
        ;;
    "gnome desktop")
        _rc=0
        DPKG_CHECK "ubuntu-desktop"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "google chrome")
        _rc=0
        DPKG_CHECK "google-chrome-stable"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "icewm desktop")
        _rc=0
        DPKG_CHECK "icewm"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "jdownloader")
        _rc=0
        DPKG_CHECK "jdownloader-installer"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "kde desktop")
        _rc=0
        DPKG_CHECK "kubuntu-desktop"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "l2tp-ipsec vpn (racoon)")
        _rc=0
        if [ ! -c "/dev/ppp" ] ; then
            ERROR "Device '/dev/ppp' not found!"
            _rc=1
        else
            DPKG_CHECK "racoon"
            if [ $? -eq 0 ] ; then
                [ "${op}" = "install" ]   && _rc=111
            else
                [ "${op}" = "uninstall" ] && _rc=112
            fi
        fi
        ;;
    "l2tp-ipsec vpn (swan)")
        _rc=0
        if [ ! -c "/dev/ppp" ] ; then
            ERROR "Device '/dev/ppp' not found!"
            _rc=1
        else
            DPKG_CHECK "strongswan"
            if [ $? -eq 0 ] ; then
                [ "${op}" = "install" ]   && _rc=111
            else
                [ "${op}" = "uninstall" ] && _rc=112
            fi
        fi
        ;;
    "lxde desktop")
        _rc=0
        DPKG_CHECK "lxde"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "mate desktop")
        _rc=0
        DPKG_CHECK "mate-desktop-environment"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "openbox desktop")
        _rc=0
        DPKG_CHECK "openbox"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "opera")
        _rc=0
        DPKG_CHECK "opera-stable"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "plex")
        _rc=0
        DPKG_CHECK "plexmediaserver"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "resilio sync")
        _rc=0
        if [ -z "${APP_DIRECTORY}" ] ; then
            LOG="CHECK_APP(): \$APP_DIRECTORY is not defined!"
           _rc=1
        else
            if [ -d "${APP_DIRECTORY}" ] ; then
                [ "${op}" = "install" ]   && _rc=111
            else
                [ "${op}" = "uninstall" ] && _rc=112
            fi
        fi
        ;;
    "rutorrent"|"rutorrent (rtorrent 0.9.2)"|"rutorrent (rtorrent 0.9.3)"|"rutorrent (rtorrent 0.9.4)"|"rutorrent (rtorrent 0.9.6)")
        _rc=0
        if [ -z "${APP_DIRECTORY}" ] ; then
            LOG="CHECK_APP(): \$APP_DIRECTORY is not defined!"
           _rc=1
        else
            if [ -d "${APP_DIRECTORY}/conf/users/${USERNAME}" ] ; then
                [ "${op}" = "install" ]   && _rc=111
            else
                [ "${op}" = "uninstall" ] && _rc=112
            fi
        fi
        ;;
    "sonarr")
        _rc=0
        DPKG_CHECK "nzbdrone"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "thunderbird")
        case "${LSB_VENDOR}" in
          "Debian")
              _pkg="icedove"
              ;;
          "Ubuntu")
              _pkg="thunderbird"
              ;;
        esac
        _rc=0
        DPKG_CHECK "${_pkg}"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "tor browser")
        _rc=0
        DPKG_CHECK "tor-browser"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "utorrent 2.2.1 (wine)")
        _rc=0
        test -e "${APP_DIRECTORY}/utorrent_2.2.1_build_25302.exe"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "vivaldi")
        _rc=0
        DPKG_CHECK "vivaldi-stable"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "wine")
        _rc=0
        case "${LSB_VENDOR}" in
          "Debian")
              DPKG_CHECK "wine"
              if [ $? -eq 0 ] ; then
                  [ "${op}" = "install" ]   && _rc=111
              else
                  [ "${op}" = "uninstall" ] && _rc=112
              fi
              ;;
          "Ubuntu")
              DPKG_CHECK "wine1.8"
              if [ $? -eq 0 ] ; then
                  [ "${op}" = "install" ]   && _rc=111
              else
                  [ "${op}" = "uninstall" ] && _rc=112
              fi
              ;;
        esac
        ;;
    "x2go server")
        _rc=0
        DPKG_CHECK "x2goserver"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "xfce desktop")
        _rc=0
        DPKG_CHECK "xubuntu-desktop"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "yandex browser")
        _rc=0
        DPKG_CHECK "yandex-browser-beta"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;

    *)
        LOG="CHECK_APP (): No check procedure defined for: '${o_app}'"
        _rc=1
        ;;
    esac

    JOB_NAME="Application installation status"
#    if [ -z "${LOG}" ] ; then
        [ ${_rc} -eq 111 ] && LOG="CHECK_APP(): '${o_app}' is already installed"
        [ ${_rc} -eq 112 ] && LOG="CHECK_APP(): '${o_app}' is not installed"
        [ ${_rc} -eq 1 ]   && LOG="CHECK_APP(): '${o_app}': Critical error!"
        [ ${_rc} -eq 0 ]   && LOG="CHECK_APP(): '${o_app}': OK to ${op}"
        LOG_RC ${_rc}
#    fi

    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}


# Check if it safe to install/uninstall application.
# Application name is passed via $1 or determined by $APP content.
# Returns:  0     - if it is safe to install/uninstall application.
#           1     - if required parameter(s) missing.
#           111   - if app is installed and installation requested.
#           112   - if app is not installed and uninstallation was requested.
# 
function CHECK_APP_YUM () {
    [ "${DEBUG}" = "yes" ] && ENTRY

    local app
    local o_app
    local script_name
    local op
    local op_RC
    local _pkg
    local _rc

    script_name=$( basename "${0}" )
    LOG=""
    _rc=0

    case ${script_name} in
    install_*)
        op="install"
        ;;
    uninstall_*)
        op="uninstall"
        ;;
    *)
        op="${2}"
        ;;
    esac

    o_app="${1}"
    [ -z "${o_app}" ] && o_app="${APP}"
    if [ -z "${o_app}" ] ; then
        ERROR "CHECK_APP_YUM(): Argument(s) missing"
        _rc=1
        return ${_rc}
    fi

    app=$( echo "${o_app}" | tr '[:upper:]' '[:lower:]' )

    case ${app} in

#    # Check rpm package status
#    ampache|brave|dropbox|midori|openbox|pyload|qupzilla|syncthing|youtube-dl)
#        _rc=0
#        DPKG_CHECK "${app}"
#        if [ $? -eq 0 ] ; then
#            [ "${op}" = "install" ]   && _rc=111
#        else
#            [ "${op}" = "uninstall" ] && _rc=112
#        fi
#        ;;
#
    # Check rpm package status
    "aria2"|"docker"|"filezilla"|"firefox"|"pidgin"|"softethervpn"|"thunderbird"|"uget"|"vlc"|"xrdp")
        _rc=0
        ${PKG_CHECK} "${app}"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;

    # Check ${APP_DIRECTORY} existence
#    btsync|couchpotato|"deluge (latest)"|elfinder|headphones|nzbget|"plex trakt scrobbler"|pydio|sabnzbd|sickbeard|sickrage|utorrent)
    "deluge 1.3.5"|"deluge 1.3.6"|"deluge 1.3.7"|"deluge 1.3.8"|"deluge 1.3.9"|"deluge 1.3.10"|"deluge 1.3.11"|"deluge 1.3.12"|"deluge 1.3.13"|"flexget"|"plexpy"|"softethervpn"|"vinaget"|"vnc")
        _rc=0
        if [ -z "${APP_DIRECTORY}" ] ; then
            LOG="CHECK_APP(): \$APP_DIRECTORY is not defined!"
           _rc=1
        else
            if [ -d "${APP_DIRECTORY}" ] ; then
                [ "${op}" = "install" ]   && _rc=111
            else
                [ "${op}" = "uninstall" ] && _rc=112
            fi
        fi
        ;;

    # Check "non-standard" apps :)
    "7zip")
        _rc=0
        RPM_CHECK "p7zip"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
#    "cinnamon desktop")
#        _rc=0
#        DPKG_CHECK "cinnamon"
#        if [ $? -eq 0 ] ; then
#            [ "${op}" = "install" ]   && _rc=111
#        else
#            [ "${op}" = "uninstall" ] && _rc=112
#        fi
#        ;;
#    "emby server")
#        _rc=0
#        DPKG_CHECK "emby-server"
#        if [ $? -eq 0 ] ; then
#            [ "${op}" = "install" ]   && _rc=111
#        else
#            [ "${op}" = "uninstall" ] && _rc=112
#        fi
#        ;;
#    "fixes for cuteftp users")
#        _rc=0
#        ;;
#    "fixes for kodi sftp connection")
#        _rc=0
#        ;;
#    "gnome desktop")
#        _rc=0
#        DPKG_CHECK "ubuntu-desktop"
#        if [ $? -eq 0 ] ; then
#            [ "${op}" = "install" ]   && _rc=111
#        else
#            [ "${op}" = "uninstall" ] && _rc=112
#        fi
#        ;;
    "google chrome")
        _rc=0
        RPM_CHECK "google-chrome-stable"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "handbrake")
        _rc=0
        if [ "${LSB_RELEASE}" = "6" ] ; then
            PKGS="handbrake-gui"
        elif [ "${LSB_RELEASE}" = "7" ] ; then
            PKGS="HandBrake-gui"
        fi
        RPM_CHECK "${PKGS}"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "icewm desktop")
        _rc=0
        RPM_CHECK "icewm"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
#    "jdownloader")
#        _rc=0
#        DPKG_CHECK "jdownloader-installer"
#        if [ $? -eq 0 ] ; then
#            [ "${op}" = "install" ]   && _rc=111
#        else
#            [ "${op}" = "uninstall" ] && _rc=112
#        fi
#        ;;
#    "kde desktop")
#        _rc=0
#        DPKG_CHECK "kubuntu-desktop"
#        if [ $? -eq 0 ] ; then
#            [ "${op}" = "install" ]   && _rc=111
#        else
#            [ "${op}" = "uninstall" ] && _rc=112
#        fi
#        ;;
    "l2tp-ipsec vpn (racoon)")
        _rc=0
        if [ ! -c "/dev/ppp" ] ; then
            ERROR "Device '/dev/ppp' not found!"
            _rc=1
        else
            RPM_CHECK "racoon"
            if [ $? -eq 0 ] ; then
                [ "${op}" = "install" ]   && _rc=111
            else
                [ "${op}" = "uninstall" ] && _rc=112
            fi
        fi
        ;;
    "l2tp-ipsec vpn (swan)")
        _rc=0
        if [ ! -c "/dev/ppp" ] ; then
            ERROR "Device '/dev/ppp' not found!"
            _rc=1
        else
            RPM_CHECK "libreswan"
            if [ $? -eq 0 ] ; then
                [ "${op}" = "install" ]   && _rc=111
            else
                [ "${op}" = "uninstall" ] && _rc=112
            fi
        fi
        ;;
#    "lxde desktop")
#        _rc=0
#        DPKG_CHECK "lxde"
#        if [ $? -eq 0 ] ; then
#            [ "${op}" = "install" ]   && _rc=111
#        else
#            [ "${op}" = "uninstall" ] && _rc=112
#        fi
#        ;;
    "mate desktop")
        _rc=0
        RPM_CHECK "mate-desktop"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "openbox desktop")
        _rc=0
        RPM_CHECK "openbox"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "opera")
        _rc=0
        RPM_CHECK "opera-stable"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "plex")
        _rc=0
        RPM_CHECK "plexmediaserver"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "resilio sync")
        _rc=0
        if [ -z "${APP_DIRECTORY}" ] ; then
            LOG="CHECK_APP(): \$APP_DIRECTORY is not defined!"
           _rc=1
        else
            if [ -d "${APP_DIRECTORY}" ] ; then
                [ "${op}" = "install" ]   && _rc=111
            else
                [ "${op}" = "uninstall" ] && _rc=112
            fi
        fi
        ;;
    "rutorrent"|"rutorrent (rtorrent 0.9.2)"|"rutorrent (rtorrent 0.9.3)"|"rutorrent (rtorrent 0.9.4)"|"rutorrent (rtorrent 0.9.6)")
        _rc=0
        if [ -z "${APP_DIRECTORY}" ] ; then
            LOG="CHECK_APP(): \$APP_DIRECTORY is not defined!"
           _rc=1
        else
            if [ -d "${APP_DIRECTORY}/conf/users/${USERNAME}" ] ; then
                [ "${op}" = "install" ]   && _rc=111
            else
                [ "${op}" = "uninstall" ] && _rc=112
            fi
        fi
        ;;
#    sonarr)
#        _rc=0
#        DPKG_CHECK "nzbdrone"
#        if [ $? -eq 0 ] ; then
#            [ "${op}" = "install" ]   && _rc=111
#        else
#            [ "${op}" = "uninstall" ] && _rc=112
#        fi
#        ;;
#    "tor browser")
#        _rc=0
#        DPKG_CHECK "tor-browser"
#        if [ $? -eq 0 ] ; then
#            [ "${op}" = "install" ]   && _rc=111
#        else
#            [ "${op}" = "uninstall" ] && _rc=112
#        fi
#        ;;
    "utorrent 2.2.1 (wine)")
        _rc=0
        test -e "${APP_DIRECTORY}/utorrent_2.2.1_build_25302.exe"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "vivaldi")
        _rc=0
        RPM_CHECK "vivaldi-stable"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "wine")
        _rc=0
        RPM_CHECK "wine"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "x2go server")
        _rc=0
        RPM_CHECK "x2goserver"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
    "xfce desktop")
        _rc=0
        RPM_CHECK "xfdesktop"
        if [ $? -eq 0 ] ; then
            [ "${op}" = "install" ]   && _rc=111
        else
            [ "${op}" = "uninstall" ] && _rc=112
        fi
        ;;
#    "yandex browser")
#        _rc=0
#        DPKG_CHECK "yandex-browser-beta"
#        if [ $? -eq 0 ] ; then
#            [ "${op}" = "install" ]   && _rc=111
#        else
#            [ "${op}" = "uninstall" ] && _rc=112
#        fi
#        ;;
#
    *)
        LOG="CHECK_APP (): No check procedure defined for: '${o_app}'"
        _rc=1
        ;;
    esac

    JOB_NAME="Application installation status"
#    if [ -z "${LOG}" ] ; then
        [ ${_rc} -eq 111 ] && LOG="CHECK_APP(): '${o_app}' is already installed"
        [ ${_rc} -eq 112 ] && LOG="CHECK_APP(): '${o_app}' is not installed"
        [ ${_rc} -eq 1 ]   && LOG="CHECK_APP(): '${o_app}': Critical error!"
        [ ${_rc} -eq 0 ]   && LOG="CHECK_APP(): '${o_app}': OK to ${op}"
        LOG_RC ${_rc}
#    fi

    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}


function CHECK_APP () {
    local _rc
    [ "${DEBUG}" = "yes" ] && ENTRY
    case "${LSB_VENDOR}" in
      "CentOS")
          CHECK_APP_YUM "${1}"
          _rc=$?
          ;;
      "Debian"|"Ubuntu")
          CHECK_APP_DEB "${1}"
          _rc=$?
          ;;
    esac
    [ "${DEBUG}" = "yes" ] && RETURN
    return ${_rc}
}
