#!/bin/bash -e

AP=false
DISABLE=false
SSID=
PASS=
CHANNEL=7
REBOOT=false

WLAN0_CFG=/etc/network/interfaces.d/wlan0
HOSTAPD_CFG=/etc/hostapd/hostapd.conf
DNSMASQ_CFG=/etc/dnsmasq.conf
DHCPCD_CFG=/etc/dhcpcd.conf
WPA_CFG=/etc/wpa_supplicant/wpa_supplicant.conf


function query_config() {
    if [ -e $WLAN0_CFG ]; then
        SSID=$(grep wpa-ssid $WLAN0_CFG |
                   sed 's/^[[:space:]]*wpa-ssid "\([^"]*\)"/\1/')
        echo "{\"ssid\": \"$SSID\", \"mode\": \"client\"}"

    else
        if [ -e $HOSTAPD_CFG -a -e /etc/default/hostapd ]; then
            SSID=$(grep ^ssid= $HOSTAPD_CFG | sed 's/^ssid=\(.*\)$/\1/')
            CHANNEL=$(grep ^channel= $HOSTAPD_CFG |
                          sed 's/^channel=\(.*\)$/\1/')

            echo -n "{\"ssid\": \"$SSID\", "
            echo "\"channel\": $CHANNEL, \"mode\": \"ap\"}"

        else
            echo "{\"mode\": \"disabled\"}"
        fi
    fi

}


function disable_wifi() {
    rm -f $WLAN0_CFG $HOSTAPD_CFG /etc/default/hostapd
}


function configure_wlan0() {
    echo "auto wlan0"
    echo "allow-hotplug wlan0"
    echo "iface wlan0 inet dhcp"
    echo "  wpa-scan-ssid 1"
    echo "  wpa-ap-scan 1"
    echo "  wpa-key-mgmt WPA-PSK"
    echo "  wpa-proto RSN WPA"
    echo "  wpa-pairwise CCMP TKIP"
    echo "  wpa-group CCMP TKIP"
    echo "  wpa-ssid \"$SSID\""

    if [ ${#PASS} -ne 0 ]; then
      echo "  wpa-psk \"$PASS\""
    fi
}


function configure_wpa() {
    echo "country=US"
    echo "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev"
    echo "update_config=1"

    if [ ${#PASS} -eq 0 ]; then
        echo "network={"
        echo "  ssid=\"$SSID\""
        echo "  key_mgmt=NONE"
        echo "}"
    fi
}


function configure_dhcpcd() {
    echo "hostname"
    echo "clientid"
    echo "persistent"
    echo "option rapid_commit"
    echo "option domain_name_servers, domain_name, domain_search, host_name"
    echo "option classless_static_routes"
    echo "option ntp_servers"
    echo "option interface_mtu"
    echo "require dhcp_server_identifier"
    echo "slaac private"

    if $AP; then
        echo
        echo "interface wlan0"
        echo "  static ip_address=192.168.43.1/24"
    fi
}


function configure_wifi() {
    disable_wifi
    echo "source-directory /etc/network/interfaces.d" > /etc/network/interfaces
    configure_wlan0  > $WLAN0_CFG
    configure_wpa    > $WPA_CFG
    configure_dhcpcd > $DHCPCD_CFG
}


function configure_dnsmasq() {
    echo "interface=wlan0"
    echo "domain-needed"
    echo "bogus-priv"
    echo "dhcp-range=192.168.43.2,192.168.43.20,255.255.255.0,12h"
}


function configure_hostapd() {
    echo "interface=wlan0"
    echo "driver=nl80211"
    echo "ssid=$SSID"
    echo "hw_mode=g"
    echo "channel=$CHANNEL"
    echo "wmm_enabled=0"
    echo "macaddr_acl=0"
    echo "auth_algs=1"
    echo "ignore_broadcast_ssid=0"
    echo "wpa=2"
    echo "wpa_passphrase=$PASS"
    echo "wpa_key_mgmt=WPA-PSK"
    echo "wpa_pairwise=TKIP"
    echo "rsn_pairwise=CCMP"
}


function is_installed() {
    dpkg-query -W --showformat='${Status}' $1 |
        grep "install ok installed" >/dev/null
    if [ $? -eq 0 ]; then echo true; else echo false; fi
}


function configure_ap() {
    disable_wifi

    # Install packages
    (
        $(is_installed dnsmasq) &&
        $(is_installed hostapd) &&
        $(is_installed iptables-persistent)

    ) || (
        export DEBIAN_FRONTEND=noninteractive
        apt-get update
        apt-get install -yq dnsmasq hostapd iptables-persistent
    )

    configure_dhcpcd  > $DHCPCD_CFG
    configure_dnsmasq > $DNSMASQ_CFG
    configure_hostapd > $HOSTAPD_CFG

    echo "DAEMON_CONF=\"/etc/hostapd/hostapd.conf\"" > /etc/default/hostapd

    # Enable IP forwarding
    sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
    echo 1 > /proc/sys/net/ipv4/ip_forward

    # Enable IP masquerading
    iptables -t nat -F
    iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    iptables-save > /etc/iptables/rules.v4
}


function usage() {
    echo "Usage: config-wifi [OPTIONS]"
    echo
    echo "Configure wifi as either a client or access point."
    echo
    echo "OPTIONS:"
    echo
    echo "  -a             Configure access point."
    echo "  -d             Disable wifi."
    echo "  -r             Reboot when done."
    echo "  -s <SSID>      Set SSID."
    echo "  -p <PASS>      Set password."
    echo "  -c <CHANNEL>   Set wifi channel."
    echo "  -j             Report wifi config as JSON data."
    echo
}


# Parse args
while [ $# -ne 0 ]; do
    case "$1" in
        -a) AP=true ;;
        -d) DISABLE=true ;;
        -r) REBOOT=true; ;;
        -s) SSID="$2"; shift ;;
        -p) PASS="$2"; shift ;;
        -c) CHANNEL="$2"; shift ;;
        -j) query_config; exit 0 ;;

        -h)
            usage
            exit 0
            ;;

        *)
            usage
            echo "Unknown argument '$1'"
            exit 1
    esac

    shift
done


if $DISABLE; then
    disable_wifi

else
    # Check args
    function clean_str() {
        echo "$1" | tr -d '\n\r"'
    }

    SSID=$(clean_str "$SSID")
    PASS=$(clean_str "$PASS")

    LANG=C LC_ALL=C # For correct string byte length

    if [ ${#SSID} -eq 0 -o 32 -lt ${#SSID} ]; then
        echo "Invalid or missing SSID '$SSID'"
        exit 1
    fi

    if [ ${#PASS} -ne 0 ]; then
      if [ ${#PASS} -lt 8 -o 128 -lt ${#PASS} ]; then
        echo "Invalid passsword"
        exit 1
      fi
    fi

    echo "$CHANNEL" | grep '^[0-9]\{1,2\}' > /dev/null
    if [ $? -ne 0 ]; then
        echo "Invalid channel '$CHANNEL'"
        exit 1
    fi

    # Execute
    if $AP; then
        echo "Configuring Wifi access point"
        configure_ap

    else
        echo "Configuring Wifi"
        configure_wifi
    fi
fi


if $REBOOT; then nohup reboot & fi
