#!/bin/sh

################### shell file helpe()
PATH=/usr/lib/alterator-net-common:$PATH

############ main config files 
netconfig="/etc/sysconfig/network"
resolv_conf="/etc/resolv.conf"
etc_hosts="/etc/hosts"
hostnameconfig="/etc/HOSTNAME"

. alterator-sh-functions
. shell-config

condifup()
{
    ifcheckup "$1" || (ifup "$1" && echo "Up $1" >&2)
}

is_ether()
{
    local iface=$1 && shift
    iflist | grep -q $iface
    return $?
}

dhcp_foreach()
{
    local i
    for i in /etc/net/ifaces/*;do
        i="${i##*/}"
        is_ether $i || continue
        ifcheckdhcp "$i" && "$1" "$i"
    done >/dev/null
}

resolve_hostname()
{
    grep -qs "^nameserver" "$resolv_conf" &&
    for i in $(/sbin/ip addr show |
        sed -ne 's,^[[:space:]]*inet[[:space:]]\+\([^/]\+\).*,\1,p'|
        grep -v '^127\.') ;do
        /usr/bin/resolve -t 2 -s "$i" && return 0
    done
    return 1
}

read_hostname()
{
    local name=
    name="$(/bin/hostname)"
    if [ "$name" != "(none)" ]; then
        echo $name
    else
        resolve_hostname || echo "localhost.localdomain"
    fi
}

################### interface modificators

list_mask()
{
    for i in `seq 32 -1 0`; do 
        printf '("%s" label "/%s (%s)")' "$i" "$i" "$(maskname "$i")"
    done
}

list_iface()
{
    iflist|
    while read iface mac; do
        printf '("%s" label "%s (%s)")' "$iface" "$iface" "$(ifaceinfo "$iface")"
    done
}

restart_iface()
{
    local name=$1 && shift
    rm -f /etc/dhcpc/dhcpcd-${name}.info
    rm -f /var/lib/dhcpcd/dhcpcd-${name}.info
    ifdown "$name" && ifup "$name"
}

restart_all_ifaces() {
    iflist|
    while read iface mac; do
        restart_iface "$iface"
    done >&2
}

# resolv.conf 
read_dns()
{
    [ -f "$resolv_conf" ] &&
    sed -n 's,^[[:space:]]*nameserver[[:space:]]\+,,p' "$resolv_conf"
}

is_ip_address()
{
    echo -n $1 | grep -Ec '^[1-2]?[0-9]?[0-9]\.[0-2]?[0-9]?[0-9]\.[0-2]?[0-9]?[0-9]\.[0-2]?[0-9]?[0-9]$' > /dev/null 
    return $?
}

print_nameservers_ip()
{
    local i=1
    if [ -f "$resolv_conf" ]; then
        exec 3<$resolv_conf
        while read nameserver ip <&3
        do
            if [ $nameserver  = "nameserver" ] && is_ip_address $ip; then
                echo "$ip"
            fi
        done
    fi
}

print_iface_dhcp_conf()
{
    local iface="$1" && shift
    if ifcheckdhcp $iface > /dev/null; then
        # Old version dhcpcd
        if [ -f /etc/dhcpc/dhcpcd-${iface}.info ]; then
          cat /etc/dhcpc/dhcpcd-${iface}.info
        # New version dhcpcd
        elif [ -f /var/lib/dhcpcd/dhcpcd-${iface}.info ]; then
          cat /var/lib/dhcpcd/dhcpcd-${iface}.info
        else
          echo "Can't receive DHCP configuration"
        fi
    fi
}

write_dns()
{
    local dns1="$1" && shift
    local dns2="$1" && shift
    local dns3="$1" && shift

    [ -f "$resolv_conf" ] || touch "$resolv_conf"
    sed -i '/^[[:space:]]*nameserver[[:space:]]\+/ d' "$resolv_conf"
    is_ip_address "$dns1" && printf "nameserver %s\n" "$dns1" >>"$resolv_conf"
    is_ip_address "$dns2" && printf "nameserver %s\n" "$dns2" >>"$resolv_conf"
    is_ip_address "$dns3" && printf "nameserver %s\n" "$dns3" >>"$resolv_conf"
}

read_search()
{
    [ -f "$resolv_conf" ] &&
    sed -n 's,^[[:space:]]*search[[:space:]]\+,,p' "$resolv_conf"|
    tr ' ' '\n'|
    sed '/^[[:space:]]*$/ d'
}

write_search()
{
    local value="$(echo "$1"|grep -v '^$'|sed -r 's,^[[:space:]]*([^[:space:]]+)[[:space:]]*,\1,'|tr '\n' ' ')"
    sed -i '/^[[:space:]]*search[[:space:]]\+/ d' "$resolv_conf"
    printf 'search %s\n' "$value" >>"$resolv_conf"

}

use_ipv4ll()
{
    local i=
    for i in /etc/net/ifaces/*;do
        i="${i##*/}"
        is_ether $i || continue
        disabled="$(ifvar "$i" "DISABLED")"
        bootproto="$(ifvar "$i" "BOOTPROTO")"
        [ -n "$disabled" ] && [ "$disabled" = "yes" ] && return 1
        [ -n "$bootproto" ] && [ "$bootproto" != "dhcp-ipv4ll" ] && return 1
    done
    return 0
}

read_dhcp_arg()
{
    local arg="$1" && shift
    grep -wqs  -- "-$arg" 
}

read_dhcp()
{
    local f
    for f in /etc/net/ifaces/*; do
        f=${f##/etc/net/ifaces/}
        is_ether $f || continue
        ifcheckdhcp "$f" && return 0
    done
    return 1
}

general_status_msg()
{
    # Information about host name
    local hname=            # host name
    hname="$(read_hostname)"
    printf "hostname \"%s\"\n" "$hname"
    if use_ipv4ll; then 
        printf "conf_type \"auto\"\n" # Auto configuration
    else
        printf "conf_type \"manual\"\n" # Manual configuration
    fi
    printf "dns \"%s\"\n" "$(print_nameservers_ip)"
    printf "search \"%s\"\n" "$(read_search)"
}

general_status()
{
    echo "("
    general_status_msg
    echo ")"
}

read_iface()
{
    local name="$1" && shift            # Interface name
    local iface_dir="/etc/net/ifaces/$name"
    local options="$iface_dir/options"
    local route="$iface_dir/ipv4route"
    local address="$iface_dir/ipv4address"

    echo "("

    #collect general information
    local info=
    ifcheckup "$name" && info="`_ "interface is up"`" || info="`_ "interface is down"`"

    if ! [ -d "/sys/class/net/$name/wireless" ];then
        ifcheckplug "$name"
        case "$?" in
            2) info="$info, `_ "plugged"`"   ;;
            3) info="$info, `_ "unplugged"`" ;;
        esac
    fi

    printf 'info "%s"' "$info"
    printf 'wireless %s' "$([ -d "/sys/class/net/$name/wireless" ] && echo "#t" || echo "#f")"

    if ! [ -d "$iface_dir" ]; then
        mkdir "$iface_dir"
        shell_config_set "$options" "TYPE" "eth"
        shell_config_set "$options" "DISABLED" "yes"
    fi

    local disabled=
    disabled="$(ifvar "$name" "DISABLED")"
    if [ "$disabled" = "yes" ]; then
        echo "disabled #t"
    else
        local bootproto=
        bootproto="$(ifvar "$name" "BOOTPROTO")"
        echo "disabled #f"
        if [ "$bootproto" = "dhcp" ]; then      # Interface configured by dhcp
            local dhcp_dns=         # Get nameservers from DHCP server: "yes" or "no"
            local dhcp_hostname=    # Get hostname from DHCP server: "yes" or "no"
            local dhcp_gw=          # Set default gateway recived via dhcp
            local dhcp_ntp=         # Set NTP configuration via dhcp
            echo "bootproto \"dhcp\""
            if args="$(read_dhcp)"; then
                echo "$args"|read_dhcp_arg "H" && dhcp_hostname="yes"       # for "H" man 8 dhcpcd
                echo "$args"|read_dhcp_arg "R" || dhcp_dns="yes"            # for "R" man 8 dhcpcd
                echo "$args"|read_dhcp_arg "G" || dhcp_gw="yes"             # for "G" man 8 dhcpcd
                echo "$args"|read_dhcp_arg "N" || dhcp_ntp="yes"            # for "R" man 8 dhcpcd
            fi
            printf "dhcp-hostname %s\n" $([ "$dhcp_hostname" = "yes" ] && echo "#t" || echo "#f")
            printf "dhcp-dns %s\n"  $([ "$dhcp_dns" = "yes" ] && echo "#t" || echo "#f")
            printf "dhcp-gw %s\n"  $([ "$dhcp_gw" = "yes" ] && echo "#t" || echo "#f")
            printf "dhcp-ntp %s\n"  $([ "$dhcp_ntp" = "yes" ] && echo "#t" || echo "#f")
            printf "dhcp_conf \"%s\"\n" "$(print_iface_dhcp_conf $name)"
        elif [ "$bootproto" = "static" ]; then # Interface have static configuration
            local addr= ip= mask=
            echo "bootproto \"static\""
            [ ! -s "/etc/net/ifaces/$name/ipv4address" ] ||
            addr=$(grep '^[0-9]' "/etc/net/ifaces/$name/ipv4address" | head -n1 || echo "")
            if [ -n "$addr" ]; then
                ip="${addr%%/*}"
                mask="${addr#$ip}"; mask="${mask#/}"
                printf 'ip "%s" mask "%s"\n' "$ip" "${mask:-32}"
                [ ! -s "/etc/net/ifaces/$name/ipv4route" ] ||
                printf 'default "%s"\n' \
                $(grep '^default' "/etc/net/ifaces/$name/ipv4route" | sed -r 's,default[[:space:]]+via[[:space:]],,' || echo "")
            fi
        elif [ "$bootproto" = "dhcp-ipv4ll" ]; then
            echo "bootproto \"ipv4ll\""
        else
            # Unknown interface configuration, nothing to do
            : # Nop
        fi
    fi

    general_status_msg

    echo ")"
}

write_dhcp_arg()
{
    local arg="$1" && shift          # dhcpcd client option
    local value="$1" && shift        # yes or no
    local mf="$1" && shift           # interface name
    local iface_dir="/etc/net/ifaces/$mf"
    local options="$iface_dir/options"

    is_ether $mf || return 0

    ifcheckdhcp "$mf" >/dev/null &&
    (
    args="$(ifvar "$mf" DHCP_ARGS | sed -r "s,(^|.*[[:space:]])-$arg([[:space:]]*.*|$),\1\2," | sed -r 's,^[[:space:]]*(.*)[[:space:]]+$,\1,')" #"
    sed -i '/^DHCP_ARGS=.*/d' "$options"
    if [ "$value" = "yes" ];then
        printf "DHCP_ARGS=\"%s -$arg\"\n" "$args" >> "$options"
    else
        [ -z "$args" ] || printf 'DHCP_ARGS="%s"\n' "$args" >> "$options"
    fi
    )
}

write_iface()
{
    local name="$1" && shift
    local iface_dir="/etc/net/ifaces/$name"
    local options="$iface_dir/options"
    local route="$iface_dir/ipv4route"
    local address="$iface_dir/ipv4address"

    [ -d "$iface_dir" ] || mkdir "$iface_dir"
    shell_config_set "$options" "TYPE" "eth"

    if [ "$in_disabled" = "yes" ];then
        shell_config_set "$options" "DISABLED" "yes"
    elif [ "$in_disabled" = "no" ]; then
        shell_config_set "$options" "DISABLED" "no"
        case "$in_bootproto" in
            static)
            shell_config_set "$options" "BOOTPROTO" "static"
            [ -n "$in_mask" ] && [ -n "$in_ip" ] && \
            printf '%s/%s\n' "$in_ip" "$in_mask" >"$address"
            if [ -n "$in_default" ] ; then
                printf 'default via %s\n' "$in_default" >"$route"
            else
                [ -s "$route" ] && /bin/sed -r -i "s,^default.*,," $route
            fi
            ;;
            dhcp)
            shell_config_set "$options" "BOOTPROTO" "dhcp"
            [ -n "$in_dhcp_dns" ] && 
            write_dhcp_arg "R" $([ "$in_dhcp_dns" = "#t" ] && echo "no" || echo "yes") $name
            [ -n "$in_dhcp_gw" ] &&
            write_dhcp_arg "G" $([ "$in_dhcp_gw" = "#t" ] && echo "no" || echo "yes") $name
            [ -n "$in_dhcp_ntp" ] &&
            write_dhcp_arg "N" $([ "$in_dhcp_ntp" = "#t" ] && echo "no" || echo "yes") $name
            [ -n "$in_dhcp_hostname" ] &&
            (
            write_dhcp_arg "H" $([ "$in_dhcp_hostname" = "#t" ] && echo "yes" || echo "no") $name
            write_dhcp_arg "D" $([ "$in_dhcp_hostname" = "#t" ] && echo "yes" || echo "no") $name
            )
            ;;
            ipv4ll)
            shell_config_set "$options" "BOOTPROTO" "dhcp-ipv4ll"
            ;;
            *)
            ;;
        esac
    fi
}

_()
{
    LANG=${in_language%%;*}.utf8 gettext "alterator-net-eth" "$1"
}

write_conf_type()
{
    local conf_type="$1" && shift
    local iface_dir=
    local iface_options=
    local bootproto=
    if [ "$conf_type" = "auto" ]; then
        # Zeroconf-avahi configuration
        # Actions:
        # 1. Write to /etc/net/ifaces/$iface/options BOOTPROTO=ipv4ll  DISABLED=no
        iflist|
        while read iface mac; do
            iface_dir="/etc/net/ifaces/$iface"
            iface_options="$iface_dir/options"
            [ -d "$iface_dir" ] || mkdir -p "$iface_dir"
            shell_config_set "$iface_options" "BOOTPROTO" "dhcp-ipv4ll"
            shell_config_set "$iface_options" "DISABLED" "no"
        done
    elif [ "$conf_type" = "manual" ]; then
        # Manual configuraion
        iflist|
        while read iface mac; do
            iface_dir="/etc/net/ifaces/$iface"
            iface_options="$iface_dir/options"
            [ -d "$iface_dir" ] || 
            (
            mkdir -p "$iface_dir"
            shell_config_set "$iface_options" "DISABLED" "yes"
            )
        done
    else
        # Unknown command, nothing to do
        : # Nop
    fi
}

write_hosts()
{
    local host_name="$1" && shift
    grep -qs "^[^#]*\<$host_name\>" "$etc_hosts" && return 0
    #bind hostname
    printf '127.0.0.1\t%s %s\n' "$host_name" "${host_name%%.*}" >> "$etc_hosts"
}

write_conf_hostname()
{
    local value="$1" && shift
    local domvalue="${value#*.}"
    shell_config_set "$netconfig" HOSTNAME "$value"
    shell_config_set "$netconfig" DOMAINNAME "$domvalue"
    printf %s\\n "$value" >"$hostnameconfig"
    hostname "$value"
    domainname "$domvalue"
    write_hosts "$value"  
}

. /usr/share/alterator/build/backend3.sh

#initial actions
ifup lo
dhcp_foreach "condifup"
iftabupdate

on_message()
{
    case "$in_action" in
        constraints)
        echo '('
        printf 'ip (ipv4-address #t label "%s")' \
        "`_ "IP address"`"
        printf 'default (ipv4-address #t label "%s")' \
        "`_ "Default gateway"`"
        printf 'hostname (hostname #t label "%s")' \
        "`_ "Hostname"`"
        printf 'dhcp-gw (default #t label "%s")' \
        "`_ "Use gateway recived via DHCP"`"
        printf 'dhcp-ntp (default #t label "%s")' \
        "`_ "Use NTP configuration recived via DHCP"`"
        printf 'dhcp-dns (default #t label "%s")' \
        "`_ "Use DNS servers recived via DHCP"`"
        printf 'dhcp-hostname (default #f label "%s")' \
        "`_ "Use hostname recived via DHCP"`"
        printf 'dns1 (ipv4-address #t label "%s")' \
        "`_ "Primary nameserver"`"
        printf 'dwn2 (ipv4-address #t label "%s")' \
        "`_ "First nameserver"`"
        printf 'dns3 (ipv4-address #t label "%s")' \
        "`_ "Ternary nameserver"`"
        echo ')'
        ;;
        list)
        echo '('
        if [ "$in__objects" == "/" ];then
            list_iface
        else
            list_mask
        fi
        echo ')'
        ;;
        read) 
        if [ "$in__objects" == "/" ];then
            general_status
        else
            read_iface "${in__objects}"
        fi
        ;;
        write)
        case "${in__objects##*/}" in
            conf_type)
            write_conf_type "$in_conf_type"
            ;;
            conf_hostname) 
            write_conf_hostname "${in_hostname}"
            ;;
            conf_resolv)
            write_dns "$in_dns1" "$in_dns2" "$in_dns3"
            write_search "$in_search"
            ;;
            conf_iface)
            write_iface "$in_iface"
            ;;
            restart_all)
            restart_all_ifaces
            /sbin/update_chrooted conf >&2 || :
            ;;
            restart)
            restart_iface "$in_iface"
            /sbin/update_chrooted conf >&2 || :
            ;;
        esac
        echo '()'
        ;;
        *)
        echo '#f'
        ;;
    esac
}

message_loop
