#!/bin/bash
# 
#  Copyright: ©2009–2013, Güralp Systems Ltd.
#  Author: Laurence Withers <lwithers@guralp.com>
#  License: GPLv3
#

gcs_subitem="$3"
netdev="${gcs_subitem/_*}"
id_str="${gcs_subitem/*_}"

# Handle navbar without loading anything else
if [ "X$1" == "X--navbar" ]
then
    echo "networktop Networking"
    echo "wlan/$netdev $netdev"
    if [ "${id_str}" = "-create" ]
    then
        echo "wlan_net/$gcs_subitem New network"
    else
        echo "wlan_net/$gcs_subitem $id_str"
    fi
    exit 0
fi

# Load support functions
script_dir=$(dirname $0)
. $script_dir/functions.sh

wpa_file="${NETCONFDIR}/${netdev}/wpa_supplicant.conf"



gcs_var_o_or_d() {
    local name="$1"
    local file="$2"
    local def="$3"
    local val

    val="$(gcs_get_varf "${name}" "${file}")"
    if [ -n "${val}" ]
    then
        gcs_var "o_${name}" "${val}"
        eval ${name}=\"${val}\"
    else
        gcs_var "d_${name}" "${def}"
        eval ${name}=\"${val}\"
    fi
}


do_scan() {
    TFILE1="`mktemp`"
    TFILE2="`mktemp`"

    ( iwlist "${netdev}" scan \
        | grep ESSID \
        | sed -e 's/^.*ESSID:"\(.*\)".*$/$I$\1$L$/' \
    ) > "${TFILE1}" \
    2> "${TFILE2}"

    if [ -s "${TFILE1}" ]
    then
        gcs_var "scan_results" "`tr '\n' ' ' < "${TFILE1}"`"
    else
        gcs_var "scan_results" "\$I\$\$B\$No access points found\$R\$"
    fi

    if [ -s "${TFILE2}" ]
    then
        gcs_err "scan_error" "`tr '\n' ' ' < "${TFILE2}"`"
    fi

    rm -f "${TFILE1}" "${TFILE2}"
}


do_read() {
    local -i i
    local alias_ip r_destn scan_var

    # sort out the title/naming of this network
    gcs_var "device" "${netdev}"
    if [ "${id_str}" = "-create" ]
    then
        gcs_var "create_mode"   "True"
        CFGFILE="/dev/null"
        gcs_var "d_key_mgmt"    "NONE"
        gcs_var "d_priority"    "0"
    else
        gcs_var "create_mode"   "False"
        gcs_var "id_str"        "${id_str}"
        CFGFILE="${NETCONFDIR}/${netdev}/ip.${id_str}"
        if [ ! -r "${CFGFILE}" ]
        then
            gcs_err fatal "No configuration file for network ${id_str}"
            return 0
        fi
        wpa_supplicant_gcs --read "${id_str}" --config "${wpa_file}"
    fi

    # wireless scan results
    do_scan

    # IP settings
    gcs_var_o_or_d mtu                  "${CFGFILE}" ""
    gcs_var_o_or_d bootproto            "${CFGFILE}" "dhcp"
    gcs_var_o_or_d default_address_ip   "${CFGFILE}" ""
    gcs_var_o_or_d default_address_broadcast "${CFGFILE}" ""
    gcs_var_o_or_d default_route_via    "${CFGFILE}" ""

    # fill IP alias table
    i=0
    while true
    do
        alias_ip="$(gcs_get_varf "alias_address_ip${i}" "${CFGFILE}")"
        [ -z "${alias_ip}" ] && break

        gcs_var "o_alias_address_ip${i}" "${alias_ip}"
        gcs_var "o_alias_address_broadcast${i}" "$(gcs_get_varf "alias_address_broadcast${i}" "${CFGFILE}")"

        (( i++ ))
    done

    # fill route table
    i=0
    while true
    do
        r_destn="$(gcs_get_varf "route_destn${i}" "${CFGFILE}")"
        [ -z "${r_destn}" ] && break

        gcs_var "o_route_destn${i}" "${r_destn}"
        gcs_var "o_route_type${i}" "$(gcs_get_varf "route_type${i}" "${CFGFILE}")"
        gcs_var "o_route_via${i}" "$(gcs_get_varf "route_via${i}" "${CFGFILE}")"
        gcs_var "o_route_args${i}" "$(gcs_get_varf "route_args${i}" "${CFGFILE}")"

        (( i++ ))
    done
}



check_route() {
    local r_type="$1"
    local r_via="$2"
    local err_var="fatal" # TODO: more specific?

    case "${r_type}" in
    unicast)
        [ -z "${r_via}" ] && gcs_err "${err_var}" "A unicast route requires a 'via' (gateway) address"
        ;;
    unreachable | blackhole | prohibit | local | broadcast)
        [ -n "${r_via}" ] && gcs_err "${err_var}" "A route of type '${r_type}' cannot have a 'via' (gateway) address"
        ;;
    esac
}

do_check() {
    local -i i

    gcs_read_vars

    # Shortcut checking if we are about to delete the network, but check the
    # config file exists in case the users try to get creative with names.
    if gcs_truefalse "${new_delete:-false}"
    then
        CFGFILE="${NETCONFDIR}/${netdev}/ip.${new_id_str}"
        [ -r "${CFGFILE}" ] || gcs_err delete "Network not found; already deleted?"
        return 0
    fi

    if [ "${new_key_mgmt}" == "WPA-PSK" ]
    then
        [ -z "${new_psk}" ] && gcs_err "psk" "WPA-PSK requires a key to be entered"
    fi

    [ -z "${new_ssid}" ] && gcs_err "ssid" "SSID is required"

    # TODO: we should probably check that each router is on a local subnet

    # for each route, we check its type and its via
    [ -n "${new_default_route_via}" ] && check_route "unicast" "${new_default_route_via}"
    
    for (( i = 0 ; i < $new_route_rows ; i++ ))
    do
        r_destn="new_route_destn${i}"
        [ -z "${!r_destn}" ] && continue

        r_type="new_route_type${i}"
        r_via="new_route_via${i}"
        check_route "${!r_type}" "${!r_via}"
    done
}



do_write() {
    declare -i i j

    do_check
    if (( gcs_errors > 0 ))
    then
        return
    fi

    CFGFILE="${NETCONFDIR}/${netdev}/ip.${new_id_str}"

    # Delete option
    if gcs_truefalse "${new_delete:-false}"
    then
        wpa_supplicant_gcs --delete "${new_id_str}" --config "${wpa_file}"
        chgrp netconf "${wpa_file}" > /dev/null 2>&1
        chmod 664 "${wpa_file}" > /dev/null 2>&1
        rm -f "${CFGFILE}"

        # Tell wpa_supplicant to pick up the changes
        wpa_cli reconfigure > /dev/null 2>&1
        return 0
    fi

    # wireless settings
    wpa_supplicant_gcs --write "${new_id_str}" --config "${wpa_file}" < "${VARFILE}"
    chgrp netconf "${wpa_file}" > /dev/null 2>&1
    chmod 664 "${wpa_file}" > /dev/null 2>&1

    # Make a copy of the existing config minus the ipalias and routing tables
    TMPFILE="$(mktemp "${NETCONFDIR}/${netdev}/.gcs_netif.XXXXXX" 2>/dev/null)"
    if [ -z "${TMPFILE}" ]
    then
        gcs_err fatal "Cannot create new configuration file."
        return
    fi

    if [ -r "${CFGFILE}" ]
    then
        sed -e '/^alias_/d' -e '/^route_/d' < "${CFGFILE}" > "${TMPFILE}"
    fi

    # IP settings
    gcs_set_varf "NETCONFIG_VERSION"            "${TMPFILE}" "1"
    gcs_set_varf "mtu"                          "${TMPFILE}" "${new_mtu}"
    gcs_set_varf "bootproto"                    "${TMPFILE}" "${new_bootproto}"
    gcs_set_varf "dhcpcd_args"                  "${TMPFILE}" ""
    gcs_set_varf "default_address_ip"           "${TMPFILE}" "${new_default_address_ip}"
    gcs_set_varf "default_address_broadcast"    "${TMPFILE}" "${new_default_address_broadcast}"
    gcs_set_varf "default_address_args"         "${TMPFILE}" ""
    gcs_set_varf "default_route_via"            "${TMPFILE}" "${new_default_route_via}"
    gcs_set_varf "default_route_args"           "${TMPFILE}" ""

    gcs_set_varf "vlanhost"                     "${TMPFILE}" "${new_vlanhost}"
    gcs_set_varf "vlantag"                      "${TMPFILE}" "${new_vlantag}"

    j=0
    for (( i = 0 ; i < $new_alias_address_rows ; i++ ))
    do
        alias_ip="new_alias_address_ip${i}"
        [ -z "${!alias_ip}" ] && continue

        alias_bcast="new_alias_address_broadcast${i}"
        alias_args="new_alias_address_args${i}"
        gcs_set_varf "alias_address_ip${j}"     "${TMPFILE}" "${!alias_ip}"
        gcs_set_varf "alias_address_bcast${j}"  "${TMPFILE}" "${!alias_bcast}"
        gcs_set_varf "alias_address_args${j}"   "${TMPFILE}" "${!alias_args}"

        (( j++ ))
    done

    j=0
    for (( i = 0 ; i < $new_route_rows ; i++ ))
    do
        r_destn="new_route_destn${i}"
        [ -z "${!r_destn}" ] && continue

        r_type="new_route_type${i}"
        r_via="new_route_via${i}"
        r_args="new_route_args${i}"
        gcs_set_varf "route_destn${j}"          "${TMPFILE}" "${!r_destn}"
        gcs_set_varf "route_type${j}"           "${TMPFILE}" "${!r_type}"
        gcs_set_varf "route_via${j}"            "${TMPFILE}" "${!r_via}"
        gcs_set_varf "route_args${j}"           "${TMPFILE}" "${!r_args}"

        (( j++ ))
    done

    # Copy the new configuration back
    if diff "${TMPFILE}" "${CFGFILE}" > /dev/null 2>&1
    then
        # New file is the same as the original so just delete the temp
        rm -f "${TMPFILE}"
    else
        chgrp "netconf" "${TMPFILE}"
        chmod 0664 "${TMPFILE}"
        mv "${TMPFILE}" "${CFGFILE}"
    fi

    # Tell wpa_supplicant to pick up the changes
    wpa_cli reconfigure > /dev/null 2>&1
}



case "X$1" in
X--check)       do_check        ;;
X--write)       do_write        ;;
X--read)        do_read         ;;
*)              exit 1          ;;
esac

gcs_cleanup
exit 0

# vim: ts=4:sw=4:expandtab
