// // DDWRT_MonitorAppDelegate.m // DDWRT-Monitor // // Created by Matthieu Lalonde & Spike Grobstein on 11-05-27. // Copyleft 2011 Spurf CC BY-SH-NC. Some rights reserved. // #import "DDWRT_MonitorAppDelegate.h" @implementation DDWRT_MonitorAppDelegate # pragma mark - # pragma mark Application Delegates: - (void) awakeFromNib { // Insert code here to initialize your application defaults = [NSUserDefaults standardUserDefaults]; // check if the app is configured yet if (![defaults boolForKey:@"configured"] || [[defaults stringForKey:@"hostname"] length] == 0) { [self showInitAlert]; [self initDefaults]; } else { [self initialize]; } [self showMenubar]; } - (void) dealloc { [AppMenu release]; [_appMenu release]; [ConfigPanel release]; [BandwidthViewer release]; [super dealloc]; } - (void) terminate:(id)sender { [self deinitialize]; [[NSUserDefaults standardUserDefaults] synchronize]; [self dealloc]; [[NSApplication sharedApplication] terminate:self]; } - (void) initialize { NSLog(@"Reading defaults..."); [self readDefaults]; _statusDataRequestNumber = 0; _statusStringData = @""; wrt_update_client = [[WRTStatusClient alloc] initWithHostname:hostname port:port protocol:protocol username:username password:password]; wrt_request_client = [[WRTStatusClient alloc] initWithHostname:hostname port:port protocol:protocol username:username password:password]; [wrt_update_client registerStatusCallback:self callback:@selector(cbUpdateStatus)]; [wrt_update_client getConnectionStatus]; } - (void) deinitialize { if (_updateTimer != nil) { [_updateTimer invalidate]; _updateTimer = nil; [_updateTimer release]; } [wrt_update_client release]; wrt_update_client = nil; [wrt_request_client release]; wrt_request_client = nil; } - (void) showInitAlert { NSAlert *alert = [[[NSAlert alloc] init] autorelease]; [alert addButtonWithTitle:@"OK"]; [alert setMessageText:@"First Launch!"]; [alert setInformativeText:@"In order to conitnue, you must first provide your router settings."]; [alert setAlertStyle:NSInformationalAlertStyle]; [alert runModal]; } - (IBAction) showBandwidthViewer:(id)sender { [ [BandwidthViewerWebView mainFrame] loadRequest: [wrt_update_client requestForBandwidthViewerForInterface:[wrt_update_client getWanPort]] ]; // Failed attempt at automagically setting the bit/byte mode in the svg graph //WebScriptObject *scriptObject = [BandwidthViewerWebView windowScriptObject]; //[scriptObject callWebScriptMethod:@"alert" withArguments:[NSArray arrayWithObject:@"Will"]]; //[scriptObject setValue:@"bits" forKey:@"unit"]; [BandwidthViewer makeKeyAndOrderFront:nil]; } # pragma mark - # pragma mark Menu Methods: - (void) showMenubar { NSLog(@"Showing Menu Item"); NSStatusBar *bar = [NSStatusBar systemStatusBar]; _appMenu = [bar statusItemWithLength:NSVariableStatusItemLength]; [_appMenu setAction:@selector(refreshMenu:)]; [_appMenu setTarget:self]; [_appMenu retain]; [self showMenubarIcon:false]; [_appMenu setHighlightMode:YES]; //[_appMenu setMenu:AppMenu]; } - (void) hideMenubar { [_appMenu release]; _appMenu = nil; [AppMenu release]; AppMenu = nil; } - (void) showMenubarIcon:(BOOL)enabled { NSImage* icon = [NSImage imageNamed:(enabled == true ? @"MenuIcon" : @"MenuIconDisabled")]; [_appMenu setImage:icon]; [_appMenu setAlternateImage:nil]; [icon release]; } - (void) hideMenubarIcon { [_appMenu setImage:nil]; [_appMenu setAlternateImage:nil]; } - (void) setMenubarText:(NSString *)menubarText { // TODO set proper line height and proper right align NSFontManager *fontManager = [NSFontManager sharedFontManager]; NSFont *menuFont = [fontManager fontWithFamily:@"Lucida Grande" traits:NSBoldFontMask weight:10 size:8 ]; NSDictionary *titleAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:menuFont, NSFontAttributeName, [NSColor blackColor], NSForegroundColorAttributeName, nil]; NSAttributedString *menuTitle = [[NSAttributedString alloc] initWithString:menubarText attributes:titleAttributes]; [_appMenu setAttributedTitle:menuTitle]; [fontManager release]; [menuFont release]; [menuTitle release]; } - (void) disableDynamicMenus { [menuSystem setEnabled:false]; [menuWan setEnabled:false]; [menuClientsItem setEnabled:false]; } - (void) enableDynamicMenus { [menuSystem setEnabled:true]; [menuWan setEnabled:true]; [menuClientsItem setEnabled:true]; } # pragma mark - # pragma mark Configs Methods: - (void) initDefaults { NSLog(@"Creating new user defaults"); // do any other initialization you want to do here - e.g. the starting default values. [defaults setValue:@"http" forKey:@"protocol"]; [defaults setValue:@"" forKey:@"hostname"]; [defaults setInteger:80 forKey:@"port"]; [defaults setValue:@"" forKey:@"username"]; [defaults setValue:@"" forKey:@"password"]; [defaults setBool:YES forKey:@"showMenuIcon"]; [defaults setBool:YES forKey:@"useBytes"]; [defaults setInteger:4 forKey:@"refreshTime"]; [defaults setBool:YES forKey:@"configured"]; [self showConfigPanel:self]; } - (void) readDefaults { hostname = [defaults valueForKey:@"hostname"]; protocol = [defaults valueForKey:@"protocol"]; port = [defaults integerForKey:@"port"]; username = [defaults valueForKey:@"username"]; password = [defaults valueForKey:@"password"]; showMenuIcon = [defaults boolForKey:@"showMenuIcon"]; useBytes = [defaults boolForKey:@"useBytes"]; refreshTime = [defaults integerForKey:@"refreshTime"]; } - (void) writeDefaults { // do any other initialization you want to do here - e.g. the starting default values. [defaults setValue:hostname forKey:@"hostname"]; [defaults setValue:protocol forKey:@"protocol"]; [defaults setInteger:port forKey:@"port"]; [defaults setValue:username forKey:@"username"]; [defaults setValue:password forKey:@"password"]; [defaults setBool:showMenuIcon forKey:@"showMenuIcon"]; [defaults setBool:useBytes forKey:@"useBytes"]; [defaults setInteger:refreshTime forKey:@"refreshTime"]; // sync the defaults to disk [defaults synchronize]; } - (IBAction) showConfigPanel:(id)sender { [configFieldShowIcon setState:([defaults boolForKey:@"showMenuIcon"] ? 1 : 0)]; [configFieldUseBytes setState:([defaults boolForKey:@"useBytes"] ? 1 : 0)]; if (hostname != nil) { [configFieldHostname setStringValue:hostname]; } [configFieldPort setIntValue:[defaults integerForKey:@"port"]]; [configFieldRefresh setIntegerValue:[defaults integerForKey:@"refreshTime"]]; [configLabelRefresh setStringValue:[NSString stringWithFormat:@"%d s", ([defaults integerForKey:@"refreshTime"] + 1)]]; if ([protocol isEqualToString:@"http"] == true) { [configFieldProtocolHTTP setState:1]; [configFieldProtocolHTTPS setState:0]; } else if ([protocol isEqualToString:@"https"] == true) { [configFieldProtocolHTTP setState:0]; [configFieldProtocolHTTPS setState:1]; } [ConfigPanel makeKeyAndOrderFront:nil]; } - (IBAction) hideConfigPanel:(id)sender { if ([hostname length] == 0 && [[sender title] isEqualToString:@"Cancel"]) { NSAlert *alert = [NSAlert alertWithMessageText:@"Application Not Configured!" defaultButton:@"Cancel" alternateButton:@"Ok" otherButton:nil informativeTextWithFormat:@"The application will quit now." ]; [alert setAlertStyle:NSCriticalAlertStyle]; NSInteger button = [alert runModal]; if (button != NSAlertDefaultReturn) { [self terminate:nil]; [ConfigPanel orderOut:nil]; } } else { [ConfigPanel orderOut:nil]; } } - (IBAction) setConfigProtocol:(id)sender { if ([configFieldProtocolHTTP state] == 1 && [[configFieldPort stringValue] isEqualToString:@"443"] == true) { [configFieldPort setStringValue:@"80"]; } else if ([configFieldProtocolHTTPS state] == 1 && [[configFieldPort stringValue] isEqualToString:@"80"] == true) { [configFieldPort setStringValue:@"443"]; } } - (IBAction) setConfigRefresh:(id)sender { [configLabelRefresh setStringValue:[NSString stringWithFormat:@"%u s", ([sender integerValue] + 1)]]; } - (IBAction) saveConfig:(id)sender { [self deinitialize]; [configStateStatus startAnimation:nil]; [configStateStatus setHidden:false]; hostname = [configFieldHostname stringValue]; port = [configFieldPort intValue]; if ([configFieldProtocolHTTP state] == 1) { protocol = @"http"; } else if ([configFieldProtocolHTTPS state] == 1) { protocol = @"https"; } refreshTime = [configFieldRefresh integerValue]; useBytes = ([configFieldUseBytes state] == 1 ? true: false); showMenuIcon = ([configFieldShowIcon state] == 1 ? true: false); [configStateStatus stopAnimation:nil]; [configStateStatus setHidden:true]; [self writeDefaults]; [defaults synchronize]; [self initialize]; [self hideConfigPanel:nil]; } # pragma mark - # pragma mark Request Handlers: - (void) cbUpdateStatus { NSLog(@"Status %@ wan port: %@", ([wrt_update_client getWrtReachable] ? @"Up" : @"Down"), [wrt_update_client getWanPort]); if ([wrt_update_client getWrtReachable] == true) { if (showMenuIcon == true) { [self showMenubarIcon:true]; } else { [self hideMenubarIcon]; } [self enableDynamicMenus]; [self getMonthlyTransfers:nil]; if (_updateTimer != nil) { [_updateTimer invalidate]; _updateTimer = nil; } _updateTimer = [NSTimer scheduledTimerWithTimeInterval:refreshTime+1 target:self selector:@selector(getThroughput:) userInfo:nil repeats:YES]; [_updateTimer fire]; } else if ([wrt_update_client getWrtReachable] == false) { [self showMenubarIcon:false]; [self setMenubarText:@""]; [self disableDynamicMenus]; if (_updateTimer != nil) { [_updateTimer invalidate]; _updateTimer = nil; } _updateTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:wrt_update_client selector:@selector(getConnectionStatus:) userInfo:nil repeats:NO]; [_updateTimer fire]; } } - (void) getThroughput:(NSTimer *)timer { //NSLog(@"Status %@ wan port: %@", ([wrt_client getWrtReachable] ? @"Up" : @"Down"), [wrt_client getWanPort]); [wrt_update_client getStatusUpdate:[NSString stringWithFormat:@"fetchif.cgi?%@", [wrt_update_client getWanPort]] delegate:self callback:@selector(cbThroughput:)]; } - (void) cbThroughput:(NSData *)data { NSString *stringData = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; NSString *key = [NSString stringWithFormat:@"%@:", [wrt_update_client getWanPort]]; stringData = [stringData substringFromIndex:([stringData rangeOfString:key].location + [key length])]; NSArray *parts = [stringData componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; NSArray *listItems = [parts filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF != ''"]]; uint64_t ifIn = strtoull([[listItems objectAtIndex:0] UTF8String], NULL, 0); uint64_t ifOut = strtoull([[listItems objectAtIndex:8] UTF8String], NULL, 0); if (_lastInThroughput != 0) { uint64_t diffIn = ifIn - _lastInThroughput; uint64_t diffOut = ifOut - _lastOutThroughput; double timeDiff = fabs([_lastDateThroughput timeIntervalSinceNow]); _lastDateThroughput = [[NSDate date] retain]; if (timeDiff <= 0) timeDiff = 1; // avoid division by zero double speedIn = diffIn / timeDiff; double speedOut = diffOut / timeDiff; speedIn = round(2.2f * speedIn) / 2.2f; speedOut = round(2.2f * speedOut) / 2.2f; [ self setMenubarText:[NSString stringWithFormat:@"%@s\n%@s", [self stringFromSpeed:speedOut], [self stringFromSpeed:speedIn]] ]; //NSLog(@"In %llu Out %llu Last In %llu Last Out %llu diffIn %llu diffOut %llu In %f Out %f Interval %f", ifIn, ifOut, _lastInThroughput, // _lastOutThroughput, diffIn, diffOut, speedIn, speedOut, timeDiff); } _lastInThroughput = ifIn; _lastOutThroughput = ifOut; } - (void) getMonthlyTransfers:(NSData *)data { if (data != nil) { NSString *stringData = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; NSRange startRange = [stringData rangeOfString:@"id=\"label\""]; NSString *smallData = [NSString stringWithString:[stringData substringFromIndex:startRange.location]]; NSString *keyIn = @"Incoming: "; NSString *keyOut = @"Outgoing: "; NSString *strMBytesIn = [smallData substringFromIndex:([smallData rangeOfString:keyIn].location + [keyIn length])]; strMBytesIn = [strMBytesIn substringToIndex:[strMBytesIn rangeOfString:@" "].location]; NSString *strMBytesOut = [smallData substringFromIndex:([smallData rangeOfString:keyOut].location + [keyOut length])]; strMBytesOut = [strMBytesOut substringToIndex:[strMBytesOut rangeOfString:@" "].location]; if ([strMBytesIn isEqualToString:@"0"] == false) { NSArray *monthData = [NSArray arrayWithObjects: strMBytesIn, strMBytesOut, nil]; [_transferData addObject:monthData]; } [stringData release]; [smallData release]; } else { //NSLog(@"%@", [NSDate date]); _transferDataRequestNumber = 0; [_transferData release]; _transferData = [[NSMutableArray alloc]init]; } if (_transferDataRequestNumber < 12) { NSDate *previousMonthDate = [self dateFromMonthsBack:_transferDataRequestNumber]; NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; [dateFormat setDateFormat:@"M-yyyy"]; NSString *url = [NSString stringWithFormat:@"ttgraph.cgi?%@", [dateFormat stringFromDate:previousMonthDate]]; [wrt_request_client getStatusUpdate:url delegate:self callback:@selector(getMonthlyTransfers:)]; _transferDataRequestNumber++; } else { /*uint8_t ii; NSLog(@"%@", [NSDate date]); for (ii=0; ii< [_transferData count]; ii++) { NSLog(@"%d %@ %@", ii, [[_transferData objectAtIndex:ii] objectAtIndex:0], [[_transferData objectAtIndex:ii] objectAtIndex:1]); }*/ [self populateMenuWanTransfers]; } } - (void) getRouterData:(NSData *)data { if (data != nil) { NSString *stringData = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; NSString *newStringData = [_statusStringData stringByAppendingString:stringData]; _statusStringData = [newStringData retain]; [stringData release]; } else { _statusStringData = @""; _statusDataRequestNumber = 0; } switch (_statusDataRequestNumber++) { case 0: [wrt_request_client getStatusUpdate:@"Status_Router.live.asp" delegate:self callback:@selector(getRouterData:)]; break; case 1: [wrt_request_client getStatusUpdate:@"Status_Internet.live.asp" delegate:self callback:@selector(getRouterData:)]; break; case 2: [wrt_request_client getStatusUpdate:@"Status_Lan.live.asp" delegate:self callback:@selector(getRouterData:)]; break; case 3: [wrt_request_client getStatusUpdate:@"Status_Wireless.live.asp" delegate:self callback:@selector(getRouterData:)]; break; case 4:/* // All the information here is redundant anyway... except possibly GPS data if some routers have that populated [wrt_request_client getStatusUpdate:@"Info.live.htm" delegate:self callback:@selector(getRouterData:)]; break; case 5:*/ default: //NSLog(@"%@", _statusStringData); // Populate the menu items [self populateMenuSystem]; [self populateMenuWan]; [self populateMenuClients]; [_appMenu popUpStatusItemMenu:AppMenu]; break; } } # pragma mark - # pragma mark Menu Handlers: - (IBAction) refreshMenu:(id)sender { NSLog(@"Refresh Menu"); if ([wrt_update_client getWrtReachable] == true) { [self getRouterData:nil]; } else { [_appMenu popUpStatusItemMenu:AppMenu]; } } - (void) populateMenuSystem { NSString *uptime = [wrt_request_client getKey:_statusStringData key:@"uptime"]; NSString *loadSplit = @", load average: "; if ([uptime length] > 0) { NSString *load = [uptime substringFromIndex:[uptime rangeOfString:loadSplit].location+[loadSplit length]]; uptime = [uptime substringToIndex:[uptime rangeOfString:@", load"].location]; // Cut the load uptime = [uptime substringFromIndex:[uptime rangeOfString:@" "].location+1]; // Trim uptime = [uptime stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[uptime substringToIndex:1] uppercaseString]]; // UCFirst [menuSystemUptime setTitle:uptime]; [menuSystemLoad setTitle:[NSString stringWithFormat:@"Load %@", load]]; [menuSystemLoad setHidden:false]; } else { [menuSystemUptime setTitle:@"Connected"]; [menuSystemLoad setHidden:true]; } NSString *memInfo = [wrt_request_client getKey:_statusStringData key:@"mem_info"]; // Remove any white spaces NSArray *parts = [memInfo componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; NSArray *filteredArray = [parts filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF != ''"]]; memInfo = [filteredArray componentsJoinedByString:@" "]; parts = nil; filteredArray = nil; // Remove any quotes parts = [memInfo componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\'"]]; filteredArray = [parts filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF != ''"]]; memInfo = [filteredArray componentsJoinedByString:@""]; NSArray *memData = [memInfo componentsSeparatedByString:@","]; uint32_t memTotal = strtoull([[memData objectAtIndex:8] UTF8String], NULL, 0); uint32_t memUsed = strtoull([[memData objectAtIndex:9] UTF8String], NULL, 0); NSString *memTitle = [NSString stringWithFormat:@"Memory %@/%@", [self stringFromSize:memUsed withUnits:false], [self stringFromSize:memTotal]]; [menuSystemMemory setTitle:memTitle]; [menuSystemMemoryIndicator setMaxValue: memTotal]; [menuSystemMemoryIndicator setDoubleValue: memUsed]; [menuSystemMemoryPercentage setTitle:[NSString stringWithFormat:@"%3.0f%%", ((memUsed / (double) memTotal)*100)]]; } - (void) populateMenuWan { NSString *wanip = [wrt_request_client getKey:_statusStringData key:@"ipinfo"]; NSRange startRange = [wanip rangeOfString:@" "]; wanip = [wanip substringFromIndex:(startRange.location+1)]; [menuWanIP setTitle:wanip]; NSString *wanStatus = [wrt_request_client getKey:_statusStringData key:@"wan_status"]; NSString *wanName = [wrt_request_client getKey:_statusStringData key:@"wan_shortproto"]; if ([wanName isEqualToString:@"pppoe"] == true) { wanName = @"PPPoE"; } else if ([wanName isEqualToString:@"static"] == true) { wanName = @"Static"; } else { wanName = [wanName uppercaseString]; } wanStatus = [wanStatus substringToIndex:[wanStatus rangeOfString:@"&"].location]; [menuWanStatus setTitle:[NSString stringWithFormat:@"%@ %@", wanName, wanStatus]]; NSString *wanUptime = [wrt_request_client getKey:_statusStringData key:@"wan_uptime"]; if ([wanStatus isEqualToString:@"Connected"] == true) { [menuWanUptime setHidden:false]; [menuWanSeparator setHidden:false]; [menuWanBandwidthGraph setEnabled:true]; [menuWanTrafficIn setHidden:false]; [menuWanTrafficOut setHidden:false]; [menuWanAvrgSpeedIn setHidden:false]; [menuWanAvrgSpeedOut setHidden:false]; [menuWanUptime setTitle:[NSString stringWithFormat:@"Up %@", wanUptime]]; NSString *trafficIn = [wrt_request_client getKey:_statusStringData key:@"ttraff_in"]; NSString *trafficOut = [wrt_request_client getKey:_statusStringData key:@"ttraff_out"]; uint64_t bytesIn = ([trafficIn longLongValue] * 1024 * 1024); uint64_t bytesOut = ([trafficOut longLongValue] * 1024 * 1024); [menuWanTrafficIn setTitle:[NSString stringWithFormat:@"In: %@", [self stringFromSize:bytesIn]]]; [menuWanTrafficOut setTitle:[NSString stringWithFormat:@"Out: %@", [self stringFromSize:bytesOut]]]; uint64_t secondsUp = [self secondsFromUptimeString:wanUptime]; double speedIn = bytesIn / secondsUp; double speedOut = bytesOut / secondsUp; speedIn = round(2.2f * speedIn) / 2.2f; speedOut = round(2.2f * speedOut) / 2.2f; [menuWanAvrgSpeedIn setTitle:[NSString stringWithFormat:@"Avrg In: %@/s", [self stringFromSpeed:speedIn]]]; [menuWanAvrgSpeedOut setTitle:[NSString stringWithFormat:@"Avrg Out: %@/s", [self stringFromSpeed:speedOut]]]; } else { [menuWanUptime setHidden:true]; [menuWanSeparator setHidden:true]; [menuWanBandwidthGraph setEnabled:false]; [menuWanTrafficIn setHidden:true]; [menuWanTrafficOut setHidden:true]; [menuWanAvrgSpeedIn setHidden:true]; [menuWanAvrgSpeedOut setHidden:true]; } NSString *wanDNS0 = [wrt_request_client getKey:_statusStringData key:@"wan_dns0"]; NSString *wanDNS1 = [wrt_request_client getKey:_statusStringData key:@"wan_dns1"]; NSString *wanDNS2 = [wrt_request_client getKey:_statusStringData key:@"wan_dns2"]; if ([wanDNS0 length] > 0) { [menuWanDNS setEnabled:true]; [menuWanDNSItem0 setTitle: wanDNS0]; [menuWanDNSItem0 setHidden:false]; } if ([wanDNS1 length] > 0) { [menuWanDNS setEnabled:true]; [menuWanDNSItem1 setTitle: wanDNS1]; [menuWanDNSItem1 setHidden:false]; } if ([wanDNS2 length] > 0) { [menuWanDNS setEnabled:true]; [menuWanDNSItem2 setTitle: wanDNS2]; [menuWanDNSItem2 setHidden:false]; } } - (void) populateMenuWanTransfers { int8_t ii; uint8_t count = [_transferData count]; NSMenuItem *monthlyMenu; for (ii = 0; ii < count; ii++) { if (ii > 0) { [menuWanTraffic addItem:[NSMenuItem separatorItem]]; } // Parse monthly transfer NSDate *previousMonthDate = [self dateFromMonthsBack:ii]; NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents *dateComp = [gregorian components:NSYearCalendarUnit | NSMonthCalendarUnit fromDate:previousMonthDate]; NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; [dateFormat setDateFormat:@"MM-yyyy"]; uint64_t bytesIn = ([[[_transferData objectAtIndex:ii] objectAtIndex:0] longLongValue] * 1024 * 1024); uint64_t bytesOut = ([[[_transferData objectAtIndex:ii] objectAtIndex:1] longLongValue] * 1024 * 1024); NSString *strMonthtlyTitle = [NSString stringWithFormat:@"%@\t%@/%@", [dateFormat stringFromDate:previousMonthDate], [self stringFromSize:bytesIn], [self stringFromSize:bytesOut]]; monthlyMenu = [[NSMenuItem alloc] initWithTitle:strMonthtlyTitle action:nil keyEquivalent:@""]; [menuWanTraffic addItem:monthlyMenu]; // Calculate average speed for the month uint64_t secondsInMonth; if (ii == 0) { NSDateComponents *todayComp = [gregorian components:NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:[NSDate date]]; secondsInMonth = ([todayComp day] * 24 * 60 * 60) + ([todayComp hour] * 60 * 60) + ([todayComp minute] * 60) + [todayComp second]; } else { NSCalendar* cal = [NSCalendar currentCalendar]; NSDateComponents* comps = [[[NSDateComponents alloc] init] autorelease]; [comps setMonth:[dateComp month]]; NSRange range = [cal rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:[cal dateFromComponents:comps]]; secondsInMonth = (range.length * 24 * 60 * 60); } NSLog(@"%llu", secondsInMonth); double speedIn = bytesIn / secondsInMonth; double speedOut = bytesOut / secondsInMonth; speedIn = round(2.2f * speedIn) / 2.2f; speedOut = round(2.2f * speedOut) / 2.2f; NSString *strMonthtlyAvrg = [NSString stringWithFormat:@"\t\t\t%@/s %@/s", [self stringFromSpeed:speedIn], [self stringFromSpeed:speedOut]]; monthlyMenu = [[NSMenuItem alloc] initWithTitle:strMonthtlyAvrg action:nil keyEquivalent:@""]; [menuWanTraffic addItem:monthlyMenu]; [gregorian release]; } } - (void) populateMenuClients { NSString *clientsStringData = [wrt_request_client getKey:_statusStringData key:@"arp_table"]; // Remove any white spaces NSArray *parts = [clientsStringData componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; NSArray *filteredArray = [parts filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF != ''"]]; clientsStringData = [filteredArray componentsJoinedByString:@" "]; parts = nil; filteredArray = nil; // Remove any quotes parts = [clientsStringData componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\'"]]; filteredArray = [parts filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF != ''"]]; clientsStringData = [filteredArray componentsJoinedByString:@""]; NSArray *clientsData = [clientsStringData componentsSeparatedByString:@","]; NSMenu *clientMenu; NSMenuItem *clientMenuItem; NSMenuItem *clientItem; NSString *ipconn = [wrt_request_client getKey:_statusStringData key:@"ip_conntrack"]; [menuClientsConnections setTitle:[NSString stringWithFormat:@"%@ Connection%@", ipconn, ([ipconn isEqualToString:@"1"] ? @"" : @"s")]]; uint16_t clientsCount = [clientsData count] / 4; [menuClientsCount setTitle:[NSString stringWithFormat:@"%lu Active Client%@", clientsCount, (clientsCount > 1 ? @"s" : @"")]]; // Clear the old client data uint16_t clientIndex; uint16_t firstItem = [menuClients indexOfItem:menuClientsSeparator]; if ([menuClients numberOfItems] > firstItem) { for (clientIndex = ([menuClients numberOfItems] - 1); clientIndex > (firstItem + 1); clientIndex--) { [menuClients removeItemAtIndex:clientIndex]; } } for (clientIndex = 0; clientIndex < [clientsData count]; clientIndex+=4) { // Allocate a new menu for the client data clientMenu = [[NSMenu alloc] init]; // Hostname clientMenuItem = [[NSMenuItem alloc] initWithTitle:[clientsData objectAtIndex:clientIndex] action:nil keyEquivalent:@""]; [clientMenuItem setSubmenu:[self createCopyMenuItem]]; [clientMenu addItem:clientMenuItem]; // IP clientMenuItem = [[NSMenuItem alloc] initWithTitle:[clientsData objectAtIndex:(clientIndex+1)] action:nil keyEquivalent:@""]; [clientMenuItem setSubmenu:[self createCopyMenuItem]]; [clientMenu addItem:clientMenuItem]; // MAC clientMenuItem = [[NSMenuItem alloc] initWithTitle:[[clientsData objectAtIndex:(clientIndex+2)] uppercaseString] action:nil keyEquivalent:@""]; [clientMenuItem setSubmenu:[self createCopyMenuItem]]; [clientMenu addItem:clientMenuItem]; // Connections uint16_t conn = strtoull([[clientsData objectAtIndex:(clientIndex+3)] UTF8String], NULL, 0); clientMenuItem = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"%lu Connection%@", conn, (conn > 1 ? @"s" : @"")] action:nil keyEquivalent:@""]; [clientMenu addItem:clientMenuItem]; clientItem = [[NSMenuItem alloc] initWithTitle:[clientsData objectAtIndex:clientIndex] action:nil keyEquivalent:@""]; [clientItem setSubmenu:clientMenu]; [menuClients addItem:clientItem]; } } - (NSMenu *) createCopyMenuItem { NSMenu *copyMenu = [[NSMenu alloc] init]; NSMenuItem *copyMenuItem = [[NSMenuItem alloc] initWithTitle:@"Copy" action:@selector(copyParentMenuTitle:) keyEquivalent:@""]; [copyMenuItem setEnabled:true]; [copyMenuItem setTarget:self]; [copyMenu addItem:copyMenuItem]; return [copyMenu retain]; } # pragma mark - # pragma mark Utilities: - (IBAction) copyParentMenuTitle:(id)sender { NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; [pasteBoard declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] owner: nil]; [pasteBoard setString:[[sender parentItem] title] forType:NSStringPboardType]; } - (NSString *) stringFromSize:(uint64_t)theBytes { return [self stringFromSize:theBytes withUnits:true]; } - (NSString *) stringFromSize:(uint64_t)theBytes withUnits:(BOOL)withUnits { NSString *units = @""; double floatSize = theBytes; if (withUnits == true) units = @"B"; if (theBytes<1023) return([NSString stringWithFormat:@"%llu%@", theBytes, units]); floatSize = floatSize / 1024; if (withUnits == true) units = @"KiB"; if (floatSize<1023) return([NSString stringWithFormat:@"%1.1f%@", floatSize, units]); floatSize = floatSize / 1024; if (withUnits == true) units = @"MiB"; if (floatSize<1023) return([NSString stringWithFormat:@"%1.2f%@", floatSize, units]); floatSize = floatSize / 1024; if (withUnits == true) units = @"GiB"; if (floatSize<1023) return([NSString stringWithFormat:@"%1.2f%@", floatSize, units]); floatSize = floatSize / 1024; if (withUnits == true) units = @"TiB"; return([NSString stringWithFormat:@"%1.2f%@", floatSize, units]); } - (NSString *) stringFromSpeed:(uint64_t)theBytes { NSString *suffix; if (useBytes == false) { theBytes *= 8; } double floatSize = theBytes; suffix = (useBytes ? @"B" : @"b"); if (theBytes<1023) return([NSString stringWithFormat:@"%llu%@", theBytes, suffix]); floatSize = floatSize / 1024; suffix = (useBytes ? @"KiB" : @"Kb"); if (floatSize<1023) return([NSString stringWithFormat:@"%1.1f%@", floatSize, suffix]); floatSize = floatSize / 1024; suffix = (useBytes ? @"MiB" : @"Mb"); if (floatSize<1023) return([NSString stringWithFormat:@"%1.2f%@", floatSize, suffix]); floatSize = floatSize / 1024; suffix = (useBytes ? @"GiB" : @"Gb"); if (floatSize<1023) return([NSString stringWithFormat:@"%1.2f%@", floatSize, suffix]); floatSize = floatSize / 1024; suffix = (useBytes ? @"TiB" : @"Tb"); return([NSString stringWithFormat:@"%1.2f%@", floatSize, suffix]); } - (uint64_t) secondsFromUptimeString:(NSString *)uptime { NSString *strUptime = [NSString stringWithString:uptime]; uint64_t seconds = 0; NSString *keyDay = @" day, "; NSRange rangeDay = [strUptime rangeOfString:keyDay]; NSString *keyDays = @" days, "; NSRange rangeDays = [strUptime rangeOfString:keyDays]; if (rangeDay.location != NSNotFound) { seconds += 86400; // One day extra strUptime = [strUptime substringFromIndex:(rangeDay.location + [keyDay length])]; } else if (rangeDays.location != NSNotFound) { uint32_t days = strtoull([[strUptime substringToIndex:rangeDays.location] UTF8String], NULL, 0); seconds += (days * 86400); strUptime = [strUptime substringFromIndex:(rangeDays.location + [keyDays length])]; } NSArray *parts = [strUptime componentsSeparatedByString:@":"]; uint8_t ii; for (ii = 0; ii < [parts count]; ii++) { double multiplicator = pow(60, (2 - ii)); if (multiplicator == 0) multiplicator = 1; seconds += (multiplicator * strtoull([[parts objectAtIndex:ii] UTF8String], NULL, 0)); } return seconds; } - (NSDate *) dateFromMonthsBack:(uint8_t)monthsBack { NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents *components = [[NSDateComponents alloc] init]; [components setMonth:(-monthsBack)]; NSDate *prevMonth = [gregorian dateByAddingComponents:components toDate:[NSDate date] options:0]; NSDateComponents *previoustMonthComponents = [gregorian components:NSYearCalendarUnit | NSMonthCalendarUnit fromDate:prevMonth]; [components release]; [gregorian autorelease]; return [gregorian dateFromComponents:previoustMonthComponents]; } @end