#!/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

vlan-exist()
{
    test -n "${1}" || return 1
    test -n "${2}" || return 2
    local vlans=${1}
    local vlan=${2}

    local elt range i=0

    for elt in ${vlans}
    do
	range=$[${i} % 2]
	test ${range} -eq 0 && test ${elt} -eq ${vlan} && return 0
	((i++))
    done
    return 1
}

show-ip-internal()
{
    echo-command-form "ip internal"
    echo-mark-cur
    echo-value "${CURRENT_IP_INTERNAL_IP} ${CURRENT_IP_INTERNAL_MASK}"

    if test "${CURRENT_IP_INTERNAL_IP}" != "${IP_INTERNAL_IP}" -o \
	"${CURRENT_IP_INTERNAL_MASK}" != "${IP_INTERNAL_MASK}" ; then
	echo-command-form "ip internal"
	echo-mark-new
	echo-value "${IP_INTERNAL_IP} ${IP_INTERNAL_MASK}"
    fi
}

show-ip-external()
{
    echo-command-form "ip external"
    echo-mark-cur

    
    case ${CURRENT_IP_EXTERNAL_MODE} in
	static)
	    echo-value "${CURRENT_IP_EXTERNAL_MODE} ${CURRENT_IP_EXTERNAL_IP} ${CURRENT_IP_EXTERNAL_MASK}"
	    ;;
	dhcp)
	    echo-value "${CURRENT_IP_EXTERNAL_MODE} (${CURRENT_IP_EXTERNAL_IP} ${CURRENT_IP_EXTERNAL_MASK})"
	    ;;
	pppoe)
	    echo-value "${CURRENT_IP_EXTERNAL_MODE} '${CURRENT_IP_EXTRNAL_PPPOE_SERVICE_NAME}' '${CURRENT_IP_EXTRNAL_PPPOE_USERNAME}' ..."
	    echo-blank-command
	    echo-value "(${CURRENT_IP_EXTERNAL_IP} ${CURRENT_IP_EXTERNAL_MASK})"
	    ;;
	*)
	    ;;
    esac

    local modified

    if test "${CURRENT_IP_EXTERNAL_MODE}" != "${IP_EXTERNAL_MODE}" ; then
	modified=yes
    else
	case ${IP_EXTERNAL_MODE} in
	    static)
		test "${CURRENT_IP_EXTERNAL_IP}" == "${IP_EXTERNAL_IP}" -a \
		     "${CURRENT_IP_EXTERNAL_MASK}" == "${IP_EXTERNAL_MASK}" || modified=yes
		;;
	    dhcp)
		;;
	    pppoe)
		test "${CURRENT_IP_EXTRNAL_PPPOE_SERVICE_NAME}" == "${IP_EXTRNAL_PPPOE_SERVICE_NAME}" -a \
		     "${CURRENT_IP_EXTRNAL_PPPOE_USERNAME}" == "${IP_EXTRNAL_PPPOE_USERNAME}" -a \
		     "${CURRENT_IP_EXTRNAL_PPPOE_PASSWORD}" == "${IP_EXTRNAL_PPPOE_PASSWORD}" || modified=yes
		;;
	    *)
		;;
	esac
    fi

    test -n "${modified}" || return 0

    echo-command-form "ip external"
    echo-mark-new

    case ${IP_EXTERNAL_MODE} in
	static)
	    echo-value "${IP_EXTERNAL_MODE} ${IP_EXTERNAL_IP} ${IP_EXTERNAL_MASK}"
	    ;;
	dhcp)
	    echo-value "${IP_EXTERNAL_MODE}"
	    ;;
	pppoe)
	    echo-value "${IP_EXTERNAL_MODE} '${IP_EXTRNAL_PPPOE_SERVICE_NAME}' '${IP_EXTRNAL_PPPOE_USERNAME}' ..."
	    ;;
	*)
	    ;;
    esac
}

show-ip-auxiliary()
{
    echo-command-form "ip auxiliary"
    echo-mark-cur
    echo-value "${CURRENT_IP_AUXILIARY_IP} ${CURRENT_IP_AUXILIARY_MASK}"

    if test "${CURRENT_IP_AUXILIARY_IP}" != "${IP_AUXILIARY_IP}" -o \
	"${CURRENT_IP_AUXILIARY_MASK}" != "${IP_AUXILIARY_MASK}" ; then
	echo-command-form "ip auxiliary"
	echo-mark-new
	echo-value "${IP_AUXILIARY_IP} ${IP_AUXILIARY_MASK}"
    fi
}

show-ip-vlan-all()
{
    local i=0 elt range
    local vlan ip netmask ip_netmask1 ip_netmask2

    for elt in ${CURRENT_IP_VLAN_LIST}
    do
	range=$[${i} % 3]
	case ${range} in
	    0)
		vlan=${elt}
		;;
	    1)
		ip=${elt}
		;;
	    2)
		netmask=${elt}
		echo-command-form "ip internal.${vlan}"
		echo-mark-cur
		echo-value "${ip} ${netmask}"
		ip_netmask1=$(get-vlan-ip-netmask ${vlan} new)
		test -n "${ip_netmask1}" || warning 2
		;;
	    *)
		return 1
		;;
	esac
	((i++))
    done
    
    i=0
    for elt in ${IP_VLAN_LIST}
    do
	range=$[${i} % 3]
	case ${range} in
	    0)
		vlan=${elt}
		;;
	    1)
		ip=${elt}
		;;
	    2)
		netmask=${elt}
		ip_netmask1=$(get-vlan-ip-netmask ${vlan} cur)
		if test "${ip_netmask1}" != "${ip} ${netmask}" ; then
		    echo-command-form "ip internal.${vlan}"
		    echo-mark-new
		    echo-value "${ip} ${netmask}"
		fi
		;;
	    *)
		return 1
		;;
	esac
	((i++))
    done
}

show-ip-vlan()
{
    if test -z "${1}" ; then
	show-ip-vlan-all
	return ${?}
    fi

    local vlan=${1}
    vlan=$((10#${vlan}))

    local ip_netmask1 ip_netmask2

    ip_netmask1=$(get-vlan-ip-netmask ${vlan} cur)
    ip_netmask2=$(get-vlan-ip-netmask ${vlan} new)

    test -n "${ip_netmask1}" -o -n "${ip_netmask2}" || return 42

    echo

    if test -n "${ip_netmask1}" ; then
	echo-command-form "ip internal.${vlan}"
	echo-mark-cur
	echo-value "${ip_netmask1}"
    else
	warning 1
    fi

    if test "${ip_netmask1}" != "${ip_netmask2}" ; then
	if test -n "${ip_netmask2}" ; then
	    echo-command-form "ip internal.${vlan}"
	    echo-mark-new
	    echo-value "${ip_netmask2}"
	else
	    warning 2
	fi
    fi

    echo
}

show-ip()
{
    local dev=${1}
    local vlan ret=0

    echo-begin-show
    if test -z "${dev}" ; then

	! contextual-command-is-allowed || show-ip-external
	show-ip-internal

	if contextual-command-is-allowed ; then
	    show-ip-auxiliary
	    show-ip-vlan
	    ret=${?}
	fi
    else
	case ${dev} in
	    internal)
		show-ip-${dev}
		ret=${?}
		;;

	    external|auxiliary)
		! contextual-command-is-allowed || show-ip-${dev}
		ret=${?}
		;;
	    vlan)
		! contextual-command-is-allowed || show-ip-vlan-all
		;;
	    *)
		if contextual-command-is-allowed ; then
		    if test "${dev:0:9}" == "internal." ; then
			vlan=${dev:9}
			if check-vlan "${vlan}" ; then
			    show-ip-vlan "${vlan}"
			    ret=${?}
			else
			    ret=41
			fi
		    else
			ret=1
		    fi
		fi
		    ;;
	esac
    fi
    echo-end-show
    return ${ret}
}

show-name1()
{
    local names=${2}

    echo-command-form "ip name"
    if test "${1}" == "new" ; then
	echo-mark-new
    else
	echo-mark-cur
    fi

    if test -z "${names}" ; then
	echo-value-null
	return 0
    fi

    local elt range i=0 n=0
    local name ip

    for elt in ${names}
    do
	range=$[${i} %2]
	case ${range} in
	    0)
		name=${elt}
		;;
	    1)
		ip=${elt}
		test ${n} -eq 0 || echo-blank-command
		echo-value "${name} ${ip}"
		((n++))
		;;
	    *)
		return 255
		;;
	esac
	((i++))
    done
}

show-name()
{
    echo-begin-show
    show-name1 'current' "${CURRENT_IP_NAME_IP_LIST}"
    test "${CURRENT_IP_NAME_IP_LIST}" == "${IP_NAME_IP_LIST}" || show-name1 'new' "${IP_NAME_IP_LIST}"
    echo-end-show
}

manage-name()
{
    if test -z "${1}" ; then show-name ; return 0 ; fi

    local action=${1}

    case ${action} in
	raz)
	    unset IP_NAME_IP_LIST
	    ;;
	add|del)

	    if test "${action}" == "add" ; then
		local len=$(record2-length-list "${IP_NAME_IP_LIST}")
		test ${len} -lt ${MAX_NAME_IP_NB} || return 90
	    fi

	    test -n "${2}" || return 1
	    local name=${2}
	    test ${name} != 'localhost' || return 32
	    test ${name} != 'localhost.localdomain' || return 32
	    
	    check-domainname ${name} || return 16

	    if check-expr-ip ${name} ; then
		INDIRECT_ERROR_CODE=520
		return 254
	    fi

	    if test ${action} == add ; then
		test -n "${3}" || return 1
		local ip=${3}
		test ${ip:0:4} != '127.' || return 204
		check-ip ${ip} || return 12
	    fi

	    IP_NAME_IP_LIST=$(remove-record-from-list 2 1 ${name} "${IP_NAME_IP_LIST}")
	    test ${action} != add || IP_NAME_IP_LIST=$(insert-record-in-slist 2 1 "${name} ${ip}" "${IP_NAME_IP_LIST}")
	    ;;
	
	*)
	    return 1
	    ;;
    esac

    SAVENV=1
}

show-route1()
{
    local routes=${2}

    echo-command-form "ip route"
    if test "${1}" == "new" ; then
	echo-mark-new
    else
	echo-mark-cur
    fi

    if test -z "${routes}" ; then
	echo-value-null
	return 0
    fi

    local elt range i=0 n=0
    local ip netmask gateway weight pinged

    for elt in ${routes}
    do
	range=$[${i} % 5]
	case ${range} in
	    0)
		ip=${elt}
		;;
	    1)
		netmask=${elt}
		;;
	    2)
		gateway=${elt}
		;;
	    3)
		weight=${elt}
		;;
	    4)
		pinged=${elt}

		if test ${pinged} == ${gateway} ; then
		    unset pinged
		else
		    pinged=" ${pinged}"
		fi

		test ${n} -eq 0 || echo-blank-command
		if test ${ip} == '0.0.0.0' -a ${netmask} == '0.0.0.0' ; then
		    echo-value "default ${gateway} ${weight}${pinged}"
		else
		    echo-value "${ip} ${netmask} ${gateway} ${weight}${pinged}"
		fi
		((n++))
		;;
	    *)
		return 1
		;;
	esac
	((i++))
    done
}

show-route()
{
    echo-begin-show
    show-route1 'current' "${CURRENT_IP_ROUTE_LIST}"
    test "${CURRENT_IP_ROUTE_LIST}" == "${IP_ROUTE_LIST}" || show-route1 'new' "${IP_ROUTE_LIST}"
    echo-end-show
}

dhcp-external-renew()
{
    user-has-admin-rights || return 31
    check-lock || return 123

    supervisor-action "dhcp-external-renew"
    test ${?} -eq 0 || return 104

    return 0
}

remove-dhcp-default-routes()
{
    if test ! -f /var/run/${EXTERNAL_DHCP_IP_CONFIGURATION} ; then
	echo ${IP_ROUTE_LIST}
	return 0
    fi

    local gws=$(get-dhcp-routers)

    if test -z "${gws}" ; then
	echo ${IP_ROUTE_LIST}
	return 0
    fi

    local gw ip_route_list=${IP_ROUTE_LIST}

    for gw in ${gws}
    do
	ip_route_list=$(remove-record-from-list 5 3 "0.0.0.0 0.0.0.0 ${gw}" "${ip_route_list}")
    done

    echo ${ip_route_list}
}

remove-pppoe-default-route()
{
    if test ! -f /var/run/${EXTERNAL_PPPOE_IP_CONFIGURATION}.new ; then
	echo ${IP_ROUTE_LIST}
	return 0
    fi

    local peer=$(get-pppoe-peer)

    if test -z "${peer}" ; then
	echo ${IP_ROUTE_LIST}
	return 0
    fi

    remove-record-from-list 5 3 "0.0.0.0 0.0.0.0 ${peer}" "${IP_ROUTE_LIST}"
}

get-default-gateways()
{
    local i=0 elt range
    local ip netmask gateway
    local default_gateways

    for elt in ${IP_ROUTE_LIST}
    do
	range=$[${i} % 5]
	case ${range} in
	    0)
		ip=${elt}
		;;
	    1)
		netmask=${elt}
		;;
	    2)
		gateway=${elt}
		;;
	    3)
		;;
	    4)
		test ${ip} != '0.0.0.0' -o ${netmask} != '0.0.0.0' || default_gateways="${default_gateways} ${gateway}"
		;;
	    *)
		return 255
		;;
	esac
	((i++))
    done

    echo ${default_gateways:1}
}

manage-route()
{
    if test -z "${1}" ; then show-route ; return 0 ; fi
    local operation=${1}

    local len
    local ip mk px gw wt pg route
    local position_ip_mk_gw position_ip_mk position_nb position
    local position_ip position_mk position_gw position_route

    case "${operation}" in
	add|del|raz)
	    ;;
	*)
	    if test "${operation:0:7}" == "insert:" ; then
		position_ip_mk_gw=${operation:7}
		operation=insert
		position=before
	    elif test "${operation:0:4}" == "add:" ; then
		position_ip_mk_gw=${operation:4}
		operation=insert
		position=after
	    elif test "${operation:0:5}" == "move:" ; then
		if check-digit ${operation:5} ; then
		    position_nb=${operation:5}
		else
		    position_ip_mk_gw=${operation:6}
		    case "${operation:5:1}" in
			+)
			    position=after
			    ;;
			-)
			    position=before
			    ;;
			*)
			    return 1
			    ;;
		    esac
		fi
		operation=move
	    else
		return 1
	    fi

	    if test -n "${position_ip_mk_gw}" ; then
		position_gw=${position_ip_mk_gw/*:}
		position_ip_mk=${position_ip_mk_gw/:*}
		
		test "${position_gw}" != "${position_ip_mk}" || return 180
		check-ip ${position_gw} || return 12
		
		if test "${position_ip_mk}" == default ; then
		    position_ip='0.0.0.0'
		    position_mk='0.0.0.0'
		else
		    position_ip=${position_ip_mk/\/*}
		    position_mk=${position_ip_mk/*\/}
		    if test "${position_ip}" != '0.0.0.0' -o "${position_mk}" != '0.0.0.0' ; then
			test "${position_ip}" != "${position_mk}" || return 180
			
			check-ip ${position_ip} || return 12

			if test ${#position_mk} -le 2 ; then
			    check-prefix ${position_mk} || return 158
			    if test ${position_mk} == 32 ; then
				position_mk='255.255.255.255'
			    elif test ${position_mk} == 0 ; then
				position_mk='0.0.0.0'
			    else
				position_mk=$(ipcalc -s ${position_ip}/${position_mk} -m)
				position_mk=${position_mk/NETMASK=/}
			    fi
			else
			    check-mask ${position_mk} || return 13
			fi
			check-net-ip-address ${position_ip} ${position_mk} || return 70
		    fi
		fi
		position_route="${position_ip} ${position_mk} ${position_gw}"
	    fi
	    ;;
    esac

    case "${operation}" in
	add|insert|move|del)
	    if test "${operation}" == "add" -o "${operation}" == "insert" ; then
		local len=$(record5-length-list "${IP_ROUTE_LIST}")
		test ${len} -lt ${MAX_IP_ROUTES_NB} || return 90
	    fi
	    test -n "${2}" || return 1
	    if test "${2}" == default ; then
		ip='0.0.0.0'
		mk='0.0.0.0'
	    else
		ip=${2}
		px=${ip/*\/}
		if test ${ip} != ${px} ; then
		    check-prefix ${px} || return 158
		    ip=${ip/\/*}
		    check-ip ${ip} || return 12
		    if test ${px} == 32 ; then
			local mk='255.255.255.255'
		    elif test ${px} == 0 ; then
			mk='0.0.0.0'
		    else
			local mk=$(ipcalc -s ${ip}/${px} -m)
			mk=${mk/NETMASK=/}
		    fi
		else
		    test -n "${3}" || return 1
		    check-ip ${ip} || return 12
		    mk=${3}
		    check-mask ${mk} || return 13
		    shift
		fi
	    fi

	    gw=${3}
	    if test ${operation} != del -o -n "${gw}" ; then
		check-ip ${gw} || return 12
	    fi

	    check-net-ip-address ${ip} ${mk} || return 70

	    case "${operation}" in
		move)
		    export IP_ROUTE_LIST
		    route="${ip} ${mk} ${gw}"
		    if test -n "${position_nb}" ; then
			IP_ROUTE_LIST=$(move-record-at-position-in-list 5 3 "${route}" "${IP_ROUTE_LIST}" ${position_nb})
		    else
			IP_ROUTE_LIST=$(move-record-in-list 5 3 "${route}" "${IP_ROUTE_LIST}" "${position_route}" ${position})
		    fi
		    test ${?} -eq 0 || return 152

		    ;;
		del)
		    export IP_ROUTE_LIST
		    if test -n "${gw}" ; then
			IP_ROUTE_LIST=$(remove-record-from-list 5 3 "${ip} ${mk} ${gw}" "${IP_ROUTE_LIST}")
		    else
			IP_ROUTE_LIST=$(remove-record-from-list 5 2 "${ip} ${mk}" "${IP_ROUTE_LIST}")
		    fi
		    ;;

		add|insert)
		    if test ${ip} == '0.0.0.0' -a ${mk} == '0.0.0.0' ; then
			local default_gws=$(get-default-gateways)
			len=$(length-list "${default_gws}")
			test ${len} -lt ${MAX_IP_DEFAUKT_ROUTES_NB} || return 90
		    fi
		    if test -n "${4}" ; then
			wt=${4}
			check-weight ${wt} || return 137
			if test -n "${5}" ; then
			    pg=${5}
			    check-ip ${pg} || return 12
			else
			    pg=${gw}
			fi
		    else
			wt=50
			pg=${gw}
		    fi

		    if test -z "${position_ip_mk_gw}" ; then
			export IP_ROUTE_LIST=$(insert-record-in-list 5 3 "${ip} ${mk} ${gw} ${wt} ${pg}" "${IP_ROUTE_LIST}")
		    else
			export IP_ROUTE_LIST
			IP_ROUTE_LIST=$(insert-record-in-list 5 3 "${ip} ${mk} ${gw} ${wt} ${pg}" "${IP_ROUTE_LIST}" "${position_route}" ${position})
			test ${?} -eq 0 || return 152
		    fi
		    ;;
		*)
		    return 255
		    ;;
	    esac
	    ;;
	
	raz)
	    export IP_ROUTE_LIST=""
	    ;;
	*)
	    return 255
	;;
    esac

    SAVENV=1
}

show-via1()
{
    local vias=${2}

    echo-command-form "ip via"
    if test "${1}" == "new" ; then
	echo-mark-new
    else
	echo-mark-cur
    fi

    if test -z "${vias}" ; then
	echo-value-null
	return 0
    fi

    local elt range i=0 n=0
    local gateway role prio

    for elt in ${vias}
    do
	range=$[${i} % 3]
	case ${range} in
	    0)
		gateway=${elt}
		;;
	    1)
		role=${elt}
		;;
	    2)
		prio=${elt}
		test ${n} -eq 0 || echo-blank-command
		echo-value "${gateway} ${role} ${prio}"
		((n++))
		;;
	    *)
		return 255
		;;
	esac
	((i++))
    done
}

show-via()
{
    echo-begin-show
    show-via1 'current' "${CURRENT_IP_VIA_LIST}"
    test "${CURRENT_IP_VIA_LIST}" == "${IP_VIA_LIST}" || show-via1 'new' "${IP_VIA_LIST}"
    echo-end-show
}

manage-via()
{
    if test -z "${1}" ; then show-via ; return 0 ; fi

    local action=${1}

    case ${action} in
	raz)
	    unset IP_VIA_LIST
	    ;;
	add|del)
	    test -n "${2}" || return 1
	    local gateway=${2}
	    check-ip ${gateway} || return 12

	    IP_VIA_LIST=$(remove-record-from-list 3 1 ${gateway} "${IP_VIA_LIST}")

	    if test ${action} == add ; then
		test -n "${3}" || return 1
		local role=${3}
		check-ha-role ${role} || return 48
		if test -z "${4}" ; then
		    case ${role} in
			master)
			    local prio=110
			    ;;
			backup)
			    local prio=100
			    ;;
			*)
			    return 255
			    ;;
		    esac
		else
		    local prio=${4}
		    check-priority ${prio} || return 47
		fi
		IP_VIA_LIST=$(insert-record-in-slist 3 1 "${gateway} ${role} ${prio}" "${IP_VIA_LIST}")
	    fi
	    ;;
	*)
	    return 1
	    ;;
    esac

    SAVENV=1
}

show-ip-neighbour()
{
    test -f /var/run/${IP_NEIGHBOUR_FILENAME} || return 0
    local ip dev mac

    echo-begin-show

    while read ip dev mac
    do
	echo-command-form "ip"
	echo-value "${ip}" 10 -n
	echo-value "${dev}" 30 -n
	echo-value "${mac}" 40
    done < /var/run/${IP_NEIGHBOUR_FILENAME}

    echo-end-show
}

echo-dhcp-report()
{
    test -n "${1}" || return 1
    test -n "${2}" || return 2
    local field=${1}
    local ftype=${2}
    local value=${3}
    shift 3
    local comment=${*}

    test -z "${comment}" || comment=" ${comment}"

    if test ${TERM} == ${WADMIN_TERM} ; then
	echo "<tr>"
	echo "<td>${field}</td>"

	case ${ftype} in
	    value)
		echo "<td>${value}</td>"
		;;
	    state)
		case ${value} in
		    OK)
			echo "<td><img src='${IMAGE_DIR}/ok.png' /></td>"
			;;
		    KO)
			echo "<td><img src='${IMAGE_DIR}/ko.png' />${comment}</td>"
			;;
		    *)
			echo "<td><img src='${IMAGE_DIR}/rotating_arrow.gif' />${comment}</td>"
			;;
		esac
		;;
	    *)
		echo "<td><img src='${IMAGE_DIR}/error.png' />${comment}</td>"
		;;
	esac

	echo "</tr>"
    else
	echo -n "${field}"
	case ${ftype} in
	    value)
		echo -e "\e[${COLUMNS}D\e[${PRINT_COL}C${value}"
		;;
	    state)
		echo -ne "\e[${COLUMNS}D\e[${PRINT_COL}C"
		case ${value} in
		    OK)
			echo -ne "[${STATE_OK}]"
			;;
		    KO)
			echo -ne "[${STATE_OK}]"
			;;
		    *)
			echo -ne "[${STATE_OO}]"
			;;
		esac
		echo "${comment}"
		;;
	    *)
		echo -e "\e[${COLUMNS}D\e[${PRINT_COL}C..."
		;;
	esac
    fi
}

get-external-dhcp-reason-text()
{
    test -n "${1}" || return 1
    local reason=${1}

    reason=${reason,,}
    reason=${reason^}

    echo ${reason}
}

gen-external-dhcp-renew-report()
{
    local dhcp_state apply_state

    test -n "${COLUMNS}" || COLUMNS=80

    if test -f /var/run/${EXTERNAL_DHCP_DONE} ; then
	dhcp_state="OO In progress..."
	apply_state="XX Waiting..."
    else
	if test -f /var/run/${EXTERNAL_DHCP_STATE} ; then

	    local dhcp_reason

	    read dhcp_reason < /var/run/${EXTERNAL_DHCP_STATE}
	    echo-dhcp-report "Last DHCP Event" value $(get-external-dhcp-reason-text ${dhcp_reason})

	    case ${dhcp_reason} in
		MEDIUM|ARPCHECK|ARPSEND|PREINIT)
		    dhcp_state="XX In progress..."
		    apply_state="XX Waiting..."
		    ;;
		BOUND|RENEW|REBIND)
		    if test -f /var/run/${EXTERNAL_DHCP_IP_CONFIGURATION} ; then

			local line i=0
			local dv sv ip mk gws ld

			while read line
			do
			    case ${i} in
				0)
				    dv=${line}
				    ;;
				1)
				    sv=${line}
				    ;;
				2)
				    ip=${line}
				    ;;
				3)
				    mk=${line}
				    ;;
				4)
				    gws=${line}
				    ;;
				5)
				    ld=${line}
				    ld=$(get-date-from-epoch-seconds ${ld})
				    test -n "${ld}" || ld='unknown'
				    break
				    ;;
				*)
				    break
				    ;;
			    esac
			    ((i++))
			done < /var/run/${EXTERNAL_DHCP_IP_CONFIGURATION}

			echo-dhcp-report "Physical NIC" value ${dv}
			echo-dhcp-report "DHCP Server IP" value ${sv}
			echo-dhcp-report "Acquired IP" value ${ip}
			echo-dhcp-report "Acquired Mask" value ${mk}
			echo-dhcp-report "Acquired Router(s)" value "${gws// /, }"
			echo-dhcp-report "Lease End Date" value ${ld}
		    fi

		    dhcp_state="OK Done"
		    if test -f ${ADMIN_LOCK_DIR}/apl_apply ; then
			apply_state="XX In progress..."
		    else
			apply_state="OK Done"
		    fi
		    ;;
		REBOOT)
		    dhcp_state="XX In progress..."
		    apply_state="XX Waiting..."
		    ;;
		FAIL)
		    dhcp_state="KO Failed"
		    apply_state="XX Waiting..."
		    ;;
		EXPIRE)
		    dhcp_state="KO Expired"
		    apply_state="XX Waiting..."
		    ;;
		RELEASE|STOP)
		    dhcp_state="XX In progress..."
		    apply_state="XX Waiting..."
		    ;;
		TIMEOUT)
		    dhcp_state="KO Failed"
		    apply_state="XX In progress..."
		    ;;
		PREINIT6|BOUND6|RENEW6|REBIND6|DEPREF6|EXPIRE6|RELEASE6|STOP6)
		    dhcp_state="KO In error[11]"
		    ;;
		*)
		    dhcp_state="KO In error[13]"
		    apply_state="XX Waiting..."
		    ;;
	    esac
	else
	    dhcp_state="KO In error[21]"
	fi
    fi

    echo-dhcp-report "Request State" state ${dhcp_state}
    echo-dhcp-report "Apply State" state ${apply_state}
}

display-external-dhcp-renew-report()
{
    if test ${TERM} == ${WADMIN_TERM} ; then
	gen-external-dhcp-renew-report
    else
	echo-begin-show
	gen-external-dhcp-renew-report
	echo-end-show
    fi
}

manage-external-dhcp()
{
    local action=${1}
    local key=${2}

    case ${action} in
	renew)
	    if test ${CURRENT_IP_EXTERNAL_MODE} != dhcp ; then
		INDIRECT_ERROR_CODE=539
		return 254
	    fi

	    case ${key} in
		report)
		    display-external-dhcp-renew-report
		    ;;
		'')
		    dhcp-external-renew
		    ;;
		*)
		    return 1
		    ;;
	    esac
	    ;;
	'')
	    export IP_EXTERNAL_MODE=${ip_external_mode}
	    SAVENV=1
	    ;;
	*)
	    return 1
	    ;;
    esac    
}

manage-external-pppoe()
{
    local encrypted=${1}

    local service_name=${ARGS[1]}
    local username=${ARGS[2]}
    local password=${ARGS[3]}

    if ! check-pppoe-service-name "${service_name}" ; then
	INDIRECT_ERROR_CODE=541
	return 254
    fi

    if ! check-pppoe-username "${username}" ; then
	INDIRECT_ERROR_CODE=542
	return 254
    fi

    if test -n "${username}" ; then
	if test -n "${encrypted}" ; then
	    password=$(decrypt-password "encrypted:${password}" "${PPPOE_PASSWD}")
	else
	    if test -z "${password}" -a ${TERM} != ${WADMIN_TERM} ; then
		test "${__BATCH_MODE}" != yes || error 111
		test -z "${TRANSACTION}" || return 106

		echo -n "Please enter the PPPoE password: "
		stty -echo
		read password
		stty echo
		echo
	    fi
	fi
    else
	unset password
    fi

    if ! check-pppoe-password "${password}" ; then
	INDIRECT_ERROR_CODE=543
	return 254
    fi

    export IP_EXTERNAL_MODE='pppoe'
    export IP_EXTRNAL_PPPOE_SERVICE_NAME=${service_name}
    export IP_EXTRNAL_PPPOE_USERNAME=${username}
    export IP_EXTRNAL_PPPOE_PASSWORD=${password}

    SAVENV=1
}

run()
{
    local interface=${ARGS[1]}
    local vlan

    case "${interface}" in
	'')
	    show-ip
	    return ${?}
	    ;;
	name)
	    shift-args
	    manage-name ${ALLARGS}
	    return ${?}
	    ;;
	neighbour)
	    update-report ip-neighbour 15 || return 104
	    show-ip-neighbour
	    return 0
	    ;;
	route)
	    shift-args
	    manage-route ${ALLARGS}
	    return ${?}
	    ;;
	via)
	    shift-args
	    manage-via ${ALLARGS}
	    return ${?}
	    ;;
	*)
	    ;;
    esac

    if test -z "${ARGS[2]}" ; then
	case ${interface} in
	    internal)
		show-ip ${interface}
		return 0
		;;

	    external|auxiliary|vlan)
		contextual-command-is-allowed || return 209
		show-ip ${interface}
		return 0
		;;

	    *)
		if test "${ARGS[1]:0:9}" == "internal." ; then
		    contextual-command-is-allowed || return 209
		    vlan=${ARGS[1]:9}
		    if check-vlan "${vlan}"; then
			show-ip-vlan "${vlan}"
			return 0
		    else
			return 41
		    fi
		else
		    return 1
		fi
		;;
	esac
    fi

    case ${interface} in
	internal)
	    ;;

	external|auxiliary|vlan)
	    contextual-command-is-allowed || return 209
	    ;;

	*)		
	    test "${ARGS[1]:0:9}" != "internal." || contextual-command-is-allowed || return 209
	    ;;
    esac

    local ip px mk
    local ip_external_mode

    case ${interface} in
	external)
	    ip_external_mode=${ARGS[2]}
	    case ${ip_external_mode} in
		static)
		    test -n "${ARGS[3]}" || return 1
		    shift-args
		    ;;
		dhcp)
		    shift-args 2
		    manage-external-dhcp ${ALLARGS}
		    return ${?}
		    ;;
		pppoe|pppoe:encrypted)
		    shift-args 2
		    manage-external-pppoe ${ip_external_mode/pppoe}
		    return ${?}
		    ;;
		*)
		    ;;
	    esac
	    ;;
	*)
	    ;;
    esac

    ip=${ARGS[2]}
    px=${ip/*\/}

    if test ${ip} != ${px} ; then
	check-prefix ${px} || return 158
	ip=${ip/\/*}
    else
	unset px
    fi

    check-ip ${ip} || return 12

    test ${ip} != '127.0.0.1' || return 38
    test ${ip} != '127.0.0.2' || return 38

    if test -z "${px}" ; then
	if test -n "${ARGS[3]}" ; then
	    mk=${ARGS[3]}
	    check-mask ${mk} || return 13
	else
	    mk=255.255.255.0
	fi
    else
	if test ${px} == 32 ; then
	    mk='255.255.255.255'
	elif test ${px} == 0 ; then
	    mk='0.0.0.0'
	else
	    mk=$(ipcalc -s ${ip}/${px} -m)
	    mk=${mk/NETMASK=/}
	fi
    fi

    host-ip-address ${ip} ${mk} || return 62

    if test ${interface} != external ; then
	if test ${mk} == 255.255.255.255 ; then
	    INDIRECT_ERROR_CODE=538
	    return 254
	fi
    fi

    case ${interface} in
	internal)
	    export IP_INTERNAL_IP=${ip}
	    export IP_INTERNAL_MASK=${mk}
	    ;;
	external)
	    export IP_EXTERNAL_MODE=static
	    export IP_EXTERNAL_IP=${ip}
	    export IP_EXTERNAL_MASK=${mk}

	    case ${CURRENT_IP_EXTERNAL_MODE} in
		dhcp)
		    export IP_ROUTE_LIST=$(remove-dhcp-default-routes)
		    ;;
		pppoe)

export IP_ROUTE_LIST=$(remove-pppoe-default-route)

		    ;;
		*)
	    esac
	    ;;
	auxiliary)
	    export IP_AUXILIARY_IP=${ip}
	    export IP_AUXILIARY_MASK=${mk}
	    ;;
	*)
	    if test "${ARGS[1]:0:9}" == "internal." ; then
		vlan=${ARGS[1]:9}

		if check-vlan "${vlan}"; then
		    vlan=$((10#${vlan}))
		    vlan-exist "${VLAN_FLOW_LIST}" "${vlan}"  || return 42
		    export IP_VLAN_LIST=$(insert-record-in-slist 3 1 "${vlan} ${ip} ${mk}" "${IP_VLAN_LIST}" numerical)
		else
		    return 41
		fi
	    else
		return 43
	    fi
	    ;;
    esac
    SAVENV=1
}

main "${@}"
