Updated iOS client.

This commit is contained in:
Armin Novak 2016-08-05 13:14:55 +02:00 committed by Armin Novak
parent 081b57905f
commit f0864108f9
10 changed files with 1187 additions and 906 deletions

View File

@ -107,7 +107,7 @@ set_target_properties(${MODULE_NAME} PROPERTIES RESOURCE "${${MODULE_NAME}_RESOU
set(EXECUTABLE_NAME "\${EXECUTABLE_NAME}")
set_target_properties(${MODULE_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${IOS_CLIENT_DIR}/iFreeRDP.plist)
set_target_properties(${MODULE_NAME} PROPERTIES XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "4.3")
set_target_properties(${MODULE_NAME} PROPERTIES XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "6.3")
set_target_properties(${MODULE_NAME} PROPERTIES XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "gnu++0x")
set_target_properties(${MODULE_NAME} PROPERTIES XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
set_target_properties(${MODULE_NAME} PROPERTIES XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC NO)

View File

@ -1,9 +1,9 @@
/*
controller for performance settings selection
Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
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/.
*/
@ -11,7 +11,7 @@
#import "ConnectionParams.h"
#import "Utils.h"
@interface PerformanceEditorController (Private)
@interface PerformanceEditorController(Private)
-(NSString*)keyPathForKey:(NSString*)key;
@end
@ -19,134 +19,177 @@
- (id)initWithConnectionParams:(ConnectionParams*)params
{
return [self initWithConnectionParams:params keyPath:nil];
return [self initWithConnectionParams:params keyPath:nil];
}
- (id)initWithConnectionParams:(ConnectionParams*)params keyPath:(NSString*)keyPath;
- (id)initWithConnectionParams:(ConnectionParams*)params keyPath:
(NSString*)keyPath;
{
self = [super initWithStyle:UITableViewStyleGrouped];
if (self) {
_params = [params retain];
_keyPath = (keyPath != nil ? [keyPath retain] : nil);
}
return self;
self = [super initWithStyle:UITableViewStyleGrouped];
if (self)
{
_params = [params retain];
_keyPath = (keyPath != nil ? [keyPath retain] : nil);
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)
interfaceOrientation
{
return YES;
return YES;
}
-(NSString*)keyPathForKey:(NSString*)key
{
if (_keyPath)
return [_keyPath stringByAppendingFormat:@".%@", key];
return key;
if (_keyPath)
return [_keyPath stringByAppendingFormat:@".%@", key];
return key;
}
- (void)dealloc
{
[super dealloc];
[_params release];
[super dealloc];
[_params release];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 7;
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:
(NSInteger)section
{
return 7;
}
// set section headers
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
- (NSString*)tableView:(UITableView*)tableView titleForHeaderInSection:
(NSInteger)section
{
return NSLocalizedString(@"Performance Settings", @"'Performance Settings': performance settings header");
return NSLocalizedString(@"Performance Settings",
@"'Performance Settings': performance settings header");
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// get the table view cell
EditFlagTableViewCell *cell = (EditFlagTableViewCell*)[self tableViewCellFromIdentifier:TableCellIdentifierYesNo];
NSAssert(cell, @"Invalid cell");
switch ([indexPath row])
{
case 0:
{
[[cell label] setText:NSLocalizedString(@"RemoteFX", @"RemoteFX performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_remotefx"]]];
break;
}
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:
(NSIndexPath*)indexPath
{
// get the table view cell
EditFlagTableViewCell* cell = (EditFlagTableViewCell*)[self
tableViewCellFromIdentifier:TableCellIdentifierYesNo];
NSAssert(cell, @"Invalid cell");
case 1:
{
[[cell label] setText:NSLocalizedString(@"Desktop Background", @"Desktop background performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_show_desktop"]]];
break;
}
switch ([indexPath row])
{
case 0:
{
[[cell label] setText:NSLocalizedString(@"RemoteFX",
@"RemoteFX performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:
@"perf_remotefx"]]];
break;
}
case 2:
{
[[cell label] setText:NSLocalizedString(@"Font Smoothing", @"Font smoothing performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_font_smoothing"]]];
break;
}
case 3:
{
[[cell label] setText:NSLocalizedString(@"Desktop Composition", @"Desktop composition performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_desktop_composition"]]];
break;
}
case 4:
{
[[cell label] setText:NSLocalizedString(@"Window contents while dragging", @"Window Dragging performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_window_dragging"]]];
break;
}
case 5:
{
[[cell label] setText:NSLocalizedString(@"Menu Animation", @"Menu Animations performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_menu_animation"]]];
break;
}
case 1:
{
[[cell label] setText:NSLocalizedString(@"GFX", @"GFX performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_gfx"]]];
break;
}
case 6:
{
[[cell label] setText:NSLocalizedString(@"Visual Styles", @"Use Themes performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_windows_themes"]]];
break;
}
case 2:
{
[[cell label] setText:NSLocalizedString(@"H264", @"H264 performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:
@"perf_h264"]]];
break;
}
default:
break;
}
[[cell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
[[cell toggle] addTarget:self action:@selector(togglePerformanceSetting:) forControlEvents:UIControlEventValueChanged];
return cell;
case 3:
{
[[cell label] setText:NSLocalizedString(@"Desktop Background",
@"Desktop background performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:
@"perf_show_desktop"]]];
break;
}
case 4:
{
[[cell label] setText:NSLocalizedString(@"Font Smoothing",
@"Font smoothing performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:
@"perf_font_smoothing"]]];
break;
}
case 5:
{
[[cell label] setText:NSLocalizedString(@"Desktop Composition",
@"Desktop composition performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:
@"perf_desktop_composition"]]];
break;
}
case 6:
{
[[cell label] setText:NSLocalizedString(@"Window contents while dragging",
@"Window Dragging performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:
@"perf_window_dragging"]]];
break;
}
case 7:
{
[[cell label] setText:NSLocalizedString(@"Menu Animation",
@"Menu Animations performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:
@"perf_menu_animation"]]];
break;
}
case 8:
{
[[cell label] setText:NSLocalizedString(@"Visual Styles",
@"Use Themes performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:
@"perf_windows_themes"]]];
break;
}
default:
break;
}
[[cell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
[[cell toggle] addTarget:self action:@selector(togglePerformanceSetting:)
forControlEvents:UIControlEventValueChanged];
return cell;
}
#pragma mark -
@ -154,40 +197,58 @@
- (void)togglePerformanceSetting:(id)sender
{
UISwitch* valueSwitch = (UISwitch*)sender;
switch(valueSwitch.tag)
{
case GET_TAG(0, 0):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_remotefx"]];
break;
UISwitch* valueSwitch = (UISwitch*)sender;
case GET_TAG(0, 1):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_show_desktop"]];
break;
case GET_TAG(0, 2):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_font_smoothing"]];
break;
case GET_TAG(0, 3):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_desktop_composition"]];
break;
switch (valueSwitch.tag)
{
case GET_TAG(0, 0):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:
@"perf_remotefx"]];
break;
case GET_TAG(0, 4):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_window_dragging"]];
break;
case GET_TAG(0, 5):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_menu_animation"]];
break;
case GET_TAG(0, 1):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:
@"perf_gfx"]];
break;
case GET_TAG(0, 6):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_windows_themes"]];
break;
case GET_TAG(0, 2):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:
@"perf_h264"]];
break;
default:
break;
}
case GET_TAG(0, 3):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:
@"perf_show_desktop"]];
break;
case GET_TAG(0, 4):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:
@"perf_font_smoothing"]];
break;
case GET_TAG(0, 5):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:
@"perf_desktop_composition"]];
break;
case GET_TAG(0, 6):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:
@"perf_window_dragging"]];
break;
case GET_TAG(0, 7):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:
@"perf_menu_animation"]];
break;
case GET_TAG(0, 8):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:
@"perf_windows_themes"]];
break;
default:
break;
}
}
@end

View File

@ -28,6 +28,10 @@
<false/>
<key>perf_remotefx</key>
<false/>
<key>perf_gfx</key>
<false/>
<key>perf_h264</key>
<false/>
<key>perf_desktop_composition</key>
<false/>
<key>enable_3g_settings</key>
@ -44,6 +48,10 @@
<integer>16</integer>
<key>perf_remotefx</key>
<false/>
<key>perf_gfx</key>
<false/>
<key>perf_h264</key>
<false/>
<key>perf_desktop_composition</key>
<false/>
<key>perf_windows_themes</key>

View File

@ -1,8 +1,8 @@
/*
RDP run-loop
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/.
*/
@ -12,6 +12,7 @@
#import <freerdp/client/channels.h>
#import <freerdp/client/cmdline.h>
#import <freerdp/freerdp.h>
#import <freerdp/gdi/gfx.h>
#import "ios_freerdp.h"
#import "ios_freerdp_ui.h"
@ -20,23 +21,99 @@
#import "RDPSession.h"
#import "Utils.h"
#define TAG FREERDP_TAG("iOS")
#pragma mark Connection helpers
static BOOL ios_pre_connect(freerdp* instance)
{
rdpSettings* settings = instance->settings;
static void ios_OnChannelConnectedEventHandler(
rdpContext* context,
ChannelConnectedEventArgs* e)
{
rdpSettings* settings;
mfContext* afc;
settings->AutoLogonEnabled = settings->Password && (strlen(settings->Password) > 0);
// Verify screen width/height are sane
if ((settings->DesktopWidth < 64) || (settings->DesktopHeight < 64) || (settings->DesktopWidth > 4096) || (settings->DesktopHeight > 4096))
if (!context || !e)
{
NSLog(@"%s: invalid dimensions %d %d", __func__, settings->DesktopWidth, settings->DesktopHeight);
WLog_FATAL(TAG, "%s(context=%p, EventArgs=%p",
__FUNCTION__, context, e);
return;
}
afc = (mfContext*) context;
settings = context->settings;
if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
{
if (settings->SoftwareGdi)
{
gdi_graphics_pipeline_init(context->gdi,
(RdpgfxClientContext*) e->pInterface);
}
else
{
WLog_WARN(TAG, "GFX without software GDI requested. "
" This is not supported, add /gdi:sw");
}
}
}
static void ios_OnChannelDisconnectedEventHandler(
rdpContext* context, ChannelDisconnectedEventArgs* e)
{
rdpSettings* settings;
mfContext* afc;
if (!context || !e)
{
WLog_FATAL(TAG, "%s(context=%p, EventArgs=%p",
__FUNCTION__, context, e);
return;
}
afc = (mfContext*) context;
settings = context->settings;
if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
{
if (settings->SoftwareGdi)
{
gdi_graphics_pipeline_uninit(context->gdi,
(RdpgfxClientContext*) e->pInterface);
}
else
{
WLog_WARN(TAG, "GFX without software GDI requested. "
" This is not supported, add /gdi:sw");
}
}
}
static BOOL ios_pre_connect(freerdp* instance)
{
int rc;
rdpSettings* settings;
if (!instance || !instance->settings)
return FALSE;
settings = instance->settings;
if (!settings->OrderSupport)
return FALSE;
settings->AutoLogonEnabled = settings->Password
&& (strlen(settings->Password) > 0);
// Verify screen width/height are sane
if ((settings->DesktopWidth < 64) || (settings->DesktopHeight < 64)
|| (settings->DesktopWidth > 4096) || (settings->DesktopHeight > 4096))
{
NSLog(@"%s: invalid dimensions %d %d", __func__, settings->DesktopWidth,
settings->DesktopHeight);
return FALSE;
}
BOOL bitmap_cache = settings->BitmapCacheEnabled;
settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE;
settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
@ -61,38 +138,154 @@ static BOOL ios_pre_connect(freerdp* instance)
settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE;
settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
settings->FrameAcknowledge = 10;
rc = PubSub_SubscribeChannelConnected(
instance->context->pubSub,
(pChannelConnectedEventHandler)
ios_OnChannelConnectedEventHandler);
if (!freerdp_client_load_addins(instance->context->channels, instance->settings))
if (rc != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "Could not subscribe to connect event handler [%l08X]", rc);
return FALSE;
}
if (freerdp_channels_pre_connect(instance->context->channels, instance) != CHANNEL_RC_OK)
rc = PubSub_SubscribeChannelDisconnected(
instance->context->pubSub,
(pChannelDisconnectedEventHandler)
ios_OnChannelDisconnectedEventHandler);
if (rc != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "Could not subscribe to disconnect event handler [%l08X]", rc);
return FALSE;
}
if (!freerdp_client_load_addins(instance->context->channels,
instance->settings))
{
WLog_ERR(TAG, "Failed to load addins [%l08X]", GetLastError());
return FALSE;
}
rc = freerdp_channels_pre_connect(instance->context->channels, instance);
if (rc != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "freerdp_channels_pre_connect failed with %l08X", rc);
return FALSE;
}
return TRUE;
}
static BOOL ios_Pointer_New(rdpContext* context, rdpPointer* pointer)
{
if (!context || !pointer || !context->gdi)
return FALSE;
return TRUE;
}
static void ios_Pointer_Free(rdpContext* context, rdpPointer* pointer)
{
if (!context || !pointer)
return;
}
static BOOL ios_Pointer_Set(rdpContext* context,
const rdpPointer* pointer)
{
if (!context)
return FALSE;
return TRUE;
}
static BOOL ios_Pointer_SetPosition(rdpContext* context,
UINT32 x, UINT32 y)
{
if (!context)
return FALSE;
return TRUE;
}
static BOOL ios_Pointer_SetNull(rdpContext* context)
{
if (!context)
return FALSE;
return TRUE;
}
static BOOL ios_Pointer_SetDefault(rdpContext* context)
{
if (!context)
return FALSE;
return TRUE;
}
static BOOL ios_register_pointer(rdpGraphics* graphics)
{
rdpPointer pointer;
if (!graphics)
return FALSE;
pointer.size = sizeof(pointer);
pointer.New = ios_Pointer_New;
pointer.Free = ios_Pointer_Free;
pointer.Set = ios_Pointer_Set;
pointer.SetNull = ios_Pointer_SetNull;
pointer.SetDefault = ios_Pointer_SetDefault;
pointer.SetPosition = ios_Pointer_SetPosition;
graphics_register_pointer(graphics, &pointer);
return TRUE;
}
static BOOL ios_post_connect(freerdp* instance)
{
mfInfo* mfi = MFI_FROM_INSTANCE(instance);
mfInfo* mfi;
if (!instance)
return FALSE;
mfi = MFI_FROM_INSTANCE(instance);
if (!mfi)
return FALSE;
if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
return FALSE;
if (!ios_register_pointer(instance->context->graphics))
return FALSE;
instance->context->cache = cache_new(instance->settings);
// Graphics callbacks
ios_allocate_display_buffer(mfi);
instance->update->BeginPaint = ios_ui_begin_paint;
instance->update->EndPaint = ios_ui_end_paint;
instance->update->DesktopResize = ios_ui_resize_window;
pointer_cache_register_callbacks(instance->update);
// Channel allocation
if (freerdp_channels_post_connect(instance->context->channels, instance) != CHANNEL_RC_OK)
if (freerdp_channels_post_connect(instance->context->channels,
instance) != CHANNEL_RC_OK)
return FALSE;
[mfi->session performSelectorOnMainThread:@selector(sessionDidConnect) withObject:nil waitUntilDone:YES];
[mfi->session performSelectorOnMainThread:@selector(sessionDidConnect)
withObject:nil waitUntilDone:YES];
return TRUE;
}
static void ios_post_disconnect(freerdp* instance)
{
if (instance && instance->context)
freerdp_channels_disconnect(instance->context->channels, instance);
gdi_free(instance);
}
#pragma mark -
#pragma mark Running the connection
@ -101,20 +294,18 @@ int ios_run_freerdp(freerdp* instance)
mfContext* context = (mfContext*)instance->context;
mfInfo* mfi = context->mfi;
rdpChannels* channels = instance->context->channels;
mfi->connection_state = TSXConnectionConnecting;
if (!freerdp_connect(instance))
{
NSLog(@"%s: inst->rdp_connect failed", __func__);
return mfi->unwanted ? MF_EXIT_CONN_CANCELED : MF_EXIT_CONN_FAILED;
}
if (mfi->unwanted)
return MF_EXIT_CONN_CANCELED;
mfi->connection_state = TSXConnectionConnected;
// Connection main loop
NSAutoreleasePool* pool;
int i;
@ -128,14 +319,12 @@ int ios_run_freerdp(freerdp* instance)
fd_set wfds_set;
struct timeval timeout;
int select_status;
memset(rfds, 0, sizeof(rfds));
memset(wfds, 0, sizeof(wfds));
while (!freerdp_shall_disconnect(instance))
{
rcount = wcount = 0;
pool = [[NSAutoreleasePool alloc] init];
if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE)
@ -144,7 +333,8 @@ int ios_run_freerdp(freerdp* instance)
break;
}
if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != TRUE)
if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds,
&wcount) != TRUE)
{
NSLog(@"%s: freerdp_chanman_get_fds failed", __func__);
break;
@ -155,54 +345,53 @@ int ios_run_freerdp(freerdp* instance)
NSLog(@"%s: ios_events_get_fds", __func__);
break;
}
max_fds = 0;
FD_ZERO(&rfds_set);
FD_ZERO(&wfds_set);
for (i = 0; i < rcount; i++)
{
fds = (int)(long)(rfds[i]);
if (fds > max_fds)
max_fds = fds;
FD_SET(fds, &rfds_set);
}
if (max_fds == 0)
break;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
select_status = select(max_fds + 1, &rfds_set, NULL, NULL, &timeout);
// timeout?
if (select_status == 0)
{
continue;
}
else if (select_status == -1)
{
/* these are not really errors */
if (!((errno == EAGAIN) ||
(errno == EWOULDBLOCK) ||
(errno == EINPROGRESS) ||
(errno == EINTR))) /* signal occurred */
timeout.tv_sec = 1;
timeout.tv_usec = 0;
select_status = select(max_fds + 1, &rfds_set, NULL, NULL, &timeout);
// timeout?
if (select_status == 0)
{
continue;
}
else if (select_status == -1)
{
/* these are not really errors */
if (!((errno == EAGAIN) ||
(errno == EWOULDBLOCK) ||
(errno == EINPROGRESS) ||
(errno == EINTR))) /* signal occurred */
{
NSLog(@"%s: select failed!", __func__);
break;
}
}
// Check the libfreerdp fds
if (freerdp_check_fds(instance) != true)
{
NSLog(@"%s: inst->rdp_check_fds failed.", __func__);
break;
}
// Check input event fds
if (ios_events_check_fds(mfi, &rfds_set) != TRUE)
{
@ -210,7 +399,7 @@ int ios_run_freerdp(freerdp* instance)
//NSLog(@"%s: ios_events_check_fds failed: terminating connection.", __func__);
break;
}
// Check channel fds
if (freerdp_channels_check_fds(channels, instance) != TRUE)
{
@ -218,121 +407,129 @@ int ios_run_freerdp(freerdp* instance)
break;
}
[pool release]; pool = nil;
}
[pool release];
pool = nil;
}
CGContextRelease(mfi->bitmap_context);
mfi->bitmap_context = NULL;
mfi->bitmap_context = NULL;
mfi->connection_state = TSXConnectionDisconnected;
// Cleanup
freerdp_channels_disconnect(channels, instance);
freerdp_disconnect(instance);
gdi_free(instance);
cache_free(instance->context->cache);
[pool release]; pool = nil;
[pool release];
pool = nil;
return MF_EXIT_SUCCESS;
}
#pragma mark -
#pragma mark Context callbacks
BOOL ios_context_new(freerdp* instance, rdpContext* context)
static BOOL ios_client_new(freerdp* instance, rdpContext* context)
{
mfInfo* mfi;
mfContext* ctx = (mfContext*)context;
if (!instance || !context)
return FALSE;
if (!(context->channels = freerdp_channels_new()))
return FALSE;
if ((ctx->mfi = calloc(1, sizeof(mfInfo))) == NULL)
return FALSE;
ctx->mfi->context = (mfContext*)context;
ctx->mfi->_context = context;
ctx->mfi->context->settings = instance->settings;
ctx->mfi->instance = instance;
if (!ios_events_create_pipe(ctx->mfi))
return FALSE;
instance->PreConnect = ios_pre_connect;
instance->PostConnect = ios_post_connect;
instance->PostDisconnect = ios_post_disconnect;
instance->Authenticate = ios_ui_authenticate;
instance->GatewayAuthenticate = ios_ui_gw_authenticate;
instance->VerifyCertificate = ios_ui_verify_certificate;
instance->VerifyChangedCertificate = ios_ui_verify_changed_certificate;
instance->LogonErrorInfo = NULL;
return TRUE;
}
static void ios_client_free(freerdp* instance, rdpContext* context)
{
mfInfo* mfi;
if (!(mfi = (mfInfo*)calloc(1, sizeof(mfInfo))))
goto fail_mfi;
if (!context)
return;
if (!(context->channels = freerdp_channels_new()))
goto fail_channels;
if (!ios_events_create_pipe(mfi))
goto fail_events;
mfi = ((mfContext*) context)->mfi;
((mfContext*) context)->mfi = mfi;
mfi->_context = context;
mfi->context = (mfContext*)context;
mfi->context->settings = instance->settings;
mfi->instance = instance;
return TRUE;
if (context->channels)
{
freerdp_channels_close(context->channels, instance);
freerdp_channels_free(context->channels);
context->channels = NULL;
}
fail_events:
freerdp_channels_free(context->channels);
context->channels = NULL;
fail_channels:
free(mfi);
fail_mfi:
return FALSE;
}
void ios_context_free(freerdp* instance, rdpContext* context)
{
mfInfo* mfi = ((mfContext*) context)->mfi;
freerdp_channels_close(context->channels, instance);
freerdp_channels_free(context->channels);
ios_events_free_pipe(mfi);
free(mfi);
}
static int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
{
ZeroMemory(pEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS));
pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
pEntryPoints->GlobalInit = NULL;
pEntryPoints->GlobalUninit = NULL;
pEntryPoints->ContextSize = sizeof(mfContext);
pEntryPoints->ClientNew = ios_client_new;
pEntryPoints->ClientFree = ios_client_free;
pEntryPoints->ClientStart = NULL;
pEntryPoints->ClientStop = NULL;
return 0;
}
#pragma mark -
#pragma mark Initialization and cleanup
freerdp* ios_freerdp_new()
{
freerdp* inst = freerdp_new();
if (!inst)
return NULL;
inst->PreConnect = ios_pre_connect;
inst->PostConnect = ios_post_connect;
inst->Authenticate = ios_ui_authenticate;
inst->VerifyCertificate = ios_ui_check_certificate;
inst->VerifyChangedCertificate = ios_ui_check_changed_certificate;
inst->ContextSize = sizeof(mfContext);
inst->ContextNew = ios_context_new;
inst->ContextFree = ios_context_free;
freerdp_context_new(inst);
// determine new home path
NSString* home_path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
free(inst->settings->HomePath);
free(inst->settings->ConfigPath);
inst->settings->HomePath = strdup([home_path UTF8String]);
inst->settings->ConfigPath = strdup([[home_path stringByAppendingPathComponent:@".freerdp"] UTF8String]);
if (!inst->settings->HomePath || !inst->settings->ConfigPath)
{
free(inst->settings->HomePath);
free(inst->settings->ConfigPath);
freerdp_context_free(inst);
freerdp_free(inst);
return NULL;
}
rdpContext* context;
RDP_CLIENT_ENTRY_POINTS clientEntryPoints;
RdpClientEntry(&clientEntryPoints);
context = freerdp_client_context_new(&clientEntryPoints);
return inst;
if (!context)
return NULL;
return context->instance;
}
void ios_freerdp_free(freerdp* instance)
{
freerdp_context_free(instance);
freerdp_free(instance);
if (!instance || !instance->context)
return;
freerdp_client_context_free(instance->context);
}
void ios_init_freerdp()
{
signal(SIGPIPE, SIG_IGN);
freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);
}
void ios_uninit_freerdp()
{
}
/* compatibilty functions */
size_t fwrite$UNIX2003( const void *ptr, size_t size, size_t nmemb, FILE *stream )
size_t fwrite$UNIX2003(const void* ptr, size_t size, size_t nmemb, FILE* stream)
{
return fwrite(ptr, size , nmemb, stream);
}

View File

@ -1,28 +1,35 @@
/*
RDP ui callbacks
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 "ios_freerdp.h"
BOOL ios_ui_begin_paint(rdpContext * context);
BOOL ios_ui_end_paint(rdpContext * context);
BOOL ios_ui_resize_window(rdpContext * context);
BOOL ios_ui_begin_paint(rdpContext* context);
BOOL ios_ui_end_paint(rdpContext* context);
BOOL ios_ui_resize_window(rdpContext* context);
BOOL ios_ui_authenticate(freerdp * instance, char** username, char** password, char** domain);
DWORD ios_ui_check_certificate(freerdp * instance, const char* common_name,
const char * subject, const char * issuer,
const char * fingerprint, BOOL host_mismatch);
DWORD ios_ui_check_changed_certificate(freerdp * instance,
const char* common_name,
const char * subject,
const char * issuer,
const char * new_fingerprint,
const char * old_fingerprint);
BOOL ios_ui_authenticate(freerdp* instance, char** username, char** password,
char** domain);
BOOL ios_ui_gw_authenticate(freerdp* instance, char** username, char** password,
char** domain);
DWORD ios_ui_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
const char* issuer,
const char* fingerprint,
BOOL host_mismatch);
DWORD ios_ui_verify_changed_certificate(freerdp* instance,
const char* common_name,
const char* subject,
const char* issuer,
const char* new_fingerprint,
const char* old_subject,
const char* old_issuer,
const char* old_fingerprint);
void ios_allocate_display_buffer(mfInfo* mfi);
void ios_resize_display_buffer(mfInfo* mfi);

View File

@ -1,8 +1,8 @@
/*
RDP ui callbacks
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/.
*/
@ -17,36 +17,37 @@
#pragma mark -
#pragma mark Certificate authentication
BOOL ios_ui_authenticate(freerdp * instance, char** username, char** password, char** domain)
static void ios_resize_display_buffer(mfInfo* mfi);
static BOOL ios_ui_authenticate_raw(freerdp* instance, char** username,
char** password,
char** domain, const char* title)
{
mfInfo* mfi = MFI_FROM_INSTANCE(instance);
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
(*username) ? [NSString stringWithUTF8String:*username] : @"", @"username",
(*password) ? [NSString stringWithUTF8String:*password] : @"", @"password",
(*domain) ? [NSString stringWithUTF8String:*domain] : @"", @"domain",
[NSString stringWithUTF8String:instance->settings->ServerHostname], @"hostname", // used for the auth prompt message; not changed
nil];
(*username) ? [NSString stringWithUTF8String:*username] : @"", @"username",
(*password) ? [NSString stringWithUTF8String:*password] : @"", @"password",
(*domain) ? [NSString stringWithUTF8String:*domain] : @"", @"domain",
[NSString stringWithUTF8String:instance->settings->ServerHostname],
@"hostname", // used for the auth prompt message; not changed
nil];
// request auth UI
[mfi->session performSelectorOnMainThread:@selector(
sessionRequestsAuthenticationWithParams:) withObject:params waitUntilDone:YES];
// wait for UI request to be completed
[[mfi->session uiRequestCompleted] lock];
[[mfi->session uiRequestCompleted] wait];
[[mfi->session uiRequestCompleted] unlock];
// request auth UI
[mfi->session performSelectorOnMainThread:@selector(sessionRequestsAuthenticationWithParams:) withObject:params waitUntilDone:YES];
// wait for UI request to be completed
[[mfi->session uiRequestCompleted] lock];
[[mfi->session uiRequestCompleted] wait];
[[mfi->session uiRequestCompleted] unlock];
if (![[params valueForKey:@"result"] boolValue])
{
mfi->unwanted = YES;
return FALSE;
}
// Free old values
free(*username);
free(*password);
free(*domain);
// set values back
*username = strdup([[params objectForKey:@"username"] UTF8String]);
*password = strdup([[params objectForKey:@"password"] UTF8String]);
@ -59,28 +60,44 @@ BOOL ios_ui_authenticate(freerdp * instance, char** username, char** password, c
free(*domain);
return FALSE;
}
return TRUE;
}
DWORD ios_ui_check_certificate(freerdp * instance, const char* common_name,
const char * subject, const char * issuer,
const char * fingerprint, BOOL host_mismatch)
BOOL ios_ui_authenticate(freerdp* instance, char** username, char** password,
char** domain)
{
return ios_ui_authenticate_raw(instance, username, password, domain, "");
}
BOOL ios_ui_gw_authenticate(freerdp* instance, char** username, char** password,
char** domain)
{
return ios_ui_authenticate_raw(instance, username, password, domain, "gateway");
}
DWORD ios_ui_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
const char* issuer,
const char* fingerprint,
BOOL host_mismatch)
{
// check whether we accept all certificates
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"security.accept_certificates"] == YES)
if ([[NSUserDefaults standardUserDefaults] boolForKey:
@"security.accept_certificates"] == YES)
return 2;
mfInfo* mfi = MFI_FROM_INSTANCE(instance);
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
(subject) ? [NSString stringWithUTF8String:subject] : @"", @"subject",
(issuer) ? [NSString stringWithUTF8String:issuer] : @"", @"issuer",
(fingerprint) ? [NSString stringWithUTF8String:subject] : @"", @"fingerprint",
nil];
(subject) ? [NSString stringWithUTF8String:subject] : @"", @"subject",
(issuer) ? [NSString stringWithUTF8String:issuer] : @"", @"issuer",
(fingerprint) ? [NSString stringWithUTF8String:subject] : @"", @"fingerprint",
nil];
// request certificate verification UI
[mfi->session performSelectorOnMainThread:@selector(sessionVerifyCertificateWithParams:) withObject:params waitUntilDone:YES];
[mfi->session performSelectorOnMainThread:@selector(
sessionVerifyCertificateWithParams:) withObject:params waitUntilDone:YES];
// wait for UI request to be completed
[[mfi->session uiRequestCompleted] lock];
[[mfi->session uiRequestCompleted] wait];
@ -95,44 +112,63 @@ DWORD ios_ui_check_certificate(freerdp * instance, const char* common_name,
return 1;
}
DWORD ios_ui_check_changed_certificate(freerdp * instance,
const char * common_name,
const char * subject,
const char * issuer,
const char * new_fingerprint,
const char * old_fingerprint)
DWORD ios_ui_verify_changed_certificate(freerdp* instance,
const char* common_name,
const char* subject,
const char* issuer,
const char* new_fingerprint,
const char* old_subject,
const char* old_issuer,
const char* old_fingerprint)
{
return ios_ui_check_certificate(instance, common_name, subject, issuer,
new_fingerprint, FALSE);
return ios_ui_verify_certificate(instance, common_name, subject, issuer,
new_fingerprint, FALSE);
}
#pragma mark -
#pragma mark Graphics updates
BOOL ios_ui_begin_paint(rdpContext * context)
BOOL ios_ui_begin_paint(rdpContext* context)
{
rdpGdi *gdi = context->gdi;
rdpGdi* gdi = context->gdi;
gdi->primary->hdc->hwnd->invalid->null = 1;
return TRUE;
return TRUE;
}
BOOL ios_ui_end_paint(rdpContext * context)
BOOL ios_ui_end_paint(rdpContext* context)
{
mfInfo* mfi = MFI_FROM_INSTANCE(context->instance);
rdpGdi *gdi = context->gdi;
CGRect dirty_rect = CGRectMake(gdi->primary->hdc->hwnd->invalid->x, gdi->primary->hdc->hwnd->invalid->y, gdi->primary->hdc->hwnd->invalid->w, gdi->primary->hdc->hwnd->invalid->h);
mfInfo* mfi = MFI_FROM_INSTANCE(context->instance);
rdpGdi* gdi = context->gdi;
CGRect dirty_rect = CGRectMake(gdi->primary->hdc->hwnd->invalid->x,
gdi->primary->hdc->hwnd->invalid->y, gdi->primary->hdc->hwnd->invalid->w,
gdi->primary->hdc->hwnd->invalid->h);
if (gdi->primary->hdc->hwnd->invalid->null == 0)
[mfi->session performSelectorOnMainThread:@selector(setNeedsDisplayInRectAsValue:) withObject:[NSValue valueWithCGRect:dirty_rect] waitUntilDone:NO];
return TRUE;
[mfi->session performSelectorOnMainThread:@selector(
setNeedsDisplayInRectAsValue:) withObject:[NSValue valueWithCGRect:dirty_rect]
waitUntilDone:NO];
return TRUE;
}
BOOL ios_ui_resize_window(rdpContext * context)
BOOL ios_ui_resize_window(rdpContext* context)
{
rdpSettings* settings;
rdpGdi* gdi;
if (!context || !context->settings)
return FALSE;
settings = context->settings;
gdi = context->gdi;
if (!gdi_resize(gdi, settings->DesktopWidth, settings->DesktopHeight))
return FALSE;
ios_resize_display_buffer(MFI_FROM_INSTANCE(context->instance));
return TRUE;
return TRUE;
}
@ -140,23 +176,28 @@ BOOL ios_ui_resize_window(rdpContext * context)
#pragma mark Exported
static void ios_create_bitmap_context(mfInfo* mfi)
{
[mfi->session performSelectorOnMainThread:@selector(sessionBitmapContextWillChange) withObject:nil waitUntilDone:YES];
rdpGdi* gdi = mfi->instance->context->gdi;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
{
[mfi->session performSelectorOnMainThread:@selector(
sessionBitmapContextWillChange) withObject:nil waitUntilDone:YES];
rdpGdi* gdi = mfi->instance->context->gdi;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
if (GetBytesPerPixel(gdi->dstFormat) == 2)
mfi->bitmap_context = CGBitmapContextCreate(gdi->primary_buffer, gdi->width, gdi->height, 5, gdi->stride, colorSpace, kCGBitmapByteOrder16Little | kCGImageAlphaNoneSkipFirst);
mfi->bitmap_context = CGBitmapContextCreate(gdi->primary_buffer, gdi->width,
gdi->height, 5, gdi->stride, colorSpace,
kCGBitmapByteOrder16Little | kCGImageAlphaNoneSkipFirst);
else
mfi->bitmap_context = CGBitmapContextCreate(gdi->primary_buffer, gdi->width, gdi->height, 8, gdi->stride, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst);
CGColorSpaceRelease(colorSpace);
[mfi->session performSelectorOnMainThread:@selector(sessionBitmapContextDidChange) withObject:nil waitUntilDone:YES];
mfi->bitmap_context = CGBitmapContextCreate(gdi->primary_buffer, gdi->width,
gdi->height, 8, gdi->stride, colorSpace,
kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst);
CGColorSpaceRelease(colorSpace);
[mfi->session performSelectorOnMainThread:@selector(
sessionBitmapContextDidChange) withObject:nil waitUntilDone:YES];
}
void ios_allocate_display_buffer(mfInfo* mfi)
{
gdi_init(mfi->instance, PIXEL_FORMAT_XRGB32);
ios_create_bitmap_context(mfi);
}
@ -166,7 +207,6 @@ void ios_resize_display_buffer(mfInfo* mfi)
CGContextRef old_context = mfi->bitmap_context;
mfi->bitmap_context = NULL;
CGContextRelease(old_context);
// Create the new context
ios_create_bitmap_context(mfi);
}

View File

@ -1,9 +1,9 @@
/*
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.
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/.
*/
@ -21,18 +21,21 @@
#include <ifaddrs.h>
#include <net/if_dl.h>
BOOL ScanHostNameAndPort(NSString* address, NSString** host, unsigned short* port)
BOOL ScanHostNameAndPort(NSString* address, NSString** host,
unsigned short* port)
{
*host = @""; *port = 0;
*host = @"";
*port = 0;
if (![address length])
return NO;
NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"rdp://%@", address]];
NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"rdp://%@",
address]];
if (!url || ![[url host] length])
return NO;
*host = [url host];
*port = [[url port] unsignedShortValue];
return YES;
@ -43,18 +46,22 @@ BOOL ScanHostNameAndPort(NSString* address, NSString** host, unsigned short* por
NSString* LocalizedFitScreen()
{
return NSLocalizedString(@"Automatic", @"Screen resolution selector: Automatic resolution (Full Screen on iPad, reasonable size on iPhone)");
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");
return NSLocalizedString(@"Custom", @"Screen resolution selector: Custom");
}
BOOL ScanScreenResolution(NSString* description, int* width, int* height, TSXScreenOptions* type)
BOOL ScanScreenResolution(NSString* description, int* width, int* height,
TSXScreenOptions* type)
{
*height = 0; *width = 0; *type = TSXScreenOptionFixed;
*height = 0;
*width = 0;
*type = TSXScreenOptionFixed;
if ([description isEqualToString:LocalizedFitScreen()])
{
*type = TSXScreenOptionFitScreen;
@ -65,58 +72,69 @@ BOOL ScanScreenResolution(NSString* description, int* width, int* height, TSXScr
*type = TSXScreenOptionCustom;
return YES;
}
NSArray* resolution_components = [description componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"x*×"]];
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];
*height = [[resolution_components objectAtIndex:1] intValue];
return YES;
}
NSString* ScreenResolutionDescription(TSXScreenOptions type, int width, int height)
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: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;
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;
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");
return NSLocalizedString(@"Automatic", @"Automatic protocl security selection");
}
NSString* ProtocolSecurityDescription(TSXProtocolSecurityOptions type)
@ -127,14 +145,15 @@ NSString* ProtocolSecurityDescription(TSXProtocolSecurityOptions type)
return @"TLS";
else if (type == TSXProtocolSecurityRDP)
return @"RDP";
return LocalizedAutomaticSecurity();
}
BOOL ScanProtocolSecurity(NSString* description, TSXProtocolSecurityOptions* type)
BOOL ScanProtocolSecurity(NSString* description,
TSXProtocolSecurityOptions* type)
{
*type = TSXProtocolSecurityRDP;
if ([description isEqualToString:@"NLA"])
{
*type = TSXProtocolSecurityNLA;
@ -155,18 +174,22 @@ BOOL ScanProtocolSecurity(NSString* description, TSXProtocolSecurityOptions* typ
*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;
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;
}
@ -178,47 +201,52 @@ NSDictionary* SelectionForSecuritySetting()
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) {
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;
NSMutableArray* result = [NSMutableArray array];
for (NSString * item in history)
{
if ([item rangeOfString:filterStr].location != NSNotFound)
[result addObject:item];
}
return result;
}
#pragma mark Version Info
@ -232,140 +260,146 @@ NSString* TSXAppFullVersion()
BOOL IsPad()
{
#ifdef UI_USER_INTERFACE_IDIOM
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
#else
return NO;
return NO;
#endif
}
BOOL IsPhone()
{
#ifdef UI_USER_INTERFACE_IDIOM
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone);
return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone);
#else
return NO;
#endif
return NO;
#endif
}
// set mouse buttons swapped flag
static BOOL g_swap_mouse_buttons = NO;
void SetSwapMouseButtonsFlag(BOOL swapped)
{
g_swap_mouse_buttons = swapped;
g_swap_mouse_buttons = swapped;
}
// set invert scrolling flag
static BOOL g_invert_scrolling = NO;
void SetInvertScrollingFlag(BOOL invert)
{
g_invert_scrolling = invert;
g_invert_scrolling = invert;
}
// return event value for left mouse button
// 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));
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
// 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));
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 (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));
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;
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
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* TSXGetPrimaryMACAddress(NSString* sep)
{
NSString* macaddress = @"";
NSString* macaddress = @"";
struct ifaddrs* addrs;
struct ifaddrs *addrs;
if (getifaddrs(&addrs) < 0)
{
NSLog(@"getPrimaryMACAddress: getifaddrs failed.");
return macaddress;
}
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;
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;
}
}
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;
freeifaddrs(addrs);
if (dlAddr->sdl_alen != 6)
continue;
return macaddress;
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:
@"/Applications/Cydia.app/"])
return YES;
if ([[NSFileManager defaultManager] fileExistsAtPath:@"/etc/apt/"])
return YES;
if ([[NSFileManager defaultManager] fileExistsAtPath:@"/etc/apt/"])
return YES;
return NO;
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;
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;
}

View File

@ -1,9 +1,9 @@
/*
Global default bookmark settings
Copyright 2013 Thincast Technologies GmbH, Author: Dorian Johnson
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
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/.
*/
@ -16,33 +16,35 @@
+ (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];
_shared_global_defaults = [[GlobalDefaults alloc] init];
}
}
return _shared_global_defaults;
return _shared_global_defaults;
}
- (id)init
{
if (!(self = [super init]))
return nil;
ComputerBookmark* bookmark = nil;
NSData* bookmark_data = [[NSUserDefaults standardUserDefaults] objectForKey:@"TSXSharedGlobalDefaultBookmark"];
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];
bookmark = [[[ComputerBookmark alloc] initWithBaseDefaultParameters]
autorelease];
_default_bookmark = [bookmark retain];
return self;
}
@ -55,11 +57,12 @@
#pragma mark -
@synthesize bookmark=_default_bookmark;
@synthesize bookmark = _default_bookmark;
- (ComputerBookmark*)newBookmark
{
return [[ComputerBookmark alloc] initWithConnectionParameters:[[self newParams] autorelease]];
return [[ComputerBookmark alloc] initWithConnectionParameters:[[self newParams]
autorelease]];
}
- (ConnectionParams*)newParams
@ -70,14 +73,16 @@
- (ComputerBookmark*)newTestServerBookmark
{
ComputerBookmark* bm = [self newBookmark];
[bm setLabel:@"Test Server"];
[[bm params] setValue:@"testservice.ifreerdp.com" forKey:@"hostname"];
[[bm params] setInt:0 forKey:@"screen_resolution_type"];
[[bm params] setInt:1024 forKey:@"width"];
[[bm params] setInt:768 forKey:@"height"];
[[bm params] setInt:32 forKey:@"colors"];
[[bm params] setBool:YES forKey:@"perf_remotefx"];
ComputerBookmark* bm = [self newBookmark];
[bm setLabel:@"Test Server"];
[[bm params] setValue:@"testservice.ifreerdp.com" forKey:@"hostname"];
[[bm params] setInt:0 forKey:@"screen_resolution_type"];
[[bm params] setInt:1024 forKey:@"width"];
[[bm params] setInt:768 forKey:@"height"];
[[bm params] setInt:32 forKey:@"colors"];
[[bm params] setBool:YES forKey:@"perf_remotefx"];
[[bm params] setBool:YES forKey:@"perf_gfx"];
[[bm params] setBool:YES forKey:@"perf_h264"];
return bm;
}

View File

@ -1,9 +1,9 @@
/*
RDP Session object
RDP Session object
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.
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/.
*/
@ -17,9 +17,10 @@
#import "ConnectionParams.h"
NSString* TSXSessionDidDisconnectNotification = @"TSXSessionDidDisconnect";
NSString* TSXSessionDidFailToConnectNotification = @"TSXSessionDidFailToConnect";
NSString* TSXSessionDidFailToConnectNotification =
@"TSXSessionDidFailToConnect";
@interface RDPSession (Private)
@interface RDPSession(Private)
- (void)runSession;
- (void)runSessionFinished:(NSNumber*)result;
- (mfInfo*)mfi;
@ -35,245 +36,315 @@ NSString* TSXSessionDidFailToConnectNotification = @"TSXSessionDidFailToConnect"
@implementation RDPSession
@synthesize delegate=_delegate, params=_params, toolbarVisible = _toolbar_visible, uiRequestCompleted = _ui_request_completed, bookmark = _bookmark;
@synthesize delegate = _delegate, params = _params,
toolbarVisible = _toolbar_visible, uiRequestCompleted = _ui_request_completed,
bookmark = _bookmark;
+ (void)initialize
{
ios_init_freerdp();
ios_init_freerdp();
}
static BOOL addArgument(int* argc, char** *argv, const char* fmt, ...)
{
va_list ap;
char* arg = NULL;
char** tmp = realloc(*argv, (*argc + 1) * sizeof(char*));
if (!tmp)
return FALSE;
*argv = tmp;
*argc = *argc + 1;
va_start(ap, fmt);
vasprintf(&arg, fmt, ap);
va_end(ap);
(*argv)[*argc - 1] = arg;
return TRUE;
}
static BOOL addFlag(int* argc, char** *argv, const char* str, BOOL flag)
{
return addArgument(argc, argv, "%s%s", flag ? "+" : "-", str);
}
static void freeArguments(int argc, char** argv)
{
int i;
for (i = 0; i < argc; i++)
free(argv[i]);
free(argv);
}
// Designated initializer.
- (id)initWithBookmark:(ComputerBookmark *)bookmark
- (id)initWithBookmark:(ComputerBookmark*)bookmark
{
int status;
char** argv = NULL;
int argc = 0;
if (!(self = [super init]))
return nil;
if (!bookmark)
[NSException raise:NSInvalidArgumentException format:@"%s: params may not be nil.", __func__];
_bookmark = [bookmark retain];
[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;
_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];
_ui_request_completed = [[NSCondition alloc] init];
BOOL connected_via_3g = ![bookmark conntectedViaWLAN];
if (!addArgument(&argc, &argv, "iFreeRDP"))
goto out_free;
if (!addArgument(&argc, &argv, "/gdi:sw"))
goto out_free;
// 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;
if (!addArgument(&argc, &argv,
"/bpp:%d", [_params intForKey:@"colors" with3GEnabled:
connected_via_3g]))
goto out_free;
// connection info
if (!(settings->ServerHostname = strdup([_params UTF8StringForKey:@"hostname"])))
if ([_params hasValueForKey:@"port"])
if (!addArgument(&argc, &argv, "/port:%d", [_params intForKey:@"port"]))
goto out_free;
if ([_params boolForKey:@"console"])
if (!addArgument(&argc, &argv, "/admin"))
goto out_free;
if (!addArgument(&argc, &argv, "/v:%s", [_params UTF8StringForKey:
@"hostname"]))
goto out_free;
// String settings
if ([[_params StringForKey:@"username"] length])
{
settings->Username = strdup([_params UTF8StringForKey:@"username"]);
if (!settings->Username)
if (!addArgument(&argc, &argv, "/u:%s", [_params UTF8StringForKey:
@"username"]))
goto out_free;
}
if ([[_params StringForKey:@"password"] length])
{
settings->Password = strdup([_params UTF8StringForKey:@"password"]);
if (!settings->Password)
if (!addArgument(&argc, &argv, "/p:%s", [_params UTF8StringForKey:
@"password"]))
goto out_free;
}
if ([[_params StringForKey:@"domain"] length])
{
settings->Domain = strdup([_params UTF8StringForKey:@"domain"]);
if (!settings->Domain)
if (!addArgument(&argc, &argv, "/d:%s", [_params UTF8StringForKey:
@"domain"]))
goto out_free;
}
settings->ShellWorkingDirectory = strdup([_params UTF8StringForKey:@"working_directory"]);
settings->AlternateShell = strdup([_params UTF8StringForKey:@"remote_program"]);
if (!settings->ShellWorkingDirectory || !settings->AlternateShell)
if ([[_params StringForKey:@"working_directory"] length])
{
if (!addArgument(&argc, &argv, "/shell-dir:%s", [_params UTF8StringForKey:
@"working_directory"]))
goto out_free;
}
if ([[_params StringForKey:@"remote_program"] length])
{
if (!addArgument(&argc, &argv, "/shell:%s", [_params UTF8StringForKey:
@"remote_program"]))
goto out_free;
}
// RemoteFX
if ([_params boolForKey:@"perf_remotefx" with3GEnabled:connected_via_3g])
if (!addArgument(&argc, &argv, "/rfx"))
goto out_free;
if ([_params boolForKey:@"perf_gfx" with3GEnabled:connected_via_3g])
if (!addArgument(&argc, &argv, "/gfx"))
goto out_free;
if ([_params boolForKey:@"perf_h264" with3GEnabled:connected_via_3g])
if (!addArgument(&argc, &argv, "/gfx-h264"))
goto out_free;
if (![_params boolForKey:@"perf_remotefx" with3GEnabled:connected_via_3g] &&
![_params boolForKey:@"perf_gfx" with3GEnabled:connected_via_3g] &&
![_params boolForKey:@"perf_h264" with3GEnabled:connected_via_3g])
if (!addArgument(&argc, &argv, "/nsc"))
goto out_free;
if (!addFlag(&argc, &argv, "bitmap-cache", TRUE))
goto out_free;
// 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;
}
if (!addFlag(&argc, &argv, "wallpaper", [_params boolForKey:@"perf_show_desktop"
with3GEnabled:connected_via_3g]))
goto out_free;
settings->BitmapCacheV3Enabled = TRUE;
if (!addFlag(&argc, &argv,
"window-drag", [_params boolForKey:@"perf_window_dragging"
with3GEnabled:connected_via_3g]))
goto out_free;
if (!addFlag(&argc, &argv,
"menu-anims", [_params boolForKey:@"perf_menu_animation"
with3GEnabled:connected_via_3g]))
goto out_free;
if (!addFlag(&argc, &argv, "themes", [_params boolForKey:@"perf_windows_themes"
with3GEnabled:connected_via_3g]))
goto out_free;
if (!addFlag(&argc, &argv, "fonts", [_params boolForKey:@"perf_font_smoothing"
with3GEnabled:connected_via_3g]))
goto out_free;
if (!addFlag(&argc, &argv, "aero", [_params boolForKey:
@"perf_desktop_composition" with3GEnabled:connected_via_3g]))
goto out_free;
// 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 (!addArgument(&argc, &argv, "/w:%d", [_params intForKey:@"width"]))
goto out_free;
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;
if (!addArgument(&argc, &argv, "/h:%d", [_params intForKey:@"height"]))
goto out_free;
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->UseRdpSecurityLayer = TRUE;
break;
// security
switch ([_params intForKey:@"security"])
{
case TSXProtocolSecurityNLA:
if (!addArgument(&argc, &argv, "/sec:NLA"))
goto out_free;
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 = TSC_PROXY_MODE_DIRECT;
settings->GatewayEnabled = TRUE;
settings->GatewayUseSameCredentials = FALSE;
break;
case TSXProtocolSecurityTLS:
if (!addArgument(&argc, &argv, "/sec:TLS"))
goto out_free;
break;
case TSXProtocolSecurityRDP:
if (!addArgument(&argc, &argv, "/sec:RDP"))
goto out_free;
break;
default:
break;
}
// ts gateway settings
if ([_params boolForKey:@"enable_tsg_settings"])
{
if (!addArgument(&argc, &argv,
"/g:%s", [_params UTF8StringForKey:@"tsg_hostname"]))
goto out_free;
if (!addArgument(&argc, &argv, "/gp:%d", [_params intForKey:@"tsg_port"]))
goto out_free;
if (!addArgument(&argc, &argv, "/gu:%s", [_params intForKey:@"tsg_username"]))
goto out_free;
if (!addArgument(&argc, &argv, "/gp:%s", [_params intForKey:@"tsg_password"]))
goto out_free;
if (!addArgument(&argc, &argv, "/gd:%s", [_params intForKey:@"tsg_domain"]))
goto out_free;
}
if (!settings->GatewayHostname || !settings->GatewayUsername || !settings->GatewayPassword
|| !settings->GatewayDomain)
{
goto out_free;
}
}
// Remote keyboard layout
settings->KeyboardLayout = 0x409;
// Audio settings
settings->AudioPlayback = FALSE;
settings->AudioCapture = FALSE;
if (!addArgument(&argc, &argv, "/kbd:%d", 0x409))
goto out_free;
status = freerdp_client_settings_parse_command_line(_freerdp->settings, argc,
argv,
FALSE);
if (0 != status)
goto out_free;
freeArguments(argc, argv);
[self mfi]->session = self;
return self;
out_free:
[self release];
return nil;
freeArguments(argc, argv);
[self release];
return nil;
}
- (void)dealloc
{
[self setDelegate:nil];
[_bookmark release];
[_name release];
[_bookmark release];
[_name release];
[_params release];
[_ui_request_completed release];
[_ui_request_completed release];
ios_freerdp_free(_freerdp);
[super dealloc];
}
- (CGContextRef)bitmapContext
{
return [self mfi]->bitmap_context;
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;
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;
}
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);
// 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"]);
ios_events_send(mfi, [NSDictionary dictionaryWithObject:@"disconnect" forKey:
@"type"]);
if (mfi->connection_state == TSXConnectionConnecting)
{
mfi->unwanted = YES;
[self sessionDidDisconnect];
return;
}
}
}
- (TSXConnectionState)connectionState
@ -284,34 +355,34 @@ out_free:
// suspends the session
-(void)suspend
{
if(!_suspended)
{
_suspended = YES;
// instance->update->SuppressOutput(instance->context, 0, NULL);
}
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];
}
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;
return _suspended;
}
#pragma mark -
@ -330,7 +401,7 @@ out_free:
{
if ([[self delegate] respondsToSelector:@selector(session:needsRedrawInRect:)])
[[self delegate] session:self needsRedrawInRect:[rect_value CGRectValue]];
}
}
#pragma mark -
@ -338,37 +409,34 @@ out_free:
- (UIImage*)getScreenshotWithSize:(CGSize)size
{
NSAssert([self mfi]->bitmap_context != nil, @"Screenshot requested while having no valid RDP drawing context");
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);
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 0, size.height);
CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1.0, -1.0);
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, size.width, size.height), cgImage);
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, size.width,
size.height), cgImage);
UIImage* viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGImageRelease(cgImage);
return viewImage;
CGImageRelease(cgImage);
return viewImage;
}
- (rdpSettings*)getSessionParams
{
return _freerdp->settings;
return _freerdp->settings;
}
- (NSString*)sessionName
{
return _name;
return _name;
}
@end
@end
#pragma mark -
@implementation RDPSession (Private)
@implementation RDPSession(Private)
- (mfInfo*)mfi
{
@ -378,91 +446,99 @@ out_free:
// 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];
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;
}
[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];
if ([[self delegate] respondsToSelector:@selector(sessionDidConnect:)])
[[self delegate] sessionDidConnect:self];
}
- (void)sessionDidFailToConnect:(int)reason
{
[[NSNotificationCenter defaultCenter] postNotificationName:TSXSessionDidFailToConnectNotification object:self];
{
[[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:)])
{
[[NSNotificationCenter defaultCenter] postNotificationName:
TSXSessionDidDisconnectNotification object:self];
if ([[self delegate] respondsToSelector:@selector(sessionDidDisconnect:)])
[[self delegate] sessionDidDisconnect:self];
}
- (void)sessionBitmapContextWillChange
{
if ([[self delegate] respondsToSelector:@selector(sessionBitmapContextWillChange:)])
if ([[self delegate] respondsToSelector:@selector(
sessionBitmapContextWillChange:)])
[[self delegate] sessionBitmapContextWillChange:self];
}
- (void)sessionBitmapContextDidChange
{
if ([[self delegate] respondsToSelector:@selector(sessionBitmapContextDidChange:)])
if ([[self delegate] respondsToSelector:@selector(sessionBitmapContextDidChange
:)])
[[self delegate] sessionBitmapContextDidChange:self];
}
- (void)sessionRequestsAuthenticationWithParams:(NSMutableDictionary*)params
{
if ([[self delegate] respondsToSelector:@selector(session:requestsAuthenticationWithParams:)])
[[self delegate] session:self requestsAuthenticationWithParams: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];
if ([[self delegate] respondsToSelector:@selector(session:
verifyCertificateWithParams:)])
[[self delegate] session:self verifyCertificateWithParams:params];
}
@end

View File

@ -1,183 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="8.00">
<data>
<int key="IBDocument.SystemTarget">1296</int>
<string key="IBDocument.SystemVersion">11D50b</string>
<string key="IBDocument.InterfaceBuilderVersion">2182</string>
<string key="IBDocument.AppKitVersion">1138.32</string>
<string key="IBDocument.HIToolboxVersion">568.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="NS.object.0">1179</string>
</object>
<array key="IBDocument.IntegratedClassDependencies">
<string>IBUIWindow</string>
<string>IBUITabBarController</string>
<string>IBUITabBar</string>
<string>IBUICustomObject</string>
<string>IBProxyObject</string>
</array>
<array key="IBDocument.PluginDependencies">
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
</array>
<object class="NSMutableDictionary" key="IBDocument.Metadata">
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
<integer value="1" key="NS.object.0"/>
</object>
<array class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
<object class="IBProxyObject" id="841351856">
<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
</object>
<object class="IBProxyObject" id="590933970">
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
</object>
<object class="IBUICustomObject" id="271699545">
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
</object>
<object class="IBUIWindow" id="380026005">
<reference key="NSNextResponder"/>
<int key="NSvFlags">1316</int>
<object class="NSPSMatrix" key="NSFrameMatrix"/>
<string key="NSFrameSize">{320, 480}</string>
<reference key="NSSuperview"/>
<object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">1</int>
<bytes key="NSRGB">MSAxIDEAA</bytes>
</object>
<bool key="IBUIOpaque">NO</bool>
<bool key="IBUIClearsContextBeforeDrawing">NO</bool>
<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<bool key="IBUIResizesToFullScreen">YES</bool>
</object>
<object class="IBUITabBarController" id="803392999">
<object class="IBUISimulatedTabBarMetrics" key="IBUISimulatedBottomBarMetrics"/>
<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
<object class="IBUISimulatedOrientationMetrics" key="IBUISimulatedOrientationMetrics">
<int key="IBUIInterfaceOrientation">1</int>
<int key="interfaceOrientation">1</int>
</object>
<bool key="IBUIDefinesPresentationContext">YES</bool>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
<bool key="IBUIHorizontal">NO</bool>
<array class="NSMutableArray" key="IBUIViewControllers"/>
<object class="IBUITabBar" key="IBUITabBar" id="690969762">
<reference key="NSNextResponder"/>
<int key="NSvFlags">266</int>
<string key="NSFrame">{{0, 431}, {320, 49}}</string>
<reference key="NSSuperview"/>
<string key="NSReuseIdentifierKey">_NS:29</string>
<object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MCAwAA</bytes>
</object>
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
</object>
</object>
</array>
<object class="IBObjectContainer" key="IBDocument.Objects">
<array class="NSMutableArray" key="connectionRecords">
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">delegate</string>
<reference key="source" ref="841351856"/>
<reference key="destination" ref="271699545"/>
</object>
<int key="connectionID">12</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">window</string>
<reference key="source" ref="271699545"/>
<reference key="destination" ref="380026005"/>
</object>
<int key="connectionID">13</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">tabBarController</string>
<reference key="source" ref="271699545"/>
<reference key="destination" ref="803392999"/>
</object>
<int key="connectionID">14</int>
</object>
</array>
<object class="IBMutableOrderedSet" key="objectRecords">
<array key="orderedObjects">
<object class="IBObjectRecord">
<int key="objectID">0</int>
<array key="object" id="0"/>
<reference key="children" ref="1000"/>
<nil key="parent"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">2</int>
<reference key="object" ref="380026005"/>
<array class="NSMutableArray" key="children"/>
<reference key="parent" ref="0"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">-1</int>
<reference key="object" ref="841351856"/>
<reference key="parent" ref="0"/>
<string key="objectName">File's Owner</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-2</int>
<reference key="object" ref="590933970"/>
<reference key="parent" ref="0"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">4</int>
<reference key="object" ref="803392999"/>
<array class="NSMutableArray" key="children">
<reference ref="690969762"/>
</array>
<reference key="parent" ref="0"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">5</int>
<reference key="object" ref="690969762"/>
<reference key="parent" ref="803392999"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">11</int>
<reference key="object" ref="271699545"/>
<reference key="parent" ref="0"/>
<string key="objectName">AppDelegate</string>
</object>
</array>
</object>
<dictionary class="NSMutableDictionary" key="flattenedProperties">
<string key="-1.CustomClassName">UIApplication</string>
<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="-2.CustomClassName">UIResponder</string>
<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="11.CustomClassName">AppDelegate</string>
<string key="11.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<dictionary class="NSMutableDictionary" key="2.IBAttributePlaceholdersKey"/>
<string key="2.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="4.CustomClassName">MainTabBarController</string>
<string key="4.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string key="5.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
</dictionary>
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
<nil key="activeLocalization"/>
<dictionary class="NSMutableDictionary" key="localizations"/>
<nil key="sourceID"/>
<int key="maxID">21</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes"/>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
<real value="1296" key="NS.object.0"/>
</object>
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
<int key="IBDocument.defaultPropertyAccessControl">3</int>
<string key="IBCocoaTouchPluginVersion">1179</string>
</data>
</archive>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10116" systemVersion="15G31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<dependencies>
<deployment version="2352" identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="UIApplication">
<connections>
<outlet property="delegate" destination="11" id="12"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<customObject id="11" userLabel="AppDelegate" customClass="AppDelegate">
<connections>
<outlet property="tabBarController" destination="4" id="14"/>
<outlet property="window" destination="2" id="13"/>
</connections>
</customObject>
<window opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="2">
<rect key="frame" x="0.0" y="0.0" width="320" height="480"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
</window>
<tabBarController definesPresentationContext="YES" id="4" customClass="MainTabBarController">
<extendedEdge key="edgesForExtendedLayout"/>
<simulatedTabBarMetrics key="simulatedBottomBarMetrics"/>
<tabBar key="tabBar" contentMode="scaleToFill" id="5">
<rect key="frame" x="0.0" y="431" width="320" height="49"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</tabBar>
</tabBarController>
</objects>
</document>