#!/bin/sh

. /lib/config/uci.sh

IFNAME=$1
CMD=$2

get_conf_var() {
	local conf="$1"
	local var="$2"
	# This finds the last "$2=" in the supplicant config and strips off leading
	# and trailing quotes. Generally the quotes are there if it's a passphrase and not if its a psk hex string
	# (passphrase is pure ascii not escaped, not even for " inside "") and for ssid
	grep "^[$(printf " \t")]*$var=" "$conf" |
		awk 'BEGIN{FS="="} {a=substr($0, index($0,$2))} END{print a}' |
		sed -e 's/^"\(.*\)"$/\1/'
}

add_interface() {
	local radio="$1"
	local ssid="$2"
	local psk="$3"
	local encryption="$4"
	local country="$(uci_get_state delos baptization WiFiCountryCode)"
	uci_add wireless wifi-iface
	uci_set wireless @wifi-iface[-1] type qcawifi
	uci_set wireless @wifi-iface[-1] device "$radio"
	uci_set wireless @wifi-iface[-1] mode ap
	uci_set wireless @wifi-iface[-1] ssid "$ssid"
	uci_set wireless @wifi-iface[-1] key "$psk"
	uci_set wireless @wifi-iface[-1] network lan
	uci_set wireless @wifi-iface[-1] channel auto
	uci_set wireless @wifi-iface[-1] country "${country:-DE}"
	uci_set wireless @wifi-iface[-1] txpower 27
	case $encryption in
		WPA2-PSK)
			uci_set wireless @wifi-iface[-1] encryption psk2
		;;
		WPA-PSK)
			uci_set wireless @wifi-iface[-1] encryption psk
		;;
		NONE)
			uci_set wireless @wifi-iface[-1] encryption none
		;;
	esac
}

add_interface_uci() {
	add_interface "$1" "$2" "$3" "$4"

	uci_commit wireless
}

# this implementation depends on having only max 4 SSIDs (2.4GHz/5GHz and normal/guest SSID)
overwrite_interface_uci() {
	local radio="$1"
	local ssid="$2"
	local psk="$3"
	local encryption="$4"
	local index=-1
	local index24=-1
	local index5=-1
	local radio24=wifi0		# 2.4GHz radio is normally wifi0
	local radio5=wifi1		# 5GHz radio is normally wifi1
	local use_common_setting=0

	# check if wifi1 is 2.4GHz radio
	if [ "$(uci_get_state wireless wifi1 hwmode)" == "11g" ]; then
		radio24=wifi1
		radio5=wifi0
	fi

	for id in 0 1 2 3; do
		# skip guest wifi
		if [ "$(uci_get_state wireless @wifi-iface[$id] dvl_guest 0)" == "0" ]; then
			# search for 2.4GHz index
			if [ "$(uci_get_state wireless @wifi-iface[$id] device)" == "$radio24" ]; then
				index24=$id
			fi
			# search for 5GHz inedx
			if [ "$(uci_get_state wireless @wifi-iface[$id] device)" == "$radio5" ]; then
				index5=$id
			fi
			# search for matching entry
			if [ "$(uci_get_state wireless @wifi-iface[$id] device)" == "$radio" ]; then
				index=$id
			fi
		fi
	done

	# if a SSID exist of both radios check if settings are equal and if they are equal overwrite both SSID settings
	if [ "$index24" != "-1" ] && [ "$index5" != "-1" ]; then
		if [ "$(uci_get_state wireless @wifi-iface[$index24] ssid)" == "$(uci_get_state wireless @wifi-iface[$index5] ssid)" ] &&
			[ "$(uci_get_state wireless @wifi-iface[$index24] key)" == "$(uci_get_state wireless @wifi-iface[$index5] key)" ] &&
			[ "$(uci_get_state wireless @wifi-iface[$index24] encryption)" == "$(uci_get_state wireless @wifi-iface[$index5] encryption)" ] &&
			[ "$(uci_get_state wireless @wifi-iface[$index24] hidden)" == "$(uci_get_state wireless @wifi-iface[$index5] hidden)" ];then
			use_common_setting=1
		fi
	fi

	# if "use common setting" modify both radio entries
	if [ "$use_common_setting" == "1" ]; then
		uci_set wireless @wifi-iface[$index24] ssid "$ssid"
		uci_set wireless @wifi-iface[$index5] ssid "$ssid"
		uci_set wireless @wifi-iface[$index24] key "$psk"
		uci_set wireless @wifi-iface[$index5] key "$psk"
		case $encryption in
			WPA2-PSK)
				uci_set wireless @wifi-iface[$index24] encryption psk2
				uci_set wireless @wifi-iface[$index5] encryption psk2
			;;
			WPA-PSK)
				uci_set wireless @wifi-iface[$index24] encryption psk
				uci_set wireless @wifi-iface[$index5] encryption psk
			;;
			NONE)
				uci_set wireless @wifi-iface[$index24] encryption none
				uci_set wireless @wifi-iface[$index5] encryption none
			;;
		esac
	elif [ "$index" != "-1" ]; then
		uci_set wireless @wifi-iface[$index] ssid "$ssid"
		uci_set wireless @wifi-iface[$index] key "$psk"
		case $encryption in
			WPA2-PSK)
				uci_set wireless @wifi-iface[$index] encryption psk2
			;;
			WPA-PSK)
				uci_set wireless @wifi-iface[$index] encryption psk
			;;
			NONE)
				uci_set wireless @wifi-iface[$index] encryption none
			;;
		esac
	else
		add_interface "$radio" "$ssid" "$psk" "$encryption"
	fi

	uci_commit wireless
}

remove_interface() {
	local ifname="$1"
	wpa_cli -g /var/run/wpa_supplicantglobal interface_remove $ifname
	[ -f /var/run/wpa_supplicant-$ifname.pid ] && kill $(cat /var/run/wpa_supplicant-$ifname.pid)
	rm -rf /var/run/wpa_supplicant-${ifname}*
	wlanconfig $ifname destroy
}

# stop all wps cloning instances
remove_all_interfaces() {
	for ifpath in $(ls -d /sys/class/net/athClone? 2>/dev/null); do
		remove_interface $(basename $ifpath)
	done
}

case "$CMD" in
	CONNECTED)
		# only accept first connect, if wps clone not successful yet
		if [ "$(uci_get_state wireless wps_clone state)" != success ]; then
			uci_set_state wireless wps_clone state success
			uci_revert_state wireless wps_clone reason

			wpa_cli -i$IFNAME -p /var/run/wpa_supplicant-$IFNAME save_config
			radio=$(cat /sys/class/net/$IFNAME/parent)
			# ssid/psk are strangely escaped (escaping \ " but not ' or $), don't use
			status="$(wpa_cli -i$IFNAME -p/var/run/wpa_supplicant-$IFNAME status)"
			encryption=$(echo "$status" | grep ^key_mgmt=)
			encryption="${encryption#*=}"
			# get ssid/psk from config instead
			ssid="$(get_conf_var /var/run/wpa_supplicant-$IFNAME.conf ssid)"
			psk="$(get_conf_var /var/run/wpa_supplicant-$IFNAME.conf psk)"


			# Check if only one ssid is allowed
			if [ "for now" != "only one ssid" ]; then
				overwrite_interface_uci "$radio" "$ssid" "$psk" "$encryption"
			else
				add_interface_uci "$radio" "$ssid" "$psk" "$encryption"
			fi

			remove_interface $IFNAME
			# we're done, stop all remaining wps cloning instances
			remove_all_interfaces
			reload_config # use procd to check for config changes
		else
			remove_interface $IFNAME
		fi
	;;
	WPS-OVERLAP-DETECTED |\
	WPS-FAIL |\
	WPS-TIMEOUT)
		if [ "$(uci_get_state wireless wps_clone state)" = running ]; then
			uci_set_state wireless wps_clone state failed
			uci_set_state wireless wps_clone reason $CMD
			remove_interface $IFNAME
			remove_all_interfaces
			# force re-up all wifi interfaces (not done by driver/hostapd)
			for ifname in $(ubus call uci state '{"config":"wireless","type":"wifi-iface"}'|\
			                jsonfilter -e "$.values[@.up='1'].ifname"); do
				ip link set $ifname down
				ip link set $ifname up
			done
		fi
	;;
esac