#!/bin/sh
#-
# Copyright (c) 2011 Nathan Whitehorn
# Copyright (c) 2013-2015 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#
############################################################ INCLUDES

BSDCFG_SHARE="/usr/share/bsdconfig"
. $BSDCFG_SHARE/common.subr || exit 1
f_include $BSDCFG_SHARE/dialog.subr

############################################################ MAIN

echo -n > $BSDINSTALL_TMPETC/wpa_supplicant.conf
chmod 0600 $BSDINSTALL_TMPETC/wpa_supplicant.conf

echo "ctrl_interface=/var/run/wpa_supplicant" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
echo "eapol_version=2" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
echo "ap_scan=1" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
echo "fast_reauth=1" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
echo >> $BSDINSTALL_TMPETC/wpa_supplicant.conf

# Try to reach wpa_supplicant. If it isn't running and we can modify the
# existing system, start it. Otherwise, fail.
(wpa_cli ping >/dev/null 2>/dev/null || ([ ! -z $BSDINSTALL_CONFIGCURRENT ] && \
	wpa_supplicant -B -i $1 -c $BSDINSTALL_TMPETC/wpa_supplicant.conf)) || \
	(dialog --backtitle "FreeBSD Installer" --title "Error" --msgbox \
	"Could not start wpa_supplicant!" 0 0; exit 1) || exit 1

# See if we succeeded
wpa_cli ping >/dev/null 2>/dev/null
if [ $? -ne 0 -a -z $BSDINSTALL_CONFIGCURRENT ]; then
	dialog --backtitle "FreeBSD Installer" --title "Error" --msgbox \
	"Wireless cannot be configured without making changes to the local system!" \ 0 0
	exit 1
fi

country_set()
{
	local error_str=
	local iface_up=
	local ifconfig_args=

	# Setup what was selected
	# NB: do not change order of arguments (or regdomain will be ignored)
	if [ ! -z "$2" ]; then
		ifconfig_args="${ifconfig_args}country $2"
	fi
	if [ ! -z "$1" ]; then
		if [ ! -z "$2" ]; then
			ifconfig_args="${ifconfig_args} "
		fi
		ifconfig_args="${ifconfig_args}regdomain $1"
	fi
	if [ -z "$ifconfig_args" ]; then
		# Nothing to do (everything was skipped)
		return $SUCCESS
	fi

	# Regdomain/country cannot be applied while interface is running
	iface_up=`ifconfig -lu | grep -w $WLAN_IFACE`
	if [ ! -z "$iface_up" ]; then
		ifconfig $WLAN_IFACE down
	fi
	error_str=`ifconfig $WLAN_IFACE $ifconfig_args 2>&1 | \
		sed 's/ifconfig: //'`
	if [ ! -z "$iface_up" ]; then
		# Restart wpa_supplicant(8) (should not fail).
		wpa_supplicant -B -i $WLAN_IFACE -c \
		    $BSDINSTALL_TMPETC/wpa_supplicant.conf
	fi
	if [ ! -z "$error_str" ]; then
		dialog --backtitle "FreeBSD Installer" --title "Error" \
		    --yes-label Change --no-label Ignore --yesno \
		    "Error while applying chosen settings ($error_str)" 0 0
		if [ $? -eq $DIALOG_OK ]; then
			return $FAILURE		# Restart
		else
			return $SUCCESS		# Skip
		fi
	else
		: > $BSDINSTALL_TMPETC/rc.conf.net.wlan
		echo create_args_$WLAN_IFACE=\"$ifconfig_args\" >> \
		    $BSDINSTALL_TMPETC/rc.conf.net.wlan
	fi

	return $SUCCESS
}

dialog_country_select()
{
	local input=
	local def_item_regdomain=
	local def_item_country=
	local regdomains=
	local countries=
	local regdomain=
	local country=

	# Parse available countries/regdomains
	input=`ifconfig $WLAN_IFACE list countries | sed 's/DEBUG//gi'`
	regdomains=`echo $input | sed 's/.*domains://' | tr ' ' '\n' | \
		sort | tr '\n' ' '`
	countries=`echo $input | sed 's/Country codes://' | \
	    sed 's/Regulatory.*//' | awk '{
		for (i = 1; i <= NF; i++) {
			printf "%s", $i
			if (match($i, "[[:lower:]]"))
				if (match($(i+1), "[[:lower:]]"))
					printf "\\\\\\ "
				else
					printf "\n"
			else
				printf " "
		}
	    }' | sort -k 2 | tr '\n' ' '`

	# Change default cursor position (if required).
	if [ "$1" != "<not selected>" ]; then
		def_item_regdomain="--default-item $1"
	fi
	if [ "$2" != "<not selected>" ]; then
		def_item_country="--default-item $2"
	fi

	f_dialog_menu_size height width rows \"Regdomain selection\" \
	    \"FreeBSD Installer\" \"Select your regdomain.\" \
	    \"\" $regdomains
	regdomain=`sh -c "dialog \
	    --backtitle \"FreeBSD Installer\" \
	    --title \"Regdomain selection\" \
	    --cancel-label \"Skip\" \
	    $def_item_regdomain \
	    --no-items \
	    --stdout \
	    --menu \"Select your regdomain.\" \
	    $height $width $rows $regdomains"`

	f_dialog_menu_size height width rows \"Country selection\" \
	    \"FreeBSD Installer\" \"Select your country.\" \
	    \"\" $countries
	country=`sh -c "dialog \
	    --backtitle \"FreeBSD Installer\" \
	    --title \"Country selection\" \
	    --cancel-label \"Skip\" \
	    $def_item_country \
	    --stdout \
	    --menu \"Select your country.\" \
	    $height $width $rows $countries"`

	country_set "$regdomain" "$country"

	return $?
}

# There is no way to check country/regdomain without (possible)
# interface state modification
if [ ! -z $BSDINSTALL_CONFIGCURRENT ]; then
	# Get current country/regdomain for selected interface
	WLAN_IFACE=`wpa_cli ifname | tail -n 1`
	INPUT=`ifconfig $WLAN_IFACE list regdomain | head -n 1`
	DEF_REGDOMAIN=`echo $INPUT | cut -w -f 2`
	if [ "$DEF_REGDOMAIN" = "0" ]; then
		DEF_REGDOMAIN="<not selected>"
	fi
	DEF_COUNTRY=`echo $INPUT | cut -w -f 4`
	if [ "$DEF_COUNTRY" = "0" ]; then
		DEF_COUNTRY="<not selected>"
	fi
	dialog --backtitle "FreeBSD Installer" --title "Regdomain/country" \
	    --yesno "Change regdomain/country (now \
	    $DEF_REGDOMAIN/$DEF_COUNTRY)?" 0 0
	if [ $? -eq 0 ]; then
		while :
		do
			dialog_country_select "$DEF_REGDOMAIN" "$DEF_COUNTRY"
			if [ $? -eq $SUCCESS ]; then
				break
			fi
		done
	fi
fi

while :
do
	output=$( wpa_cli scan 2>&1 )
	f_dprintf "%s" "$output"
	dialog --backtitle "FreeBSD Installer" --title "Scanning" \
	    --ok-label "Skip" \
	    --pause "Waiting 5 seconds to scan for wireless networks..." \
	    9 40 5 || exit 1

	SCAN_RESULTS=`wpa_cli scan_results`
	NETWORKS=`echo "$SCAN_RESULTS" | awk -F '\t' \
	   '/..:..:..:..:..:../ {if (length($5) > 0) \
	   printf("\"%s\"\t%s\n", $5, $4);}' | sort | uniq`

	if [ -z "$NETWORKS" ]; then
		dialog --backtitle "FreeBSD Installer" --title "Error" \
		    --yesno "No wireless networks were found. Rescan?" 0 0 && \
		    continue
		exit 1
	fi

	exec 3>&1
	NETWORK=`sh -c "dialog --extra-button --extra-label \"Rescan\" \
	    --backtitle \"FreeBSD Installer\" --title \"Network Selection\" \
	    --menu \"Select a wireless network to connect to.\" 0 0 0 \
	    $(echo $NETWORKS | tr '\n' ' ')" 2>&1 1>&3`
	case $? in
	0)	# OK
		break
		;;
	1)	# Cancel
		exit 1
		;;
	3)	# Rescan
		;;
	esac
	exec 3>&-
done

ENCRYPTION=`echo "$NETWORKS" | awk -F '\t' \
    "/^\"$NETWORK\"\t/ {printf(\"%s\n\", \\\$2 );}"`

if echo $ENCRYPTION | grep -q 'PSK'; then
	exec 3>&1
	PASS=`dialog --insecure --backtitle "FreeBSD Installer" \
	    --title "WPA Setup" --mixedform "" 0 0 0 \
		"SSID" 1 0 "$NETWORK" 1 12 0 0 2 \
		"Password" 2 0 "" 2 12 15 63 1 \
		2>&1 1>&3` \
	|| exec $0 $@
	exec 3>&-
echo "network={
	ssid=\"$NETWORK\"
	psk=\"$PASS\"
	priority=5
}" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
elif echo $ENCRYPTION | grep -q EAP; then
	exec 3>&1
	USERPASS=`dialog --insecure --backtitle "FreeBSD Installer" \
	    --title "WPA-Enterprise Setup" --mixedform "" 0 0 0 \
		"SSID" 1 0 "$NETWORK" 1 12 0 0 2 \
		"Username" 2 0 "" 2 12 25 63 0 \
		"Password" 3 0 "" 3 12 25 63 1 \
		2>&1 1>&3` \
	|| exec $0 $@
	exec 3>&-
echo "network={
	ssid=\"$NETWORK\"
	key_mgmt=WPA-EAP" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
echo "$USERPASS" | awk '
{
	if (NR == 1) {
		printf "	identity=\"%s\"\n", $1;
	} else if (NR == 2) {
		printf "	password=\"%s\"\n", $1;
	}
}' >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
echo "	priority=5
}" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
elif echo $ENCRYPTION | grep -q WEP; then
	exec 3>&1
	WEPKEY=`dialog --insecure --backtitle "FreeBSD Installer" \
	    --title "WEP Setup" --mixedform "" 0 0 0 \
		"SSID" 1 0 "$NETWORK" 1 12 0 0 2 \
		"WEP Key 0" 2 0 "" 2 12 15 0 1 \
		2>&1 1>&3` \
	|| exec $0 $@
echo "network={
	ssid=\"$NETWORK\"
	key_mgmt=NONE
	wep_key0=\"$WEPKEY\"
	wep_tx_keyidx=0
	priority=5
}" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
else	# Open
echo "network={
	ssid=\"$NETWORK\"
	key_mgmt=NONE
	priority=5
}" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf
fi

# Connect to any open networks policy
echo "network={
	priority=0
	key_mgmt=NONE
}" >> $BSDINSTALL_TMPETC/wpa_supplicant.conf

# Bring up new network
if [ "$BSDINSTALL_CONFIGCURRENT" ]; then
	output=$( wpa_cli reconfigure 2>&1 )
	f_dprintf "%s" "$output"
fi

exit $SUCCESS

################################################################################
# END
################################################################################