#!/bin/bash

DH_CONF="/var/cache/dhclient.conf"
NETWATCH_CONF="/etc/netwatch.conf"

SYS_STATIC_CONF="/etc/static_ip.conf"
BOOT_STATIC_CONF="/boot/static_ip.conf"
STATIC_CONF="/data/etc/static_ip.conf"

SYS_INTERFACES_CONF="/etc/network/interfaces"
BOOT_INTERFACES_CONF="/boot/network/interfaces"
INTERFACES_CONF="/data/etc/network/interfaces"

CP_CONF="/etc/captive-portal.conf"
CONNMAN_CONF="/etc/connman/main.conf"

LINK_NEGO_TIMEOUT=10


test -s ${CONNMAN_CONF} && exit 0

test -n "${OS_VERSION}" || source /etc/init.d/base

source ${NETWATCH_CONF}
source ${CP_CONF}

prepare_conf ${STATIC_CONF} ${SYS_STATIC_CONF} ${BOOT_STATIC_CONF}
test -r ${STATIC_CONF} && source ${STATIC_CONF}

prepare_conf ${INTERFACES_CONF} ${SYS_INTERFACES_CONF} ${BOOT_INTERFACES_CONF}

mkdir -p /var/lib/dhcp


function watch_eth() {
    count=0
    while true; do
        sleep 5
        if [[ "$(cat /sys/class/net/${OS_ETH}/carrier 2>/dev/null)" == 1 ]]; then
            count=0
        else
            if [[ ${count} -lt ${LINK_WATCH_TIMEOUT} ]]; then
                count=$((${count} + 5))
                logger -t network "ethernet disconnected"
            else
                panic action network "ethernet disconnected for ${LINK_WATCH_TIMEOUT} seconds"
            fi
        fi
    done
}

function watch_ip() {
    iface=$1
    count=0
    while true; do
        sleep 5
        if ip addr show dev ${iface} | grep inet &>/dev/null; then
            count=0
        else
            if [[ ${count} -lt ${IP_WATCH_TIMEOUT} ]]; then
                count=$((${count} + 5))
                logger -t network "${iface} has no IP address"
            else
                panic action network "${iface} had no IP address for ${IP_WATCH_TIMEOUT} seconds"
            fi
        fi
    done
}

function start_lo() {
    if [[ -r ${INTERFACES_CONF} ]] && grep -q "^iface lo" ${INTERFACES_CONF}; then
        ifup -i ${INTERFACES_CONF} lo 2>&1 | logger -t network
    else
        ifconfig lo up
    fi
}

function start_wlan() {
    # $1 - index
    index=$1
    test "${index}" == 0 && index=
    iface_var=OS_WLAN${index}
    iface_upper=$(tr a-z A-Z <<< ${!iface_var})
    static_ip_var=STATIC_IP_${iface_upper}

    msg_begin "Configuring wireless network on ${!iface_var}"
    if ! ifconfig ${!iface_var} &>/dev/null; then
        msg_fail "no device"
        return 1
    fi

    if [[ "$(cat /sys/class/net/${!iface_var}/carrier 2>/dev/null)" != 1 ]]; then
        msg_fail "no link"
        return 1
    fi

    if [[ -r ${INTERFACES_CONF} ]] && grep -q "^iface ${!iface_var}" ${INTERFACES_CONF}; then
        ifup -i ${INTERFACES_CONF} ${!iface_var} 2>&1 | logger -t network
        test ${PIPESTATUS[0]} == 0 && msg_done || msg_fail
    else
        if [[ -n "${STATIC_IP}" ]]; then
            msg_done ${STATIC_IP}
            ifconfig ${!iface_var} ${STATIC_IP} up
            STATIC_IP="" # won't be used again
        elif [[ -n "${!static_ip_var}" ]]; then
            msg_done ${!static_ip_var}
            ifconfig ${!iface_var} ${!static_ip_var} up
        else
            msg_done dhcp
            cp ${DH_CONF} ${DH_CONF}.${!iface_var}
            dhclient -cf ${DH_CONF}.${!iface_var} ${!iface_var}
        fi
    fi

    if [[ "${IP_WATCH}" == "true" ]] && ip addr show dev ${!iface_var} | grep inet &>/dev/null; then
        watch_ip ${!iface_var} &
    fi
}

function start_eth() {
    msg_begin "Configuring wired network"
    
    iface_upper=$(tr a-z A-Z <<< ${OS_ETH})
    static_ip_var=STATIC_IP_${iface_upper}

    # wait for driver
    w=3
    count=0
    while ! ifconfig ${OS_ETH} >/dev/null 2>&1; do
        sleep 1
        count=$((${count} + 1))
        if [[ ${count} -ge ${w} ]]; then
            msg_done "no device"
            return 1
        fi
    done

    # bring it up
    ifconfig ${OS_ETH} up

    # wait for link
    test "${LINK_WATCH}" == "true" || LINK_NEGO_TIMEOUT=5
    count=0
    while [[ "$(cat /sys/class/net/${OS_ETH}/carrier 2>&1)" != 1 ]]; do
        sleep 1
        count=$((${count} + 1))
        if [[ ${count} -ge ${LINK_NEGO_TIMEOUT} ]]; then
            msg_done "no link"
            return 1
        fi
    done
    
    if [[ -r ${INTERFACES_CONF} ]] && grep -q "^iface ${OS_ETH}" ${INTERFACES_CONF}; then
        ifup -i ${INTERFACES_CONF} ${OS_ETH} 2>&1 | logger -t network
        test ${PIPESTATUS[0]} == 0 && msg_done || msg_fail
    else
        if [[ -n "${STATIC_IP}" ]]; then
            msg_done ${STATIC_IP}
            ifconfig ${OS_ETH} ${STATIC_IP} up
            STATIC_IP="" # won't be used again
        elif [[ -n "${!static_ip_var}" ]]; then
            msg_done ${!static_ip_var}
            ifconfig ${OS_ETH} ${!static_ip_var} up
        else
            msg_done dhcp
            cp ${DH_CONF} ${DH_CONF}.${OS_ETH}
            dhclient -cf ${DH_CONF}.${OS_ETH} ${OS_ETH}
        fi
    fi

    if [[ "${LINK_WATCH}" == "true" ]]; then
        watch_eth &
    fi

    if [[ "${IP_WATCH}" == "true" ]] && ip addr show dev ${OS_ETH} | grep inet &>/dev/null; then
        watch_ip ${OS_ETH} &
    fi
}

function dhclient_reduce_request() {
    # Disables requesting gateway, DNS, etc, strictly configuring the interface.
    grep -q request ${DH_CONF} || echo "request subnet-mask, broadcast-address, time-offset, interface-mtu;" >> ${DH_CONF}
}

function start() {
    hostname=$(hostname)
    echo "send host-name = \"${hostname}\";" > ${DH_CONF}
    
    # If we've got static settings for gateway and DNS server, ignore corresponding DHCP settings
    test -n "${STATIC_GW}" && test -n "${STATIC_DNS}" && dhclient_reduce_request

    start_lo

    test "${OS_NETWORKLESS}" == "true" && return 0

    ssid=$(cat /data/etc/wpa_supplicant.conf 2>&1 | grep ssid | grep -v scan_ssid | cut -d '"' -f 2)
    ssid1=$(cat /data/etc/wpa_supplicant1.conf 2>&1 | grep ssid | grep -v scan_ssid | cut -d '"' -f 2)
    test -n "${OS_WLAN}" -a -n "${ssid}" && start_wlan 0 && wlan_ok="ok" && dhclient_reduce_request
    test -n "${OS_WLAN1}" -a -n "${ssid1}" && start_wlan 1 && wlan_ok="ok" && dhclient_reduce_request
    test -n "${OS_PPP}" -a -r /data/etc/ppp/modem && ifconfig | grep ${OS_PPP} &>/dev/null && ppp_ok="ok" && dhclient_reduce_request
    def_route_ok=$(ip route get 1.1.1.1 &>/dev/null && echo "ok")
    
    if [[ -n "${OS_ETH}" ]]; then
        # if wifi or ppp link ok, start eth in background
        if [[ "${wlan_ok}" == "ok" ]] || [[ "${ppp_ok}" == "ok" ]] && [[ "${def_route_ok}" == "ok" ]]; then
            start_eth &>/dev/null &
        else
            start_eth && eth_ok="ok" && dhclient_reduce_request
        fi
    fi

    if [[ "${eth_ok}" != "ok" ]] && [[ "${wlan_ok}" != "ok" ]] && [[ "${ppp_ok}" != "ok" ]]; then
        panic=false
        if [[ "${LINK_WATCH}" == true ]]; then
            if [[ ${CAPTIVE_PORTAL_ENABLED} == false ]] || \
               [[ -z "${CAPTIVE_PORTAL_CONFIGURED_CMD}" ]] || \
               ${CAPTIVE_PORTAL_CONFIGURED_CMD} &>/dev/null; then

               panic=true
           fi
        fi
        if [[ ${panic} == true ]]; then
            panic action network "no network connection available"
            return 1
        else
            logger -t network "no network connection available"
            return 0
        fi
    fi

    if [[ -r ${INTERFACES_CONF} ]]; then
        # ifup doesn't set the DNS server, so we have to set it manually
        STATIC_DNS=$(cat ${INTERFACES_CONF} | grep dns-nameserver | tr -s ' ' | cut -d ' ' -f 3 | head -n 11)
        if [[ -n "${STATIC_DNS}" ]]; then
            msg_begin "Setting static DNS server to ${STATIC_DNS}"
            echo "nameserver ${STATIC_DNS}" > /etc/resolv.conf
            test $? == 0 && msg_done || msg_fail
        fi
        
        # Make sure all auto interfaces are brought up
        ifup -i ${INTERFACES_CONF} -a >/dev/null
    else
        if [[ -n "${STATIC_GW}" ]]; then
            msg_begin "Setting static gateway to ${STATIC_GW}"
            ip route add default via ${STATIC_GW} &>/dev/null || ip route change default via ${STATIC_GW} &>/dev/null
            test $? == 0 && msg_done || msg_fail
        fi

        if [[ -n "${STATIC_DNS}" ]]; then
            msg_begin "Setting static DNS server to ${STATIC_DNS}"
            echo "nameserver ${STATIC_DNS}" > /etc/resolv.conf
            test $? == 0 && msg_done || msg_fail
        fi
    fi

    # re-evalutate default route, as it might have changed with start_eth or static IP
    def_route_ok=$(ip route get 1.1.1.1 &>/dev/null && echo "ok")
    if [[ "${def_route_ok}" != "ok" ]]; then
        panic=false
        if [[ "${IP_WATCH}" == true ]]; then
            if [[ ${CAPTIVE_PORTAL_ENABLED} == false ]] || \
               [[ -z "${CAPTIVE_PORTAL_CONFIGURED_CMD}" ]] || \
               ${CAPTIVE_PORTAL_CONFIGURED_CMD} &>/dev/null; then

               panic=true
           fi
        fi
    
        if [[ ${panic} == true ]]; then
            panic action network "no default route"
            return 1
        else
            logger -t network "no default route"
            return 0
        fi
    fi
}

function stop() {
    msg_begin "Stopping network"
    if [[ -r ${INTERFACES_CONF} ]]; then
        ifdown -i ${INTERFACES_CONF} -a 2>&1 | logger -t network
    fi
    ps | grep S40network | grep -v $$ | grep -v grep | tr -s ' ' | sed -e 's/^\s//' | cut -d ' ' -f 1 | xargs -r kill
    killall dhclient &>/dev/null
    msg_done
}

case "$1" in
    start)
        start
        ;;

    stop)
        stop
        ;;

    restart)
        stop
        start
        ;;

    *)
        echo "Usage: $0 {start|stop|restart}"
        exit 1
esac

exit $?
