#!/bin/sh
# Usage: join [interface] ap [ "" | "pass" ] [ wpa2ccmp | wpa2tkip | wpaccmp | wpatkip | wep | none ]
# Supports arguments from both local shell and WLCommandRunner
WLANINTF=wlan0
[ $1 ] && echo $1 | grep -q "^wlan[0-9]$" && WLANINTF=$1 && shift
SSID="netflix"
[ "$1" ] && SSID=$1
# Handle missing pass or escaped "" for open APs
[ "$2" ] && [ "$2" != '""' ] && HAS_PSK=1 && PSK=$2
# Mode is passed by main app:
MODE=$3
[ "$MODE" = "open" ] && unset HAS_PSK
[ "$4" = "-c" ] && FREQ=$5
[ "$6" = "-b" ] && BSSID=$7

if [ `ps -p $PPID -o comm=` == sh ]; then
    INTERACTIVE=1
fi

NETWORK=0

echo "=== WIFI: Join $SSID $MODE $FREQ ==="

alias wcmd="wpa_cli -i$WLANINTF -p/tmp/wpa_ctrl"
alias stat="wpa_cli -i$WLANINTF -p/tmp/wpa_ctrl status | grep wpa_state"

if ! wcmd ping | grep -q PONG; then
    echo "!!! WPA Supplicant did not respond !!!"
    echo "!!! Restart Wifi or reboot system !!!"
    touch /tmp/wifi-supp-down
    return 1
fi
rm -f /tmp/wifi-supp-down

wcmd status | grep "bssid" && wcmd disconnect >/dev/null && usleep 300000

# Can't use flush command here as it also removes P2P GO
for i in $(wpa_cli -p /tmp/wpa_ctrl -i $WLANINTF list_networks | tail -n +2 |cut -c1-2); do 
	wcmd remove_network $i > /dev/null
done

NETWORK=$(wcmd add_network)

alias wset="wpa_cli -i$WLANINTF -p/tmp/wpa_ctrl set_network $NETWORK"

wset scan_ssid 1 > /dev/null
echo "--- Setting SSID: $SSID"
unset FAIL
if [ ! $INTERACTIVE ]; then
    # Roku hex encoded SSID:
    ! wset ssid $SSID | grep -q OK && FAIL=1
else
    ! wset ssid "\"$SSID\"" | grep -q OK && FAIL=1
fi
if [ $FAIL ]; then
    echo "!!! SSID failed ($SSID)"
    wcmd remove_network $NETWORK >/dev/null
    return 1
fi
if [ "$MODE" = "wep" ]; then
    echo "--- Setting WEP"
    wset key_mgmt NONE >/dev/null
    WEP_KEY=$PSK  # clarify context
    LEN=${#WEP_KEY}

    if [ ! $INTERACTIVE ]; then
        LEN=$((LEN - 2))  # subtract quote lengths

        if [ $LEN -eq 10 -o $LEN -eq 26 ]; then
            # remove open-close quotes
            WEP_KEY=`echo $WEP_KEY | cut -c 2- | rev | cut -c 2- | rev`
        fi
    fi

    if [ $LEN -eq 5 -o $LEN -eq 13 ]; then
        echo "Setting WEP ascii key"
    elif [ $LEN -eq 10 -o $LEN -eq 26 ]; then
        echo "Setting WEP hex key"
    else
        echo "!!! Invalid WEP key"
        wcmd remove_network $NETWORK >/dev/null
        return 1
    fi

    if ! wset wep_key0 $WEP_KEY | grep -q OK ; then
        echo "!!! WEP KEY failed"
        wcmd remove_network $NETWORK >/dev/null
        return 1
    fi
    wset wep_key1 >/dev/null
    wset wep_key2 >/dev/null
    wset wep_key3 >/dev/null
    unset HAS_PSK
fi
if [ $HAS_PSK ]; then
    echo "--- Setting PSK"
    unset FAIL
    if [ ! $INTERACTIVE ]; then
        LEN=${#PSK}
        LEN=$((LEN - 2))  # subtract quote lengths

        if [ $LEN -ge 8 -a $LEN -le 63 ]; then
            echo "Setting WPA passphrase"
        elif [ $LEN -eq 64 ]; then
            echo "Setting WPA hex PSK directly"
            # remove open-close quotes
            PSK=`echo $PSK | cut -c 2- | rev | cut -c 2- | rev`
        else
            echo "!!! Invalid WPA PSK"
            wcmd remove_network $NETWORK >/dev/null
            return 1
        fi
        ! wset psk "$PSK" | grep -q OK && FAIL=1
    else
        # Typical user-input case: assume passphrase
        ! wset psk \"$PSK\" | grep -q OK && FAIL=1
    fi

    if [ $FAIL ]; then
        echo "!!! PSK failed"
        wcmd remove_network $NETWORK >/dev/null
        return 1
    fi
    # Default is WPA2 CCMP+AES
    wset key_mgmt WPA-PSK >/dev/null
    case $MODE in
    wpa2ccmp)
        PROTO=WPA2
        ENC=CCMP
        ;;
    wpa2tkip)
        PROTO=WPA2
        ENC=TKIP
        ;;
    wpaccmp)
        PROTO=WPA
        ENC=CCMP
        ;;
    wpatkip)
        PROTO=WPA
        ENC=TKIP
        ;;
    *)
        PROTO=WPA2
        ENC=CCMP
    esac
    wset proto $PROTO >/dev/null
    wset pairwise $ENC >/dev/null
else
    wset key_mgmt NONE >/dev/null
fi
[ $FREQ ] && wset freq_list $FREQ > /dev/null
[ $FREQ ] && wset scan_freq $FREQ > /dev/null
[ $BSSID ] && wset bssid $BSSID > /dev/null
wcmd select_network $NETWORK >/dev/null
TIMEOUT=120
unset FAIL
rm -f /tmp/wlan-join-fail-disassoc
while ! stat | grep -q COMPLETED; do
    [ "$TIMEOUT" -le "0" ] && FAIL=timeout && break
    if stat | grep -q DISCONNECTED; then
        FAIL=disassoc
        touch /tmp/wlan-join-fail-disassoc
        break
    fi
    usleep 100000
    let TIMEOUT=TIMEOUT-1
done
if [ $FAIL ]; then
    echo "!!! JOIN failed: $FAIL"
    wcmd remove_network $NETWORK >/dev/null
    wcmd disconnect >/dev/null
    return 1
fi
# Disable roaming (Roku std)
wcmd sta_autoconnect 0 >/dev/null
echo "--- Joined $SSID $PROTO $ENC"
# If called by main app, don't DHCP here
[ ! $INTERACTIVE ] && return 0
echo "---------------------------------"
udhcpc -i $WLANINTF -qn -s /etc/udhcpc.sh
echo "---------------------------------"
return 0

