#!/bin/sh
#
# Small Wi-Fi utility to quickly connect to a network. Easy network connection
# is most important, this tool provides a quick way to connect or change Wi-Fi
# settings while full network configuration is done in TazPanel.
#
# Copyright (C) 2012-2016 SliTaz GNU/Linux - GNU GPL v2
#
# Authors: Christophe Lincoln <pankso@slitaz.org>
#

. /lib/libtaz.sh
export TEXTDOMAIN='slitaz-boxes' #i18n

usage() {
	newline; _ 'Small Wi-Fi utility to quickly connect to a network.'
	newline; boldify "$(_ 'Usage:')"
	echo "  $(basename $0) [$(_ 'interface')]"
	newline
}


# Start a Wi-Fi connection

start_wifi() {
	sed -i \
		-e s'/^DHCP=.*/DHCP="yes"/' \
		-e s'/^STATIC=.*/STATIC="no"/' \
		-e s'/^WIFI=.*/WIFI="yes"/' \
		/etc/network.conf
	ifconfig $WIFI_INTERFACE up
	if [ "$(wifi_backend)" = wext ]; then
		iwconfig $WIFI_INTERFACE txpower auto
	fi
	/etc/init.d/network.sh start
}

# Radio killed: Tx-Power off (WEXT) or interface down (nl80211).
radio_off() {
	if [ -d /sys/class/net/$WIFI_INTERFACE/phy80211 ]; then
		! ip link show "$WIFI_INTERFACE" 2>/dev/null | grep -qE "<[^>]*UP"
	else
		iwconfig 2>/dev/null | grep -q 'Tx-Power=off'
	fi
}


# Catch ESSIDs and format output for GTK tree. We get the list of
# networks by Cell and without spaces.

# Scan backend for this interface: nl80211 (iw) on modern drivers,
# legacy WEXT (iwlist) on old hardware.
wifi_backend() {
	if [ -d /sys/class/net/$WIFI_INTERFACE/phy80211 ] && \
		iw dev $WIFI_INTERFACE info >/dev/null 2>&1; then
		echo nl80211
	elif [ -d /sys/class/net/$WIFI_INTERFACE/wireless ]; then
		echo wext
	fi
}

# Signal level in dBm (iw) to percent for the Quality column.
dbm_to_quality() {
	dbm=${1%%.*}
	[ -z "$dbm" ] && dbm=-100
	q=$(( (dbm + 100) * 2 ))
	[ $q -lt 0 ] && q=0
	[ $q -gt 100 ] && q=100
	echo "$q%"
}

# nl80211 scan: one TAB-separated line per BSS with
# essid, signal in dBm, RSN/WPA/Privacy flags.
scan_nl80211() {
	iw dev $WIFI_INTERFACE scan 2>/dev/null | awk '
		function flush() {
			if (have)
				printf "%s\t%s\t%d\t%d\t%d\n", \
					ssid, sig, rsn, wpa, priv
		}
		/^BSS / {
			flush()
			ssid = ""; sig = ""; rsn = 0; wpa = 0; priv = 0
			have = 1
			next
		}
		/SSID: / {
			ssid = substr($0, index($0, "SSID: ") + 6)
			next
		}
		/signal: / { sig = $2; next }
		/RSN:/ { rsn = 1; next }
		/WPA:/ { wpa = 1; next }
		/Privacy/ { priv = 1; next }
		END { flush() }
	'
}

detect_nl80211() {
	ifconfig $WIFI_INTERFACE up
	link=$(iw dev $WIFI_INTERFACE link 2>/dev/null | \
		sed -n 's/^.*SSID: //p')
	scan_nl80211 | while IFS='	' read -r essid sig rsn wpa priv; do
		quality=$(dbm_to_quality "$sig")
		if [ "$rsn" = 1 ] || [ "$wpa" = 1 ]; then
			crypto="WPA"
		elif [ "$priv" = 1 ]; then
			crypto="WEP"
		else
			crypto="NONE"
		fi
		if [ -n "$essid" ] && [ "$essid" = "$link" ]; then
			status="$(_n 'connected')"
		else
			status="$(_n '-')"
		fi
		echo -e "$essid\n$quality\n$crypto\n$status"
	done
}

detect_wext() {
	if [ -d /sys/class/net/$WIFI_INTERFACE/wireless ]; then
		ifconfig $WIFI_INTERFACE up
		for i in $(iwlist $WIFI_INTERFACE scan | sed s/"Cell "/Cell-/ | grep "Cell-" | awk '{print $1}')
		do
			scan=$(iwlist $WIFI_INTERFACE scan last | \
				awk '/(Cell|ESS|Qual|Encry|IE: WPA|WPA2)/ {print}' | \
				sed s/"Cell "/Cell-/ | grep -A 5 "$i")
			essid=$(echo $scan | cut -d '"' -f 2)

			if echo "$scan" | grep -q Quality; then
				quality=$(echo $scan | sed 's/.*Quality=\([^ ]*\).*/\1/' | sed 's/.*Quality:\([^ ]*\).*/\1/')
			else
				quality="$(_n '-')"
			fi

			crypto=$(echo $scan | sed 's/.*key:\([^ ]*\).*/\1/')
			# Check encryption type
			if echo "$scan" | grep -q WPA*; then
				crypto="WPA"
			fi

			# Connected or not connected...
			if ifconfig | grep -A 1 $WIFI_INTERFACE | \
				grep -q inet && iwconfig $WIFI_INTERFACE | \
				grep ESSID | grep -q -w "$essid"; then
				status="$(_n 'connected')"
			else
				status="$(_n '-')"
			fi

			echo -e "$essid\n$quality\n${crypto/off/NONE}\n$status"
		done
	fi
}

detect_wifi() {
	echo -e "$( _n 'any')\n$(_n 'N/A')\n$(_n 'none')\n$(_n '-')"
	case $(wifi_backend) in
		nl80211) detect_nl80211 ;;
		wext)    detect_wext ;;
	esac
}


# Prompt for password or connect

connect_main() {
	case $keytype in
		WPA)	label="$(_n 'WPA Password:')" ;;
		WEP)	label="$(_n 'WEP Password:')" ;;
		*)		label= ;;
	esac
	case $keytype in
		WPA|WEP)
			icon='network-wireless'
			yad --title="$(_n 'Wi-Fi connection')" --window-icon=$icon \
				--width=520 --height=140 --on-top --center \
				--image=$icon --image-on-top \
				--text="$(_n 'Connection to:') <b>$essid</b>" \
				--form \
				--field="$label:H" ;;
		none) continue ;;
		*) exit 0 ;;
	esac
}


connect() {
	main=$(connect_main)
	ret=$?
	# Deal with --button values
	case $ret in
		1) exit 0 ;;
		*) continue ;;
	esac
	/etc/init.d/network.sh stop
	sleep 1
	key=$(echo "$main" | cut -d '|' -f 1)
	sed -i \
		-e s"/^WIFI_ESSID=.*/WIFI_ESSID=\"$essid\""/ \
		-e s"/^WIFI_KEY=.*/WIFI_KEY=\"$key\"/" \
		-e s"/^WIFI_KEY_TYPE=.*/WIFI_KEY_TYPE=\"$keytype\"/" \
		/etc/network.conf
	start_wifi
}


# Main GUI box function with pure Yad spec

wifi_main() {
	icon='network-wireless'
	if radio_off; then
		startstop="$(_n 'Start Wi-Fi')!media-playback-start:4"
		refresh=''
	else
		startstop="$(_n 'Stop Wi-Fi')!media-playback-stop:3"
		refresh="--button=gtk-refresh:5"
	fi
	detect_wifi | yad --title="$(_n 'Wi-Fi network')" --window-icon=$icon \
		--width=520 --height=300 --center \
		--image=$icon --image-on-top \
		--text="$(_n '<b>Connect to a Wi-Fi network</b> (Double click to connect)')" \
		--list \
		--column "$(_n 'ESSID Name')" --column "$(_n 'Quality')" \
		--column "$(_n 'Encryption')" --column "$(_n 'Status')" \
		--button="$startstop" $refresh \
		--button="gtk-preferences:2" --button="gtk-close:1"
}


# Main function

wifi() {
	# Store box results
	main=$(wifi_main)
	ret=$?
	# Deal with --button values
	case $ret in
		1) exit 0 ;;
		2) tazpanel network#wifi; exit 0 ;;
		3) /etc/init.d/network.sh stop; $0 ;;
		4) start_wifi; $0 ;;
		5) $0 ;;
	esac
	if [ -n "$main" ]; then
		essid=$(echo "$main" | cut -d "|" -f 1)
		keytype=$(echo "$main" | cut -d "|" -f 3)
		connect
	fi
}


#
# Script commands
#

case "$1" in
	-h|--help|usage|help|-*)
		usage ;;
	*)
		# Only for root.
		if [ $(id -u) -ne 0 ]; then
			exec tazbox su $0 $@
			exit 0
		fi

		. /etc/network.conf
		[ -n "$1" ] && WIFI_INTERFACE="$1"
		wifi ;;
esac

exit 0

