// // 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 //@synthesize window; //- (void)applicationDidFinishLaunching:(NSNotification *)aNotification - (void) awakeFromNib { // Insert code here to initialize your application [self showMenubar]; _wrtReachable = false; defaults = [NSUserDefaults standardUserDefaults]; // check if the app is configured yet if (![defaults boolForKey:@"configured"]) { [self initDefaults]; } NSLog(@"Reading defaults..."); [self readDefaults]; // initialize the client wrt_client = [[WRTStatusClient alloc] initWithHostname:hostname port:port protocol:protocol username:username password:password]; [wrt_client getConnectionStatus]; NSLog(@"Status %@ wan port: %@", ([wrt_client wrtReachable] ? @"Up" : @"Down"), [wrt_client getWanPort]); _readTimer = [NSTimer scheduledTimerWithTimeInterval:refreshTime+1 target:self selector:@selector(updateThroughput:) userInfo:nil repeats:YES]; [_readTimer fire]; } - (void) dealloc { //[_readTimer invalidate]; [AppMenu release]; [_appMenu release]; [ConfigPanel release]; //[BandwidthViewer release]; [modalWindow release]; [super dealloc]; } - (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:@"192.168.1.1" 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"]; // sync the defaults to disk //[defaults registerDefaults:appDefaults]; [defaults synchronize]; // TODO: Add modal alert "First launch" here... [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 registerDefaults:appDefaults]; [defaults synchronize]; } - (void) terminate:(id)sender { [_readTimer invalidate]; [[NSUserDefaults standardUserDefaults] synchronize]; [self dealloc]; [[NSApplication sharedApplication] terminate:self]; } - (void) showMenubar { NSLog(@"Showing Menu Item"); NSStatusBar* bar = [NSStatusBar systemStatusBar]; _appMenu = [bar statusItemWithLength:NSVariableStatusItemLength]; [_appMenu setAction:@selector(refreshMenu:)]; [_appMenu setTarget:self]; [_appMenu retain]; //[self setMenubarText:@"000KB/s\n000KB/s"]; //BOOL showIcon = [[NSUserDefaults standardUserDefaults] boolForKey:@"showMenuIcon"]; //if (showIcon == true) { [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) showConfigPanel:(id)sender { [configFieldShowIcon setState:([defaults boolForKey:@"showMenuIcon"] ? 1 : 0)]; [configFieldUseBytes setState:([defaults boolForKey:@"useBytes"] ? 1 : 0)]; if (hostname != nil) { [configFieldHostname setStringValue:hostname]; } // TODO [configFieldPort setIntValue:[defaults integerForKey:@"port"]]; [configFieldRefresh setIntegerValue:[defaults integerForKey:@"refreshTime"]]; [configLabelRefresh setStringValue:[NSString stringWithFormat:@"%d s", ([defaults integerForKey:@"refreshTime"] + 1)]]; [ConfigPanel makeKeyAndOrderFront:nil]; } - (void) hideConfigPanel:(id)sender { /*NSString *hostname = [[NSUserDefaults standardUserDefaults] stringForKey:@"hostname"]; if (hostname == nil && [[sender title] isEqualToString:@"Cancel"]) { // TODO: Add modal alert "will quit if not configured" [self terminate:nil]; } */ [ConfigPanel orderOut:nil]; } - (void) showBandwidthViewer:(id)sender { //NSURLRequest *request = [[wrt_client requestForBandwidthViewerForInterface:[wrt_client getWanPort]] retain]; NSString *urlAddress = [NSString stringWithFormat:@"%@://%@:%@@%@:%d/graph_if.svg?%@", protocol, username, password, hostname, port, [wrt_client getWanPort]]; NSLog(@"Building request form %@", urlAddress); NSURL *url = [NSURL URLWithString:urlAddress]; NSURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: url]; [ [BandwidthViewerWebView mainFrame] loadRequest: [request autorelease] ]; [BandwidthViewer makeKeyAndOrderFront:nil]; } - (void) hideBandwidthViewer:(id)sender { [BandwidthViewer orderOut:nil]; [BandwidthViewer release]; } - (void) setConfigHostname:(id)sender { NSLog(@"%@", [sender title]); } - (IBAction) setConfigProtocol:(id)sender { NSLog(@"%@", [sender title]); if ([sender state] == NSOnState) { NSLog(@"Yes"); //NSLog(@"%s", [sender title]); } else { NSLog(@"No"); //NSLog(@"%s", [sender title]); } } - (void) setConfigPort:(id)sender { } - (void) setConfigRefresh:(id)sender { [configLabelRefresh setStringValue:[NSString stringWithFormat:@"%u s", ([sender integerValue] + 1)]]; } - (void) setConfigWan:(id)sender { } - (void) setConfigBytes:(id)sender { } - (void) setConfigIcon:(id)sender { } - (void) saveConfig:(id)sender { [configStateStatus startAnimation:nil]; [configStateStatus setHidden:false]; //WRTRequest *wrtr = [[WRTRequest alloc] init]; // TODO check that the request is actually successful hostname = [configFieldHostname stringValue]; [defaults setValue:hostname forKey:@"hostname"]; port = [configFieldPort intValue]; [defaults setInteger:port forKey:@"port"]; //NSLog(@"%d", [configFieldProtocol state]); //NSLog(@"%d", [configFieldProtocolHTTP state]); //NSLog(@"%d", [configFieldProtocolHTTPS state]); refreshTime = [configFieldRefresh integerValue]; [defaults setInteger:refreshTime forKey:@"refreshTime"]; [_readTimer invalidate]; _readTimer = nil; _readTimer = [NSTimer scheduledTimerWithTimeInterval:refreshTime+1 target:self selector:@selector(updateThroughput:) userInfo:nil repeats:YES]; [_readTimer fire]; useBytes = ([configFieldUseBytes state] == 1 ? true: false); [defaults setBool:useBytes forKey:@"useBytes"]; if ([configFieldShowIcon state] == NSOffState && [defaults boolForKey:@"showMenuIcon"] == true) { [self hideMenubarIcon]; } else if ([configFieldShowIcon state] == NSOnState && [defaults boolForKey:@"showMenuIcon"] == false) { [self showMenubarIcon:[wrt_client wrtReachable]]; } showMenuIcon = ([configFieldShowIcon state] == 1 ? true: false); [defaults setBool:showMenuIcon forKey:@"showMenuIcon"]; [configStateStatus stopAnimation:nil]; [configStateStatus setHidden:true]; [defaults synchronize]; [self hideConfigPanel:nil]; } - (void) updateThroughput:(NSTimer*)timer { NSLog(@"Status %@ wan port: %@", ([wrt_client wrtReachable] ? @"Up" : @"Down"), [wrt_client getWanPort]); if ([wrt_client wrtReachable] == true && _wrtReachable == false) { _wrtReachable = true; if (showMenuIcon == true) { [self showMenubarIcon:true]; } else { [self hideMenubarIcon]; } } else if ([wrt_client wrtReachable] == false && _wrtReachable == true) { _wrtReachable = false; [self showMenubarIcon:false]; } if (_wrtReachable == true) { [wrt_client getStatusUpdate:[NSString stringWithFormat:@"fetchif.cgi?%@", [wrt_client getWanPort]] delegate:self callback:@selector(throughputCallback:)]; } } - (void) throughputCallback:(NSData *)data { NSString *stringData = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; NSString *key = [NSString stringWithFormat:@"%@:", [wrt_client getWanPort]]; stringData = [stringData substringFromIndex:([stringData rangeOfString:key].location + [key length])]; NSArray *parts = [stringData componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; NSArray *filteredArray = [parts filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF != ''"]]; stringData = [filteredArray componentsJoinedByString:@" "]; NSArray *listItems = [stringData componentsSeparatedByString:@" "]; 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)doUpdateStatus:(NSData *)data { [wrt_client getStatusUpdate:@"Status_Internet.live.asp" delegate:self callback:@selector(wanRequestCallback:)]; NSString *stringData = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; NSString *ipconn = [wrt_client getKey:stringData key:@"ip_conntrack"]; [menuClientsConnections setTitle:[NSString stringWithFormat:@"%@ Connection%@", ipconn, ([ipconn isEqualToString:@"1"] ? @"" : @"s")]]; NSString *wanip = [wrt_client getKey:stringData key:@"ipinfo"]; NSRange startRange = [wanip rangeOfString:@" "]; wanip = [wanip substringFromIndex:(startRange.location+1)]; [menuWanIP setTitle:wanip]; NSString *uptime = [wrt_client getKey:stringData 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 [menuUptime setTitle:uptime]; //[menuUptime setHidden:false]; [menuLoad setTitle:load]; [menuLoad setHidden:false]; //[[AppMenu itemAtIndex:2] setHidden:false]; } else { [menuUptime setTitle:@"Connected"]; //[menuUptime setHidden:true]; [menuLoad setHidden:true]; //[[AppMenu itemAtIndex:2] setHidden:true]; } /* NSString *memInfo = [wrt_client getKey:stringData 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:@","]; unint32_t memTotal = strtoull([[memData objectAtIndex:17] UTF8String], NULL, 0); unint32_t memFree = strtoull([[memData objectAtIndex:21] UTF8String], NULL, 0); */ } - (void) refreshMenu:(id)sender { NSLog(@"Refresh Menu"); if ([wrt_client wrtReachable] == true) { [_readTimer invalidate]; _readTimer = nil; [wrt_client getStatusUpdate:@"Status_Router.live.asp" delegate:self callback:@selector(doUpdateStatus:)]; } else { [_appMenu popUpStatusItemMenu:AppMenu]; } } - (void) refreshSystemMenu:(id)sender { } - (void) refreshWanMenu:(id)sender { } - (void) wanRequestCallback:(NSData *)data { [wrt_client getStatusUpdate:@"Status_Lan.live.asp" delegate:self callback:@selector(cbClientsRequest:)]; NSString *stringData = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; NSString *wanStatus = [wrt_client getKey:stringData key:@"wan_status"]; NSString *wanName = [wrt_client getKey:stringData 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]]; /* if ([_appMenu image] != nil) { [self showMenubarIcon:[wanStatus isEqualToString:@"Connected"]]; } */ NSString *wanUptime = [wrt_client getKey:stringData key:@"wan_uptime"]; if ([wanStatus isEqualToString:@"Connected"] == true) { [menuWanUptime setTitle:wanUptime]; [menuWanUptime setHidden:false]; [menuWanSeparator setHidden:false]; [menuWanBandwidthGraph setEnabled:true]; [menuWanTrafficIn setHidden:false]; [menuWanTrafficOut setHidden:false]; } else { [menuWanUptime setHidden:true]; [menuWanSeparator setHidden:true]; [menuWanBandwidthGraph setEnabled:false]; [menuWanTrafficIn setHidden:true]; [menuWanTrafficOut setHidden:true]; } NSString *trafficIn = [wrt_client getKey:stringData key:@"ttraff_in"]; NSString *trafficOut = [wrt_client getKey:stringData key:@"ttraff_out"]; trafficIn = [self stringFromSize:([trafficIn longLongValue] * 1024 * 1024)]; trafficOut = [self stringFromSize:([trafficOut longLongValue] * 1024 * 1024)]; [menuWanTrafficIn setTitle:[NSString stringWithFormat:@"In: %@", trafficIn]]; [menuWanTrafficOut setTitle:[NSString stringWithFormat:@"Out: %@", trafficOut]]; NSString *wanDNS0 = [wrt_client getKey:stringData key:@"wan_dns0"]; NSString *wanDNS1 = [wrt_client getKey:stringData key:@"wan_dns1"]; NSString *wanDNS2 = [wrt_client getKey:stringData 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]; } [stringData release]; } - (void) refreshClientsMenu:(id)sender { } - (void) cbClientsRequest:(NSData*)data { NSString * clientsStringData; NSString *stringData = [ [NSString alloc] initWithData:data encoding:NSASCIIStringEncoding ]; NSString *keyData = @"{arp_table::"; clientsStringData = [ stringData substringFromIndex:([stringData rangeOfString:keyData].location + [keyData length]) ]; clientsStringData = [ clientsStringData substringToIndex:[clientsStringData rangeOfString:@"}"].location ]; // 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; NSMenu *copyMenu; NSMenuItem *copyMenuItem; NSMenuItem *clientMenuItem; NSMenuItem *clientItem; uint32_t clientsCount = [clientsData count] / 4; [menuClientsCount setTitle:[NSString stringWithFormat:@"%lu Active Client%@", clientsCount, (clientsCount > 1 ? @"s" : @"")]]; // Clear the old client data uint32_t clientIndex; uint32_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) { /*NSLog(@"Client: %@ IP: %@ MAC: %@ Connections: %@", [clientsData objectAtIndex:clientIndex], [clientsData objectAtIndex:clientIndex+1], [clientsData objectAtIndex:clientIndex+2], [clientsData objectAtIndex:clientIndex+3]); */ clientMenu = [[NSMenu alloc] init]; // Hostname copyMenu = [[NSMenu alloc] init]; copyMenuItem = [[NSMenuItem alloc] initWithTitle:@"Copy" action:@selector(copyParentMenuTitle:) keyEquivalent:@""]; [copyMenuItem setEnabled:true]; [copyMenuItem setTarget:self]; [copyMenu addItem:copyMenuItem]; clientMenuItem = [[NSMenuItem alloc] initWithTitle:[clientsData objectAtIndex:clientIndex] action:nil keyEquivalent:@""]; [clientMenuItem setSubmenu:copyMenu]; [clientMenu addItem:clientMenuItem]; // IP copyMenu = [[NSMenu alloc] init]; copyMenuItem = [[NSMenuItem alloc] initWithTitle:@"Copy" action:@selector(copyParentMenuTitle:) keyEquivalent:@""]; [copyMenuItem setEnabled:true]; [copyMenuItem setTarget:self]; [copyMenu addItem:copyMenuItem]; clientMenuItem = [[NSMenuItem alloc] initWithTitle:[clientsData objectAtIndex:(clientIndex+1)] action:nil keyEquivalent:@""]; [clientMenuItem setSubmenu:copyMenu]; [clientMenu addItem:clientMenuItem]; // MAC copyMenu = [[NSMenu alloc] init]; copyMenuItem = [[NSMenuItem alloc] initWithTitle:@"Copy" action:@selector(copyParentMenuTitle:) keyEquivalent:@""]; [copyMenuItem setEnabled:true]; [copyMenuItem setTarget:self]; [copyMenu addItem:copyMenuItem]; clientMenuItem = [[NSMenuItem alloc] initWithTitle:[clientsData objectAtIndex:(clientIndex+2)] action:nil keyEquivalent:@""]; [clientMenuItem setSubmenu:copyMenu]; [clientMenu addItem:clientMenuItem]; // Connections uint32_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]; } [_appMenu popUpStatusItemMenu:AppMenu]; _readTimer = [NSTimer scheduledTimerWithTimeInterval:refreshTime+1 target:self selector:@selector(updateThroughput:) userInfo:nil repeats:YES]; [_readTimer fire]; } - (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 { double floatSize = theBytes; if (theBytes<1023) return([NSString stringWithFormat:@"%lluB", theBytes]); floatSize = floatSize / 1024; if (floatSize<1023) return([NSString stringWithFormat:@"%1.1fKiB", floatSize]); floatSize = floatSize / 1024; if (floatSize<1023) return([NSString stringWithFormat:@"%1.2fMiB", floatSize]); floatSize = floatSize / 1024; if (floatSize<1023) return([NSString stringWithFormat:@"%1.2fGiB", floatSize]); floatSize = floatSize / 1024; return([NSString stringWithFormat:@"%1.2fTiB", floatSize]); } - (NSString *) stringFromSpeed:(uint64_t)theBytes { unsigned int minSize = /*(useBytes ? */1023/* : 999)*/; unsigned int divSize = /*(useBytes ? */1024/* : 1000)*/; NSString *suffix; if (useBytes == false) { theBytes *= 8; } double floatSize = theBytes; suffix = (useBytes ? @"B" : @"b"); if (theBytes