#!/bin/bash

###########################################################################
#
# MODULE:       Commands
# COPYRIGHT:    (C) 2009-2025 by CacheGuard Technologies Ltd (UK)
# COPYRIGHT:    (C) 2026-2026 by CacheGuard Technologies SAS (FR)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###########################################################################

source functions

initialise-setup()
{
    test -n "${1}" || retrun 1
    local role=${1}

    local i bar len_bar=79
    local i blk="|"
    local len_blk=$((len_bar - 2))

    for ((i=0 ; i< ${len_blk} ; i++))
    do
	bar="${bar}-"
	blk="${blk} "
    done
    bar="${bar}--"
    blk="${blk}|"

    SETUP_DIALOG_OK=0
    SETUP_DIALOG_OPTIONS="--no-shadow --ascii-lines --colors"
    SETUP_PROGRAM_NAME="Startup Configuration"
    SETUP_BACK_TITLE="${COMMERCIAL_NAME} ${role^} ${SETUP_PROGRAM_NAME}"
    SETUP_FILE=${ADMIN_TMP_DIR}/${SETUP}.conf.${$}
    SETUP_BAR=${bar}
    SETUP_BLK=${blk}
    SETUP_SYSTEM_HARD=$(get-machine-type)

    set-first-startup-action
    initialise ${MANAGER_CONTEXT_ENV}
}

clean-setup()
{
    rm -f ${SETUP_FILE} \
       ${ADMIN_TMP_DIR}/setup.${$}
}

exit-cb()
{
    clean-setup
    clear
    exit 0
}

exec-setup-conf()
{
    test -n "${1}" || return 1
    local message=${1}
    test -f ${SETUP_FILE} || return 11

    local ret path=${PATH}
    PATH=${COMMAND_PATH}:${path}
    local tty=$(tty 2> /dev/null)

    transaction close
    test ! -s ${SETUP_FILE} || transaction open < ${SETUP_FILE}

    transaction commit log 2>&1 | sed -e $'s/.\\{72\\}/&\\\n/g' | dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "${message}" --programbox "List of commands to execute:" 12 76

    ret=${PIPESTATUS[0]}

    clean-setup

    PATH=${path}
    return ${ret}
}

check-gw-connected()
{
    test -n "${1}" || return 1
    test -n "${2}" || return 1
    test -n "${3}" || return 1
    local gw=${1}
    local ip=${2}
    local mk=${3}

    local net_brd

    local net=$(ipcalc -s ${ip} ${mk} -n)
    local brd=$(ipcalc -s ${ip} ${mk} -b)

    net=${net/NETWORK=/}
    brd=${brd/BROADCAST=/}

    net_brd=$(ip-is-included-in-valid-boradcast ${gw} ${net} ${brd} ${mk})
}

echo-welcome-msg()
{
    test -n "${1}" || return 1
    test -n "${2}" || return 2
    test -n "${3}" || return 3
    local message_read=${1}
    local message_exec=${2}
    local message_apply=${3}

    local message_overview="This program performs the startup configuration by:"

    clear

    dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "Welcome" --msgbox "\nWelcome to the \Z1setup\Zn program. ${message_overview}\n\n${message_read}\n${message_exec}\n${message_apply}" 12 60
}

read-timezone-conf()
{
    test -n "${1}" || return 1
    test -n "${2}" || return 2
    local message=${1}
    local main_title=${2}

    test ${SETUP_SYSTEM_HARD} != "OS" || return 0

    local continent timezones timezone

    dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "${message}" --no-cancel --default-item "${TIMEZONE/\/*}" --menu "\nPlease select your continent:\n\n" 17 50 8 Africa "The Africa Continent" America "The America Continent" Antarctica "The Antarctica Continent" Asia "The Asia Continent" Atlantic "The Atlantic Continent" Australia "The Australia Continent" Europe "The Europe Continent" Pacific "The Pacific Continent" 2> ${ADMIN_TMP_DIR}/setup.${$}

    read continent < ${ADMIN_TMP_DIR}/setup.${$}
    rm -f ${ADMIN_TMP_DIR}/setup.${$}

    while read timezone
    do
	test -n "${timezone}" || continue
	test "${timezone/\/*}" == "${continent}" || continue
	timezones="${timezones} ${timezone/${continent}\/} ${timezone}"
    done < /etc/timezones
    timezones=${timezones:1}

    dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "${main_title}" --no-cancel --default-item ${TIMEZONE/${continent}\/} --menu "\nPlease select your timezone:\n\n" 20 0 16 ${timezones} 2> ${ADMIN_TMP_DIR}/setup.${$}
    read timezone < ${ADMIN_TMP_DIR}/setup.${$}
    rm -f ${ADMIN_TMP_DIR}/setup.${$}

    TIMEZONE=${continent}/${timezone}
}

read-network-static-conf()
{
    test -n "${1}" || return 1
    test -n "${2}" || return 2
    local role=${1}
    local message=${2}
    local external=${3}

    local internal_dev=${BOND_INTERNALS/ *}
    local external_dev=${BOND_EXTERNALS/* }
    local ret

    case ${role} in
	gateway)
	    local ip_internal_ip=${DEFAULT_GATEWAY_IP_INTERNAL_IP}
	    local default_ip_internal_ip=$(if test ${IP_INTERNAL_IP} == 0.0.0.0 ; then echo ${ip_internal_ip} ; else echo ${IP_INTERNAL_IP} ; fi)

	    local ip_internal_mk=${DEFAULT_GATEWAY_IP_INTERNAL_MASK}
	    local default_ip_internal_mk=$(if test ${IP_INTERNAL_MASK} == 0.0.0.0 ; then echo ${ip_internal_mk} ; else echo ${IP_INTERNAL_MASK} ; fi)

	    if test -n "${external}" ; then
		local ip_external_ip=${DEFAULT_IP_EXTERNAL_IP}
		local default_ip_external_ip=$(if test ${IP_EXTERNAL_IP} == 0.0.0.0 ; then echo ${ip_external_ip} ; else echo ${IP_EXTERNAL_IP} ; fi)

		local ip_external_mk=${DEFAULT_IP_EXTERNAL_MASK}
		local default_ip_external_mk=$(if test ${IP_EXTERNAL_MASK} == 0.0.0.0 ; then echo ${ip_external_mk} ; else echo ${IP_EXTERNAL_MASK} ; fi)
	    fi
	    ;;
	manager)
	    local ip_internal_ip=${DEFAULT_MANAGER_IP_INTERNAL_IP}
	    local default_ip_internal_ip=$(if test ${IP_INTERNAL_IP} == 0.0.0.0 ; then echo ${ip_internal_ip} ; else echo ${IP_INTERNAL_IP} ; fi)

	    local ip_internal_mk=${DEFAULT_MANAGER_IP_INTERNAL_MASK}
	    local default_ip_internal_mk=$(if test ${IP_INTERNAL_MASK} == 0.0.0.0 ; then echo ${ip_internal_mk} ; else echo ${IP_INTERNAL_MASK} ; fi)

	    local dns_ip
	    ;;
	*)
	    return 255
	    ;;
    esac

    local ip_default_route_ip
    local in_errors ex_errors ns_errors gw_errors
    local errors error

    ip_internal_ip=${default_ip_internal_ip}
    ip_internal_mk=${default_ip_internal_mk}

    case ${role} in
	gateway)
	    if test -n "${external}" ; then
		ip_external_ip=${default_ip_external_ip}
		ip_external_mk=${default_ip_external_mk}
		ip_default_route_ip=$(get-last-ip ${ip_external_ip} ${ip_external_mk})
	    fi

	    local line i

	    while true
	    do
		if test -n "${external}" ; then
		    dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "${message}" --no-cancel --form "\nPlease enter your network configuration:\n(use arrow keys)" 0 0 5 \
			   "Internal [${internal_dev}] IP address:" 1 1  "${ip_internal_ip}" 1 40 16 0 \
			   "Internal [${internal_dev}] IP mask:" 2 1  "${ip_internal_mk}" 2 40 16 0 \
			   "External [${external_dev}] IP address:" 3 1  "${ip_external_ip}" 3 40 16 0 \
			   "External [${external_dev}] IP mask:" 4 1  "${ip_external_mk}" 4 40 16 0 \
			   "Default gateway IP address:" 5 1  "${ip_default_route_ip}" 5 40 16 0 \
			   2> ${ADMIN_TMP_DIR}/setup.${$}
		else
		    dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "${message}" --no-cancel --form "\nPlease enter your network configuration:\n(use arrow keys)" 0 0 2 \
			   "Internal [${internal_dev}] IP address:" 1 1  "${ip_internal_ip}" 1 40 16 0 \
				   "Internal [${internal_dev}] IP mask:" 2 1  "${ip_internal_mk}" 2 40 16 0 \
				   2> ${ADMIN_TMP_DIR}/setup.${$}
		fi

		ret=${?}

		unset in_errors ex_errors gw_errors errors

		i=0
		while read line
		do
		    case ${i} in
			0)
			    ip_internal_ip=${line}
			    ;;
			1)
			    ip_internal_mk=${line}
			    ;;
			2)
			    test -n "${external}" || break
			    ip_external_ip=${line}
			    ;;
			3)
			    test -n "${external}" || break
			    ip_external_mk=${line}
			    ;;
			4)
			    test -n "${external}" || break
			    ip_default_route_ip=${line}
			    ;;
			*)
			    break
			    ;;
		    esac
		    ((i++))
		done < ${ADMIN_TMP_DIR}/setup.${$}
		rm -f ${ADMIN_TMP_DIR}/setup.${$}

		check-ip ${ip_internal_ip} || in_errors="${in_errors} 12"
		check-mask ${ip_internal_mk} || in_errors="${in_errors} 13"
		test -n "${in_errors}" || host-ip-address ${ip_internal_ip} ${ip_internal_mk} || in_errors="${in_errors} 62"
		test ${ip_internal_mk} != 255.255.255.255 || in_errors="${in_errors} 538"

		if test -n "${external}" ; then
		    check-ip ${ip_external_ip} || ex_errors="${ex_errors} 12"
		    check-mask ${ip_external_mk} || ex_errors="${ex_errors} 13"
		    test -n "${ex_errors}" || host-ip-address ${ip_external_ip} ${ip_external_mk} || ex_errors="${ex_errors} 62"

		    if test -n "${ip_default_route_ip}" ; then
			check-ip ${ip_default_route_ip} || gw_errors="${gw_errors} 12"
		    
			if ! check-gw-connected ${ip_default_route_ip} ${ip_internal_ip} ${ip_internal_mk} ; then
			    if test ${ip_external_mk} != 255.255.255.255 ; then
				check-gw-connected ${ip_default_route_ip} ${ip_external_ip} ${ip_external_mk} ||
				    gw_errors="${gw_errors} 110"
			    fi
			fi
		    fi
		fi

		in_errors=${in_errors:1}
		ex_errors=${ex_errors:1}
		gw_errors=${gw_errors:1}

		test -n "${in_errors}" -o -n "${ex_errors}" -o -n "${gw_errors}" || break

		if test -n "${in_errors}" ; then
		    errors="${errors}\n\Z1Internal IP ${ip_internal_ip}/${ip_internal_mk}:\Zn\n"
		    for error in ${in_errors}
		    do
			errors="${errors}*** Errors ${error}: ${Errors[${error}]}\n"
		    done
		fi

		if test -n "${external}" ; then
		    if test -n "${ex_errors}" ; then
			errors="${errors}\n\Z1External IP ${ip_external_ip}/${ip_external_mk}:\Zn\n"
			for error in ${ex_errors}
			do
			    errors="${errors}*** Errors ${error}: ${Errors[${error}]}\n"
			done
		    fi

		    if test -n "${gw_errors}" ; then
			errors="${errors}\n\Z1Default Gateway ${ip_default_route_ip}:\Zn\n"
			for error in ${gw_errors}
			do
			    errors="${errors}*** Errors ${error}: ${Errors[${error}]}\n"
			done
		    fi
		fi

		dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "Network configuration error" --msgbox "${errors}" 0 0
	    done
	    ;;
	manager)
	    ip_default_route_ip=$(get-last-ip ${ip_internal_ip} ${ip_internal_mk})
	    dns_ip=${ip_default_route_ip}

	    local line i

	    while true
	    do
		dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "${message}" --no-cancel --form "\nPlease enter your network configuration:\n(use arrow keys)" 0 0 4 \
		       "Internal IP address:" 1 1  "${ip_internal_ip}" 1 40 16 0 \
		       "Internal IP mask:" 2 1  "${ip_internal_mk}" 2 40 16 0 \
		       "Default gateway IP address:" 3 1  "${ip_default_route_ip}" 3 40 16 0 \
		       "DNS IP address:" 4 1  "${dns_ip}" 4 40 16 0 \
		       2> ${ADMIN_TMP_DIR}/setup.${$}

		ret=${?}

		unset in_errors ns_errors gw_errors errors

		i=0
		while read line
		do
		    case ${i} in
			0)
			    ip_internal_ip=${line}
			    ;;
			1)
			    ip_internal_mk=${line}
			    ;;
			2)
			    ip_default_route_ip=${line}
			    ;;
			3)
			    dns_ip=${line}
			    ;;
			*)
			    break
			    ;;
		    esac
		    ((i++))
		done < ${ADMIN_TMP_DIR}/setup.${$}
		rm -f ${ADMIN_TMP_DIR}/setup.${$}

		check-ip ${ip_internal_ip} || in_errors="${in_errors} 12"
		check-mask ${ip_internal_mk} || in_errors="${in_errors} 13"
		test -n "${in_errors}" || host-ip-address ${ip_internal_ip} ${ip_internal_mk} || in_errors="${in_errors} 62"

		if test -n "${ip_default_route_ip}" ; then
		    check-ip ${ip_default_route_ip} || gw_errors="${gw_errors} 12"
		    check-gw-connected ${ip_default_route_ip} ${ip_internal_ip} ${ip_internal_mk} || gw_errors="${gw_errors} 110"
		fi

		if test -n "${dns_ip}" ; then
		    check-ip ${dns_ip} || ns_errors="${ns_errors} 12"
		    check-local-ip ${dns_ip} || ns_errors="${ns_errors} 38"
		fi

		in_errors=${in_errors:1}
		gw_errors=${gw_errors:1}
		ns_errors=${ns_errors:1}

		test -n "${in_errors}" -o -n "${ns_errors}" -o -n "${gw_errors}" || break

		if test -n "${in_errors}" ; then
		    errors="${errors}\n\Z1Internal IP ${ip_internal_ip}/${ip_internal_mk}:\Zn\n"
		    for error in ${in_errors}
		    do
			errors="${errors}*** Errors ${error}: ${Errors[${error}]}\n"
		    done
		fi

		if test -n "${ns_errors}" ; then
		    errors="${errors}\n\Z1DNS IP ${dns_ip}:\Zn\n"
		    for error in ${ns_errors}
		    do
			errors="${errors}*** Errors ${error}: ${Errors[${error}]}\n"
		    done
		fi

		if test -n "${gw_errors}" ; then
		    errors="${errors}\n\Z1Default Gateway ${ip_default_route_ip}:\Zn\n"
		    for error in ${gw_errors}
		    do
			errors="${errors}*** Errors ${error}: ${Errors[${error}]}\n"
		    done
		fi

		dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "Network configuration error" --msgbox "${errors}" 0 0
	    done
	    ;;
	*)
	    return 255
	    ;;
    esac

    local admin_internal_net=$(get-network ${ip_internal_ip} ${ip_internal_mk})
    local admin_external_net=$(get-network ${ip_external_ip} ${ip_external_mk})
    local ip_file_ip=$(get-first-ip ${ip_internal_ip} ${ip_internal_mk})

    case ${role} in
	gateway)
	    echo ip internal ${ip_internal_ip} ${ip_internal_mk}		>> ${SETUP_FILE}
	    if test -n "${external}" ; then
		echo ip external static ${ip_external_ip} ${ip_external_mk}	>> ${SETUP_FILE}
		echo ip route raz						>> ${SETUP_FILE}
		test -z "${ip_default_route_ip}" || \
		    echo ip route add default ${ip_default_route_ip}		>> ${SETUP_FILE}
	    fi
	    ;;

	manager)
	    echo ip internal ${ip_internal_ip} ${ip_internal_mk}		>> ${SETUP_FILE}
	    echo ip route raz							>> ${SETUP_FILE}
	    test -z "${ip_default_route_ip}" || \
		echo ip route add default ${ip_default_route_ip}		>> ${SETUP_FILE}

	    echo dns raz      							>> ${SETUP_FILE}
	    test -z "${dns_ip}" || echo dns add ${dns_ip}      			>> ${SETUP_FILE}
	    ;;

	*)
	    return 255
	    ;;
    esac

    test ${SETUP_SYSTEM_HARD} == "OS" || echo timezone ${TIMEZONE}			>> ${SETUP_FILE}

    ADMIN_URL="https://${ip_internal_ip}:${port_wadmin_port}"
}

read-external-ip-mode()
{
    dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "External (WAN) IP Configuration" --stdout --no-cancel --default-item "static" --menu "\nYou can either connect your appliance to the external network (Internet, WAN) using a static IP address or obtain its IP address using DHCP or PPPoE. Please select your connectivity mode:\n\n" 0 0 1 static "Static IP Configuration" dhcp "DHCP (Dynamic Host Configuration Protocol)" pppoe "PPPoE (Point-to-Point Protocol over Ethernet)"
}

read-network-pppoe-conf()
{
    test -n "${1}" || return 1
    local message=${1}

    local external_dev=${BOND_EXTERNALS/* }
    local service_name username password1 password2
    local len=64 visible_len=32 col=18
    local ret in_errors
    local line i

    while true
    do
	dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "${message}" --no-cancel --form "Please enter your PPPoE Service Name (if any) and Username to connect the External [${external_dev}] Network Interface :\n\n(use arrow keys)" 0 0 2 \
	       "Service Name:" 1 1 "${service_name}" 1 ${col} ${visible_len} ${len} \
	       "Userame:" 2 1 "${username}" 2 ${col} ${visible_len} ${len} \
	       2> ${ADMIN_TMP_DIR}/setup.${$}
	ret=${?}

	unset in_errors errors

	i=0
	while read line
	do
	    case ${i} in
		0)
		    service_name=${line}
		    ;;
		1)
		    username=${line}
		    ;;
		*)
		    break
		    ;;
	    esac
	    ((i++))
	done < ${ADMIN_TMP_DIR}/setup.${$}
	rm -f ${ADMIN_TMP_DIR}/setup.${$}

	check-pppoe-service-name "${service_name}" || in_errors="${in_errors} 541"
	check-pppoe-username "${username}"  || in_errors="${in_errors} 542"

	test -n "${in_errors}" || break

	if test -n "${in_errors}" ; then
	    errors="${errors}\n\Z1External IP PPPoE '${service_name}' '${username}' ...:\Zn\n"
	    for error in ${in_errors}
	    do
		errors="${errors}*** Errors ${error}: ${Errors[${error}]}\n"
	    done
	fi
	
	dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "Network configuration error" --msgbox "${errors}" 0 0
    done

    if test -n "${username}" ; then
	while true
	do
	    dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "${message}" --no-cancel --insecure --passwordform "Please enter your PPPoE Password to connect the External [${external_dev}] Network Interface :\n\n(use arrow keys)" 0 0 2 \
		   "Password:" 1 1 "${password1}" 1 ${col} ${visible_len} ${len} \
		   "Retype Password:" 2 1 "${password2}" 2 ${col} ${visible_len} ${len} \
		   2> ${ADMIN_TMP_DIR}/setup.${$}
	    ret=${?}

	    unset in_errors errors

	    i=0
	    while read line
	    do
		case ${i} in
		    0)
			password1=${line}
			;;
		    1)
			password2=${line}
			;;
		    *)
			break
			;;
		esac
		((i++))
	    done < ${ADMIN_TMP_DIR}/setup.${$}
	    rm -f ${ADMIN_TMP_DIR}/setup.${$}

	    if test "${password1}" == "${password2}" ; then
		check-pppoe-password "${password1}" || in_errors="${in_errors} 543"
	    else
		in_errors="${in_errors} 146"
	    fi

	    test -n "${in_errors}" || break

	    if test -n "${in_errors}" ; then
		errors="${errors}\n\Z1External IP PPPoE '${service_name}' '${username}' ...:\Zn\n"
		for error in ${in_errors}
		do
		    errors="${errors}*** Errors ${error}: ${Errors[${error}]}\n"
		done
	    fi
	
	    dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "Network configuration error" --msgbox "${errors}" 0 0
	done
    fi

    test -n "${password1}" || unset username
    echo "ip external pppoe '${service_name}' '${username}' '${password1}'" >> ${SETUP_FILE}
}

read-network-conf()
{
    test -n "${1}" || return 1
    test -n "${2}" || return 2
    local role=${1}
    local message=${2}

    clean-setup

    case ${role} in
	gateway)
	    local mode=$(read-external-ip-mode)

	    case ${mode} in
		static)
		    read-network-static-conf ${role} "${message}" external
		    ;;
		dhcp)
		    echo "ip external dhcp" >> ${SETUP_FILE}
		    read-network-static-conf ${role} "${message}"
		    ;;
		pppoe)
		    read-network-pppoe-conf "${message}"
		    read-network-static-conf ${role} "${message}"
		    ;;
		*)
		    ;;
	    esac
	    ;;
	manager)
	    read-network-static-conf ${role} "${message}"
	    ;;
	*)
	    return 255
	    ;;
    esac
}

apply-setup-conf()
{
    test -n "${1}" || return 1
    test -n "${2}" || return 2
    local message_apply=${1}
    local message_setup=${2}

    local ret

    dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "${message_apply}" --yesno "\nDo you confirm the apply operation?" 0 0
    if test ${?} -eq ${SETUP_DIALOG_OK} ; then
	apply force
	ret=${?}
    else
	dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "Apply abandoned" --msgbox "${message_setup}" 6 40
	clear
	ret=11
    fi

    return ${ret}
}

apply-performed-msg()
{
    test -n "${1}" || return 1
    local message_setup=${1}

    local message_0="You have performed a basic startup configuration."

    local message_1="1. Wait a few seconds for the apply operation to terminate."
    local message_11="   Use the command 'apply report' to monitor the apply state."

    local message_2="2. Connect the internal (${BOND_INTERNALS/ *}) port to your LAN."
    local message_21="   Connect the external (${BOND_EXTERNALS/ *}) port to your Internet router."

    local message_3="3. Configure the appliance via the CLI or the Web GUI."
    local message_31="   The Web GUI administration URL is: ${ADMIN_URL}"
    local message_32="   If using the CLI, use the command 'help' to get help. Use the"
    local message_33="   <TAB> key to get command and argument completions."

    dialog ${SETUP_DIALOG_OPTIONS} --backtitle "${SETUP_BACK_TITLE}" --title "Final instructions" --msgbox "\n${message_0}\n\n${message_1}\n${message_11}\n\n${message_2}\n${message_21}\n\n${message_3}\n${message_31}\n${message_32}\n${message_33}\n\n${message_setup}" 20 70
    clear
}

align-message()
{
    test -n "${1}" || retrun 1
    
    local len=${1}
    local message="| ${2}"

    local len_message=${#message} i
    len=$[${len} - ${len_message} - 2]
    
    for ((i=0 ; i < ${len} ; i++))
    do
	message="${message} "
    done

    local message="${message} |"

    echo "${message}"
    return 0
}

run()
{
    test -n "${1}" || retrun 1
    local role=${1}
    shift

    test -z "${TRANSACTION}" || return 106
    test ${TERM} != ${WADMIN_TERM} || return 0
    test "${__BATCH_MODE}" != yes || error 111

    check-lock || return 123

    push-args "${@}"
    initialise-setup ${role}

    trap exit-cb INT QUIT TERM

    local message_read="1. Reading some basic network parameters."
    local message_exec="2. Executing commands using the entered parameters."
    local message_apply="3. Applying the new configuration to the system."
    local message_setup="You can run this program at any time by typing the 'setup' command."

    echo-welcome-msg "${message_read}" "${message_exec}" "${message_apply}" || return 0
    read-timezone-conf "${message_read}" "${message_read}" || return 0
    read-network-conf ${role} "${message_read}" || return 0
    exec-setup-conf "${message_exec}" || return 0
    apply-setup-conf "${message_apply}" "${message_setup}" || return 0
    apply-performed-msg "${message_setup}" || return 0
}

run-setup()
{
    case ${CLOUD_NAME} in
	aws|azure)
	    error 143
	    ;;
	*)
	    ;;
    esac

    test -z "${TRANSACTION}" || return 106
    local role=$(get-contextual-role)


    case ${role} in
	gateway)
	    ;;
	manager)
	    ! is-in-manager-exec-context || error 234
	    ;;
	*)
	    error 255
	    return 255
	    ;;
    esac

    if ! user-has-admin-rights ; then
	error 31
	return 31
    fi

    local ret

    run ${role} "${@}"
    ret=${?}

    test ${ret} -eq 0 || error ${ret}
}

run-setup "${@}"
