iOS: initial release of iFreeRDP

This is the initial release of iFreeRDP the FreeRDP iOS client.
Build instructions can be found in docs/README.ios.
This commit is contained in:
Bernhard Miklautz
2013-02-14 14:59:12 +01:00
parent e168da48e1
commit e5cf8ff7fb
183 changed files with 18818 additions and 47 deletions

View File

@@ -0,0 +1,46 @@
/*
Bookmark model abstraction
Copyright 2013 Thinstuff Technologies GmbH, Authors: 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 <Foundation/Foundation.h>
#import "ConnectionParams.h"
@interface ComputerBookmark : NSObject <NSCoding> {
@protected
ComputerBookmark* _parent;
NSString* _uuid, * _label;
UIImage* _image;
ConnectionParams* _connection_params;
BOOL _connected_via_wlan;
}
@property (nonatomic,assign) ComputerBookmark* parent;
@property (nonatomic,readonly) NSString* uuid;
@property (nonatomic,copy) NSString* label;
@property (nonatomic,retain) UIImage* image;
@property (readonly, nonatomic) ConnectionParams* params;
@property (nonatomic, assign) BOOL conntectedViaWLAN;
// Creates a copy of this object, with a new UUID
- (id)copy;
// Whether user can delete, move, or rename this entry
- (BOOL)isDeletable;
- (BOOL)isMovable;
- (BOOL)isRenamable;
- (BOOL)hasImmutableHost;
- (id)initWithConnectionParameters:(ConnectionParams*)params;
- (id)initWithBaseDefaultParameters;
// A copy of @params, with _bookmark_uuid set.
- (ConnectionParams*)copyMarkedParams;
@end

View File

@@ -0,0 +1,250 @@
/*
Bookmark model abstraction
Copyright 2013 Thinstuff Technologies GmbH, Author: 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 "Bookmark.h"
#import "TSXAdditions.h"
#import "Utils.h"
#import "GlobalDefaults.h"
@interface ComputerBookmark (Private)
- (void)willChangeValueForKeyPath:(NSString *)keyPath;
- (void)didChangeValueForKeyPath:(NSString *)keyPath;
@end
@implementation ComputerBookmark
@synthesize parent=_parent, uuid=_uuid, label=_label, image=_image;
@synthesize params=_connection_params, conntectedViaWLAN = _connected_via_wlan;
- (id)init
{
if (!(self = [super init]))
return nil;
_uuid = [[NSString stringWithUUID] retain];
_label = @"";
_connected_via_wlan = NO;
return self;
}
// Designated initializer.
- (id)initWithConnectionParameters:(ConnectionParams*)params
{
if (!(self = [super init]))
return nil;
_connection_params = [params copy];
_connected_via_wlan = NO;
return self;
}
- (id)initWithCoder:(NSCoder *)decoder
{
if (!(self = [self init]))
return nil;
if (![decoder allowsKeyedCoding])
[NSException raise:NSInvalidArgumentException format:@"coder must support keyed archiving"];
if ([decoder containsValueForKey:@"uuid"])
{
[_uuid release];
_uuid = [[decoder decodeObjectForKey:@"uuid"] retain];
}
if ([decoder containsValueForKey:@"label"])
[self setLabel:[decoder decodeObjectForKey:@"label"]];
if ([decoder containsValueForKey:@"connectionParams"])
{
[_connection_params release];
_connection_params = [[decoder decodeObjectForKey:@"connectionParams"] retain];
}
return self;
}
- (id)initWithBaseDefaultParameters
{
return [self initWithConnectionParameters:[[[ConnectionParams alloc] initWithBaseDefaultParameters] autorelease]];
}
- (id)copy
{
ComputerBookmark* copy = [[[self class] alloc] init];
[copy setLabel:[self label]];
copy->_connection_params = [_connection_params copy];
return copy;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
if (![coder allowsKeyedCoding])
[NSException raise:NSInvalidArgumentException format:@"coder must support keyed archiving"];
[coder encodeObject:_uuid forKey:@"uuid"];
[coder encodeObject:_label forKey:@"label"];
[coder encodeObject:_connection_params forKey:@"connectionParams"];
}
- (void)dealloc
{
_parent = nil;
[_label release]; _label = nil;
[_uuid release]; _uuid = nil;
[_connection_params release]; _connection_params = nil;
[super dealloc];
}
- (UIImage*)image
{
return nil;
}
- (BOOL)isEqual:(id)object
{
return [object respondsToSelector:@selector(uuid)] && [[object uuid] isEqual:_uuid];
}
- (NSString*)description
{
return ([self label] != nil) ? [self label] : _uuid;
}
- (BOOL)validateValue:(id *)val forKey:(NSString *)key error:(NSError **)error
{
NSString* string_value = *val;
if ([key isEqualToString:@"label"])
{
if (![[string_value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length])
{
if (error)
*error = [NSError errorWithDomain:@"" code:NSKeyValueValidationError userInfo:
[NSDictionary dictionaryWithObjectsAndKeys:
NSLocalizedString(@"Connection labels cannot be blank", @"Bookmark data validation: label blank title."), NSLocalizedDescriptionKey,
NSLocalizedString(@"Please enter the short description of this Connection that will appear in the Connection list.", @"Bookmark data validation: label blank message."), NSLocalizedRecoverySuggestionErrorKey,
nil]];
return NO;
}
}
return YES;
}
- (BOOL)validateValue:(id *)val forKeyPath:(NSString *)keyPath error:(NSError **)error
{
// Could be used to validate params.hostname, params.password, params.port, etc.
return [super validateValue:val forKeyPath:keyPath error:error];
}
- (BOOL)isDeletable { return YES; }
- (BOOL)isMovable { return YES; }
- (BOOL)isRenamable { return YES; }
- (BOOL)hasImmutableHost { return NO; }
#pragma mark Custom KVC
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath
{
if ([keyPath isEqualToString:@"params.resolution"])
{
int width, height;
TSXScreenOptions type;
if (ScanScreenResolution(value, &width, &height, &type))
{
[_connection_params willChangeValueForKey:@"resolution"];
[[self params] setInt:type forKey:@"screen_resolution_type"];
if (type == TSXScreenOptionFixed)
{
[[self params] setInt:width forKey:@"width"];
[[self params] setInt:height forKey:@"height"];
}
[_connection_params didChangeValueForKey:@"resolution"];
}
else
[NSException raise:NSInvalidArgumentException format:@"%s got invalid screen resolution '%@'", __func__, value];
}
else
{
[self willChangeValueForKeyPath:keyPath];
[super setValue:value forKeyPath:keyPath];
[self didChangeValueForKeyPath:keyPath];
}
}
- (id)valueForKeyPath:(NSString *)keyPath
{
if ([keyPath isEqualToString:@"params.resolution"])
return ScreenResolutionDescription([[self params] intForKey:@"screen_resolution_type"], [[self params] intForKey:@"width"], [[self params] intForKey:@"height"]);
return [super valueForKeyPath:keyPath];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([[change objectForKey:NSKeyValueChangeNotificationIsPriorKey] boolValue])
[self willChangeValueForKeyPath:keyPath];
else
[self didChangeValueForKeyPath:keyPath];
}
- (NSDictionary*)targetForChangeNotificationForKeyPath:(NSString*)keyPath
{
NSString* changed_key = keyPath;
NSObject* changed_object = self;
if ([keyPath rangeOfString:@"params."].location == 0)
{
changed_key = [keyPath substringFromIndex:[@"params." length]];
changed_object = _connection_params;
}
return [NSDictionary dictionaryWithObjectsAndKeys:changed_key, @"key", changed_object, @"object", nil];
}
- (void)willChangeValueForKeyPath:(NSString *)keyPath
{
NSDictionary* target = [self targetForChangeNotificationForKeyPath:keyPath];
[[target objectForKey:@"object"] willChangeValueForKey:[target objectForKey:@"key"]];
}
- (void)didChangeValueForKeyPath:(NSString *)keyPath
{
NSDictionary* target = [self targetForChangeNotificationForKeyPath:keyPath];
[[target objectForKey:@"object"] didChangeValueForKey:[target objectForKey:@"key"]];
}
- (ConnectionParams*)copyMarkedParams
{
ConnectionParams* param_copy = [[self params] copy];
[param_copy setValue:[self uuid] forKey:@"_bookmark_uuid"];
return param_copy;
}
#pragma mark No children
- (NSUInteger)numberOfChildren { return 0; }
- (NSUInteger)numberOfDescendants { return 1; }
- (BookmarkBase *)childAtIndex:(NSUInteger)index { return nil; }
- (NSUInteger)indexOfChild:(BookmarkBase *)child { return 0; }
- (void)removeChild:(BookmarkBase *)child { }
- (void)addChild:(BookmarkBase *)child { }
- (void)addChild:(BookmarkBase *)child afterExistingChild:(BookmarkBase *)existingChild { }
- (void)addChild:(BookmarkBase *)child atIndex:(NSInteger)index { }
- (BOOL)hasDescendant:(BookmarkBase *)needle { return NO; }
- (BOOL)canContainChildren { return NO; }
@end

View File

@@ -0,0 +1,47 @@
/*
Connection Parameters abstraction
Copyright 2013 Thinstuff Technologies GmbH, Author: 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 <Foundation/Foundation.h>
@interface ConnectionParams : NSObject
{
@private
NSMutableDictionary* _connection_params;
}
// Designated initializer.
- (id)initWithDictionary:(NSDictionary*)dict;
- (id)initWithBaseDefaultParameters;
// Getting/setting values
- (NSArray*)allKeys;
- (void)setValue:(id)value forKey:(NSString *)key;
- (id)valueForKey:(NSString*)key;
- (BOOL)hasValueForKey:(NSString*)key;
- (void)setInt:(int)integer forKey:(NSString*)key;
- (int)intForKey:(NSString*)key;
- (void)setBool:(BOOL)v forKey:(NSString*)key;
- (BOOL)boolForKey:(NSString*)key;
- (const char*)UTF8StringForKey:(NSString*)key;
- (NSString*)StringForKey:(NSString*)key;
- (BOOL)hasValueForKeyPath:(NSString*)key;
- (void)setInt:(int)integer forKeyPath:(NSString*)key;
- (int)intForKeyPath:(NSString*)key;
- (void)setBool:(BOOL)v forKeyPath:(NSString*)key;
- (BOOL)boolForKeyPath:(NSString*)key;
- (const char*)UTF8StringForKeyPath:(NSString*)key;
- (NSString*)StringForKeyPath:(NSString*)key;
- (int)intForKey:(NSString*)key with3GEnabled:(BOOL)enabled;
- (BOOL)boolForKey:(NSString*)key with3GEnabled:(BOOL)enabled;
@end

View File

@@ -0,0 +1,247 @@
/*
Connection Parameters abstraction
Copyright 2013 Thinstuff Technologies GmbH, Author: 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 "ConnectionParams.h"
#import "GlobalDefaults.h"
#import "EncryptionController.h"
#import "Utils.h"
#import "TSXAdditions.h"
@interface ConnectionParams (Private)
- (id)initWithConnectionParams:(ConnectionParams*)params;
@end
@implementation ConnectionParams
// Designated initializer.
- (id)initWithDictionary:(NSDictionary*)dict
{
if (!(self = [super init]))
return nil;
_connection_params = [dict mutableDeepCopy];
if ([[_connection_params objectForKey:@"password"] isKindOfClass:[NSData class]])
{
NSString* plaintext_password = [[[EncryptionController sharedEncryptionController] decryptor] decryptString:[_connection_params objectForKey:@"password"]];
[self setValue:plaintext_password forKey:@"password"];
}
return self;
}
- (id)initWithBaseDefaultParameters
{
return [self initWithDictionary:[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"TSXDefaultComputerBookmarkSettings"]];
}
- (id)init
{
return [self initWithDictionary:[NSDictionary dictionary]];
}
- (id)initWithConnectionParams:(ConnectionParams*)params
{
return [self initWithDictionary:params->_connection_params];
}
- (void)dealloc
{
[_connection_params release]; _connection_params = nil;
[super dealloc];
}
- (id)copyWithZone:(NSZone *)zone
{
return [[ConnectionParams alloc] initWithDictionary:_connection_params];
}
- (NSString*)description
{
return [NSString stringWithFormat:@"ConnectionParams: %@", [_connection_params description]];
}
#pragma mark -
#pragma mark NSCoder
- (id)initWithCoder:(NSCoder *)decoder
{
if ([decoder containsValueForKey:@"connectionParams"])
return [self initWithDictionary:[decoder decodeObjectForKey:@"connectionParams"]];
return [self init];
}
- (void)encodeWithCoder:(NSCoder *)coder
{
NSSet* unserializable_keys = [NSSet setWithObjects:@"view", nil];
NSMutableDictionary* serializable_params = [[NSMutableDictionary alloc] initWithCapacity:[_connection_params count]];
for (NSString* k in _connection_params)
if ( ([k characterAtIndex:0] != '_') && ![unserializable_keys containsObject:k])
[serializable_params setObject:[_connection_params objectForKey:k] forKey:k];
if ([serializable_params objectForKey:@"password"] != nil)
{
NSData* encrypted_password = [[[EncryptionController sharedEncryptionController] encryptor] encryptString:[serializable_params objectForKey:@"password"]];
if (encrypted_password)
[serializable_params setObject:encrypted_password forKey:@"password"];
else
[serializable_params removeObjectForKey:@"password"];
}
[coder encodeObject:serializable_params forKey:@"connectionParams"];
[serializable_params release];
}
#pragma mark -
#pragma mark NSKeyValueCoding
- (void)setValue:(id)value forKey:(NSString *)key
{
[self willChangeValueForKey:key];
if (value == nil)
[self setNilValueForKey:key];
else
[_connection_params setValue:value forKey:key];
[self didChangeValueForKey:key];
}
- (void)setValue:(id)value forKeyPath:(NSString *)key
{
[self willChangeValueForKey:key];
if (value == nil)
[self setNilValueForKey:key];
else
[_connection_params setValue:value forKeyPath:key];
[self didChangeValueForKey:key];
}
- (void)setNilValueForKey:(NSString *)key
{
[_connection_params removeObjectForKey:key];
}
- (id)valueForKey:(NSString*)key
{
return [_connection_params valueForKey:key];
}
- (NSArray*)allKeys
{
return [_connection_params allKeys];
}
#pragma mark -
#pragma mark KV convenience
- (BOOL)hasValueForKey:(NSString*)key
{
return [_connection_params objectForKey:key] != nil;
}
- (void)setInt:(int)integer forKey:(NSString*)key
{
[self setValue:[NSNumber numberWithInteger:integer] forKey:key];
}
- (int)intForKey:(NSString*)key
{
return [[self valueForKey:key] intValue];
}
- (void)setBool:(BOOL)v forKey:(NSString*)key
{
[self setValue:[NSNumber numberWithBool:v] forKey:key];
}
- (BOOL)boolForKey:(NSString*)key
{
return [[_connection_params objectForKey:key] boolValue];
}
- (const char*)UTF8StringForKey:(NSString*)key
{
id val = [self valueForKey:key];
const char* str;
if ([val respondsToSelector:@selector(UTF8String)] && (str = [val UTF8String]))
return str;
return "";
}
- (NSString*)StringForKey:(NSString*)key
{
return [self valueForKey:key];
}
- (BOOL)hasValueForKeyPath:(NSString*)key
{
return [_connection_params valueForKeyPath:key] != nil;
}
- (void)setInt:(int)integer forKeyPath:(NSString*)key
{
[self setValue:[NSNumber numberWithInteger:integer] forKeyPath:key];
}
- (int)intForKeyPath:(NSString*)key
{
return [[self valueForKeyPath:key] intValue];
}
- (void)setBool:(BOOL)v forKeyPath:(NSString*)key
{
[self setValue:[NSNumber numberWithBool:v] forKeyPath:key];
}
- (BOOL)boolForKeyPath:(NSString*)key
{
return [[self valueForKeyPath:key] boolValue];
}
- (const char*)UTF8StringForKeyPath:(NSString*)key
{
id val = [self valueForKeyPath:key];
const char* str;
if ([val respondsToSelector:@selector(UTF8String)] && (str = [val UTF8String]))
return str;
return "";
}
- (NSString*)StringForKeyPath:(NSString*)key
{
return [self valueForKeyPath:key];
}
- (int)intForKey:(NSString*)key with3GEnabled:(BOOL)enabled
{
if (enabled && [self boolForKey:@"enable_3g_settings"])
return [self intForKeyPath:[NSString stringWithFormat:@"settings_3g.%@", key]];
return [self intForKeyPath:key];
}
- (BOOL)boolForKey:(NSString*)key with3GEnabled:(BOOL)enabled
{
if (enabled && [self boolForKey:@"enable_3g_settings"])
return [self boolForKeyPath:[NSString stringWithFormat:@"settings_3g.%@", key]];
return [self boolForKeyPath:key];
}
@end

View File

@@ -0,0 +1,42 @@
/*
Password Encryptor
Copyright 2013 Thinstuff Technologies GmbH, Author: 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/.
*/
/* Encrypts data using AES 128 with a 256 bit key derived using PBKDF2-HMAC-SHA1 */
#import <Foundation/Foundation.h>
// Encryption block cipher config
#define TSXEncryptorBlockCipherAlgo kCCAlgorithmAES128
#define TSXEncryptorBlockCipherKeySize kCCKeySizeAES256
#define TSXEncryptorBlockCipherOptions kCCOptionPKCS7Padding
#define TSXEncryptorBlockCipherBlockSize 16
// Key generation: If any of these are changed, existing password stores will no longer work
#define TSXEncryptorPBKDF2Rounds 100
#define TSXEncryptorPBKDF2Salt "9D¶3L}S¿lA[e€3C«"
#define TSXEncryptorPBKDF2SaltLen TSXEncryptorBlockCipherOptions
#define TSXEncryptorPBKDF2KeySize TSXEncryptorBlockCipherKeySize
@interface Encryptor : NSObject {
@private
NSData* _encryption_key;
NSString* _plaintext_password;
}
@property(readonly) NSString* plaintextPassword;
- (id)initWithPassword:(NSString*)plaintext_password;
- (NSData*)encryptData:(NSData*)plaintext_data;
- (NSData*)decryptData:(NSData*)encrypted_data;
- (NSData*)encryptString:(NSString*)plaintext_string;
- (NSString*)decryptString:(NSData*)encrypted_string;
@end

View File

@@ -0,0 +1,173 @@
/*
Password Encryptor
Copyright 2013 Thinstuff Technologies GmbH, Author: 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/.
*/
/* We try to use CommonCrypto as much as possible. PBKDF2 was added to CommonCrypto in iOS 5, so use OpenSSL only as a fallback to do PBKDF2 on pre iOS 5 systems. */
#import "Encryptor.h"
#import <CommonCrypto/CommonKeyDerivation.h>
#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonDigest.h>
#import <openssl/evp.h> // For PBKDF2 on < 5.0
#include <fcntl.h>
#pragma mark -
@interface Encryptor (Private)
- (NSData*)randomInitializationVector;
@end
@implementation Encryptor
@synthesize plaintextPassword=_plaintext_password;
- (id)initWithPassword:(NSString*)plaintext_password
{
if (plaintext_password == nil)
return nil;
if ( !(self = [super init]) )
return nil;
_plaintext_password = [plaintext_password retain];
const char* plaintext_password_data = [plaintext_password length] ? [plaintext_password UTF8String] : " ";
if (!plaintext_password_data || !strlen(plaintext_password_data))
[NSException raise:NSInternalInconsistencyException format:@"%s: plaintext password data is zero length!", __func__];
uint8_t* derived_key = calloc(1, TSXEncryptorPBKDF2KeySize);
if (CCKeyDerivationPBKDF != NULL)
{
int rounds = CCCalibratePBKDF(kCCPBKDF2, strlen(plaintext_password_data), TSXEncryptorPBKDF2SaltLen, kCCPRFHmacAlgSHA1, TSXEncryptorPBKDF2KeySize, 100);
int ret = CCKeyDerivationPBKDF(kCCPBKDF2, plaintext_password_data, strlen(plaintext_password_data)-1, (const uint8_t*)TSXEncryptorPBKDF2Salt, TSXEncryptorPBKDF2SaltLen, kCCPRFHmacAlgSHA1, rounds, derived_key, TSXEncryptorPBKDF2KeySize);
//NSLog(@"CCKeyDerivationPBKDF ret = %d; key: %@", ret, [NSData dataWithBytesNoCopy:derived_key length:TWEncryptorPBKDF2KeySize freeWhenDone:NO]);
if (ret)
{
NSLog(@"%s: CCKeyDerivationPBKDF ret == %d, indicating some sort of failure.", __func__, ret);
[self autorelease];
return nil;
}
}
else
{
// iOS 4.x or earlier -- use OpenSSL
unsigned long ret = PKCS5_PBKDF2_HMAC_SHA1(plaintext_password_data, (int)strlen(plaintext_password_data)-1, (const unsigned char*)TSXEncryptorPBKDF2Salt, TSXEncryptorPBKDF2SaltLen, TSXEncryptorPBKDF2Rounds, TSXEncryptorPBKDF2KeySize, derived_key);
//NSLog(@"PKCS5_PBKDF2_HMAC_SHA1 ret = %lu; key: %@", ret, [NSData dataWithBytesNoCopy:derived_key length:TWEncryptorPBKDF2KeySize freeWhenDone:NO]);
if (ret != 1)
{
NSLog(@"%s: PKCS5_PBKDF2_HMAC_SHA1 ret == %lu, indicating some sort of failure.", __func__, ret);
[self release];
return nil;
}
}
_encryption_key = [[NSData alloc] initWithBytesNoCopy:derived_key length:TSXEncryptorPBKDF2KeySize freeWhenDone:YES];
return self;
}
#pragma mark -
#pragma mark Encrypting/Decrypting data
- (NSData*)encryptData:(NSData*)plaintext_data
{
if (![plaintext_data length])
return nil;
NSData* iv = [self randomInitializationVector];
NSMutableData* encrypted_data = [NSMutableData dataWithLength:[iv length] + [plaintext_data length] + TSXEncryptorBlockCipherBlockSize];
[encrypted_data replaceBytesInRange:NSMakeRange(0, [iv length]) withBytes:[iv bytes]];
size_t data_out_moved = 0;
int ret = CCCrypt(kCCEncrypt, TSXEncryptorBlockCipherAlgo, TSXEncryptorBlockCipherOptions, [_encryption_key bytes], TSXEncryptorBlockCipherKeySize, [iv bytes], [plaintext_data bytes], [plaintext_data length], [encrypted_data mutableBytes]+[iv length], [encrypted_data length]-[iv length], &data_out_moved);
switch (ret)
{
case kCCSuccess:
[encrypted_data setLength:[iv length] + data_out_moved];
return encrypted_data;
default:
NSLog(@"%s: uncaught error, ret CCCryptorStatus = %d (plaintext len = %lu; buffer size = %lu)", __func__, ret, (unsigned long)[plaintext_data length], (unsigned long)([encrypted_data length]-[iv length]));
return nil;
}
return nil;
}
- (NSData*)decryptData:(NSData*)encrypted_data
{
if ([encrypted_data length] <= TSXEncryptorBlockCipherBlockSize)
return nil;
NSMutableData* plaintext_data = [NSMutableData dataWithLength:[encrypted_data length] + TSXEncryptorBlockCipherBlockSize];
size_t data_out_moved = 0;
int ret = CCCrypt(kCCDecrypt, TSXEncryptorBlockCipherAlgo, TSXEncryptorBlockCipherOptions, [_encryption_key bytes], TSXEncryptorBlockCipherKeySize, [encrypted_data bytes], [encrypted_data bytes] + TSXEncryptorBlockCipherBlockSize, [encrypted_data length] - TSXEncryptorBlockCipherBlockSize, [plaintext_data mutableBytes], [plaintext_data length], &data_out_moved);
switch (ret)
{
case kCCSuccess:
[plaintext_data setLength:data_out_moved];
return plaintext_data;
case kCCBufferTooSmall: // Our output buffer is big enough to decrypt valid data. This return code indicates malformed data.
case kCCAlignmentError: // Shouldn't get this, since we're using padding.
case kCCDecodeError: // Wrong key.
return nil;
default:
NSLog(@"%s: uncaught error, ret CCCryptorStatus = %d (encrypted data len = %lu; buffer size = %lu; dom = %lu)", __func__, ret, (unsigned long)[encrypted_data length], (unsigned long)[plaintext_data length], data_out_moved);
return nil;
}
return nil;
}
- (NSData*)encryptString:(NSString*)plaintext_string
{
return [self encryptData:[plaintext_string dataUsingEncoding:NSUTF8StringEncoding]];
}
- (NSString*)decryptString:(NSData*)encrypted_string
{
return [[[NSString alloc] initWithData:[self decryptData:encrypted_string] encoding:NSUTF8StringEncoding] autorelease];
}
- (NSData*)randomInitializationVector
{
NSMutableData* iv = [NSMutableData dataWithLength:TSXEncryptorBlockCipherBlockSize];
int fd;
if ( (fd = open("/dev/urandom", O_RDONLY)) < 0)
return nil;
NSInteger bytes_needed = [iv length];
char* p = [iv mutableBytes];
while (bytes_needed)
{
long bytes_read = read(fd, p, bytes_needed);
if (bytes_read < 0)
continue;
p += bytes_read;
bytes_needed -= bytes_read;
}
close(fd);
return iv;
}
@end

View File

@@ -0,0 +1,28 @@
/*
Global default bookmark settings
Copyright 2013 Thinstuff Technologies GmbH, Author: 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 <Foundation/Foundation.h>
@class ConnectionParams, ComputerBookmark;
@interface GlobalDefaults : NSObject{
@private
ComputerBookmark* _default_bookmark;
}
+ (GlobalDefaults*)sharedGlobalDefaults;
// The same object is always returned from this method.
@property (readonly,nonatomic) ComputerBookmark* bookmark;
- (ConnectionParams*)newParams;
- (ComputerBookmark*)newBookmark;
@end

View File

@@ -0,0 +1,71 @@
/*
Global default bookmark settings
Copyright 2013 Thinstuff Technologies GmbH, Author: 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 "GlobalDefaults.h"
#import "Bookmark.h"
#import "ConnectionParams.h"
@implementation GlobalDefaults
+ (GlobalDefaults*)sharedGlobalDefaults
{
static GlobalDefaults* _shared_global_defaults = nil;
if (_shared_global_defaults == nil)
{
@synchronized(self)
{
if (_shared_global_defaults == nil)
_shared_global_defaults = [[GlobalDefaults alloc] init];
}
}
return _shared_global_defaults;
}
- (id)init
{
if (!(self = [super init]))
return nil;
ComputerBookmark* bookmark = nil;
NSData* bookmark_data = [[NSUserDefaults standardUserDefaults] objectForKey:@"TSXSharedGlobalDefaultBookmark"];
if (bookmark_data && [bookmark_data length])
bookmark = [NSKeyedUnarchiver unarchiveObjectWithData:bookmark_data];
if (!bookmark)
bookmark = [[[ComputerBookmark alloc] initWithBaseDefaultParameters] autorelease];
_default_bookmark = [bookmark retain];
return self;
}
- (void)dealloc
{
[_default_bookmark release];
[super dealloc];
}
#pragma mark -
@synthesize bookmark=_default_bookmark;
- (ComputerBookmark*)newBookmark
{
return [[ComputerBookmark alloc] initWithConnectionParameters:[[self newParams] autorelease]];
}
- (ConnectionParams*)newParams
{
ConnectionParams* param_copy = [[[self bookmark] params] copy];
return param_copy;
}
@end

View File

@@ -0,0 +1,76 @@
/*
RDP Keyboard helper
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
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 <Foundation/Foundation.h>
#import "RDPSession.h"
@class RDPKeyboard;
@protocol RDPKeyboardDelegate <NSObject>
@optional
- (void)modifiersChangedForKeyboard:(RDPKeyboard*)keyboard;
@end
@interface RDPKeyboard : NSObject {
RDPSession* _session;
int _virtual_key_map[256];
int _unicode_map[256];
NSDictionary* _special_keys;
NSObject<RDPKeyboardDelegate>* _delegate;
BOOL _ctrl_pressed;
BOOL _alt_pressed;
BOOL _shift_pressed;
BOOL _win_pressed;
}
@property (assign) id <RDPKeyboardDelegate> delegate;
@property (readonly) BOOL ctrlPressed;
@property (readonly) BOOL altPressed;
@property (readonly) BOOL shiftPressed;
@property (readonly) BOOL winPressed;
// returns a keyboard instance
+ (RDPKeyboard*)getSharedRDPKeyboard;
// init the keyboard and assign the given rdp session and delegate
- (void)initWithSession:(RDPSession*)session delegate:(NSObject<RDPKeyboardDelegate>*)delegate;
// called to reset any pending key states (i.e. pressed modifier keys)
- (void)reset;
// sends the given unicode character to the server
- (void)sendUnicode:(int)character;
// send a key stroke event using the given virtual key code
- (void)sendVirtualKeyCode:(int)keyCode;
// toggle ctrl key, returns true if pressed, otherwise false
- (void)toggleCtrlKey;
// toggle alt key, returns true if pressed, otherwise false
- (void)toggleAltKey;
// toggle shift key, returns true if pressed, otherwise false
- (void)toggleShiftKey;
// toggle windows key, returns true if pressed, otherwise false
- (void)toggleWinKey;
// send key strokes
- (void)sendEnterKeyStroke;
- (void)sendEscapeKeyStroke;
- (void)sendBackspaceKeyStroke;
@end

View File

@@ -0,0 +1,306 @@
/*
RDP Keyboard helper
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
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 "RDPKeyboard.h"
#include <freerdp/locale/keyboard.h>
@interface RDPKeyboard (Private)
- (void)sendVirtualKey:(int)vKey up:(BOOL)up;
- (void)handleSpecialKey:(int)character;
- (void)handleAlphaNumChar:(int)character;
- (void)notifyDelegateModifiersChanged;
@end
@implementation RDPKeyboard
@synthesize delegate = _delegate, ctrlPressed = _ctrl_pressed, altPressed = _alt_pressed, shiftPressed = _shift_pressed, winPressed = _win_pressed;
- (id)init
{
if((self = [super init]) != nil)
{
[self initWithSession:nil delegate:nil];
memset(_virtual_key_map, 0, sizeof(_virtual_key_map));
memset(_unicode_map, 0, sizeof(_unicode_map));
// init vkey map - used for alpha-num characters
_virtual_key_map['0'] = VK_KEY_0;
_virtual_key_map['1'] = VK_KEY_1;
_virtual_key_map['2'] = VK_KEY_2;
_virtual_key_map['3'] = VK_KEY_3;
_virtual_key_map['4'] = VK_KEY_4;
_virtual_key_map['5'] = VK_KEY_5;
_virtual_key_map['6'] = VK_KEY_6;
_virtual_key_map['7'] = VK_KEY_7;
_virtual_key_map['8'] = VK_KEY_8;
_virtual_key_map['9'] = VK_KEY_9;
_virtual_key_map['a'] = VK_KEY_A;
_virtual_key_map['b'] = VK_KEY_B;
_virtual_key_map['c'] = VK_KEY_C;
_virtual_key_map['d'] = VK_KEY_D;
_virtual_key_map['e'] = VK_KEY_E;
_virtual_key_map['f'] = VK_KEY_F;
_virtual_key_map['g'] = VK_KEY_G;
_virtual_key_map['h'] = VK_KEY_H;
_virtual_key_map['i'] = VK_KEY_I;
_virtual_key_map['j'] = VK_KEY_J;
_virtual_key_map['k'] = VK_KEY_K;
_virtual_key_map['l'] = VK_KEY_L;
_virtual_key_map['m'] = VK_KEY_M;
_virtual_key_map['n'] = VK_KEY_N;
_virtual_key_map['o'] = VK_KEY_O;
_virtual_key_map['p'] = VK_KEY_P;
_virtual_key_map['q'] = VK_KEY_Q;
_virtual_key_map['r'] = VK_KEY_R;
_virtual_key_map['s'] = VK_KEY_S;
_virtual_key_map['t'] = VK_KEY_T;
_virtual_key_map['u'] = VK_KEY_U;
_virtual_key_map['v'] = VK_KEY_V;
_virtual_key_map['w'] = VK_KEY_W;
_virtual_key_map['x'] = VK_KEY_X;
_virtual_key_map['y'] = VK_KEY_Y;
_virtual_key_map['z'] = VK_KEY_Z;
// init scancode map - used for special characters
_unicode_map['-'] = 45;
_unicode_map['/'] = 47;
_unicode_map[':'] = 58;
_unicode_map[';'] = 59;
_unicode_map['('] = 40;
_unicode_map[')'] = 41;
_unicode_map['&'] = 38;
_unicode_map['@'] = 64;
_unicode_map['.'] = 46;
_unicode_map[','] = 44;
_unicode_map['?'] = 63;
_unicode_map['!'] = 33;
_unicode_map['\''] = 39;
_unicode_map['\"'] = 34;
_unicode_map['['] = 91;
_unicode_map[']'] = 93;
_unicode_map['{'] = 123;
_unicode_map['}'] = 125;
_unicode_map['#'] = 35;
_unicode_map['%'] = 37;
_unicode_map['^'] = 94;
_unicode_map['*'] = 42;
_unicode_map['+'] = 43;
_unicode_map['='] = 61;
_unicode_map['_'] = 95;
_unicode_map['\\'] = 92;
_unicode_map['|'] = 124;
_unicode_map['~'] = 126;
_unicode_map['<'] = 60;
_unicode_map['>'] = 62;
_unicode_map['$'] = 36;
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
#pragma mark -
#pragma mark class methods
// return a keyboard instance
+ (RDPKeyboard*)getSharedRDPKeyboard
{
static RDPKeyboard* _shared_keyboard = nil;
if (_shared_keyboard == nil)
{
@synchronized(self)
{
if (_shared_keyboard == nil)
_shared_keyboard = [[RDPKeyboard alloc] init];
}
}
return _shared_keyboard;
}
// reset the keyboard instance and assign the given rdp instance
- (void)initWithSession:(RDPSession *)session delegate:(NSObject<RDPKeyboardDelegate> *)delegate
{
_alt_pressed = NO;
_ctrl_pressed = NO;
_shift_pressed = NO;
_win_pressed = NO;
_session = session;
_delegate = delegate;
}
- (void)reset
{
// reset pressed ctrl, alt, shift or win key
if(_shift_pressed)
[self toggleShiftKey];
if(_alt_pressed)
[self toggleAltKey];
if(_ctrl_pressed)
[self toggleCtrlKey];
if(_win_pressed)
[self toggleWinKey];
}
// handles button pressed input event from the iOS keyboard
// performs all conversions etc.
- (void)sendUnicode:(int)character
{
if(isalnum(character))
[self handleAlphaNumChar:character];
else
[self handleSpecialKey:character];
[self reset];
}
// send a backspace key press
- (void)sendVirtualKeyCode:(int)keyCode
{
[self sendVirtualKey:keyCode up:NO];
[self sendVirtualKey:keyCode up:YES];
}
#pragma mark modifier key handling
// toggle ctrl key, returns true if pressed, otherwise false
- (void)toggleCtrlKey
{
[self sendVirtualKey:VK_LCONTROL up:_ctrl_pressed];
_ctrl_pressed = !_ctrl_pressed;
[self notifyDelegateModifiersChanged];
}
// toggle alt key, returns true if pressed, otherwise false
- (void)toggleAltKey
{
[self sendVirtualKey:VK_LMENU up:_alt_pressed];
_alt_pressed = !_alt_pressed;
[self notifyDelegateModifiersChanged];
}
// toggle shift key, returns true if pressed, otherwise false
- (void)toggleShiftKey
{
[self sendVirtualKey:VK_LSHIFT up:_shift_pressed];
_shift_pressed = !_shift_pressed;
[self notifyDelegateModifiersChanged];
}
// toggle windows key, returns true if pressed, otherwise false
- (void)toggleWinKey
{
[self sendVirtualKey:VK_LWIN up:_win_pressed];
_win_pressed = !_win_pressed;
[self notifyDelegateModifiersChanged];
}
#pragma mark Sending special key strokes
- (void)sendEnterKeyStroke
{
[self sendVirtualKeyCode:VK_RETURN];
}
- (void)sendEscapeKeyStroke
{
[self sendVirtualKeyCode:VK_ESCAPE];
}
- (void)sendBackspaceKeyStroke
{
[self sendVirtualKeyCode:VK_BACK];
}
@end
#pragma mark -
@implementation RDPKeyboard (Private)
- (void)handleAlphaNumChar:(int)character
{
// if we recive an uppercase letter - make it lower and send an shift down event to server
BOOL shift_was_sent = NO;
if(isupper(character) && _shift_pressed == NO)
{
character = tolower(character);
[self sendVirtualKey:VK_SHIFT up:NO];
shift_was_sent = YES;
}
// convert the character to a VK
int vk = _virtual_key_map[character];
if(vk != 0)
{
// send key pressed
[self sendVirtualKey:vk up:NO];
[self sendVirtualKey:vk up:YES];
}
// send the missing shift up if we had a shift down
if(shift_was_sent)
[self sendVirtualKey:VK_SHIFT up:YES];
}
- (void)handleSpecialKey:(int)character
{
NSDictionary* eventDescriptor = nil;
if(character < 256)
{
// convert the character to a unicode character
int code = _unicode_map[character];
if(code != 0)
eventDescriptor = [NSDictionary dictionaryWithObjectsAndKeys:
@"keyboard", @"type",
@"unicode", @"subtype",
[NSNumber numberWithUnsignedShort:0], @"flags",
[NSNumber numberWithUnsignedShort:code], @"unicode_char",
nil];
}
if (eventDescriptor == nil)
eventDescriptor = [NSDictionary dictionaryWithObjectsAndKeys:
@"keyboard", @"type",
@"unicode", @"subtype",
[NSNumber numberWithUnsignedShort:0], @"flags",
[NSNumber numberWithUnsignedShort:character], @"unicode_char",
nil];
[_session sendInputEvent:eventDescriptor];
}
// sends the vk code to the session
- (void)sendVirtualKey:(int)vKey up:(BOOL)up
{
RDP_SCANCODE scancode = freerdp_keyboard_get_rdp_scancode_from_virtual_key_code(vKey);
int flags = (up ? KBD_FLAGS_RELEASE : KBD_FLAGS_DOWN);
flags |= (RDP_SCANCODE_EXTENDED(scancode) ? KBD_FLAGS_EXTENDED : 0);
[_session sendInputEvent:[NSDictionary dictionaryWithObjectsAndKeys:
@"keyboard", @"type",
@"scancode", @"subtype",
[NSNumber numberWithUnsignedShort:flags], @"flags",
[NSNumber numberWithUnsignedShort:RDP_SCANCODE_CODE(scancode)], @"scancode",
nil]];
}
- (void)notifyDelegateModifiersChanged
{
if ([[self delegate] respondsToSelector:@selector(modifiersChangedForKeyboard:)])
[[self delegate] modifiersChangedForKeyboard:self];
}
@end

View File

@@ -0,0 +1,108 @@
/*
RDP Session object
Copyright 2013 Thinstuff 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 <Foundation/Foundation.h>
#include <freerdp/freerdp.h>
// forward declaration
@class RDPSession;
@class ComputerBookmark;
@class ConnectionParams;
// notification handler for session disconnect
extern NSString* TSXSessionDidDisconnectNotification;
extern NSString* TSXSessionDidFailToConnectNotification;
// protocol for session notifications
@protocol RDPSessionDelegate <NSObject>
@optional
- (void)session:(RDPSession*)session didFailToConnect:(int)reason;
- (void)sessionWillConnect:(RDPSession*)session;
- (void)sessionDidConnect:(RDPSession*)session;
- (void)sessionWillDisconnect:(RDPSession*)session;
- (void)sessionDidDisconnect:(RDPSession*)session;
- (void)sessionBitmapContextWillChange:(RDPSession*)session;
- (void)sessionBitmapContextDidChange:(RDPSession*)session;
- (void)session:(RDPSession*)session needsRedrawInRect:(CGRect)rect;
- (CGSize)sizeForFitScreenForSession:(RDPSession*)session;
- (void)showGoProScreen:(RDPSession*)session;
- (void)session:(RDPSession*)session requestsAuthenticationWithParams:(NSMutableDictionary*)params;
- (void)session:(RDPSession*)session verifyCertificateWithParams:(NSMutableDictionary*)params;
@end
// rdp session
@interface RDPSession : NSObject
{
@private
freerdp* _freerdp;
ComputerBookmark* _bookmark;
ConnectionParams* _params;
NSObject<RDPSessionDelegate>* _delegate;
NSCondition* _ui_request_completed;
NSString* _name;
// flag if the session is suspended
BOOL _suspended;
// flag that specifies whether the RDP toolbar is visible
BOOL _toolbar_visible;
}
@property (readonly) ConnectionParams* params;
@property (readonly) ComputerBookmark* bookmark;
@property (assign) id <RDPSessionDelegate> delegate;
@property (assign) BOOL toolbarVisible;
@property (readonly) CGContextRef bitmapContext;
@property (readonly) NSCondition* uiRequestCompleted;
// initialize a new session with the given bookmark
- (id)initWithBookmark:(ComputerBookmark*)bookmark;
#pragma mark - session control functions
// connect the session
-(void)connect;
// disconnect session
-(void)disconnect;
// suspends the session
-(void)suspend;
// resumes a previously suspended session
-(void)resume;
// returns YES if the session is started
-(BOOL)isSuspended;
// send input event to the server
-(void)sendInputEvent:(NSDictionary*)event;
// session needs a refresh of its view
- (void)setNeedsDisplayInRectAsValue:(NSValue*)rect_value;
// get a small session screenshot
- (UIImage*)getScreenshotWithSize:(CGSize)size;
// returns the session's current paramters
- (rdpSettings*)getSessionParams;
// returns the session's name (usually the label of the bookmark the session was created with)
- (NSString*)sessionName;
@end

View File

@@ -0,0 +1,430 @@
/*
RDP Session object
Copyright 2013 Thinstuff 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 "ios_freerdp.h"
#import "ios_freerdp_ui.h"
#import "ios_freerdp_events.h"
#import "RDPSession.h"
#import "TSXTypes.h"
#import "Bookmark.h"
#import "ConnectionParams.h"
NSString* TSXSessionDidDisconnectNotification = @"TSXSessionDidDisconnect";
NSString* TSXSessionDidFailToConnectNotification = @"TSXSessionDidFailToConnect";
@interface RDPSession (Private)
- (void)runSession;
- (void)runSessionFinished:(NSNumber*)result;
- (mfInfo*)mfi;
// The connection thread calls these on the main thread.
- (void)sessionWillConnect;
- (void)sessionDidConnect;
- (void)sessionDidDisconnect;
- (void)sessionDidFailToConnect:(int)reason;
- (void)sessionBitmapContextWillChange;
- (void)sessionBitmapContextDidChange;
@end
@implementation RDPSession
@synthesize delegate=_delegate, params=_params, toolbarVisible = _toolbar_visible, uiRequestCompleted = _ui_request_completed, bookmark = _bookmark;
+ (void)initialize
{
ios_init_freerdp();
}
// Designated initializer.
- (id)initWithBookmark:(ComputerBookmark *)bookmark
{
if (!(self = [super init]))
return nil;
if (!bookmark)
[NSException raise:NSInvalidArgumentException format:@"%s: params may not be nil.", __func__];
_bookmark = [bookmark retain];
_params = [[bookmark params] copy];
_name = [[bookmark label] retain];
_delegate = nil;
_toolbar_visible = YES;
_freerdp = ios_freerdp_new();
rdpSettings* settings = _freerdp->settings;
_ui_request_completed = [[NSCondition alloc] init];
BOOL connected_via_3g = ![bookmark conntectedViaWLAN];
// Screen Size is set on connect (we need a valid delegate in case the user choose an automatic screen size)
// Other simple numeric settings
if ([_params hasValueForKey:@"colors"])
settings->ColorDepth = [_params intForKey:@"colors" with3GEnabled:connected_via_3g];
if ([_params hasValueForKey:@"port"])
settings->ServerPort = [_params intForKey:@"port"];
if ([_params boolForKey:@"console"])
settings->ConsoleSession = 1;
// connection info
settings->ServerHostname = strdup([_params UTF8StringForKey:@"hostname"]);
// String settings
if ([[_params StringForKey:@"username"] length])
settings->Username = strdup([_params UTF8StringForKey:@"username"]);
if ([[_params StringForKey:@"password"] length])
settings->Password = strdup([_params UTF8StringForKey:@"password"]);
if ([[_params StringForKey:@"domain"] length])
settings->Domain = strdup([_params UTF8StringForKey:@"domain"]);
settings->ShellWorkingDirectory = strdup([_params UTF8StringForKey:@"working_directory"]);
settings->AlternateShell = strdup([_params UTF8StringForKey:@"remote_program"]);
// RemoteFX
if ([_params boolForKey:@"perf_remotefx" with3GEnabled:connected_via_3g])
{
settings->RemoteFxCodec = TRUE;
settings->FastPathOutput = TRUE;
settings->ColorDepth = 32;
settings->LargePointerFlag = TRUE;
settings->FrameMarkerCommandEnabled = TRUE;
}
// Performance flags
settings->DisableWallpaper = ![_params boolForKey:@"perf_show_desktop" with3GEnabled:connected_via_3g];
settings->DisableFullWindowDrag = ![_params boolForKey:@"perf_window_dragging" with3GEnabled:connected_via_3g];
settings->DisableMenuAnims = ![_params boolForKey:@"perf_menu_animation" with3GEnabled:connected_via_3g];
settings->DisableThemes = ![_params boolForKey:@"perf_windows_themes" with3GEnabled:connected_via_3g];
settings->AllowFontSmoothing = [_params boolForKey:@"perf_font_smoothing" with3GEnabled:connected_via_3g];
settings->AllowDesktopComposition = [_params boolForKey:@"perf_desktop_composition" with3GEnabled:connected_via_3g];
settings->PerformanceFlags = PERF_FLAG_NONE;
if (settings->DisableWallpaper)
settings->PerformanceFlags |= PERF_DISABLE_WALLPAPER;
if (settings->DisableFullWindowDrag)
settings->PerformanceFlags |= PERF_DISABLE_FULLWINDOWDRAG;
if (settings->DisableMenuAnims)
settings->PerformanceFlags |= PERF_DISABLE_MENUANIMATIONS;
if (settings->DisableThemes)
settings->PerformanceFlags |= PERF_DISABLE_THEMING;
if (settings->AllowFontSmoothing)
settings->PerformanceFlags |= PERF_ENABLE_FONT_SMOOTHING;
if (settings->AllowDesktopComposition)
settings->PerformanceFlags |= PERF_ENABLE_DESKTOP_COMPOSITION;
if ([_params hasValueForKey:@"width"])
settings->DesktopWidth = [_params intForKey:@"width"];
if ([_params hasValueForKey:@"height"])
settings->DesktopHeight = [_params intForKey:@"height"];
// security
switch ([_params intForKey:@"security"])
{
case TSXProtocolSecurityNLA:
settings->RdpSecurity = FALSE;
settings->TlsSecurity = FALSE;
settings->NlaSecurity = TRUE;
settings->ExtSecurity = FALSE;
break;
case TSXProtocolSecurityTLS:
settings->RdpSecurity = FALSE;
settings->TlsSecurity = TRUE;
settings->NlaSecurity = FALSE;
settings->ExtSecurity = FALSE;
break;
case TSXProtocolSecurityRDP:
settings->RdpSecurity = TRUE;
settings->TlsSecurity = FALSE;
settings->NlaSecurity = FALSE;
settings->ExtSecurity = FALSE;
settings->DisableEncryption = TRUE;
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
break;
default:
break;
}
// Remote keyboard layout
settings->KeyboardLayout = 0x409;
// Audio settings
settings->AudioPlayback = FALSE;
settings->AudioCapture = FALSE;
[self mfi]->session = self;
return self;
}
- (void)dealloc
{
[self setDelegate:nil];
[_bookmark release];
[_name release];
[_params release];
[_ui_request_completed release];
ios_freerdp_free(_freerdp);
[super dealloc];
}
- (CGContextRef)bitmapContext
{
return [self mfi]->bitmap_context;
}
#pragma mark -
#pragma mark Connecting and disconnecting
- (void)connect
{
// Set Screen Size to automatic if widht or height are still 0
rdpSettings* settings = _freerdp->settings;
if (settings->DesktopWidth == 0 || settings->DesktopHeight == 0)
{
CGSize size = CGSizeZero;
if ([[self delegate] respondsToSelector:@selector(sizeForFitScreenForSession:)])
size = [[self delegate] sizeForFitScreenForSession:self];
if (!CGSizeEqualToSize(CGSizeZero, size))
{
[_params setInt:size.width forKey:@"width"];
[_params setInt:size.height forKey:@"height"];
settings->DesktopWidth = size.width;
settings->DesktopHeight = size.height;
}
}
// TODO: This is a hack to ensure connections to RDVH with 16bpp don't have an odd screen resolution width
// Otherwise this could result in screen corruption ..
if (settings->ColorDepth <= 16)
settings->DesktopWidth &= (~1);
[self performSelectorInBackground:@selector(runSession) withObject:nil];
}
- (void)disconnect
{
mfInfo* mfi = [self mfi];
ios_events_send(mfi, [NSDictionary dictionaryWithObject:@"disconnect" forKey:@"type"]);
if (mfi->connection_state == TSXConnectionConnecting)
{
mfi->unwanted = YES;
[self sessionDidDisconnect];
return;
}
}
- (TSXConnectionState)connectionState
{
return [self mfi]->connection_state;
}
// suspends the session
-(void)suspend
{
if(!_suspended)
{
_suspended = YES;
// instance->update->SuppressOutput(instance->context, 0, NULL);
}
}
// resumes a previously suspended session
-(void)resume
{
if(_suspended)
{
/* RECTANGLE_16 rec;
rec.left = 0;
rec.top = 0;
rec.right = instance->settings->width;
rec.bottom = instance->settings->height;
*/
_suspended = NO;
// instance->update->SuppressOutput(instance->context, 1, &rec);
// [delegate sessionScreenSettingsChanged:self];
}
}
// returns YES if the session is started
-(BOOL)isSuspended
{
return _suspended;
}
#pragma mark -
#pragma mark Input events
- (void)sendInputEvent:(NSDictionary*)eventDescriptor
{
if ([self mfi]->connection_state == TSXConnectionConnected)
ios_events_send([self mfi], eventDescriptor);
}
#pragma mark -
#pragma mark Server events (main thread)
- (void)setNeedsDisplayInRectAsValue:(NSValue*)rect_value
{
if ([[self delegate] respondsToSelector:@selector(session:needsRedrawInRect:)])
[[self delegate] session:self needsRedrawInRect:[rect_value CGRectValue]];
}
#pragma mark -
#pragma mark interface functions
- (UIImage*)getScreenshotWithSize:(CGSize)size
{
NSAssert([self mfi]->bitmap_context != nil, @"Screenshot requested while having no valid RDP drawing context");
CGImageRef cgImage = CGBitmapContextCreateImage([self mfi]->bitmap_context);
UIGraphicsBeginImageContext(size);
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 0, size.height);
CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1.0, -1.0);
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, size.width, size.height), cgImage);
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGImageRelease(cgImage);
return viewImage;
}
- (rdpSettings*)getSessionParams
{
return _freerdp->settings;
}
- (NSString*)sessionName
{
return _name;
}
@end
#pragma mark -
@implementation RDPSession (Private)
- (mfInfo*)mfi
{
return MFI_FROM_INSTANCE(_freerdp);
}
// Blocks until rdp session finishes.
- (void)runSession
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// Run the session
[self performSelectorOnMainThread:@selector(sessionWillConnect) withObject:nil waitUntilDone:YES];
int result_code = ios_run_freerdp(_freerdp);
[self mfi]->connection_state = TSXConnectionDisconnected;
[self performSelectorOnMainThread:@selector(runSessionFinished:) withObject:[NSNumber numberWithInt:result_code] waitUntilDone:YES];
[pool release];
}
// Main thread.
- (void)runSessionFinished:(NSNumber*)result
{
int result_code = [result intValue];
switch (result_code)
{
case MF_EXIT_CONN_CANCELED:
[self sessionDidDisconnect];
break;
case MF_EXIT_LOGON_TIMEOUT:
case MF_EXIT_CONN_FAILED:
[self sessionDidFailToConnect:result_code];
break;
case MF_EXIT_SUCCESS:
default:
[self sessionDidDisconnect];
break;
}
}
#pragma mark -
#pragma mark Session management (main thread)
- (void)sessionWillConnect
{
if ([[self delegate] respondsToSelector:@selector(sessionWillConnect:)])
[[self delegate] sessionWillConnect:self];
}
- (void)sessionDidConnect
{
if ([[self delegate] respondsToSelector:@selector(sessionDidConnect:)])
[[self delegate] sessionDidConnect:self];
}
- (void)sessionDidFailToConnect:(int)reason
{
[[NSNotificationCenter defaultCenter] postNotificationName:TSXSessionDidFailToConnectNotification object:self];
if ([[self delegate] respondsToSelector:@selector(session:didFailToConnect:)])
[[self delegate] session:self didFailToConnect:reason];
}
- (void)sessionDidDisconnect
{
[[NSNotificationCenter defaultCenter] postNotificationName:TSXSessionDidDisconnectNotification object:self];
if ([[self delegate] respondsToSelector:@selector(sessionDidDisconnect:)])
[[self delegate] sessionDidDisconnect:self];
}
- (void)sessionBitmapContextWillChange
{
if ([[self delegate] respondsToSelector:@selector(sessionBitmapContextWillChange:)])
[[self delegate] sessionBitmapContextWillChange:self];
}
- (void)sessionBitmapContextDidChange
{
if ([[self delegate] respondsToSelector:@selector(sessionBitmapContextDidChange:)])
[[self delegate] sessionBitmapContextDidChange:self];
}
- (void)showGoProScreen
{
if ([[self delegate] respondsToSelector:@selector(showGoProScreen:)])
[[self delegate] showGoProScreen:self];
}
- (void)sessionRequestsAuthenticationWithParams:(NSMutableDictionary*)params
{
if ([[self delegate] respondsToSelector:@selector(session:requestsAuthenticationWithParams:)])
[[self delegate] session:self requestsAuthenticationWithParams:params];
}
- (void)sessionVerifyCertificateWithParams:(NSMutableDictionary*)params
{
if ([[self delegate] respondsToSelector:@selector(session:verifyCertificateWithParams:)])
[[self delegate] session:self verifyCertificateWithParams:params];
}
@end