#!/bin/sh

cachedir="/var/cache/alterator/net-eth"

rdelim='[[:space:]]\+'
wdelim=' '

. alterator-sh-functions
. alterator-net-functions
. shell-config


### cache
init_cache()
{
    local ifacedir="/etc/net/ifaces/$1"

    if [ ! -d "$cachedir/$1" ] ;then
	[ -d "$ifacedir" ] && cp -a "$ifacedir" "$cachedir"
	mkdir -p "$cachedir/$1"
    fi

    [ -f "$cachedir/iftab" ] || cp /etc/iftab "$cachedir/iftab"
    [ -f "$cachedir/resolv.conf" ] || cp /etc/resolv.conf "$cachedir/resolv.conf"
    [ -f "$cachedir/network" ] || cp /etc/sysconfig/network "$cachedir/network"
}

clear_cache()
{
    rm -rf "$cachedir"
    mkdir "$cachedir"
}

exit_handler()
{
    local rc=$?
    trap - EXIT
    [ -z "$TMPDIR" ] || rm -rf -- "$TMPDIR"
    exit $rc
}

create_tmpdir()
{
    TMPDIR=
    TMPDIR="$(mktemp -dt "alterator.XXXXXXXX")"
}

commit_hostname()
{
    local value="$(shell_config_get /etc/sysconfig/network HOSTNAME)"
    [ -n "$value" ] || return

    hostname "$value"
    printf %s\\n "$value" >/etc/HOSTNAME

    #bind hostname
    DETECTED=0
    POOL=`grep -s "^[^#]*\<$value\>" /etc/hosts`
    for i in "$POOL"
    do
        [ "$i" == "$value" ] && DETECTED=1
    done

    [ "$DETECTED" == 1 ] || (create_tmpdir
        cp /etc/hosts $TMPDIR/hosts.tmp &&
        sed -e "/127.0.0.2/d" $TMPDIR/hosts.tmp > /etc/hosts &&
        printf '127.0.0.2\t%s %s\n' "$value" "${value%%.*}" >> /etc/hosts)
}

commit_cache()
{
    [ -f "$cachedir/iftab" ] && mv -f "$cachedir/iftab" /etc/iftab
    [ -f "$cachedir/resolv.conf" ] && mv -f "$cachedir/resolv.conf" /etc/resolv.conf
    [ -f "$cachedir/network" ] && mv -f "$cachedir/network" /etc/sysconfig/network
    commit_hostname

    find $cachedir -maxdepth 1 -mindepth 1 -type d|
	while read iface; do
	    [ -n "$iface" ] || exit
	    [ "$in_restart" = '#f' -o "$(read_iface_option "$iface" DISABLED)" != "yes" ] || ifdown "${iface##*/}"

	    rm -rf "/etc/net/ifaces/${iface##*/}"
	    mv -f "$iface" "/etc/net/ifaces/${iface##*/}"
	done

    clear_cache
}

### dns

read_dns()
{
	local resolv_conf="/etc/resolv.conf"
	[ -f "$cachedir/resolv.conf" ] && resolv_conf="$cachedir/resolv.conf"

	shell_config_get "$resolv_conf" nameserver "$rdelim"| tr '\n' ' '
}

write_dns()
{
	local resolv_conf="$cachedir/resolv.conf"

	shell_config_del "$resolv_conf" nameserver "$rdelim"

	local IFS=' '
	for i in $1;do
	    printf 'nameserver %s\n' "$i" >>"$resolv_conf"
	done
}

read_search()
{
	local resolv_conf="/etc/resolv.conf"
	[ -f "$cachedir/resolv.conf" ] && resolv_conf="$cachedir/resolv.conf"

	shell_config_get "$resolv_conf" search "$rdelim"|
	    tail -n1
}

write_search()
{
	local resolv_conf="$cachedir/resolv.conf"
	local IFS=' '

	shell_config_del "$resolv_conf" search "$rdelim"
	shell_config_set "$resolv_conf" search "$1" "$rdelim" "$wdelim"
}

### hostname

read_hostname()
{
	local netconfig="/etc/sysconfig/network"
	[ -f "$cachedir/network" ] && netconfig="$cachedir/network"
	
	local value="$(shell_config_get "$netconfig" HOSTNAME)"

	[ -n "$value" ] || value="localhost.localdomain"
	echo "$value"
}

write_hostname()
{
	local netconfig="$cachedir/network"

	shell_config_set "$netconfig" HOSTNAME "$1"
	shell_config_del "$netconfig" DOMAINNAME
}

### interface work

list_mask()
{
    for i in `seq 32 -1 0`; do 
	write_enum_item "$i" "/$i ($(maskname "$i"))"
    done
}

list_hw_binding()
{
    write_enum_item "missing" "`_ "missing"`"
    write_enum_item "mac" "`_ "by MAC address"`"
    write_enum_item "businfo" "`_ "by bus location"`"
}

list_configuration()
{
    write_enum_item "off" "`_ "Turned off"`"
    [ ! -f "/usr/sbin/NetworkManager" ] || write_enum_item "networkmanager" "`_ "Managed by user (NetworkManager)"`"
    write_enum_item "dhcp" "`_ "Use DHCP"`"
    write_enum_item "ipv4ll" "`_ "Use Zeroconf"`"
    write_enum_item "static" "`_ "Manually"`"
}

read_hw_binding()
{
    local config=

    if [ -f "$cachedir/iftab" ];then
	config="$cachedir/iftab"
    else
	config="/etc/iftab"
    fi

    local line="$(grep "^[[:space:]]*$1[[:space:]]" "$config")"

    if [ -z "$line" ]; then
	echo "missing"
    else
	if echo "$line" | fgrep -qsw mac; then
	    echo "mac"
	elif echo "$line" | fgrep -qsw businfo; then
	    echo "businfo"
	else
	    echo "missing"
	fi
    fi
}

read_info()
{
	local info=
	ifcheckup "$name" && info="`_ "interface is up"`" || info="`_ "interface is down"`"
	
	if ! ifcheckwireless "$name"; then
	    ifcheckplug "$name"
	    case "$?" in
		2) info="$info, `_ "plugged"`"   ;;
		3) info="$info, `_ "unplugged"`" ;;
	    esac
	fi
	echo "$info"
}

read_configuration()
{
    local disabled="$(read_iface_option "$1" DISABLED)"
    local nm_controlled="$(read_iface_option "$1" NM_CONTROLLED)"
    local bootproto="$(read_iface_option "$1" BOOTPROTO)"

    if [ "$(write_bool "$nm_controlled")" = "#t" ];then
	echo 'networkmanager'
    elif [ "$(write_bool "$disabled")" = "#t" ];then
        echo 'off'
    elif [ "$bootproto" = "static" ];then
	echo 'static'
    elif [ "$bootproto" = "ipv4ll" ];then
	echo 'ipv4ll'
    else #dhcp by default
	echo 'dhcp'
    fi
}

read_iface()
{
	local name="$1"; shift
	local ifacedir=

	if [ -d "$cachedir/$name" ];then
	    ifacedir="$cachedir/$name"
	else
	    ifacedir="/etc/net/ifaces/$name"
	fi

	#collect general information

	write_string_param info "$(read_info)"
	write_string_param hw_binding "$(read_hw_binding "$name")"
	write_string_param configuration "$(read_configuration "$ifacedir")"
	write_bool_param wireless "$(ifcheckwireless "$name" && echo "yes" || echo "no")"

	local addr= ip= mask=
	[ ! -s "/$ifacedir/ipv4address" ] ||
		addr=$(grep '^[0-9]' "$ifacedir/ipv4address" | head -n1 || echo "")

	if [ -n "$addr" ]; then
		ip="${addr%%/*}"
		mask="${addr#$ip}"; mask="${mask#/}"
	fi

	write_string_param ip "$ip"
	write_string_param mask "${mask:-24}"

	[ ! -s "/$ifacedir/ipv4route" ] ||
		write_string_param \
			default \
			$(grep '^default' "$ifacedir/ipv4route" | sed -r 's,default[[:space:]]+via[[:space:]],,' || echo "")
}


write_hw_binding()
{
    local name="$1";shift
    local value="$1";shift
    local config="$cachedir/iftab"

    local mac="$(ifread "$name"|cut -f1)"
    local businfo="$(ifread "$name"|cut -f2)"

    if [ -s "$config" ]; then
	sed -r \
	    -e "/^$name[[:space:]]/ d" \
	    -i "$config"

	[ -z "$mac" ] ||
	[ "$mac" = "00:00:00:00:00:00" ] ||
	    sed -r \
		-e "/[[:space:]]mac[[:space:]]+$mac([[:space:]]|\$)/ d" \
	        -i "$config"

	[ -z "$businfo" ] ||
	    sed -r \
		-e "/[[:space:]]businfo[[:space:]]+$businfo([[:space:]]|\$)/ d" \
	    	-i "$config"
    fi

    case "$value" in
	none) ;;
	mac)
	    [ -z "$mac" ] ||
	    [ "$mac" = "00:00:00:00:00:00" ] ||
	    printf "%s\tmac %s\n" "$name" "$mac" >>"$config"
	    ;;
	businfo)
	    [ -z "$businfo" ] ||
	    printf "%s\tbusinfo %s\n" "$name" "$businfo" >>"$config"
	    ;;
    esac
}

write_iface()
{
	local name="$1" && shift
	local ifacedir="$cachedir/$name"

	[ -n "$in_mask" ] && [ -n "$in_ip" ] && \
		printf '%s/%s\n' "$in_ip" "$in_mask" >"/$ifacedir/ipv4address"

	[ -n "$in_default" ] && [ -s "/$ifacedir/ipv4address" ] && \
		printf 'default via %s\n' "$in_default" >"/$ifacedir/ipv4route"

	write_iface_option "$ifacedir" TYPE eth

	case "$in_configuration" in
	    off)
		write_iface_option "$ifacedir" DISABLED yes
		write_iface_option "$ifacedir" NM_CONTROLLED no
		;;
	    networkmanager)
		write_iface_option "$ifacedir" DISABLED yes
		write_iface_option "$ifacedir" NM_CONTROLLED yes
		;;
	    static)
		write_iface_option "$ifacedir" DISABLED no
		write_iface_option "$ifacedir" NM_CONTROLLED no
		write_iface_option "$ifacedir" BOOTPROTO static
		;;
	    dhcp)
		write_iface_option "$ifacedir" DISABLED no
		write_iface_option "$ifacedir" NM_CONTROLLED no
		write_iface_option "$ifacedir" BOOTPROTO dhcp
		;;
	    ipv4ll)
		write_iface_option "$ifacedir" DISABLED no
		write_iface_option "$ifacedir" NM_CONTROLLED no
		write_iface_option "$ifacedir" BOOTPROTO ipv4ll
		;;
	esac

	[ -n "$in_hw_binding" ] &&
	    write_hw_binding "$name" "$in_hw_binding"
}

commit_iface()
{
    commit_cache
    [ "$in_restart" = '#f' ] ||
	iflist|
	    while read iface rest; do
		[ -d "/etc/net/ifaces/$iface" ] || continue
		if [ -z "$DURING_INSTALL" ] || ! ifcheckup $iface; then
#		    echo "commit_cache: restarting $iface"
		    ifdown "$iface" && ifup "$iface"
		fi
	    done >&2
    /sbin/update_chrooted conf >&2 || :
}

reset_iface()
{
    clear_cache
}

#initial actions
ifup lo
clear_cache

on_message()
{
	case "$in_action" in
		constraints)
			echo '('
			printf 'hostname (hostname #t label "%s" default "localhost.localdomain")\n' \
				"`_ "Host name"`"
			 printf 'search (hostname #t label "%s")\n' \
				"`_ "Search domains"`"
			printf 'dns (ipv4-address #t label "%s")' \
				"`_ "DNS servers"`"
			printf 'ip (ipv4-address #t label "%s")' \
				"`_ "IP address"`"
			printf 'default (ipv4-address #t label "%s")' \
				"`_ "Default gateway"`"
			echo ')'
			;;
		list)
			echo '('
			case "${in__objects##*/}" in
			    avail_masks) list_mask ;;
			    avail_hw_bindings) list_hw_binding ;;
			    avail_configurations) list_configuration ;;
			    *) list_eth|write_enum ;;
			esac
			echo ')'
			;;
		read) 
			echo "("
			local name="${in_ifname}"
			[ -n "$name" ] || name="$(iflist|cut -f1 -d' '|head -n1)"
			[ -n "$name" ] && read_iface "$name"

			write_string_param name "$name"
			write_string_param ifname "$name"

			write_string_param hostname "$(read_hostname)"
			write_string_param dns "$(read_dns)"
			write_string_param search "$(read_search)"

			echo ")"
			;;
		write)
			local name="${in_ifname}"
			[ -n "$name" ] || name="$(iflist|cut -f1 -d' '|head -n1)"

			init_cache "$name"

			[ -n "$name" ] && write_iface "$name"

			[ -n "$in_hostname" ] && write_hostname "$in_hostname"
			[ -n "$in_dns" ] && write_dns "$in_dns"
			[ -n "$in_search" ] && write_search "$in_search"

			[ -n "$in_commit" ] && commit_iface
			[ -n "$in_reset" ] && reset_iface
			write_nop
			;;
		*)
			echo '#f'
			;;
	esac
}

message_loop
