FreeRDP
Utils.m
1 /*
2  Utility functions
3 
4  Copyright 2013 Thincast Technologies GmbH, Authors: Martin Fleisz, Dorian Johnson
5 
6  This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
7  If a copy of the MPL was not distributed with this file, You can obtain one at
8  http://mozilla.org/MPL/2.0/.
9  */
10 
11 #import "Utils.h"
12 #import "OrderedDictionary.h"
13 #import "TSXAdditions.h"
14 
15 #import <freerdp/input.h>
16 #import <freerdp/version.h>
17 #import <freerdp/config.h>
18 
19 #include <sys/types.h>
20 #include <sys/sysctl.h>
21 #include <sys/socket.h>
22 #include <ifaddrs.h>
23 #include <net/if_dl.h>
24 
25 BOOL ScanHostNameAndPort(NSString *address, NSString **host, unsigned short *port)
26 {
27  *host = @"";
28  *port = 0;
29 
30  if (![address length])
31  return NO;
32 
33  NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"rdp://%@", address]];
34 
35  if (!url || ![[url host] length])
36  return NO;
37 
38  *host = [url host];
39  *port = [[url port] unsignedShortValue];
40  return YES;
41 }
42 
43 #pragma mark -
44 #pragma mark Working with Screen Resolutions
45 
46 NSString *LocalizedFitScreen()
47 {
48  return NSLocalizedString(@"Automatic", @"Screen resolution selector: Automatic resolution "
49  @"(Full Screen on iPad, reasonable size on iPhone)");
50 }
51 
52 NSString *LocalizedCustom()
53 {
54  return NSLocalizedString(@"Custom", @"Screen resolution selector: Custom");
55 }
56 
57 BOOL ScanScreenResolution(NSString *description, int *width, int *height, TSXScreenOptions *type)
58 {
59  *height = 0;
60  *width = 0;
61  *type = TSXScreenOptionFixed;
62 
63  if ([description isEqualToString:LocalizedFitScreen()])
64  {
65  *type = TSXScreenOptionFitScreen;
66  return YES;
67  }
68  else if ([description isEqualToString:LocalizedCustom()])
69  {
70  *type = TSXScreenOptionCustom;
71  return YES;
72  }
73 
74  NSArray *resolution_components = [description
75  componentsSeparatedByCharactersInSet:[NSCharacterSet
76  characterSetWithCharactersInString:@"x*×"]];
77 
78  if ([resolution_components count] != 2)
79  return NO;
80 
81  *width = [[resolution_components objectAtIndex:0] intValue];
82  *height = [[resolution_components objectAtIndex:1] intValue];
83  return YES;
84 }
85 
86 NSString *ScreenResolutionDescription(TSXScreenOptions type, int width, int height)
87 {
88  if (type == TSXScreenOptionFitScreen)
89  return LocalizedFitScreen();
90  else if (type == TSXScreenOptionCustom)
91  return LocalizedCustom();
92 
93  return [NSString stringWithFormat:@"%dx%d", width, height];
94 }
95 
96 NSDictionary *SelectionForColorSetting()
97 {
98  OrderedDictionary *dict = [OrderedDictionary dictionaryWithCapacity:3];
99  [dict setValue:[NSNumber numberWithInt:8]
100  forKey:NSLocalizedString(@"Palette Color (8 Bit)", @"8 bit color selection")];
101  [dict setValue:[NSNumber numberWithInt:15]
102  forKey:NSLocalizedString(@"High Color (15 Bit)", @"15 bit color selection")];
103  [dict setValue:[NSNumber numberWithInt:16]
104  forKey:NSLocalizedString(@"High Color (16 Bit)", @"16 bit color selection")];
105  [dict setValue:[NSNumber numberWithInt:24]
106  forKey:NSLocalizedString(@"True Color (24 Bit)", @"24 bit color selection")];
107  [dict setValue:[NSNumber numberWithInt:32]
108  forKey:NSLocalizedString(@"Highest Quality (32 Bit)", @"32 bit color selection")];
109  return dict;
110 }
111 
112 NSArray *ResolutionModes()
113 {
114  NSArray *array =
115  [NSArray arrayWithObjects:ScreenResolutionDescription(TSXScreenOptionFitScreen, 0, 0),
116  ScreenResolutionDescription(TSXScreenOptionFixed, 640, 480),
117  ScreenResolutionDescription(TSXScreenOptionFixed, 800, 600),
118  ScreenResolutionDescription(TSXScreenOptionFixed, 1024, 768),
119  ScreenResolutionDescription(TSXScreenOptionFixed, 1280, 1024),
120  ScreenResolutionDescription(TSXScreenOptionFixed, 1440, 900),
121  ScreenResolutionDescription(TSXScreenOptionFixed, 1440, 1050),
122  ScreenResolutionDescription(TSXScreenOptionFixed, 1600, 1200),
123  ScreenResolutionDescription(TSXScreenOptionFixed, 1920, 1080),
124  ScreenResolutionDescription(TSXScreenOptionFixed, 1920, 1200),
125  ScreenResolutionDescription(TSXScreenOptionCustom, 0, 0), nil];
126  return array;
127 }
128 
129 #pragma mark Working with Security Protocols
130 
131 NSString *LocalizedAutomaticSecurity()
132 {
133  return NSLocalizedString(@"Automatic", @"Automatic protocl security selection");
134 }
135 
136 NSString *ProtocolSecurityDescription(TSXProtocolSecurityOptions type)
137 {
138  if (type == TSXProtocolSecurityNLA)
139  return @"NLA";
140  else if (type == TSXProtocolSecurityTLS)
141  return @"TLS";
142  else if (type == TSXProtocolSecurityRDP)
143  return @"RDP";
144 
145  return LocalizedAutomaticSecurity();
146 }
147 
148 BOOL ScanProtocolSecurity(NSString *description, TSXProtocolSecurityOptions *type)
149 {
150  *type = TSXProtocolSecurityRDP;
151 
152  if ([description isEqualToString:@"NLA"])
153  {
154  *type = TSXProtocolSecurityNLA;
155  return YES;
156  }
157  else if ([description isEqualToString:@"TLS"])
158  {
159  *type = TSXProtocolSecurityTLS;
160  return YES;
161  }
162  else if ([description isEqualToString:@"RDP"])
163  {
164  *type = TSXProtocolSecurityRDP;
165  return YES;
166  }
167  else if ([description isEqualToString:LocalizedAutomaticSecurity()])
168  {
169  *type = TSXProtocolSecurityAutomatic;
170  return YES;
171  }
172 
173  return NO;
174 }
175 
176 NSDictionary *SelectionForSecuritySetting()
177 {
178  OrderedDictionary *dict = [OrderedDictionary dictionaryWithCapacity:4];
179  [dict setValue:[NSNumber numberWithInt:TSXProtocolSecurityAutomatic]
180  forKey:ProtocolSecurityDescription(TSXProtocolSecurityAutomatic)];
181  [dict setValue:[NSNumber numberWithInt:TSXProtocolSecurityRDP]
182  forKey:ProtocolSecurityDescription(TSXProtocolSecurityRDP)];
183  [dict setValue:[NSNumber numberWithInt:TSXProtocolSecurityTLS]
184  forKey:ProtocolSecurityDescription(TSXProtocolSecurityTLS)];
185  [dict setValue:[NSNumber numberWithInt:TSXProtocolSecurityNLA]
186  forKey:ProtocolSecurityDescription(TSXProtocolSecurityNLA)];
187  return dict;
188 }
189 
190 #pragma mark -
191 #pragma mark Bookmarks
192 
193 #import "Bookmark.h"
194 
195 NSMutableArray *FilterBookmarks(NSArray *bookmarks, NSArray *filter_words)
196 {
197  NSMutableArray *matching_items = [NSMutableArray array];
198  NSArray *searched_keys = [NSArray
199  arrayWithObjects:@"label", @"params.hostname", @"params.username", @"params.domain", nil];
200 
201  for (ComputerBookmark *cur_bookmark in bookmarks)
202  {
203  double match_score = 0.0;
204 
205  for (int i = 0; i < [searched_keys count]; i++)
206  {
207  NSString *val = [cur_bookmark valueForKeyPath:[searched_keys objectAtIndex:i]];
208 
209  if (![val isKindOfClass:[NSString class]] || ![val length])
210  continue;
211 
212  for (NSString *word in filter_words)
213  if ([val rangeOfString:word
214  options:(NSCaseInsensitiveSearch | NSWidthInsensitiveSearch)]
215  .location != NSNotFound)
216  match_score += (1.0 / [filter_words count]) * pow(2, [searched_keys count] - i);
217  }
218 
219  if (match_score > 0.001)
220  [matching_items
221  addObject:[NSDictionary
222  dictionaryWithObjectsAndKeys:cur_bookmark, @"bookmark",
223  [NSNumber numberWithFloat:match_score],
224  @"score", nil]];
225  }
226 
227  [matching_items
228  sortUsingComparator:^NSComparisonResult(NSDictionary *obj1, NSDictionary *obj2) {
229  return [[obj2 objectForKey:@"score"] compare:[obj1 objectForKey:@"score"]];
230  }];
231  return matching_items;
232 }
233 
234 NSMutableArray *FilterHistory(NSArray *history, NSString *filterStr)
235 {
236  NSMutableArray *result = [NSMutableArray array];
237 
238  for (NSString *item in history)
239  {
240  if ([item rangeOfString:filterStr].location != NSNotFound)
241  [result addObject:item];
242  }
243 
244  return result;
245 }
246 
247 #pragma mark Version Info
248 NSString *TSXAppFullVersion()
249 {
250  return [NSString stringWithUTF8String:FREERDP_GIT_REVISION];
251 }
252 
253 #pragma mark iPad/iPhone detection
254 
255 BOOL IsPad()
256 {
257 #ifdef UI_USER_INTERFACE_IDIOM
258  return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
259 #else
260  return NO;
261 #endif
262 }
263 
264 BOOL IsPhone()
265 {
266 #ifdef UI_USER_INTERFACE_IDIOM
267  return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone);
268 #else
269  return NO;
270 #endif
271 }
272 
273 // set mouse buttons swapped flag
274 static BOOL g_swap_mouse_buttons = NO;
275 void SetSwapMouseButtonsFlag(BOOL swapped)
276 {
277  g_swap_mouse_buttons = swapped;
278 }
279 
280 // set invert scrolling flag
281 static BOOL g_invert_scrolling = NO;
282 void SetInvertScrollingFlag(BOOL invert)
283 {
284  g_invert_scrolling = invert;
285 }
286 
287 // return event value for left mouse button
288 int GetLeftMouseButtonClickEvent(BOOL down)
289 {
290  if (g_swap_mouse_buttons)
291  return (PTR_FLAGS_BUTTON2 | (down ? PTR_FLAGS_DOWN : 0));
292  else
293  return (PTR_FLAGS_BUTTON1 | (down ? PTR_FLAGS_DOWN : 0));
294 }
295 
296 // return event value for right mouse button
297 int GetRightMouseButtonClickEvent(BOOL down)
298 {
299  if (g_swap_mouse_buttons)
300  return (PTR_FLAGS_BUTTON1 | (down ? PTR_FLAGS_DOWN : 0));
301  else
302  return (PTR_FLAGS_BUTTON2 | (down ? PTR_FLAGS_DOWN : 0));
303 }
304 
305 // get mouse move event
306 int GetMouseMoveEvent()
307 {
308  return (PTR_FLAGS_MOVE);
309 }
310 
311 // return mouse wheel event
312 int GetMouseWheelEvent(BOOL down)
313 {
314  if (g_invert_scrolling)
315  down = !down;
316 
317  if (down)
318  return (PTR_FLAGS_WHEEL | PTR_FLAGS_WHEEL_NEGATIVE | (0x0088));
319  else
320  return (PTR_FLAGS_WHEEL | (0x0078));
321 }
322 
323 // scrolling gesture detection delta
324 CGFloat GetScrollGestureDelta()
325 {
326  return 10.0f;
327 }
328 
329 // this hack activates the iphone's WWAN interface in case it is offline
330 void WakeUpWWAN()
331 {
332  NSURL *url = [[[NSURL alloc] initWithString:@"http://www.nonexistingdummyurl.com"] autorelease];
333  // NSData * data =
334  [NSData dataWithContentsOfURL:url]; // we don't need data but assigning one causes a "data not
335  // used" compiler warning
336 }
337 
338 #pragma mark System Info functions
339 
340 NSString *TSXGetPrimaryMACAddress(NSString *sep)
341 {
342  NSString *macaddress = @"";
343  struct ifaddrs *addrs;
344 
345  if (getifaddrs(&addrs) < 0)
346  {
347  NSLog(@"getPrimaryMACAddress: getifaddrs failed.");
348  return macaddress;
349  }
350 
351  for (struct ifaddrs *cursor = addrs; cursor != NULL; cursor = cursor->ifa_next)
352  {
353  if (strcmp(cursor->ifa_name, "en0"))
354  continue;
355 
356  if ((cursor->ifa_addr->sa_family == AF_LINK) &&
357  (((struct sockaddr_dl *)cursor->ifa_addr)->sdl_type == 0x6 /*IFT_ETHER*/))
358  {
359  struct sockaddr_dl *dlAddr = (struct sockaddr_dl *)cursor->ifa_addr;
360 
361  if (dlAddr->sdl_alen != 6)
362  continue;
363 
364  unsigned char *base = (unsigned char *)&dlAddr->sdl_data[dlAddr->sdl_nlen];
365  macaddress = [NSString hexStringFromData:base
366  ofSize:6
367  withSeparator:sep
368  afterNthChar:1];
369  break;
370  }
371  }
372 
373  freeifaddrs(addrs);
374  return macaddress;
375 }
376 
377 BOOL TSXDeviceHasJailBreak()
378 {
379  if ([[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/Cydia.app/"])
380  return YES;
381 
382  if ([[NSFileManager defaultManager] fileExistsAtPath:@"/etc/apt/"])
383  return YES;
384 
385  return NO;
386 }
387 
388 NSString *TSXGetPlatform()
389 {
390  size_t size;
391  sysctlbyname("hw.machine", NULL, &size, NULL, 0);
392  char *machine = malloc(size);
393  sysctlbyname("hw.machine", machine, &size, NULL, 0);
394  NSString *platform = [NSString stringWithCString:machine encoding:NSASCIIStringEncoding];
395  free(machine);
396  return platform;
397 }