FreeRDP/client/iOS/Models/RDPSession.m

451 lines
13 KiB
Objective-C

/*
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;
settings->FrameAcknowledge = 10;
}
else
{
// enable NSCodec if remotefx is not used
settings->NSCodec = TRUE;
}
settings->BitmapCacheV3Enabled = 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;
}
// ts gateway settings
if ([_params boolForKey:@"enable_tsg_settings"])
{
settings->GatewayHostname = strdup([_params UTF8StringForKey:@"tsg_hostname"]);
settings->GatewayPort = [_params intForKey:@"tsg_port"];
settings->GatewayUsername = strdup([_params UTF8StringForKey:@"tsg_username"]);
settings->GatewayPassword = strdup([_params UTF8StringForKey:@"tsg_password"]);
settings->GatewayDomain = strdup([_params UTF8StringForKey:@"tsg_domain"]);
settings->GatewayUsageMethod = TRUE;
settings->GatewayUseSameCredentials = FALSE;
}
// 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