+#!/bin/bash
+
+#########################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the version 3 of the GNU General Public License #
+# as published by the Free Software Foundation. #
+# #
+# This program is distributed in the hope that it will be useful, but #
+# WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
+# General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+# Written by and Copyright (C) Francois Fleuret #
+# Contact <francois@fleuret.org> for comments & bug reports #
+#########################################################################
+
+INTERFACE=wlan0
+MTU=512
+
+SCAN_OUTPUT=$(mktemp /tmp/scanresult.XXXXXX)
+SHOW_CLOSED=0
+
+######################################################################
+
+VT_CURSOR_OFF=$'\033[?25l'
+VT_CURSOR_ON=$'\033[?25h'
+
+VT_RESET=$'\033[0m'
+VT_BOLD=$'\033[1m'
+VT_UNDERLINE=$'\033[4m'
+VT_BLINK=$'\033[5m'
+
+VT_BLACK_FG=$'\033[30m'
+VT_RED_FG=$'\033[31m'
+VT_GREEN_FG=$'\033[32m'
+VT_YELLOW_FG=$'\033[33m'
+VT_BLUE_FG=$'\033[34m'
+VT_MAGENTA_FG=$'\033[35m'
+VT_CYAN_FG=$'\033[36m'
+VT_WHITE_FG=$'\033[37m'
+
+VT_BLACK_BG=$'\033[40m'
+VT_RED_BG=$'\033[41m'
+VT_GREEN_BG=$'\033[42m'
+VT_YELLOW_BG=$'\033[43m'
+VT_BLUE_BG=$'\033[44m'
+VT_MAGENTA_BG=$'\033[45m'
+VT_CYAN_BG=$'\033[46m'
+VT_WHITE_BG=$'\033[47m'
+
+######################################################################
+
+function cleanup-before-quit () {
+ echo ${VT_CURSOR_ON}
+ stty "$stty_state"
+ rm -f ${SCAN_OUTPUT}
+ if [[ "${interface_was_up}" == "" ]]; then
+ echo "The interface was down."
+ ifconfig ${INTERFACE} down
+ fi
+}
+
+function sigint-handler () {
+ cleanup-before-quit
+ echo "Interrupted"
+ exit 0
+}
+
+function scan () {
+ iwconfig ${INTERFACE} ap off essid ""
+ iwlist ${INTERFACE} scan | \
+ sed -e "s/^[\t ]*//" | grep ^"Cell\|ESSID\|Quality\|Encryption" | \
+ sed \
+ -e "s/Cell [0-9]* - Address: \([0-9]*\)/AP,\1/" \
+ -e "s/^ *ESSID:\\\"\([^\\\"]*\)\\\".*$/ESSID,\1/" \
+ -e "s/Quality=\([0-9]*\).*$/QUALITY,\1/" \
+ -e "s/Encryption key:/ENCRYPTION,/" | \
+ awk 'BEGIN { FS="," }
+ {
+ if($1 == "ESSID") { essid=$2 }
+ else if($1 == "AP") { ap=$2 }
+ else if($1 == "QUALITY") { quality=$2; }
+ else if($1 == "ENCRYPTION") {
+ if($2 == "off") {
+ open=" "
+ printf("%d,%s,%s,%s\n",quality,open,essid,ap);
+ } else {
+ if('${SHOW_CLOSED}') {
+ open="(closed)"
+ printf("%d,%s,%s,%s\n",quality,open,essid,ap);
+ }
+ }
+ }
+ }' | \
+ sort -rn > ${SCAN_OUTPUT}
+
+ number_of_aps=$(wc -l ${SCAN_OUTPUT} | awk '{print $1}')
+
+ chmod a+rw ${SCAN_OUTPUT}
+}
+
+function redisplay () {
+ clear
+
+ echo
+ echo -n " ${VT_UNDERLINE}Hotspot selection${VT_RESET}"
+ if [[ $SHOW_CLOSED == 0 ]]; then
+ echo " (show only open networks)"
+ else
+ echo
+ fi
+ echo
+ echo " [s,r] scan [m] switch the free-only view and scan [q] quit"
+ echo " [e] select essid + dhcp [a] selects essid/ap + dhcp [k] kill dhcp and quit"
+ echo
+
+ for i in $(ifconfig -s | grep -E -v ^lo\|Iface\|wmaster | awk '{print $1}'); do
+ echo " Warning: $i is up"
+ done
+ echo
+
+ if [[ ${number_of_aps} == "0" ]]; then
+ echo " ${VT_RED_FG}${VT_BOLD}No access point detected.${VT_RESET}"
+ else
+
+ awk < ${SCAN_OUTPUT} 'BEGIN { nb=1; FS="," }
+ {
+ if(nb == '$current_ap') {
+ printf(" =>");
+ } else {
+ printf(" ");
+ }
+ if($2 == "(closed)") {
+ printf("'${VT_RED_FG}'");
+ printf("% 3s %s \"%s\" %s'${VT_RESET}'\n", $1, $2, $3, $4);
+ } else {
+ printf("'${VT_GREEN_FG}'");
+ printf("% 3s %s \"%s\" %s'${VT_RESET}'\n", $1, $2, $3, $4);
+ }
+ nb=nb+1;
+ }'
+ fi
+}
+
+function get-selected-essid-ap () {
+ cat ${SCAN_OUTPUT} | \
+ awk 'BEGIN { nb=1; FS="," }
+ {
+ if(nb == '$current_ap') {
+ printf("%s,%s\n", $3, $4);
+ }
+ nb=nb+1;
+ }'
+}
+
+function kill-dhcp () {
+ PID=$(pidof dhclient)
+ if [[ ${PID} ]]; then
+ echo "Killing dhclient"
+ dhclient -x ${INTERFACE}
+ fi
+}
+
+######################################################################
+
+function process-key () {
+
+ case $1 in
+ e) # Selects essid + dhcp
+ SELECTED=$(get-selected-essid-ap)
+ ESSID=$(echo ${SELECTED} | cut -f 1 -d,)
+ echo "Running DHCP on ${INTERFACE} for ESSID ${ESSID}."
+ iwconfig ${INTERFACE} ap auto essid "${ESSID}"
+ kill-dhcp
+ echo
+ dhclient ${INTERFACE}
+ # if [[ $? == 0 ]]; then
+ # iwconfig ${INTERFACE} > ~/.hotspot-ap
+ # fi
+ ifconfig ${INTERFACE} mtu ${MTU}
+ interface_was_up=1
+ cont=0
+ ;;
+
+ "return"|a) # Selects essid/ap + dhcp
+ SELECTED=$(get-selected-essid-ap)
+ ESSID=$(echo ${SELECTED} | cut -f 1 -d,)
+ AP=$(echo ${SELECTED} | cut -f 2 -d,)
+ echo "Running DHCP on ${INTERFACE} for ESSID ${ESSID} and AP ${AP}."
+ iwconfig ${INTERFACE} ap ${AP} essid "${ESSID}"
+ kill-dhcp
+ echo
+ dhclient ${INTERFACE}
+ # if [[ $? == 0 ]]; then
+ # iwconfig ${INTERFACE} > ~/.hotspot-ap
+ # fi
+ ifconfig ${INTERFACE} mtu ${MTU}
+ interface_was_up=1
+ cont=0
+ ;;
+
+ k) # kill dhcp
+ echo "Killing DHCP and bringing down ${INTERFACE}."
+ kill-dhcp
+ ifconfig ${INTERFACE} down
+ cont=0
+ ;;
+
+ r|s) # re-scanning the access points
+ echo "Scanning ..."
+ scan
+ redisplay
+ ;;
+
+ m) # Switching the mode to show the protected spots
+ SHOW_CLOSED=$((1-SHOW_CLOSED))
+ echo "Scanning ..."
+ scan
+ redisplay
+ ;;
+
+ "down"|n)
+ current_ap=$((current_ap+1))
+ if [[ $current_ap -gt $number_of_aps ]]; then
+ current_ap=$number_of_aps
+ fi
+ redisplay
+ ;;
+
+ "up"|p)
+ current_ap=$((current_ap-1))
+ if [[ $current_ap -lt 1 ]]; then
+ current_ap=1
+ fi
+ redisplay
+ ;;
+
+ "esc-esc"|q)
+ echo "quit"
+ cont=0
+ ;;
+
+ *)
+ ;;
+ esac
+}
+
+######################################################################
+## The main
+
+if [[ $1 == "-k" ]]; then
+ echo "Killing DHCP and bringing down ${INTERFACE}."
+ kill-dhcp
+ ifconfig ${INTERFACE} down
+ exit 1
+fi
+
+stty_state=$(stty -g)
+
+trap sigint-handler SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+
+stty -echo -icrnl -icanon -xcase min 1 time 0
+
+echo ${VT_CURSOR_OFF}
+
+current_ap=1
+cont=1
+current_keymap=default
+
+interface_was_up=$(ifconfig | grep ${INTERFACE})
+
+ifconfig ${INTERFACE} up
+
+scan
+
+redisplay
+
+while [[ ${cont} == 1 ]]; do
+
+ CHAR=$(dd bs=1 count=1 2>/dev/null)
+
+ case ${current_keymap} in
+ default) ##################################################
+ case ${CHAR} in
+
+ [a-z])
+ process-key ${CHAR}
+ ;;
+
+ "\r")
+ process-key "return"
+ ;;
+
+ "\ e")
+ process-key "down"
+ ;;
+
+ "\10")
+ process-key "up"
+ ;;
+
+ "\e") #$'\033'")
+ current_keymap=escape
+ ;;
+
+ *)
+ ;;
+ esac
+ ;;
+
+ escape) ##################################################
+ case ${CHAR} in
+ "$'\033'")
+ process-key "esc-esc"
+ ;;
+ "[")
+ current_keymap=cursor
+ ;;
+ *)
+ current_keymap=default
+ ;;
+ esac
+ ;;
+
+ cursor) ##################################################
+
+ current_keymap=default
+
+ case ${CHAR} in
+ A)
+ process-key "up"
+ ;;
+ B)
+ process-key "down"
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+
+ *)
+ echo "Unknown keymap. This is an internal and weird bug."
+ cont=0
+ ;;
+ esac
+
+ done
+
+ cleanup-before-quit