/* Utility functions Copyright 2013 Thincast Technologies GmbH, Authors: Martin Fleisz, Dorian Johnson This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #import "Utils.h" #import "OrderedDictionary.h" #import "TSXAdditions.h" #import #import #import "config.h" #include #include #include #include #include BOOL ScanHostNameAndPort(NSString *address, NSString **host, unsigned short *port) { *host = @""; *port = 0; if (![address length]) return NO; NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"rdp://%@", address]]; if (!url || ![[url host] length]) return NO; *host = [url host]; *port = [[url port] unsignedShortValue]; return YES; } #pragma mark - #pragma mark Working with Screen Resolutions NSString *LocalizedFitScreen() { return NSLocalizedString(@"Automatic", @"Screen resolution selector: Automatic resolution " @"(Full Screen on iPad, reasonable size on iPhone)"); } NSString *LocalizedCustom() { return NSLocalizedString(@"Custom", @"Screen resolution selector: Custom"); } BOOL ScanScreenResolution(NSString *description, int *width, int *height, TSXScreenOptions *type) { *height = 0; *width = 0; *type = TSXScreenOptionFixed; if ([description isEqualToString:LocalizedFitScreen()]) { *type = TSXScreenOptionFitScreen; return YES; } else if ([description isEqualToString:LocalizedCustom()]) { *type = TSXScreenOptionCustom; return YES; } NSArray *resolution_components = [description componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"x*×"]]; if ([resolution_components count] != 2) return NO; *width = [[resolution_components objectAtIndex:0] intValue]; *height = [[resolution_components objectAtIndex:1] intValue]; return YES; } NSString *ScreenResolutionDescription(TSXScreenOptions type, int width, int height) { if (type == TSXScreenOptionFitScreen) return LocalizedFitScreen(); else if (type == TSXScreenOptionCustom) return LocalizedCustom(); return [NSString stringWithFormat:@"%dx%d", width, height]; } NSDictionary *SelectionForColorSetting() { OrderedDictionary *dict = [OrderedDictionary dictionaryWithCapacity:3]; [dict setValue:[NSNumber numberWithInt:8] forKey:NSLocalizedString(@"Palette Color (8 Bit)", @"8 bit color selection")]; [dict setValue:[NSNumber numberWithInt:15] forKey:NSLocalizedString(@"High Color (15 Bit)", @"15 bit color selection")]; [dict setValue:[NSNumber numberWithInt:16] forKey:NSLocalizedString(@"High Color (16 Bit)", @"16 bit color selection")]; [dict setValue:[NSNumber numberWithInt:24] forKey:NSLocalizedString(@"True Color (24 Bit)", @"24 bit color selection")]; [dict setValue:[NSNumber numberWithInt:32] forKey:NSLocalizedString(@"Highest Quality (32 Bit)", @"32 bit color selection")]; return dict; } NSArray *ResolutionModes() { NSArray *array = [NSArray arrayWithObjects:ScreenResolutionDescription(TSXScreenOptionFitScreen, 0, 0), ScreenResolutionDescription(TSXScreenOptionFixed, 640, 480), ScreenResolutionDescription(TSXScreenOptionFixed, 800, 600), ScreenResolutionDescription(TSXScreenOptionFixed, 1024, 768), ScreenResolutionDescription(TSXScreenOptionFixed, 1280, 1024), ScreenResolutionDescription(TSXScreenOptionFixed, 1440, 900), ScreenResolutionDescription(TSXScreenOptionFixed, 1440, 1050), ScreenResolutionDescription(TSXScreenOptionFixed, 1600, 1200), ScreenResolutionDescription(TSXScreenOptionFixed, 1920, 1080), ScreenResolutionDescription(TSXScreenOptionFixed, 1920, 1200), ScreenResolutionDescription(TSXScreenOptionCustom, 0, 0), nil]; return array; } #pragma mark Working with Security Protocols NSString *LocalizedAutomaticSecurity() { return NSLocalizedString(@"Automatic", @"Automatic protocl security selection"); } NSString *ProtocolSecurityDescription(TSXProtocolSecurityOptions type) { if (type == TSXProtocolSecurityNLA) return @"NLA"; else if (type == TSXProtocolSecurityTLS) return @"TLS"; else if (type == TSXProtocolSecurityRDP) return @"RDP"; return LocalizedAutomaticSecurity(); } BOOL ScanProtocolSecurity(NSString *description, TSXProtocolSecurityOptions *type) { *type = TSXProtocolSecurityRDP; if ([description isEqualToString:@"NLA"]) { *type = TSXProtocolSecurityNLA; return YES; } else if ([description isEqualToString:@"TLS"]) { *type = TSXProtocolSecurityTLS; return YES; } else if ([description isEqualToString:@"RDP"]) { *type = TSXProtocolSecurityRDP; return YES; } else if ([description isEqualToString:LocalizedAutomaticSecurity()]) { *type = TSXProtocolSecurityAutomatic; return YES; } return NO; } NSDictionary *SelectionForSecuritySetting() { OrderedDictionary *dict = [OrderedDictionary dictionaryWithCapacity:4]; [dict setValue:[NSNumber numberWithInt:TSXProtocolSecurityAutomatic] forKey:ProtocolSecurityDescription(TSXProtocolSecurityAutomatic)]; [dict setValue:[NSNumber numberWithInt:TSXProtocolSecurityRDP] forKey:ProtocolSecurityDescription(TSXProtocolSecurityRDP)]; [dict setValue:[NSNumber numberWithInt:TSXProtocolSecurityTLS] forKey:ProtocolSecurityDescription(TSXProtocolSecurityTLS)]; [dict setValue:[NSNumber numberWithInt:TSXProtocolSecurityNLA] forKey:ProtocolSecurityDescription(TSXProtocolSecurityNLA)]; return dict; } #pragma mark - #pragma mark Bookmarks #import "Bookmark.h" NSMutableArray *FilterBookmarks(NSArray *bookmarks, NSArray *filter_words) { NSMutableArray *matching_items = [NSMutableArray array]; NSArray *searched_keys = [NSArray arrayWithObjects:@"label", @"params.hostname", @"params.username", @"params.domain", nil]; for (ComputerBookmark *cur_bookmark in bookmarks) { double match_score = 0.0; for (int i = 0; i < [searched_keys count]; i++) { NSString *val = [cur_bookmark valueForKeyPath:[searched_keys objectAtIndex:i]]; if (![val isKindOfClass:[NSString class]] || ![val length]) continue; for (NSString *word in filter_words) if ([val rangeOfString:word options:(NSCaseInsensitiveSearch | NSWidthInsensitiveSearch)] .location != NSNotFound) match_score += (1.0 / [filter_words count]) * pow(2, [searched_keys count] - i); } if (match_score > 0.001) [matching_items addObject:[NSDictionary dictionaryWithObjectsAndKeys:cur_bookmark, @"bookmark", [NSNumber numberWithFloat:match_score], @"score", nil]]; } [matching_items sortUsingComparator:^NSComparisonResult(NSDictionary *obj1, NSDictionary *obj2) { return [[obj2 objectForKey:@"score"] compare:[obj1 objectForKey:@"score"]]; }]; return matching_items; } NSMutableArray *FilterHistory(NSArray *history, NSString *filterStr) { NSMutableArray *result = [NSMutableArray array]; for (NSString *item in history) { if ([item rangeOfString:filterStr].location != NSNotFound) [result addObject:item]; } return result; } #pragma mark Version Info NSString *TSXAppFullVersion() { return [NSString stringWithUTF8String:GIT_REVISION]; } #pragma mark iPad/iPhone detection BOOL IsPad() { #ifdef UI_USER_INTERFACE_IDIOM return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad); #else return NO; #endif } BOOL IsPhone() { #ifdef UI_USER_INTERFACE_IDIOM return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone); #else return NO; #endif } // set mouse buttons swapped flag static BOOL g_swap_mouse_buttons = NO; void SetSwapMouseButtonsFlag(BOOL swapped) { g_swap_mouse_buttons = swapped; } // set invert scrolling flag static BOOL g_invert_scrolling = NO; void SetInvertScrollingFlag(BOOL invert) { g_invert_scrolling = invert; } // return event value for left mouse button int GetLeftMouseButtonClickEvent(BOOL down) { if (g_swap_mouse_buttons) return (PTR_FLAGS_BUTTON2 | (down ? PTR_FLAGS_DOWN : 0)); else return (PTR_FLAGS_BUTTON1 | (down ? PTR_FLAGS_DOWN : 0)); } // return event value for right mouse button int GetRightMouseButtonClickEvent(BOOL down) { if (g_swap_mouse_buttons) return (PTR_FLAGS_BUTTON1 | (down ? PTR_FLAGS_DOWN : 0)); else return (PTR_FLAGS_BUTTON2 | (down ? PTR_FLAGS_DOWN : 0)); } // get mouse move event int GetMouseMoveEvent() { return (PTR_FLAGS_MOVE); } // return mouse wheel event int GetMouseWheelEvent(BOOL down) { if (g_invert_scrolling) down = !down; if (down) return (PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | (0x0088)); else return (PTR_FLAGS_WHEEL | (0x0078)); } // scrolling gesture detection delta CGFloat GetScrollGestureDelta() { return 10.0f; } // this hack activates the iphone's WWAN interface in case it is offline void WakeUpWWAN() { NSURL *url = [[[NSURL alloc] initWithString:@"http://www.nonexistingdummyurl.com"] autorelease]; // NSData * data = [NSData dataWithContentsOfURL:url]; // we don't need data but assigning one causes a "data not // used" compiler warning } #pragma mark System Info functions NSString *TSXGetPrimaryMACAddress(NSString *sep) { NSString *macaddress = @""; struct ifaddrs *addrs; if (getifaddrs(&addrs) < 0) { NSLog(@"getPrimaryMACAddress: getifaddrs failed."); return macaddress; } for (struct ifaddrs *cursor = addrs; cursor != NULL; cursor = cursor->ifa_next) { if (strcmp(cursor->ifa_name, "en0")) continue; if ((cursor->ifa_addr->sa_family == AF_LINK) && (((struct sockaddr_dl *)cursor->ifa_addr)->sdl_type == 0x6 /*IFT_ETHER*/)) { struct sockaddr_dl *dlAddr = (struct sockaddr_dl *)cursor->ifa_addr; if (dlAddr->sdl_alen != 6) continue; unsigned char *base = (unsigned char *)&dlAddr->sdl_data[dlAddr->sdl_nlen]; macaddress = [NSString hexStringFromData:base ofSize:6 withSeparator:sep afterNthChar:1]; break; } } freeifaddrs(addrs); return macaddress; } BOOL TSXDeviceHasJailBreak() { if ([[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/Cydia.app/"]) return YES; if ([[NSFileManager defaultManager] fileExistsAtPath:@"/etc/apt/"]) return YES; return NO; } NSString *TSXGetPlatform() { size_t size; sysctlbyname("hw.machine", NULL, &size, NULL, 0); char *machine = malloc(size); sysctlbyname("hw.machine", machine, &size, NULL, 0); NSString *platform = [NSString stringWithCString:machine encoding:NSASCIIStringEncoding]; free(machine); return platform; }