// // AirportSensor.m // Pennyworth // // Created by Chris Karr on 12/24/07. // Copyright 2007 Chris J. Karr. All rights reserved. // #import "AirportSensor.h" #import "Context.h" #import "Apple80211.h" #import "SensorsController.h" #define SENSOR_NAME @"Airport Networks" // #define AIRPORT_TOOL @"/System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport" #define ALWAYS_SCAN @"Always_Scan" #define SCAN_FOR_NETWORKS @"WiFi_Scan" static NSString * macToString (const UInt8 * mac) { return [NSString stringWithFormat:@"%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]]; } @implementation AirportSensor /*+ (id) airportTool:(NSArray *) args { NSTask * task = [NSTask new]; NSData * output; [task setLaunchPath:AIRPORT_TOOL]; [task setArguments:[args arrayByAddingObject:@"--xml"]]; [task setStandardOutput:[NSPipe pipe]]; [task setStandardError:[task standardOutput]]; @synchronized (AIRPORT_TOOL) { [task launch]; output = [[[task standardOutput] fileHandleForReading] readDataToEndOfFile]; } [task release]; id plist = nil; if (output && [output length] > 0) { NSString* error; plist = [NSPropertyListSerialization propertyListFromData:output mutabilityOption:NSPropertyListImmutable format:NULL errorDescription:&error]; if (error) return [[[NSString alloc] initWithBytes:[output bytes] length:[output length] encoding:NSUTF8StringEncoding] autorelease]; } return plist; } + (NSArray *) availableNetworks { return [AirportSensor airportTool:[NSArray arrayWithObject:@"-s"]]; } + (NSDictionary *) currentNetwork { NSString * currentString = [AirportSensor airportTool:[NSArray arrayWithObject:@"-I"]]; NSString * ssid = nil; NSString * bssid = nil; NSString * rssi = nil; NSArray * lines = [currentString componentsSeparatedByString:@"\n"]; NSEnumerator * iter = [lines objectEnumerator]; NSString * line = nil; while ((line = [iter nextObject]) != nil) { if ([line rangeOfString:@"BSSID"].location != NSNotFound) bssid = [line substringFromIndex:17]; else if ([line rangeOfString:@"SSID"].location != NSNotFound) ssid = [line substringFromIndex:17]; else if ([line rangeOfString:@"agrCtlRSSI"].location != NSNotFound) rssi = [line substringFromIndex:17]; } if ([ssid length] > 0) { NSMutableDictionary * dict = [NSMutableDictionary dictionary]; [dict setValue:bssid forKey:@"BSSID"]; [dict setValue:ssid forKey:@"SSID"]; [dict setValue:rssi forKey:@"RSSI"]; return dict; } else return nil; } */ - (void) update: (NSTimer *) theTimer { if (![[SensorsController sharedController] canFire:SENSOR_NAME]) { NSMutableDictionary * note = [NSMutableDictionary dictionary]; [note setValue:@"Current Wireless Network" forKey:OBSERVATION_SENSOR]; [[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note]; [note setValue:@"Current Wireless Signal Level" forKey:OBSERVATION_SENSOR]; [[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note]; [note setValue:@"Available Wireless Networks" forKey:OBSERVATION_SENSOR]; [[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note]; return; } if (!WirelessIsAvailable ()) return; WirelessContextPtr wctxt = 0; WirelessInfo info; BOOL scan = YES; WIErr err; if ((err = WirelessAttach (&wctxt, 0)) != noErr) { NSLog (@"%@ >> WirelessAttached failed with error code 0x%08x", [self class], err); return; } if ((WirelessGetInfo (wctxt, &info) == noErr) && (info.power > 0) && (info.link_qual > 0)) { NSString * ssid = [NSString stringWithCString:(const char *) info.name encoding:NSISOLatin1StringEncoding]; NSString * mac = macToString (info.macAddress); NSString * desc = [NSString stringWithFormat:@"%@ (%@)", ssid, mac]; NSMutableDictionary * note = [NSMutableDictionary dictionary]; [note setValue:@"Current Wireless Network" forKey:OBSERVATION_SENSOR]; [note setValue:desc forKey:OBSERVATION_OBSERVATION]; [note setValue:[NSNumber numberWithInteger:120] forKey:OBSERVATION_LIFESPAN]; [[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note]; /* note = [NSMutableDictionary dictionary]; [note setValue:@"Current Wireless Link Quality" forKey:OBSERVATION_SENSOR]; [note setValue:[NSNumber numberWithUnsignedShort:info.link_qual] forKey:OBSERVATION_OBSERVATION]; [note setValue:[NSNumber numberWithInteger:120] forKey:OBSERVATION_LIFESPAN]; [[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note]; */ note = [NSMutableDictionary dictionary]; [note setValue:@"Current Wireless Signal Level" forKey:OBSERVATION_SENSOR]; [note setValue:[NSNumber numberWithFloat:(100 - (((pow (2, 16)) - 1) - ((float) info.signal)))] forKey:OBSERVATION_OBSERVATION]; [note setValue:[NSNumber numberWithInteger:120] forKey:OBSERVATION_LIFESPAN]; [[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note]; scan = NO; } NSObject * defaultsScan = [[NSUserDefaults standardUserDefaults] objectForKey:ALWAYS_SCAN]; if (defaultsScan != nil && [[NSUserDefaults standardUserDefaults] boolForKey:ALWAYS_SCAN]) scan = YES; if (scan) { NSArray * list = nil; if (WirelessScan (wctxt, (CFArrayRef *) &list, 0) != noErr) { } else if (!list) { } else { NSMutableArray * networks = [NSMutableArray array]; NSData * data; for (data in list) { const WirelessNetworkInfo * ap; ap = (const WirelessNetworkInfo *) [data bytes]; NSString * ssid = [NSString stringWithCString:(const char *) ap->name encoding:NSISOLatin1StringEncoding]; NSString * mac = macToString (ap->macAddress); NSString * desc = [NSString stringWithFormat:@"%@ (%@)", ssid, mac]; [networks addObject:desc]; } [networks sortUsingSelector:@selector(compare:)]; NSMutableDictionary * note = [NSMutableDictionary dictionary]; [note setValue:@"Available Wireless Networks" forKey:OBSERVATION_SENSOR]; [note setValue:networks forKey:OBSERVATION_OBSERVATION]; [note setValue:[NSNumber numberWithInteger:120] forKey:OBSERVATION_LIFESPAN]; [[NSNotificationCenter defaultCenter] postNotificationName:OBSERVATION_UPDATE object:self userInfo:note]; } } WirelessDetach (wctxt); } - (void) awakeFromNib { [[NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(update:) userInfo:nil repeats:YES] retain]; [self update:nil]; [[SensorsController sharedController] addSensor:SENSOR_NAME]; } @end