#!/usr/bin/perl
#
# essid-pick: configure a wireless interface to use one of a prioritized list
# of available interfaces.
#
# Copyright 2004-2005 Patrick Reynolds (reynolds .at. cs duke edu)
#
# Usage:
#   essid-pick <interface> <essid1> [<essid2> [...]]
# For example:
#   essid-pick wlan0 Home Work CoffeeHouse
#
# If none of the requested interfaces is available (or if ESSID scanning
# fails), essid-pick will fall back on "any," which lets the card choose one.
#
# If you need extra arguments to iwconfig for a specific network (e.g.,
# an encryption key), specify them in /etc/essid-pick.conf.  All such
# arguments will be passed verbatim to iwconfig.  For example:
#    [Home]
#    key s:abcde
#
# Debian users: the easiest way to incorporate this script into your 
# boot process is as a "pre-up" line in /etc/network/interfaces.
# For example:
#    iface wlan0 inet dhcp
#       pre-up /usr/sbin/essid-pick wlan0 Home Work CoffeeHouse
#

$proc = "/proc/net/wireless";
$iwlist = "/sbin/iwlist";
$iwconfig = "/sbin/iwconfig";
$conf = "/etc/essid-pick.conf";

if ($#ARGV < 1) {
	print STDERR "Usage:\n  $0 interface essid [essid2 [essid3 [...]]]\n";
	exit 1;
}

$iface = shift;
find_interfaces($iface);

read_config();

print "Requested APs:";
foreach (@ARGV) {
	print " $_($found{$_})";
}
print "\n";
foreach (@ARGV) {
	if ($found{$_}) {
		system("$iwconfig $iface essid \"$_\" $args{$_}");
		print "Configuring $iface to use $_:\n";
		$args{$_} =~ s/key\s+\S+/key <hidden>/g;
		$args{$_} =~ s/enc\s+\S+/enc <hidden>/g;
		print "  $args{$_}\n";
		exit 0;
	}
}

print STDERR "None of the requested interfaces was found!\n";
system("$iwconfig $iface essid any");
exit 0;



sub find_interfaces {
	my $iface = shift;
	print "Available APs for $iface:";

	system("ifconfig $iface up");
	open(IWLIST, "$iwlist $iface scan 2>&1 |") || die "$iwlist: $!";
	while (<IWLIST>) {
		chomp;
		if (/ESSID:\s*"([^"]+)"/) {
			print " \"$1\"";
			$found{$1}++;
		}
		elsif (/Failed to read scan data/) {
			print "$iwlist failed here.  Blah.\n";
			system("$iwconfig $iface essid any");
			exit 0;
		}
	}
	print "\n";
	close(IWLIST);
	system("ifconfig $iface down");
}


sub read_config {
	if (!open(CONF, "<$conf")) { print "$0: $conf not found\n"; return; }
	my $ssid;
	while (<CONF>) {
		chomp;
		s/#.*//;
		next if /^$/;
		if (/^\[\s*(.+?)\s*\]$/) {
			$ssid = $1;
		}
		else {
			$args{$ssid} .= " $_";
		}
	}
	close(CONF);
}
