#!/bin/bash

set -e

# Configure networking for all wired and wireless devices.
#
# Creates network-manager connections.

function get-interfaces {
    WIRED_IFACES=$(nmcli --terse --fields type,device device | grep "^ethernet:" | cut -d: -f2 | sort -V)
    NO_OF_WIRED_IFACES=$(echo $WIRED_IFACES | wc -w)

    WIRELESS_IFACES=$(nmcli --terse --fields type,device device | grep "^wifi:" | cut -d: -f2 | sort -V)
    NO_OF_WIRELESS_IFACES=$(echo $WIRELESS_IFACES | wc -w)
}

function add-connection {
    local connection_name="$1"
    shift
    local interface="$1"
    shift
    local remaining_arguments="$@"

    already_exists=$(nmcli --terse --fields name,device con show | grep "$connection_name:$interface" || true)
    if [ -n "$already_exists" ]; then
        echo "Connection '$connection_name' already exists for device '$interface', not adding."
    else
        nmcli con add con-name "$connection_name" ifname "$interface" $remaining_arguments
    fi
}

function activate-connection {
    connection_name="$1"
    nohup nmcli con up "$connection_name" &>/dev/null &
}

function configure-regular-interface {
    local interface="$1"
    local zone="$2"
    local connection_name="FreedomBox WAN"

    # Create n-m connection for a regular interface
    add-connection "$connection_name" "$interface" type ethernet
    nmcli con modify "$connection_name" connection.autoconnect TRUE
    nmcli con modify "$connection_name" connection.zone "$zone"
    activate-connection "$connection_name"

    echo "Configured interface '$interface' for '$zone' use as '$connection_name'."
}

function configure-shared-interface {
    local interface="$1"
    local connection_name="FreedomBox LAN $interface"

    # Create n-m connection for eth1
    add-connection "$connection_name" "$interface" type ethernet
    nmcli con modify "$connection_name" connection.autoconnect TRUE
    nmcli con modify "$connection_name" connection.zone internal

    # Configure this interface to be shared with other computers.
    #  - Self-assign an address and network
    #  - Start and manage DNS server (dnsmasq)
    #  - Start and manage DHCP server (dnsmasq)
    #  - Register address with mDNS
    #  - Add firewall rules for NATing from this interface
    nmcli con modify "$connection_name" ipv4.method shared

    activate-connection "$connection_name"

    echo "Configured interface '$interface' for shared use as '$connection_name'."
}

function configure-wireless-interface {
    local interface="$1"
    local connection_name="FreedomBox $interface"
    local ssid="FreedomBox$interface"
    local secret="freedombox123"

    add-connection "$connection_name" "$interface" type wifi ssid "$ssid"
    nmcli con modify "$connection_name" connection.autoconnect TRUE
    nmcli con modify "$connection_name" connection.zone internal
    nmcli con modify "$connection_name" ipv4.method shared
    nmcli con modify "$connection_name" wifi.mode ap
    nmcli con modify "$connection_name" wifi-sec.key-mgmt wpa-psk
    nmcli con modify "$connection_name" wifi-sec.psk "$secret"
    activate-connection "$connection_name"

    echo "Configured interface '$interface' for shared use as '$connection_name'."
}

function multi-wired-setup {
    local first_interface="$1"
    shift
    local remaining_interfaces="$@"

    configure-regular-interface "$first_interface" external

    for interface in $remaining_interfaces
    do
        configure-shared-interface "$interface"
    done
}

function one-wired-setup {
    local interface="$1"

    case $NO_OF_WIRELESS_IFACES in
        "0")
            configure-regular-interface "$interface" internal
            ;;
        *)
            configure-regular-interface "$interface" external
            ;;
    esac
}

function wireless-setup {
    local interfaces="$@"

    for interface in $interfaces
    do
        configure-wireless-interface "$interface"
    done
}

function setup {
    echo "Setting up network configuration..."
    get-interfaces

    case $NO_OF_WIRED_IFACES in
        "0")
            echo "No wired interfaces detected."
            ;;
        "1")
            one-wired-setup $WIRED_IFACES
            ;;
        *)
            multi-wired-setup $WIRED_IFACES
    esac

    wireless-setup $WIRELESS_IFACES

    echo "Done setting up network configuration."
}

#
# For a user who installed using freedombox-setup Debian package, when
# FreedomBox Service (Plinth) is run for the first time, don't run network
# setup. This is ensured by checking for the file
# /var/lib/freedombox/is-freedombox-disk-image which will not exist.
#
# For a user who installed using FreedomBox disk image, when FreedomBox Service
# (Plinth) runs for the first time, setup process executes and triggers the
# script due networks module being an essential module.
#
if [ -f "/var/lib/freedombox/is-freedombox-disk-image" ]
then
    setup
else
    echo "Not a FreedomBox disk image. Skipping network configuration."
fi
