Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,19 @@
/*
Application info controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import <UIKit/UIKit.h>
@interface AboutController : UIViewController <UIWebViewDelegate>
{
NSString *last_link_clicked;
UIWebView *webView;
}
@end

View File

@@ -0,0 +1,120 @@
/*
Application info controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "AboutController.h"
#import "Utils.h"
#import "BlockAlertView.h"
@implementation AboutController
// The designated initializer. Override if you create the controller programmatically and want to
// perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]))
{
// set title and tab-bar image
[self setTitle:NSLocalizedString(@"About", @"About Controller title")];
UIImage *tabBarIcon = [UIImage
imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tabbar_icon_about"
ofType:@"png"]];
[self setTabBarItem:[[[UITabBarItem alloc]
initWithTitle:NSLocalizedString(@"About", @"Tabbar item about")
image:tabBarIcon
tag:0] autorelease]];
last_link_clicked = nil;
}
return self;
}
- (void)dealloc
{
[super dealloc];
[last_link_clicked release];
}
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
webView = [[[UIWebView alloc] initWithFrame:CGRectZero] autorelease];
[webView
setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
[webView setAutoresizesSubviews:YES];
[webView setDelegate:self];
[webView setDataDetectorTypes:UIDataDetectorTypeNone];
[self setView:webView];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *filename = (IsPhone() ? @"about_phone" : @"about");
NSString *htmlString = [[[NSString alloc]
initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:filename
ofType:@"html"
inDirectory:@"about_page"]
encoding:NSUTF8StringEncoding
error:nil] autorelease];
[webView
loadHTMLString:[NSString stringWithFormat:htmlString, TSXAppFullVersion(),
[[UIDevice currentDevice] systemName],
[[UIDevice currentDevice] systemVersion],
[[UIDevice currentDevice] model]]
baseURL:[NSURL fileURLWithPath:[[[NSBundle mainBundle] bundlePath]
stringByAppendingPathComponent:@"about_page"]]];
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#pragma mark -
#pragma mark UIWebView callbacks
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType
{
if ([[request URL] isFileURL])
return YES;
if (navigationType == UIWebViewNavigationTypeLinkClicked)
{
[last_link_clicked release];
last_link_clicked = [[[request URL] absoluteString] retain];
BlockAlertView *alert = [BlockAlertView
alertWithTitle:NSLocalizedString(@"External Link", @"External Link Alert Title")
message:[NSString stringWithFormat:
NSLocalizedString(
@"Open [%@] in Browser?",
@"Open link in browser (with link as parameter)"),
last_link_clicked]];
[alert setCancelButtonWithTitle:NSLocalizedString(@"No", @"No Button") block:nil];
[alert addButtonWithTitle:NSLocalizedString(@"OK", @"OK Button")
block:^{
[[UIApplication sharedApplication]
openURL:[NSURL URLWithString:last_link_clicked]];
}];
[alert show];
return NO;
}
return YES;
}
@end

View File

@@ -0,0 +1,26 @@
/*
Controller to edit advanced bookmark settings
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "EditorBaseController.h"
@class ComputerBookmark;
@class ConnectionParams;
@interface AdvancedBookmarkEditorController : EditorBaseController
{
@private
ComputerBookmark *_bookmark;
ConnectionParams *_params;
}
// init for the given bookmark
- (id)initWithBookmark:(ComputerBookmark *)bookmark;
@end

View File

@@ -0,0 +1,407 @@
/*
Controller to edit advanced bookmark settings
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "AdvancedBookmarkEditorController.h"
#import "Bookmark.h"
#import "Utils.h"
#import "EditorSelectionController.h"
#import "ScreenSelectionController.h"
#import "PerformanceEditorController.h"
#import "BookmarkGatewaySettingsController.h"
@interface AdvancedBookmarkEditorController ()
@end
#define SECTION_ADVANCED_SETTINGS 0
#define SECTION_COUNT 1
@implementation AdvancedBookmarkEditorController
- (id)initWithBookmark:(ComputerBookmark *)bookmark
{
if ((self = [super initWithStyle:UITableViewStyleGrouped]))
{
// set additional settings state according to bookmark data
_bookmark = [bookmark retain];
_params = [bookmark params];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self setTitle:NSLocalizedString(@"Advanced Settings", @"Advanced Settings title")];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// we need to reload the table view data here to have up-to-date data for the
// advanced settings accessory items (like for resolution/color mode settings)
[[self tableView] reloadData];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return SECTION_COUNT;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
switch (section)
{
case SECTION_ADVANCED_SETTINGS: // advanced settings
return 9;
default:
break;
}
return 0;
}
// set section headers
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
switch (section)
{
case SECTION_ADVANCED_SETTINGS:
return NSLocalizedString(@"Advanced", @"'Advanced': advanced settings header");
}
return @"unknown";
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// determine the required cell type
NSString *cellType = nil;
switch ([indexPath section])
{
case SECTION_ADVANCED_SETTINGS: // advanced settings
{
switch ([indexPath row])
{
case 0: // Enable/Disable TSG Settings
cellType = TableCellIdentifierYesNo;
break;
case 1: // TS Gateway Settings
cellType = TableCellIdentifierSubEditor;
break;
case 2: // 3G Settings
cellType = TableCellIdentifierYesNo;
break;
case 3: // 3G screen/color depth
cellType = TableCellIdentifierSelection;
break;
case 4: // 3G performance settings
cellType = TableCellIdentifierSubEditor;
break;
case 5: // security mode
cellType = TableCellIdentifierSelection;
break;
case 6: // remote program
case 7: // work dir
cellType = TableCellIdentifierText;
break;
case 8: // console mode
cellType = TableCellIdentifierYesNo;
break;
default:
break;
}
break;
}
}
NSAssert(cellType != nil, @"Couldn't determine cell type");
// get the table view cell
UITableViewCell *cell = [self tableViewCellFromIdentifier:cellType];
NSAssert(cell, @"Invalid cell");
// set cell values
switch ([indexPath section])
{
// advanced settings
case SECTION_ADVANCED_SETTINGS:
[self initAdvancedSettings:indexPath cell:cell];
break;
default:
break;
}
return cell;
}
// updates advanced settings in the UI
- (void)initAdvancedSettings:(NSIndexPath *)indexPath cell:(UITableViewCell *)cell
{
BOOL enable_3G_settings = [_params boolForKey:@"enable_3g_settings"];
switch (indexPath.row)
{
case 0:
{
EditFlagTableViewCell *flagCell = (EditFlagTableViewCell *)cell;
[[flagCell label]
setText:NSLocalizedString(@"Enable TS Gateway",
@"'Enable TS Gateway': Bookmark enable TSG settings")];
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
[[flagCell toggle] setOn:[_params boolForKey:@"enable_tsg_settings"]];
[[flagCell toggle] addTarget:self
action:@selector(toggleSettingValue:)
forControlEvents:UIControlEventValueChanged];
break;
}
case 1:
{
BOOL enable_tsg_settings = [_params boolForKey:@"enable_tsg_settings"];
EditSubEditTableViewCell *editCell = (EditSubEditTableViewCell *)cell;
[[editCell label]
setText:NSLocalizedString(@"TS Gateway Settings",
@"'TS Gateway Settings': Bookmark TS Gateway Settings")];
[[editCell label] setEnabled:enable_tsg_settings];
[editCell setSelectionStyle:enable_tsg_settings ? UITableViewCellSelectionStyleBlue
: UITableViewCellSelectionStyleNone];
break;
}
case 2:
{
EditFlagTableViewCell *flagCell = (EditFlagTableViewCell *)cell;
[[flagCell label]
setText:NSLocalizedString(@"3G Settings",
@"'3G Settings': Bookmark enable 3G settings")];
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
[[flagCell toggle] setOn:[_params boolForKey:@"enable_3g_settings"]];
[[flagCell toggle] addTarget:self
action:@selector(toggleSettingValue:)
forControlEvents:UIControlEventValueChanged];
break;
}
case 3:
{
EditSelectionTableViewCell *selCell = (EditSelectionTableViewCell *)cell;
[[selCell label]
setText:NSLocalizedString(@"3G Screen",
@"'3G Screen': Bookmark 3G Screen settings")];
NSString *resolution = ScreenResolutionDescription(
[_params intForKeyPath:@"settings_3g.screen_resolution_type"],
[_params intForKeyPath:@"settings_3g.width"],
[_params intForKeyPath:@"settings_3g.height"]);
int colorBits = [_params intForKeyPath:@"settings_3g.colors"];
[[selCell selection]
setText:[NSString stringWithFormat:@"%@@%d", resolution, colorBits]];
[[selCell label] setEnabled:enable_3G_settings];
[[selCell selection] setEnabled:enable_3G_settings];
[selCell setSelectionStyle:enable_3G_settings ? UITableViewCellSelectionStyleBlue
: UITableViewCellSelectionStyleNone];
break;
}
case 4:
{
EditSubEditTableViewCell *editCell = (EditSubEditTableViewCell *)cell;
[[editCell label]
setText:NSLocalizedString(@"3G Performance",
@"'3G Performance': Bookmark 3G Performance Settings")];
[[editCell label] setEnabled:enable_3G_settings];
[editCell setSelectionStyle:enable_3G_settings ? UITableViewCellSelectionStyleBlue
: UITableViewCellSelectionStyleNone];
break;
}
case 5:
{
EditSelectionTableViewCell *selCell = (EditSelectionTableViewCell *)cell;
[[selCell label]
setText:NSLocalizedString(@"Security",
@"'Security': Bookmark protocol security settings")];
[[selCell selection]
setText:ProtocolSecurityDescription([_params intForKey:@"security"])];
break;
}
case 6:
{
EditTextTableViewCell *textCell = (EditTextTableViewCell *)cell;
[[textCell label]
setText:NSLocalizedString(@"Remote Program",
@"'Remote Program': Bookmark remote program settings")];
[[textCell textfield] setText:[_params StringForKey:@"remote_program"]];
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
[[textCell textfield]
setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
[self adjustEditTextTableViewCell:textCell];
break;
}
case 7:
{
EditTextTableViewCell *textCell = (EditTextTableViewCell *)cell;
[[textCell label]
setText:NSLocalizedString(
@"Working Directory",
@"'Working Directory': Bookmark working directory settings")];
[[textCell textfield] setText:[_params StringForKey:@"working_dir"]];
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
[[textCell textfield]
setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
[self adjustEditTextTableViewCell:textCell];
break;
}
case 8:
{
EditFlagTableViewCell *flagCell = (EditFlagTableViewCell *)cell;
[[flagCell label]
setText:NSLocalizedString(@"Console Mode",
@"'Console Mode': Bookmark console mode settings")];
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
[[flagCell toggle] setOn:[_params boolForKey:@"console"]];
[[flagCell toggle] addTarget:self
action:@selector(toggleSettingValue:)
forControlEvents:UIControlEventValueChanged];
break;
}
default:
NSLog(@"Invalid row index in settings table!");
break;
}
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIViewController *viewCtrl = nil;
// determine view
switch ([indexPath row])
{
case 1:
if ([_params boolForKey:@"enable_tsg_settings"])
viewCtrl = [[[BookmarkGatewaySettingsController alloc] initWithBookmark:_bookmark]
autorelease];
break;
case 3:
if ([_params boolForKey:@"enable_3g_settings"])
viewCtrl = [[[ScreenSelectionController alloc]
initWithConnectionParams:_params
keyPath:@"settings_3g"] autorelease];
break;
case 4:
if ([_params boolForKey:@"enable_3g_settings"])
viewCtrl = [[[PerformanceEditorController alloc]
initWithConnectionParams:_params
keyPath:@"settings_3g"] autorelease];
break;
case 5:
viewCtrl = [[[EditorSelectionController alloc]
initWithConnectionParams:_params
entries:[NSArray arrayWithObject:@"security"]
selections:[NSArray arrayWithObject:SelectionForSecuritySetting()]]
autorelease];
break;
default:
break;
}
// display view
if (viewCtrl)
[[self navigationController] pushViewController:viewCtrl animated:YES];
}
#pragma mark -
#pragma mark Text Field delegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return NO;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
switch (textField.tag)
{
// update remote program/work dir settings
case GET_TAG(SECTION_ADVANCED_SETTINGS, 6):
{
[_params setValue:[textField text] forKey:@"remote_program"];
break;
}
case GET_TAG(SECTION_ADVANCED_SETTINGS, 7):
{
[_params setValue:[textField text] forKey:@"working_dir"];
break;
}
default:
break;
}
return YES;
}
#pragma mark - Action handlers
- (void)toggleSettingValue:(id)sender
{
UISwitch *valueSwitch = (UISwitch *)sender;
switch (valueSwitch.tag)
{
case GET_TAG(SECTION_ADVANCED_SETTINGS, 0):
{
[_params setBool:[valueSwitch isOn] forKey:@"enable_tsg_settings"];
NSArray *indexPaths =
[NSArray arrayWithObjects:[NSIndexPath indexPathForRow:1
inSection:SECTION_ADVANCED_SETTINGS],
[NSIndexPath indexPathForRow:2
inSection:SECTION_ADVANCED_SETTINGS],
nil];
[[self tableView] reloadRowsAtIndexPaths:indexPaths
withRowAnimation:UITableViewRowAnimationNone];
break;
}
case GET_TAG(SECTION_ADVANCED_SETTINGS, 2):
{
[_params setBool:[valueSwitch isOn] forKey:@"enable_3g_settings"];
NSArray *indexPaths =
[NSArray arrayWithObjects:[NSIndexPath indexPathForRow:3
inSection:SECTION_ADVANCED_SETTINGS],
[NSIndexPath indexPathForRow:2
inSection:SECTION_ADVANCED_SETTINGS],
nil];
[[self tableView] reloadRowsAtIndexPaths:indexPaths
withRowAnimation:UITableViewRowAnimationNone];
break;
}
case GET_TAG(SECTION_ADVANCED_SETTINGS, 8):
[_params setBool:[valueSwitch isOn] forKey:@"console"];
break;
default:
break;
}
}
@end

View File

@@ -0,0 +1,15 @@
/*
Controller to specify application wide settings
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "EditorBaseController.h"
@interface AppSettingsController : EditorBaseController
@end

View File

@@ -0,0 +1,360 @@
/*
Controller to specify application wide settings
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "AppSettingsController.h"
#import "Utils.h"
#import "Toast+UIView.h"
@implementation AppSettingsController
// keep this up-to-date for correct section display/hiding
#define SECTION_UI_SETTINGS 0
#define SECTION_CERTIFICATE_HANDLING_SETTINGS 1
#define SECTION_NUM_SECTIONS 2
#pragma mark -
#pragma mark Initialization
- (id)initWithStyle:(UITableViewStyle)style
{
if ((self = [super initWithStyle:style]))
{
UIImage *tabBarIcon = [UIImage
imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tabbar_icon_settings"
ofType:@"png"]];
[self
setTabBarItem:[[[UITabBarItem alloc]
initWithTitle:NSLocalizedString(@"Settings", @"Tabbar item settings")
image:tabBarIcon
tag:0] autorelease]];
}
return self;
}
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// set title
[self setTitle:NSLocalizedString(@"Settings", @"App Settings title")];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return SECTION_NUM_SECTIONS;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
switch (section)
{
case SECTION_UI_SETTINGS: // UI settings
return 5;
case SECTION_CERTIFICATE_HANDLING_SETTINGS: // certificate handling settings
return 2;
default:
break;
}
return 0;
}
// set section headers
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
switch (section)
{
case SECTION_UI_SETTINGS:
return NSLocalizedString(@"User Interface", @"UI settings section title");
case SECTION_CERTIFICATE_HANDLING_SETTINGS:
return NSLocalizedString(@"Server Certificate Handling",
@"Server Certificate Handling section title");
default:
return nil;
}
return @"unknown";
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// determine the required cell type
NSString *cellIdentifier = nil;
switch ([indexPath section])
{
case SECTION_UI_SETTINGS:
{
switch ([indexPath row])
{
case 0:
case 1:
case 2:
case 3:
case 4:
cellIdentifier = TableCellIdentifierYesNo;
break;
}
break;
}
case SECTION_CERTIFICATE_HANDLING_SETTINGS:
{
switch ([indexPath row])
{
case 0:
cellIdentifier = TableCellIdentifierYesNo;
break;
case 1:
cellIdentifier = TableCellIdentifierSubEditor;
break;
}
break;
}
}
NSAssert(cellIdentifier != nil, @"Couldn't determine cell type");
// get the table view cell
UITableViewCell *cell = [self tableViewCellFromIdentifier:cellIdentifier];
NSAssert(cell, @"Invalid cell");
// set cell values
switch ([indexPath section])
{
case SECTION_UI_SETTINGS:
[self initUISettings:indexPath cell:cell];
break;
case SECTION_CERTIFICATE_HANDLING_SETTINGS:
[self initCertificateHandlingSettings:indexPath cell:cell];
break;
default:
break;
}
return cell;
}
#pragma mark - Initialization helpers
// updates UI settings in the UI
- (void)initUISettings:(NSIndexPath *)indexPath cell:(UITableViewCell *)cell
{
switch ([indexPath row])
{
case 0:
{
EditFlagTableViewCell *flagCell = (EditFlagTableViewCell *)cell;
[[flagCell label] setText:NSLocalizedString(@"Hide Status Bar",
"Show/Hide Phone Status Bar setting")];
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
[[flagCell toggle]
setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"ui.hide_status_bar"]];
[[flagCell toggle] addTarget:self
action:@selector(toggleSettingValue:)
forControlEvents:UIControlEventValueChanged];
break;
}
case 1:
{
EditFlagTableViewCell *flagCell = (EditFlagTableViewCell *)cell;
[[flagCell label]
setText:NSLocalizedString(@"Hide Tool Bar", "Show/Hide Tool Bar setting")];
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
[[flagCell toggle]
setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"ui.hide_tool_bar"]];
[[flagCell toggle] addTarget:self
action:@selector(toggleSettingValue:)
forControlEvents:UIControlEventValueChanged];
break;
}
case 2:
{
EditFlagTableViewCell *flagCell = (EditFlagTableViewCell *)cell;
[[flagCell label]
setText:NSLocalizedString(@"Swap Mouse Buttons", "Swap Mouse Button UI setting")];
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
[[flagCell toggle]
setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"ui.swap_mouse_buttons"]];
[[flagCell toggle] addTarget:self
action:@selector(toggleSettingValue:)
forControlEvents:UIControlEventValueChanged];
break;
}
case 3:
{
EditFlagTableViewCell *flagCell = (EditFlagTableViewCell *)cell;
[[flagCell label]
setText:NSLocalizedString(@"Invert Scrolling", "Invert Scrolling UI setting")];
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
[[flagCell toggle]
setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"ui.invert_scrolling"]];
[[flagCell toggle] addTarget:self
action:@selector(toggleSettingValue:)
forControlEvents:UIControlEventValueChanged];
break;
}
case 4:
{
EditFlagTableViewCell *flagCell = (EditFlagTableViewCell *)cell;
[[flagCell label] setText:NSLocalizedString(@"Touch Pointer Auto Scroll",
"Touch Pointer Auto Scroll UI setting")];
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
[[flagCell toggle] setOn:[[NSUserDefaults standardUserDefaults]
boolForKey:@"ui.auto_scroll_touchpointer"]];
[[flagCell toggle] addTarget:self
action:@selector(toggleSettingValue:)
forControlEvents:UIControlEventValueChanged];
break;
}
default:
NSLog(@"Invalid row index in settings table!");
break;
}
}
// updates certificate handling settings in the UI
- (void)initCertificateHandlingSettings:(NSIndexPath *)indexPath cell:(UITableViewCell *)cell
{
switch ([indexPath row])
{
case 0:
{
EditFlagTableViewCell *flagCell = (EditFlagTableViewCell *)cell;
[[flagCell label] setText:NSLocalizedString(@"Accept all Certificates",
"Accept All Certificates setting")];
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
[[flagCell toggle] setOn:[[NSUserDefaults standardUserDefaults]
boolForKey:@"security.accept_certificates"]];
[[flagCell toggle] addTarget:self
action:@selector(toggleSettingValue:)
forControlEvents:UIControlEventValueChanged];
break;
}
case 1:
{
EditSubEditTableViewCell *subCell = (EditSubEditTableViewCell *)cell;
[[subCell label] setText:NSLocalizedString(@"Erase Certificate Cache",
@"Erase certificate cache button")];
break;
}
default:
NSLog(@"Invalid row index in settings table!");
break;
}
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// deselect any row to fake a button-pressed like effect
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// ensure everything is stored in our settings before we proceed
[[self view] endEditing:NO];
// clear certificate cache
if ([indexPath section] == SECTION_CERTIFICATE_HANDLING_SETTINGS && [indexPath row] == 1)
{
// delete certificates cache
NSError *err;
if ([[NSFileManager defaultManager]
removeItemAtPath:[[NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES) lastObject]
stringByAppendingPathComponent:@"/.freerdp"]
error:&err])
[[self view] makeToast:NSLocalizedString(@"Certificate Cache cleared!",
@"Clear Certificate cache success message")
duration:ToastDurationNormal
position:@"center"];
else
[[self view] makeToast:NSLocalizedString(@"Error clearing the Certificate Cache!",
@"Clear Certificate cache failed message")
duration:ToastDurationNormal
position:@"center"];
}
}
#pragma mark -
#pragma mark Action Handlers
- (void)toggleSettingValue:(id)sender
{
UISwitch *valueSwitch = (UISwitch *)sender;
switch ([valueSwitch tag])
{
case GET_TAG(SECTION_UI_SETTINGS, 0):
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn]
forKey:@"ui.hide_status_bar"];
break;
case GET_TAG(SECTION_UI_SETTINGS, 1):
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn]
forKey:@"ui.hide_tool_bar"];
break;
case GET_TAG(SECTION_UI_SETTINGS, 2):
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn]
forKey:@"ui.swap_mouse_buttons"];
SetSwapMouseButtonsFlag([valueSwitch isOn]);
break;
case GET_TAG(SECTION_UI_SETTINGS, 3):
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn]
forKey:@"ui.invert_scrolling"];
SetInvertScrollingFlag([valueSwitch isOn]);
break;
case GET_TAG(SECTION_UI_SETTINGS, 4):
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn]
forKey:@"ui.auto_scroll_touchpointer"];
SetInvertScrollingFlag([valueSwitch isOn]);
break;
case GET_TAG(SECTION_CERTIFICATE_HANDLING_SETTINGS, 0):
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn]
forKey:@"security.accept_certificates"];
break;
default:
break;
}
}
@end

View File

@@ -0,0 +1,38 @@
/*
Bookmark editor controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import <UIKit/UIKit.h>
#import "EditorBaseController.h"
@class ComputerBookmark;
@class ConnectionParams;
@protocol BookmarkEditorDelegate <NSObject>
// bookmark editing finished
- (void)commitBookmark:(ComputerBookmark *)bookmark;
@end
@interface BookmarkEditorController : EditorBaseController
{
@private
ComputerBookmark *_bookmark;
ConnectionParams *_params;
BOOL _display_server_settings;
id<BookmarkEditorDelegate> delegate;
}
@property(nonatomic, assign) id<BookmarkEditorDelegate> delegate;
// init for the given bookmark
- (id)initWithBookmark:(ComputerBookmark *)bookmark;
@end

View File

@@ -0,0 +1,427 @@
/*
Bookmark editor controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "BookmarkEditorController.h"
#import "Bookmark.h"
#import "Utils.h"
#import "ScreenSelectionController.h"
#import "PerformanceEditorController.h"
#import "CredentialsEditorController.h"
#import "AdvancedBookmarkEditorController.h"
#import "BlockAlertView.h"
@implementation BookmarkEditorController
@synthesize delegate;
#define SECTION_SERVER 0
#define SECTION_CREDENTIALS 1
#define SECTION_SETTINGS 2
#define SECTION_COUNT 3
#pragma mark -
#pragma mark Initialization
- (id)initWithBookmark:(ComputerBookmark *)bookmark
{
if ((self = [super initWithStyle:UITableViewStyleGrouped]))
{
// set additional settings state according to bookmark data
if ([[bookmark uuid] length] == 0)
_bookmark = [bookmark copy];
else
_bookmark = [bookmark copyWithUUID];
_params = [_bookmark params];
_display_server_settings = YES;
}
return self;
}
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// replace back button with a custom handler that checks if the required bookmark settings were
// specified
UIBarButtonItem *saveButton =
[[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Save", @"Save Button title")
style:UIBarButtonItemStyleDone
target:self
action:@selector(handleSave:)] autorelease];
UIBarButtonItem *cancelButton =
[[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Cancel", @"Cancel Button title")
style:UIBarButtonItemStyleBordered
target:self
action:@selector(handleCancel:)] autorelease];
[[self navigationItem] setLeftBarButtonItem:cancelButton];
[[self navigationItem] setRightBarButtonItem:saveButton];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// we need to reload the table view data here to have up-to-date data for the
// advanced settings accessory items (like for resolution/color mode settings)
[[self tableView] reloadData];
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return SECTION_COUNT;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
switch (section)
{
case SECTION_SERVER: // server settings
return (_display_server_settings ? 3 : 0);
case SECTION_CREDENTIALS: // credentials
return 1;
case SECTION_SETTINGS: // session settings
return 3;
default:
break;
}
return 0;
}
// set section headers
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
switch (section)
{
case SECTION_SERVER:
return (_display_server_settings
? NSLocalizedString(@"Host", @"'Host': host settings header")
: nil);
case SECTION_CREDENTIALS:
return NSLocalizedString(@"Credentials", @"'Credentials': credentials settings header");
case SECTION_SETTINGS:
return NSLocalizedString(@"Settings", @"'Session Settings': session settings header");
}
return @"unknown";
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// determine the required cell type
NSString *cellType = nil;
switch ([indexPath section])
{
case SECTION_SERVER:
cellType = TableCellIdentifierText;
break;
case SECTION_CREDENTIALS:
cellType = TableCellIdentifierSelection;
break;
case SECTION_SETTINGS: // settings
{
switch ([indexPath row])
{
case 0: // screen/color depth
cellType = TableCellIdentifierSelection;
break;
case 1: // performance settings
case 2: // advanced settings
cellType = TableCellIdentifierSubEditor;
break;
default:
break;
}
}
break;
default:
break;
}
NSAssert(cellType != nil, @"Couldn't determine cell type");
// get the table view cell
UITableViewCell *cell = [self tableViewCellFromIdentifier:cellType];
NSAssert(cell, @"Invalid cell");
// set cell values
switch ([indexPath section])
{
// server settings
case SECTION_SERVER:
[self initServerSettings:indexPath cell:cell];
break;
// credentials
case SECTION_CREDENTIALS:
[self initCredentialSettings:indexPath cell:cell];
break;
// session settings
case SECTION_SETTINGS:
[self initSettings:indexPath cell:cell];
break;
default:
break;
}
return cell;
}
// updates server settings in the UI
- (void)initServerSettings:(NSIndexPath *)indexPath cell:(UITableViewCell *)cell
{
EditTextTableViewCell *textCell = (EditTextTableViewCell *)cell;
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
switch ([indexPath row])
{
case 0:
[[textCell label] setText:NSLocalizedString(@"Label", @"'Label': Bookmark label")];
[[textCell textfield] setText:[_bookmark label]];
[[textCell textfield]
setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
break;
case 1:
[[textCell label] setText:NSLocalizedString(@"Host", @"'Host': Bookmark hostname")];
[[textCell textfield] setText:[_params StringForKey:@"hostname"]];
[[textCell textfield]
setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
break;
case 2:
[[textCell label] setText:NSLocalizedString(@"Port", @"'Port': Bookmark port")];
[[textCell textfield]
setText:[NSString stringWithFormat:@"%d", [_params intForKey:@"port"]]];
[[textCell textfield] setKeyboardType:UIKeyboardTypeNumberPad];
break;
default:
NSLog(@"Invalid row index in settings table!");
break;
}
[self adjustEditTextTableViewCell:textCell];
}
// updates credentials in the UI
- (void)initCredentialSettings:(NSIndexPath *)indexPath cell:(UITableViewCell *)cell
{
EditSelectionTableViewCell *selCell = (EditSelectionTableViewCell *)cell;
switch (indexPath.row)
{
case 0:
[[selCell label]
setText:NSLocalizedString(@"Credentials", @"'Credentials': Bookmark credentials")];
[[selCell selection] setText:[_params StringForKey:@"username"]];
break;
default:
NSLog(@"Invalid row index in settings table!");
break;
}
}
// updates session settings in the UI
- (void)initSettings:(NSIndexPath *)indexPath cell:(UITableViewCell *)cell
{
switch (indexPath.row)
{
case 0:
{
EditSelectionTableViewCell *selCell = (EditSelectionTableViewCell *)cell;
[[selCell label]
setText:NSLocalizedString(@"Screen", @"'Screen': Bookmark Screen settings")];
NSString *resolution = ScreenResolutionDescription(
[_params intForKey:@"screen_resolution_type"], [_params intForKey:@"width"],
[_params intForKey:@"height"]);
int colorBits = [_params intForKey:@"colors"];
[[selCell selection]
setText:[NSString stringWithFormat:@"%@@%d", resolution, colorBits]];
break;
}
case 1:
{
EditSubEditTableViewCell *editCell = (EditSubEditTableViewCell *)cell;
[[editCell label]
setText:NSLocalizedString(@"Performance",
@"'Performance': Bookmark Performance Settings")];
break;
}
case 2:
{
EditSubEditTableViewCell *editCell = (EditSubEditTableViewCell *)cell;
[[editCell label]
setText:NSLocalizedString(@"Advanced", @"'Advanced': Bookmark Advanced Settings")];
break;
}
default:
NSLog(@"Invalid row index in settings table!");
break;
}
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIViewController *viewCtrl = nil;
// determine view
switch ([indexPath section])
{
case SECTION_CREDENTIALS:
{
if ([indexPath row] == 0)
viewCtrl =
[[[CredentialsEditorController alloc] initWithBookmark:_bookmark] autorelease];
break;
}
case SECTION_SETTINGS:
{
switch ([indexPath row])
{
case 0:
viewCtrl = [[[ScreenSelectionController alloc] initWithConnectionParams:_params]
autorelease];
break;
case 1:
viewCtrl = [[[PerformanceEditorController alloc]
initWithConnectionParams:_params] autorelease];
break;
case 2:
viewCtrl = [[[AdvancedBookmarkEditorController alloc]
initWithBookmark:_bookmark] autorelease];
break;
default:
break;
}
break;
}
}
// display view
if (viewCtrl)
[[self navigationController] pushViewController:viewCtrl animated:YES];
}
#pragma mark -
#pragma mark Text Field delegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return NO;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
switch (textField.tag)
{
// update server settings
case GET_TAG(SECTION_SERVER, 0):
[_bookmark setLabel:[textField text]];
break;
case GET_TAG(SECTION_SERVER, 1):
[_params setValue:[textField text] forKey:@"hostname"];
break;
case GET_TAG(SECTION_SERVER, 2):
[_params setInt:[[textField text] intValue] forKey:@"port"];
break;
default:
break;
}
return YES;
}
#pragma mark -
#pragma mark Action Handlers
- (void)handleSave:(id)sender
{
// resign any first responder (so that we finish editing any bookmark parameter that might be
// currently edited)
[[self view] endEditing:NO];
// verify that bookmark is complete (only for manual bookmarks)
if ([[_bookmark label] length] == 0 || [[_params StringForKey:@"hostname"] length] == 0 ||
[_params intForKey:@"port"] == 0)
{
BlockAlertView *alertView = [BlockAlertView
alertWithTitle:NSLocalizedString(@"Cancel without saving?",
@"Incomplete bookmark error title")
message:NSLocalizedString(@"Press 'Cancel' to abort!\nPress 'Continue' to "
@"specify the required fields!",
@"Incomplete bookmark error message")];
[alertView
setCancelButtonWithTitle:NSLocalizedString(@"Cancel", @"Cancel Button")
block:^{
// cancel bookmark editing and return to previous view controller
[[self navigationController] popViewControllerAnimated:YES];
}];
[alertView addButtonWithTitle:NSLocalizedString(@"Continue", @"Continue Button") block:nil];
[alertView show];
return;
}
// commit bookmark
if ([[self delegate] respondsToSelector:@selector(commitBookmark:)])
[[self delegate] commitBookmark:_bookmark];
// return to previous view controller
[[self navigationController] popViewControllerAnimated:YES];
}
- (void)handleCancel:(id)sender
{
// return to previous view controller
[[self navigationController] popViewControllerAnimated:YES];
}
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc that aren't in use.
}
- (void)dealloc
{
[super dealloc];
[_bookmark autorelease];
}
@end

View File

@@ -0,0 +1,26 @@
/*
Controller to edit ts gateway bookmark settings
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "EditorBaseController.h"
@class ComputerBookmark;
@class ConnectionParams;
@interface BookmarkGatewaySettingsController : EditorBaseController
{
@private
ComputerBookmark *_bookmark;
ConnectionParams *_params;
}
// init for the given bookmark
- (id)initWithBookmark:(ComputerBookmark *)bookmark;
@end

View File

@@ -0,0 +1,242 @@
//
// BookmarkGatewaySettingsController.m
// FreeRDP
//
// Created by a Thincast Developer on 4/30/13.
//
//
#import "BookmarkGatewaySettingsController.h"
#import "Bookmark.h"
#import "Utils.h"
#import "EditorSelectionController.h"
#define SECTION_TSGATEWAY_SETTINGS 0
#define SECTION_COUNT 1
@interface BookmarkGatewaySettingsController ()
@end
@implementation BookmarkGatewaySettingsController
- (id)initWithBookmark:(ComputerBookmark *)bookmark
{
if ((self = [super initWithStyle:UITableViewStyleGrouped]))
{
// set additional settings state according to bookmark data
_bookmark = [bookmark retain];
_params = [bookmark params];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self setTitle:NSLocalizedString(@"TS Gateway Settings", @"TS Gateway Settings title")];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// we need to reload the table view data here to have up-to-date data for the
// advanced settings accessory items (like for resolution/color mode settings)
[[self tableView] reloadData];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void)dealloc
{
[super dealloc];
[_bookmark release];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return SECTION_COUNT;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
switch (section)
{
case SECTION_TSGATEWAY_SETTINGS: // ts gateway settings
return 5;
default:
break;
}
return 0;
}
// set section headers
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
switch (section)
{
case SECTION_TSGATEWAY_SETTINGS:
return NSLocalizedString(@"TS Gateway", @"'TS Gateway': ts gateway settings header");
}
return @"unknown";
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// determine the required cell type
NSString *cellType = nil;
switch ([indexPath section])
{
case SECTION_TSGATEWAY_SETTINGS: // advanced settings
{
switch ([indexPath row])
{
case 0: // hostname
case 1: // port
case 2: // username
case 4: // domain
cellType = TableCellIdentifierText;
break;
case 3: // password
cellType = TableCellIdentifierSecretText;
break;
default:
break;
}
break;
}
}
NSAssert(cellType != nil, @"Couldn't determine cell type");
// get the table view cell
UITableViewCell *cell = [self tableViewCellFromIdentifier:cellType];
NSAssert(cell, @"Invalid cell");
// set cell values
switch ([indexPath section])
{
// advanced settings
case SECTION_TSGATEWAY_SETTINGS:
[self initGatewaySettings:indexPath cell:cell];
break;
default:
break;
}
return cell;
}
// updates server settings in the UI
- (void)initGatewaySettings:(NSIndexPath *)indexPath cell:(UITableViewCell *)cell
{
EditTextTableViewCell *textCell = (EditTextTableViewCell *)cell;
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
switch ([indexPath row])
{
case 0:
{
[[textCell label] setText:NSLocalizedString(@"Host", @"'Host': Bookmark hostname")];
[[textCell textfield] setText:[_params StringForKey:@"tsg_hostname"]];
[[textCell textfield]
setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
break;
}
case 1:
{
int port = [_params intForKey:@"tsg_port"];
if (port == 0)
port = 443;
[[textCell label] setText:NSLocalizedString(@"Port", @"'Port': Bookmark port")];
[[textCell textfield] setText:[NSString stringWithFormat:@"%d", port]];
[[textCell textfield] setKeyboardType:UIKeyboardTypeNumberPad];
break;
}
case 2:
{
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
[[textCell label]
setText:NSLocalizedString(@"Username", @"'Username': Bookmark username")];
[[textCell textfield] setText:[_params StringForKey:@"tsg_username"]];
[[textCell textfield]
setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
break;
}
case 3:
{
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
[[textCell label]
setText:NSLocalizedString(@"Password", @"'Password': Bookmark password")];
[[textCell textfield] setText:[_params StringForKey:@"tsg_password"]];
[[textCell textfield]
setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
break;
}
case 4:
{
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
[[textCell label] setText:NSLocalizedString(@"Domain", @"'Domain': Bookmark domain")];
[[textCell textfield] setText:[_params StringForKey:@"tsg_domain"]];
[[textCell textfield]
setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
break;
}
default:
NSLog(@"Invalid row index in settings table!");
break;
}
[self adjustEditTextTableViewCell:textCell];
}
#pragma mark -
#pragma mark Text Field delegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return NO;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
switch (textField.tag)
{
// update server settings
case GET_TAG(SECTION_TSGATEWAY_SETTINGS, 0):
[_params setValue:[textField text] forKey:@"tsg_hostname"];
break;
case GET_TAG(SECTION_TSGATEWAY_SETTINGS, 1):
[_params setInt:[[textField text] intValue] forKey:@"tsg_port"];
break;
case GET_TAG(SECTION_TSGATEWAY_SETTINGS, 2):
[_params setValue:[textField text] forKey:@"tsg_username"];
break;
case GET_TAG(SECTION_TSGATEWAY_SETTINGS, 3):
[_params setValue:[textField text] forKey:@"tsg_password"];
break;
case GET_TAG(SECTION_TSGATEWAY_SETTINGS, 4):
[_params setValue:[textField text] forKey:@"tsg_domain"];
break;
default:
break;
}
return YES;
}
@end

View File

@@ -0,0 +1,56 @@
/*
bookmarks and active session view controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import <UIKit/UIKit.h>
#import "Bookmark.h"
#import "BookmarkTableCell.h"
#import "SessionTableCell.h"
#import "BookmarkEditorController.h"
#import "Reachability.h"
@interface BookmarkListController : UIViewController <UISearchBarDelegate, UITableViewDelegate,
UITableViewDataSource, BookmarkEditorDelegate>
{
// custom bookmark and session table cells
BookmarkTableCell *_bmTableCell;
SessionTableCell *_sessTableCell;
// child views
UISearchBar *_searchBar;
UITableView *_tableView;
// array with search results (or nil if no search active)
NSMutableArray *_manual_search_result;
NSMutableArray *_history_search_result;
// bookmark arrays
NSMutableArray *_manual_bookmarks;
// bookmark star images
UIImage *_star_on_img;
UIImage *_star_off_img;
// array with active sessions
NSMutableArray *_active_sessions;
// array with connection history entries
NSMutableArray *_connection_history;
// temporary bookmark when asking if the user wants to store a bookmark for a session initiated
// by a quick connect
ComputerBookmark *_temporary_bookmark;
}
@property(nonatomic, retain) IBOutlet UISearchBar *searchBar;
@property(nonatomic, retain) IBOutlet UITableView *tableView;
@property(nonatomic, retain) IBOutlet BookmarkTableCell *bmTableCell;
@property(nonatomic, retain) IBOutlet SessionTableCell *sessTableCell;
@end

View File

@@ -0,0 +1,957 @@
/*
bookmarks and active session view controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "BookmarkListController.h"
#import "Utils.h"
#import "BookmarkEditorController.h"
#import "RDPSessionViewController.h"
#import "Toast+UIView.h"
#import "Reachability.h"
#import "GlobalDefaults.h"
#import "BlockAlertView.h"
#define SECTION_SESSIONS 0
#define SECTION_BOOKMARKS 1
#define NUM_SECTIONS 2
@interface BookmarkListController (Private)
#pragma mark misc functions
- (UIButton *)disclosureButtonWithImage:(UIImage *)image;
- (void)performSearch:(NSString *)searchText;
#pragma mark Persisting bookmarks
- (void)scheduleWriteBookmarksToDataStore;
- (void)writeBookmarksToDataStore;
- (void)scheduleWriteManualBookmarksToDataStore;
- (void)writeManualBookmarksToDataStore;
- (void)readManualBookmarksFromDataStore;
- (void)writeArray:(NSArray *)bookmarks toDataStoreURL:(NSURL *)url;
- (NSMutableArray *)arrayFromDataStoreURL:(NSURL *)url;
- (NSURL *)manualBookmarksDataStoreURL;
- (NSURL *)connectionHistoryDataStoreURL;
@end
@implementation BookmarkListController
@synthesize searchBar = _searchBar, tableView = _tableView, bmTableCell = _bmTableCell,
sessTableCell = _sessTableCell;
// The designated initializer. Override if you create the controller programmatically and want to
// perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]))
{
// load bookmarks
[self readManualBookmarksFromDataStore];
// load connection history
[self readConnectionHistoryFromDataStore];
// init search result array
_manual_search_result = nil;
// register for session notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sessionDisconnected:)
name:TSXSessionDidDisconnectNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sessionFailedToConnect:)
name:TSXSessionDidFailToConnectNotification
object:nil];
// set title and tabbar controller image
[self setTitle:NSLocalizedString(@"Connections",
@"'Connections': bookmark controller title")];
[self setTabBarItem:[[[UITabBarItem alloc]
initWithTabBarSystemItem:UITabBarSystemItemBookmarks
tag:0] autorelease]];
// load images
_star_on_img = [[UIImage
imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"icon_accessory_star_on"
ofType:@"png"]] retain];
_star_off_img =
[[UIImage imageWithContentsOfFile:[[NSBundle mainBundle]
pathForResource:@"icon_accessory_star_off"
ofType:@"png"]] retain];
// init reachability detection
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(reachabilityChanged:)
name:kReachabilityChangedNotification
object:nil];
// init other properties
_active_sessions = [[NSMutableArray alloc] init];
_temporary_bookmark = nil;
}
return self;
}
- (void)loadView
{
[super loadView];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
// set edit button to allow bookmark list editing
[[self navigationItem] setRightBarButtonItem:[self editButtonItem]];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// in case we had a search - search again cause the bookmark searchable items could have changed
if ([[_searchBar text] length] > 0)
[self performSearch:[_searchBar text]];
// to reflect any bookmark changes - reload table
[_tableView reloadData];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// clear any search
[_searchBar setText:@""];
[_searchBar resignFirstResponder];
[self performSearch:@""];
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_temporary_bookmark release];
[_connection_history release];
[_active_sessions release];
[_manual_search_result release];
[_manual_bookmarks release];
[_star_on_img release];
[_star_off_img release];
[super dealloc];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return NUM_SECTIONS;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
switch (section)
{
case SECTION_SESSIONS:
return 0;
break;
case SECTION_BOOKMARKS:
{
// (+1 for Add Bookmark entry)
if (_manual_search_result != nil)
return ([_manual_search_result count] + [_history_search_result count] + 1);
return ([_manual_bookmarks count] + 1);
}
break;
default:
break;
}
return 0;
}
- (UITableViewCell *)cellForGenericListEntry
{
static NSString *CellIdentifier = @"BookmarkListCell";
UITableViewCell *cell = [[self tableView] dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[cell setAccessoryView:[self disclosureButtonWithImage:_star_off_img]];
}
return cell;
}
- (BookmarkTableCell *)cellForBookmark
{
static NSString *BookmarkCellIdentifier = @"BookmarkCell";
BookmarkTableCell *cell = (BookmarkTableCell *)[[self tableView]
dequeueReusableCellWithIdentifier:BookmarkCellIdentifier];
if (cell == nil)
{
[[NSBundle mainBundle] loadNibNamed:@"BookmarkTableViewCell" owner:self options:nil];
[_bmTableCell setAccessoryView:[self disclosureButtonWithImage:_star_on_img]];
cell = _bmTableCell;
_bmTableCell = nil;
}
return cell;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
switch ([indexPath section])
{
case SECTION_SESSIONS:
{
// get custom session cell
static NSString *SessionCellIdentifier = @"SessionCell";
SessionTableCell *cell = (SessionTableCell *)[tableView
dequeueReusableCellWithIdentifier:SessionCellIdentifier];
if (cell == nil)
{
[[NSBundle mainBundle] loadNibNamed:@"SessionTableViewCell" owner:self options:nil];
cell = _sessTableCell;
_sessTableCell = nil;
}
// set cell data
RDPSession *session = [_active_sessions objectAtIndex:[indexPath row]];
[[cell title] setText:[session sessionName]];
[[cell server] setText:[[session params] StringForKey:@"hostname"]];
[[cell username] setText:[[session params] StringForKey:@"username"]];
[[cell screenshot]
setImage:[session getScreenshotWithSize:[[cell screenshot] bounds].size]];
[[cell disconnectButton] setTag:[indexPath row]];
return cell;
}
case SECTION_BOOKMARKS:
{
// special handling for first cell - quick connect/quick create Bookmark cell
if ([indexPath row] == 0)
{
// if a search text is entered the cell becomes a quick connect/quick create
// bookmark cell - otherwise it's just an add bookmark cell
UITableViewCell *cell = [self cellForGenericListEntry];
if ([[_searchBar text] length] == 0)
{
[[cell textLabel]
setText:[@" " stringByAppendingString:
NSLocalizedString(@"Add Connection",
@"'Add Connection': button label")]];
[((UIButton *)[cell accessoryView]) setHidden:YES];
}
else
{
[[cell textLabel] setText:[@" " stringByAppendingString:[_searchBar text]]];
[((UIButton *)[cell accessoryView]) setHidden:NO];
}
return cell;
}
else
{
// do we have a history cell or bookmark cell?
if ([self isIndexPathToHistoryItem:indexPath])
{
UITableViewCell *cell = [self cellForGenericListEntry];
[[cell textLabel]
setText:[@" " stringByAppendingString:
[_history_search_result
objectAtIndex:
[self historyIndexFromIndexPath:indexPath]]]];
[((UIButton *)[cell accessoryView]) setHidden:NO];
return cell;
}
else
{
// set cell properties
ComputerBookmark *entry;
BookmarkTableCell *cell = [self cellForBookmark];
if (_manual_search_result == nil)
entry = [_manual_bookmarks
objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]];
else
entry = [[_manual_search_result
objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]]
valueForKey:@"bookmark"];
[[cell title] setText:[entry label]];
[[cell subTitle] setText:[[entry params] StringForKey:@"hostname"]];
return cell;
}
}
}
default:
break;
}
NSAssert(0, @"Failed to create cell");
return nil;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// dont allow to edit Add Bookmark item
if ([indexPath section] == SECTION_SESSIONS)
return NO;
if ([indexPath section] == SECTION_BOOKMARKS && [indexPath row] == 0)
return NO;
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Delete the row from the data source
switch ([indexPath section])
{
case SECTION_BOOKMARKS:
{
if (_manual_search_result == nil)
[_manual_bookmarks
removeObjectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]];
else
{
// history item or bookmark?
if ([self isIndexPathToHistoryItem:indexPath])
{
[_connection_history
removeObject:
[_history_search_result
objectAtIndex:[self historyIndexFromIndexPath:indexPath]]];
[_history_search_result
removeObjectAtIndex:[self historyIndexFromIndexPath:indexPath]];
}
else
{
[_manual_bookmarks
removeObject:
[[_manual_search_result
objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]]
valueForKey:@"bookmark"]];
[_manual_search_result
removeObjectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]];
}
}
[self scheduleWriteManualBookmarksToDataStore];
break;
}
}
[tableView reloadSections:[NSIndexSet indexSetWithIndex:[indexPath section]]
withRowAnimation:UITableViewRowAnimationNone];
}
}
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView
moveRowAtIndexPath:(NSIndexPath *)fromIndexPath
toIndexPath:(NSIndexPath *)toIndexPath
{
if ([fromIndexPath compare:toIndexPath] != NSOrderedSame)
{
switch ([fromIndexPath section])
{
case SECTION_BOOKMARKS:
{
int fromIdx = [self bookmarkIndexFromIndexPath:fromIndexPath];
int toIdx = [self bookmarkIndexFromIndexPath:toIndexPath];
ComputerBookmark *temp_bookmark =
[[_manual_bookmarks objectAtIndex:fromIdx] retain];
[_manual_bookmarks removeObjectAtIndex:fromIdx];
if (toIdx >= [_manual_bookmarks count])
[_manual_bookmarks addObject:temp_bookmark];
else
[_manual_bookmarks insertObject:temp_bookmark atIndex:toIdx];
[temp_bookmark release];
[self scheduleWriteManualBookmarksToDataStore];
break;
}
}
}
}
// prevent that an item is moved before the Add Bookmark item
- (NSIndexPath *)tableView:(UITableView *)tableView
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
// don't allow to move:
// - items between sections
// - the quick connect/quick create bookmark cell
// - any item while a search is applied
if ([proposedDestinationIndexPath row] == 0 ||
([sourceIndexPath section] != [proposedDestinationIndexPath section]) ||
_manual_search_result != nil)
{
return sourceIndexPath;
}
else
{
return proposedDestinationIndexPath;
}
}
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// dont allow to reorder Add Bookmark item
if ([indexPath section] == SECTION_BOOKMARKS && [indexPath row] == 0)
return NO;
return YES;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (section == SECTION_SESSIONS && [_active_sessions count] > 0)
return NSLocalizedString(@"My Sessions", @"'My Session': section sessions header");
if (section == SECTION_BOOKMARKS)
return NSLocalizedString(@"Manual Connections",
@"'Manual Connections': section manual bookmarks header");
return nil;
}
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
return nil;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([indexPath section] == SECTION_SESSIONS)
return 72;
return [tableView rowHeight];
}
#pragma mark -
#pragma mark Table view delegate
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
[[self tableView] setEditing:editing animated:animated];
}
- (void)accessoryButtonTapped:(UIControl *)button withEvent:(UIEvent *)event
{
// forward a tap on our custom accessory button to the real accessory button handler
NSIndexPath *indexPath =
[[self tableView] indexPathForRowAtPoint:[[[event touchesForView:button] anyObject]
locationInView:[self tableView]]];
if (indexPath == nil)
return;
[[[self tableView] delegate] tableView:[self tableView]
accessoryButtonTappedForRowWithIndexPath:indexPath];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([indexPath section] == SECTION_SESSIONS)
{
// resume session
RDPSession *session = [_active_sessions objectAtIndex:[indexPath row]];
UIViewController *ctrl =
[[[RDPSessionViewController alloc] initWithNibName:@"RDPSessionView"
bundle:nil
session:session] autorelease];
[ctrl setHidesBottomBarWhenPushed:YES];
[[self navigationController] pushViewController:ctrl animated:YES];
}
else
{
ComputerBookmark *bookmark = nil;
if ([indexPath section] == SECTION_BOOKMARKS)
{
// first row has either quick connect or add bookmark item
if ([indexPath row] == 0)
{
if ([[_searchBar text] length] == 0)
{
// show add bookmark controller
ComputerBookmark *bookmark =
[[[ComputerBookmark alloc] initWithBaseDefaultParameters] autorelease];
BookmarkEditorController *bookmarkEditorController =
[[[BookmarkEditorController alloc] initWithBookmark:bookmark] autorelease];
[bookmarkEditorController
setTitle:NSLocalizedString(@"Add Connection", @"Add Connection title")];
[bookmarkEditorController setDelegate:self];
[bookmarkEditorController setHidesBottomBarWhenPushed:YES];
[[self navigationController] pushViewController:bookmarkEditorController
animated:YES];
}
else
{
// create a quick connect bookmark and add an entry to the quick connect history
// (if not already in the history)
bookmark = [self bookmarkForQuickConnectTo:[_searchBar text]];
if (![_connection_history containsObject:[_searchBar text]])
{
[_connection_history addObject:[_searchBar text]];
[self scheduleWriteConnectionHistoryToDataStore];
}
}
}
else
{
if (_manual_search_result != nil)
{
if ([self isIndexPathToHistoryItem:indexPath])
{
// create a quick connect bookmark for a history item
NSString *item = [_history_search_result
objectAtIndex:[self historyIndexFromIndexPath:indexPath]];
bookmark = [self bookmarkForQuickConnectTo:item];
}
else
bookmark = [[_manual_search_result
objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]]
valueForKey:@"bookmark"];
}
else
bookmark = [_manual_bookmarks
objectAtIndex:[self bookmarkIndexFromIndexPath:
indexPath]]; // -1 because of ADD BOOKMARK entry
}
// set reachability status
WakeUpWWAN();
[bookmark
setConntectedViaWLAN:[[Reachability
reachabilityWithHostName:[[bookmark params]
StringForKey:@"hostname"]]
currentReachabilityStatus] == ReachableViaWiFi];
}
if (bookmark != nil)
{
// create rdp session
RDPSession *session = [[[RDPSession alloc] initWithBookmark:bookmark] autorelease];
UIViewController *ctrl =
[[[RDPSessionViewController alloc] initWithNibName:@"RDPSessionView"
bundle:nil
session:session] autorelease];
[ctrl setHidesBottomBarWhenPushed:YES];
[[self navigationController] pushViewController:ctrl animated:YES];
[_active_sessions addObject:session];
}
}
}
- (void)tableView:(UITableView *)tableView
accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
// get the bookmark
NSString *bookmark_editor_title =
NSLocalizedString(@"Edit Connection", @"Edit Connection title");
ComputerBookmark *bookmark = nil;
if ([indexPath section] == SECTION_BOOKMARKS)
{
if ([indexPath row] == 0)
{
// create a new bookmark and init hostname and label
bookmark = [self bookmarkForQuickConnectTo:[_searchBar text]];
bookmark_editor_title = NSLocalizedString(@"Add Connection", @"Add Connection title");
}
else
{
if (_manual_search_result != nil)
{
if ([self isIndexPathToHistoryItem:indexPath])
{
// create a new bookmark and init hostname and label
NSString *item = [_history_search_result
objectAtIndex:[self historyIndexFromIndexPath:indexPath]];
bookmark = [self bookmarkForQuickConnectTo:item];
bookmark_editor_title =
NSLocalizedString(@"Add Connection", @"Add Connection title");
}
else
bookmark = [[_manual_search_result
objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]]
valueForKey:@"bookmark"];
}
else
bookmark = [_manual_bookmarks
objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]]; // -1 because of ADD
// BOOKMARK entry
}
}
// bookmark found? - start the editor
if (bookmark != nil)
{
BookmarkEditorController *editBookmarkController =
[[[BookmarkEditorController alloc] initWithBookmark:bookmark] autorelease];
[editBookmarkController setHidesBottomBarWhenPushed:YES];
[editBookmarkController setTitle:bookmark_editor_title];
[editBookmarkController setDelegate:self];
[[self navigationController] pushViewController:editBookmarkController animated:YES];
}
}
#pragma mark -
#pragma mark Search Bar Delegates
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
// show cancel button
[searchBar setShowsCancelButton:YES animated:YES];
return YES;
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
// clear search result
[_manual_search_result release];
_manual_search_result = nil;
// clear text and remove cancel button
[searchBar setText:@""];
[searchBar resignFirstResponder];
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
[searchBar setShowsCancelButton:NO animated:YES];
// re-enable table selection
[_tableView setAllowsSelection:YES];
return YES;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[_searchBar resignFirstResponder];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
[self performSearch:searchText];
[_tableView reloadData];
}
#pragma mark - Session handling
// session was added
- (void)sessionDisconnected:(NSNotification *)notification
{
// remove session from active sessions
RDPSession *session = (RDPSession *)[notification object];
[_active_sessions removeObject:session];
// if this view is currently active refresh entries
if ([[self navigationController] visibleViewController] == self)
[_tableView reloadSections:[NSIndexSet indexSetWithIndex:SECTION_SESSIONS]
withRowAnimation:UITableViewRowAnimationNone];
// if session's bookmark is not in the bookmark list ask the user if he wants to add it
// (this happens if the session is created using the quick connect feature)
if (![_manual_bookmarks containsObject:[session bookmark]])
{
// retain the bookmark in case we want to save it later
_temporary_bookmark = [[session bookmark] retain];
// ask the user if he wants to save the bookmark
NSString *title =
NSLocalizedString(@"Save Connection Settings?", @"Save connection settings title");
NSString *message = NSLocalizedString(
@"Your Connection Settings have not been saved. Do you want to save them?",
@"Save connection settings message");
BlockAlertView *alert = [BlockAlertView alertWithTitle:title message:message];
[alert setCancelButtonWithTitle:NSLocalizedString(@"No", @"No Button") block:nil];
[alert addButtonWithTitle:NSLocalizedString(@"Yes", @"Yes Button")
block:^{
if (_temporary_bookmark)
{
[_manual_bookmarks addObject:_temporary_bookmark];
[_tableView
reloadSections:[NSIndexSet
indexSetWithIndex:SECTION_BOOKMARKS]
withRowAnimation:UITableViewRowAnimationNone];
[_temporary_bookmark autorelease];
_temporary_bookmark = nil;
}
}];
[alert show];
}
}
- (void)sessionFailedToConnect:(NSNotification *)notification
{
// remove session from active sessions
RDPSession *session = (RDPSession *)[notification object];
[_active_sessions removeObject:session];
// display error toast
[[self view] makeToast:NSLocalizedString(@"Failed to connect to session!",
@"Failed to connect error message")
duration:ToastDurationNormal
position:@"center"];
}
#pragma mark - Reachability notification
- (void)reachabilityChanged:(NSNotification *)notification
{
// no matter how the network changed - we will disconnect
// disconnect session (if there is any)
if ([_active_sessions count] > 0)
{
RDPSession *session = [_active_sessions objectAtIndex:0];
[session disconnect];
}
}
#pragma mark - BookmarkEditorController delegate
- (void)commitBookmark:(ComputerBookmark *)bookmark
{
// if we got a manual bookmark that is not in the list yet - add it otherwise replace it
BOOL found = NO;
for (int idx = 0; idx < [_manual_bookmarks count]; ++idx)
{
if ([[bookmark uuid] isEqualToString:[[_manual_bookmarks objectAtIndex:idx] uuid]])
{
[_manual_bookmarks replaceObjectAtIndex:idx withObject:bookmark];
found = YES;
break;
}
}
if (!found)
[_manual_bookmarks addObject:bookmark];
// remove any quick connect history entry with the same hostname
NSString *hostname = [[bookmark params] StringForKey:@"hostname"];
if ([_connection_history containsObject:hostname])
{
[_connection_history removeObject:hostname];
[self scheduleWriteConnectionHistoryToDataStore];
}
[self scheduleWriteManualBookmarksToDataStore];
}
- (IBAction)disconnectButtonPressed:(id)sender
{
// disconnect session and refresh table view
RDPSession *session = [_active_sessions objectAtIndex:[sender tag]];
[session disconnect];
}
#pragma mark - Misc functions
- (BOOL)hasNoBookmarks
{
return ([_manual_bookmarks count] == 0);
}
- (UIButton *)disclosureButtonWithImage:(UIImage *)image
{
// we make the button a little bit bigger (image width * 2, height + 10) so that the user
// doesn't accidentally connect to the bookmark ...
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setFrame:CGRectMake(0, 0, [image size].width * 2, [image size].height + 10)];
[button setImage:image forState:UIControlStateNormal];
[button addTarget:self
action:@selector(accessoryButtonTapped:withEvent:)
forControlEvents:UIControlEventTouchUpInside];
[button setUserInteractionEnabled:YES];
return button;
}
- (void)performSearch:(NSString *)searchText
{
[_manual_search_result autorelease];
if ([searchText length] > 0)
{
_manual_search_result = [FilterBookmarks(
_manual_bookmarks,
[searchText componentsSeparatedByCharactersInSet:[NSCharacterSet
whitespaceAndNewlineCharacterSet]])
retain];
_history_search_result = [FilterHistory(_connection_history, searchText) retain];
}
else
{
_history_search_result = nil;
_manual_search_result = nil;
}
}
- (int)bookmarkIndexFromIndexPath:(NSIndexPath *)indexPath
{
return [indexPath row] -
((_history_search_result != nil) ? [_history_search_result count] : 0) - 1;
}
- (int)historyIndexFromIndexPath:(NSIndexPath *)indexPath
{
return [indexPath row] - 1;
}
- (BOOL)isIndexPathToHistoryItem:(NSIndexPath *)indexPath
{
return (([indexPath row] - 1) < [_history_search_result count]);
}
- (ComputerBookmark *)bookmarkForQuickConnectTo:(NSString *)host
{
ComputerBookmark *bookmark =
[[[ComputerBookmark alloc] initWithBaseDefaultParameters] autorelease];
[bookmark setLabel:host];
[[bookmark params] setValue:host forKey:@"hostname"];
return bookmark;
}
#pragma mark - Persisting bookmarks
- (void)scheduleWriteBookmarksToDataStore
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self writeBookmarksToDataStore];
}];
}
- (void)writeBookmarksToDataStore
{
[self writeManualBookmarksToDataStore];
}
- (void)scheduleWriteManualBookmarksToDataStore
{
[[NSOperationQueue mainQueue]
addOperation:[[[NSInvocationOperation alloc]
initWithTarget:self
selector:@selector(writeManualBookmarksToDataStore)
object:nil] autorelease]];
}
- (void)writeManualBookmarksToDataStore
{
[self writeArray:_manual_bookmarks toDataStoreURL:[self manualBookmarksDataStoreURL]];
}
- (void)scheduleWriteConnectionHistoryToDataStore
{
[[NSOperationQueue mainQueue]
addOperation:[[[NSInvocationOperation alloc]
initWithTarget:self
selector:@selector(writeConnectionHistoryToDataStore)
object:nil] autorelease]];
}
- (void)writeConnectionHistoryToDataStore
{
[self writeArray:_connection_history toDataStoreURL:[self connectionHistoryDataStoreURL]];
}
- (void)writeArray:(NSArray *)bookmarks toDataStoreURL:(NSURL *)url
{
NSData *archived_data = [NSKeyedArchiver archivedDataWithRootObject:bookmarks];
[archived_data writeToURL:url atomically:YES];
}
- (void)readManualBookmarksFromDataStore
{
[_manual_bookmarks autorelease];
_manual_bookmarks = [self arrayFromDataStoreURL:[self manualBookmarksDataStoreURL]];
if (_manual_bookmarks == nil)
{
_manual_bookmarks = [[NSMutableArray alloc] init];
[_manual_bookmarks
addObject:[[[GlobalDefaults sharedGlobalDefaults] newTestServerBookmark] autorelease]];
}
}
- (void)readConnectionHistoryFromDataStore
{
[_connection_history autorelease];
_connection_history = [self arrayFromDataStoreURL:[self connectionHistoryDataStoreURL]];
if (_connection_history == nil)
_connection_history = [[NSMutableArray alloc] init];
}
- (NSMutableArray *)arrayFromDataStoreURL:(NSURL *)url
{
NSData *archived_data = [NSData dataWithContentsOfURL:url];
if (!archived_data)
return nil;
return [[NSKeyedUnarchiver unarchiveObjectWithData:archived_data] retain];
}
- (NSURL *)manualBookmarksDataStoreURL
{
return [NSURL
fileURLWithPath:[NSString stringWithFormat:@"%@/%@",
[NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES)
lastObject],
@"com.freerdp.ifreerdp.bookmarks.plist"]];
}
- (NSURL *)connectionHistoryDataStoreURL
{
return [NSURL
fileURLWithPath:[NSString
stringWithFormat:@"%@/%@",
[NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES)
lastObject],
@"com.freerdp.ifreerdp.connection_history.plist"]];
}
@end

View File

@@ -0,0 +1,26 @@
/*
Controller to edit bookmark credentials
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "EditorBaseController.h"
@class ComputerBookmark;
@class ConnectionParams;
@interface CredentialsEditorController : EditorBaseController
{
@private
ComputerBookmark *_bookmark;
ConnectionParams *_params;
}
// init for the given bookmark
- (id)initWithBookmark:(ComputerBookmark *)bookmark;
@end

View File

@@ -0,0 +1,215 @@
/*
Controller to edit bookmark credentials
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "CredentialsEditorController.h"
#import "Bookmark.h"
#import "Utils.h"
@interface CredentialsEditorController ()
@end
#define SECTION_CREDENTIALS 0
#define SECTION_COUNT 1
@implementation CredentialsEditorController
- (id)initWithBookmark:(ComputerBookmark *)bookmark
{
if ((self = [super initWithStyle:UITableViewStyleGrouped]))
{
// set additional settings state according to bookmark data
_bookmark = [bookmark retain];
_params = [bookmark params];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self setTitle:NSLocalizedString(@"Credentials", @"Credentials title")];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// foce any active editing to stop
[[self view] endEditing:NO];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void)dealloc
{
[super dealloc];
[_bookmark release];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return SECTION_COUNT;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
switch (section)
{
case SECTION_CREDENTIALS: // credentials
return 3;
default:
break;
}
return 0;
}
// set section headers
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
switch (section)
{
case SECTION_CREDENTIALS:
return NSLocalizedString(@"Credentials", @"'Credentials': credentials settings header");
}
return @"unknown";
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// determine the required cell type
NSString *cellType = nil;
switch ([indexPath section])
{
case SECTION_CREDENTIALS: // credentials
if ([indexPath row] == 1)
cellType = TableCellIdentifierSecretText; // password field
else
cellType = TableCellIdentifierText;
break;
default:
break;
}
NSAssert(cellType != nil, @"Couldn't determine cell type");
// get the table view cell
UITableViewCell *cell = [self tableViewCellFromIdentifier:cellType];
NSAssert(cell, @"Invalid cell");
// set cell values
switch ([indexPath section])
{
// credentials
case SECTION_CREDENTIALS:
[self initCredentialSettings:indexPath cell:cell];
break;
default:
break;
}
return cell;
}
// updates credentials in the UI
- (void)initCredentialSettings:(NSIndexPath *)indexPath cell:(UITableViewCell *)cell
{
switch (indexPath.row)
{
case 0:
{
EditTextTableViewCell *textCell = (EditTextTableViewCell *)cell;
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
[[textCell label]
setText:NSLocalizedString(@"Username", @"'Username': Bookmark username")];
[[textCell textfield] setText:[_params StringForKey:@"username"]];
[[textCell textfield]
setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
break;
}
case 1:
{
EditSecretTextTableViewCell *textCell = (EditSecretTextTableViewCell *)cell;
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
[[textCell label]
setText:NSLocalizedString(@"Password", @"'Password': Bookmark password")];
[[textCell textfield] setText:[_params StringForKey:@"password"]];
[[textCell textfield]
setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
break;
}
case 2:
{
EditTextTableViewCell *textCell = (EditTextTableViewCell *)cell;
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
[[textCell label] setText:NSLocalizedString(@"Domain", @"'Domain': Bookmark domain")];
[[textCell textfield] setText:[_params StringForKey:@"domain"]];
[[textCell textfield]
setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
break;
}
default:
NSLog(@"Invalid row index in settings table!");
break;
}
}
#pragma mark -
#pragma mark Text Field delegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return NO;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
switch (textField.tag)
{
// update credentials settings
case GET_TAG(SECTION_CREDENTIALS, 0):
[_params setValue:[textField text] forKey:@"username"];
break;
case GET_TAG(SECTION_CREDENTIALS, 1):
[_params setValue:[textField text] forKey:@"password"];
break;
case GET_TAG(SECTION_CREDENTIALS, 2):
[_params setValue:[textField text] forKey:@"domain"];
break;
default:
break;
}
return YES;
}
@end

View File

@@ -0,0 +1,35 @@
/*
Credentials input controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import <UIKit/UIKit.h>
@class RDPSession;
@interface CredentialsInputController : UIViewController
{
@private
IBOutlet UITextField *_textfield_username;
IBOutlet UITextField *_textfield_password;
IBOutlet UITextField *_textfield_domain;
IBOutlet UIButton *_btn_login;
IBOutlet UIButton *_btn_cancel;
IBOutlet UIScrollView *_scroll_view;
IBOutlet UILabel *_lbl_message;
RDPSession *_session;
NSMutableDictionary *_params;
}
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
session:(RDPSession *)session
params:(NSMutableDictionary *)params;
@end

View File

@@ -0,0 +1,160 @@
/*
Credentials input controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "CredentialsInputController.h"
#import "RDPSession.h"
#import "Utils.h"
@implementation CredentialsInputController
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
session:(RDPSession *)session
params:(NSMutableDictionary *)params
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
_session = session;
_params = params;
[self setModalPresentationStyle:UIModalPresentationFormSheet];
// on iphone we have the problem that the buttons are hidden by the keyboard
// we solve this issue by registering keyboard notification handlers and adjusting the
// scrollview accordingly
if (IsPhone())
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// set localized strings
[_lbl_message
setText:NSLocalizedString(
@"Please provide the missing user information in order to proceed and login.",
@"Credentials input view message")];
[_textfield_username
setPlaceholder:NSLocalizedString(@"Username", @"Credentials Input Username hint")];
[_textfield_password
setPlaceholder:NSLocalizedString(@"Password", @"Credentials Input Password hint")];
[_textfield_domain
setPlaceholder:NSLocalizedString(@"Domain", @"Credentials Input Domain hint")];
[_btn_login setTitle:NSLocalizedString(@"Login", @"Login Button")
forState:UIControlStateNormal];
[_btn_cancel setTitle:NSLocalizedString(@"Cancel", @"Cancel Button")
forState:UIControlStateNormal];
// init scrollview content size
[_scroll_view setContentSize:[_scroll_view frame].size];
// set params in the view
[_textfield_username setText:[_params valueForKey:@"username"]];
[_textfield_password setText:[_params valueForKey:@"password"]];
[_textfield_domain setText:[_params valueForKey:@"domain"]];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
// set signal
[[_session uiRequestCompleted] signal];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void)dealloc
{
[super dealloc];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark -
#pragma mark iOS Keyboard Notification Handlers
- (void)keyboardWillShow:(NSNotification *)notification
{
CGRect keyboardEndFrame =
[[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect keyboardFrame = [[self view] convertRect:keyboardEndFrame toView:nil];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:[[[notification userInfo]
objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
[UIView
setAnimationDuration:[[[notification userInfo]
objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
CGRect frame = [_scroll_view frame];
frame.size.height -= keyboardFrame.size.height;
[_scroll_view setFrame:frame];
[UIView commitAnimations];
}
- (void)keyboardWillHide:(NSNotification *)notification
{
CGRect keyboardEndFrame =
[[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect keyboardFrame = [[self view] convertRect:keyboardEndFrame toView:nil];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:[[[notification userInfo]
objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
[UIView
setAnimationDuration:[[[notification userInfo]
objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
CGRect frame = [_scroll_view frame];
frame.size.height += keyboardFrame.size.height;
[_scroll_view setFrame:frame];
[UIView commitAnimations];
}
#pragma mark - Action handlers
- (IBAction)loginPressed:(id)sender
{
// read input back in
[_params setValue:[_textfield_username text] forKey:@"username"];
[_params setValue:[_textfield_password text] forKey:@"password"];
[_params setValue:[_textfield_domain text] forKey:@"domain"];
[_params setValue:[NSNumber numberWithBool:YES] forKey:@"result"];
// dismiss controller
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)cancelPressed:(id)sender
{
[_params setValue:[NSNumber numberWithBool:NO] forKey:@"result"];
// dismiss controller
[self dismissModalViewControllerAnimated:YES];
}
@end

View File

@@ -0,0 +1,44 @@
/*
Basic interface for settings editors
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import <UIKit/UIKit.h>
#import "EditTextTableViewCell.h"
#import "EditFlagTableViewCell.h"
#import "EditSelectionTableViewCell.h"
#import "EditSubEditTableViewCell.h"
#import "EditSecretTextTableViewCell.h"
#import "EditButtonTableViewCell.h"
extern NSString *TableCellIdentifierText;
extern NSString *TableCellIdentifierSecretText;
extern NSString *TableCellIdentifierYesNo;
extern NSString *TableCellIdentifierSelection;
extern NSString *TableCellIdentifierSubEditor;
extern NSString *TableCellIdentifierMultiChoice;
extern NSString *TableCellIdentifierButton;
@interface EditorBaseController : UITableViewController <UITextFieldDelegate>
{
@private
IBOutlet EditTextTableViewCell *_textTableViewCell;
IBOutlet EditSecretTextTableViewCell *_secretTextTableViewCell;
IBOutlet EditFlagTableViewCell *_flagTableViewCell;
IBOutlet EditSelectionTableViewCell *_selectionTableViewCell;
IBOutlet EditSubEditTableViewCell *_subEditTableViewCell;
IBOutlet EditButtonTableViewCell *_buttonTableViewCell;
}
// returns one of the requested table view cells
- (UITableViewCell *)tableViewCellFromIdentifier:(NSString *)identifier;
// Adjust text input cells label/textfield width according to the label's text size
- (void)adjustEditTextTableViewCell:(EditTextTableViewCell *)cell;
@end

View File

@@ -0,0 +1,110 @@
/*
Basic interface for settings editors
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "EditorBaseController.h"
@interface EditorBaseController ()
@end
NSString *TableCellIdentifierText = @"cellIdText";
NSString *TableCellIdentifierSecretText = @"cellIdSecretText";
NSString *TableCellIdentifierYesNo = @"cellIdYesNo";
NSString *TableCellIdentifierSelection = @"cellIdSelection";
NSString *TableCellIdentifierSubEditor = @"cellIdSubEditor";
NSString *TableCellIdentifierMultiChoice = @"cellIdMultiChoice";
NSString *TableCellIdentifierButton = @"cellIdButton";
@implementation EditorBaseController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#pragma mark - Create table view cells
- (UITableViewCell *)tableViewCellFromIdentifier:(NSString *)identifier
{
// try to reuse a cell
UITableViewCell *cell = [[self tableView] dequeueReusableCellWithIdentifier:identifier];
if (cell != nil)
return cell;
// we have to create a new cell
if ([identifier isEqualToString:TableCellIdentifierText])
{
[[NSBundle mainBundle] loadNibNamed:@"EditTextTableViewCell" owner:self options:nil];
cell = _textTableViewCell;
_textTableViewCell = nil;
}
else if ([identifier isEqualToString:TableCellIdentifierSecretText])
{
[[NSBundle mainBundle] loadNibNamed:@"EditSecretTextTableViewCell" owner:self options:nil];
cell = _secretTextTableViewCell;
_secretTextTableViewCell = nil;
}
else if ([identifier isEqualToString:TableCellIdentifierYesNo])
{
[[NSBundle mainBundle] loadNibNamed:@"EditFlagTableViewCell" owner:self options:nil];
cell = _flagTableViewCell;
_flagTableViewCell = nil;
}
else if ([identifier isEqualToString:TableCellIdentifierSelection])
{
[[NSBundle mainBundle] loadNibNamed:@"EditSelectionTableViewCell" owner:self options:nil];
cell = _selectionTableViewCell;
_selectionTableViewCell = nil;
}
else if ([identifier isEqualToString:TableCellIdentifierSubEditor])
{
[[NSBundle mainBundle] loadNibNamed:@"EditSubEditTableViewCell" owner:self options:nil];
cell = _subEditTableViewCell;
_subEditTableViewCell = nil;
}
else if ([identifier isEqualToString:TableCellIdentifierButton])
{
[[NSBundle mainBundle] loadNibNamed:@"EditButtonTableViewCell" owner:self options:nil];
cell = _buttonTableViewCell;
_buttonTableViewCell = nil;
}
else if ([identifier isEqualToString:TableCellIdentifierMultiChoice])
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:identifier] autorelease];
}
else
{
NSAssert(false, @"Unknown table cell identifier");
}
return cell;
}
#pragma mark - Utility functions
- (void)adjustEditTextTableViewCell:(EditTextTableViewCell *)cell
{
UILabel *label = [cell label];
UITextField *textField = [cell textfield];
// adjust label
CGFloat width = [[label text] sizeWithFont:[label font]].width;
CGRect frame = [label frame];
CGFloat delta = width - frame.size.width;
frame.size.width = width;
[label setFrame:frame];
// adjust text field
frame = [textField frame];
frame.origin.x += delta;
frame.size.width -= delta;
[textField setFrame:frame];
}
@end

View File

@@ -0,0 +1,34 @@
/*
Generic controller to select a single item from a list of options
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "EditorBaseController.h"
@class ConnectionParams;
@interface EditorSelectionController : EditorBaseController
{
ConnectionParams *_params;
// array with entries in connection parameters that are altered
NSArray *_entries;
// array with dictionaries containing label/value pairs that represent the available values for
// each entry
NSArray *_selections;
// current selections
NSMutableArray *_cur_selections;
}
- (id)initWithConnectionParams:(ConnectionParams *)params
entries:(NSArray *)entries
selections:(NSArray *)selections;
@end

View File

@@ -0,0 +1,143 @@
/*
Generic controller to select a single item from a list of options
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "EditorSelectionController.h"
#import "ConnectionParams.h"
#import "OrderedDictionary.h"
@interface EditorSelectionController (Private)
- (OrderedDictionary *)selectionForIndex:(int)index;
@end
@implementation EditorSelectionController
- (id)initWithConnectionParams:(ConnectionParams *)params
entries:(NSArray *)entries
selections:(NSArray *)selections
{
self = [super initWithStyle:UITableViewStyleGrouped];
if (self)
{
_params = [params retain];
_entries = [entries retain];
_selections = [selections retain];
// allocate and init current selections array
_cur_selections = [[NSMutableArray alloc] initWithCapacity:[_entries count]];
for (int i = 0; i < [entries count]; ++i)
{
NSString *entry = [entries objectAtIndex:i];
if ([_params hasValueForKeyPath:entry])
{
NSUInteger idx = [(OrderedDictionary *)[selections objectAtIndex:i]
indexForValue:[NSNumber numberWithInt:[_params intForKeyPath:entry]]];
[_cur_selections addObject:[NSNumber numberWithInt:(idx != NSNotFound ? idx : 0)]];
}
else
[_cur_selections addObject:[NSNumber numberWithInt:0]];
}
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
[_params autorelease];
[_entries autorelease];
[_selections autorelease];
[_cur_selections autorelease];
}
#pragma mark - View lifecycle
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [_entries count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [[self selectionForIndex:section] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self tableViewCellFromIdentifier:TableCellIdentifierMultiChoice];
// get selection
OrderedDictionary *selection = [self selectionForIndex:[indexPath section]];
// set cell properties
[[cell textLabel] setText:[selection keyAtIndex:[indexPath row]]];
// set default checkmark
if ([indexPath row] == [[_cur_selections objectAtIndex:[indexPath section]] intValue])
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
else
[cell setAccessoryType:UITableViewCellAccessoryNone];
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// has selection change?
int cur_selection = [[_cur_selections objectAtIndex:[indexPath section]] intValue];
if ([indexPath row] != cur_selection)
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
NSIndexPath *oldIndexPath = [NSIndexPath indexPathForRow:cur_selection
inSection:[indexPath section]];
// clear old checkmark
UITableViewCell *old_sel_cell = [tableView cellForRowAtIndexPath:oldIndexPath];
old_sel_cell.accessoryType = UITableViewCellAccessoryNone;
// set new checkmark
UITableViewCell *new_sel_cell = [tableView cellForRowAtIndexPath:indexPath];
new_sel_cell.accessoryType = UITableViewCellAccessoryCheckmark;
// get value from selection dictionary
OrderedDictionary *dict = [self selectionForIndex:[indexPath section]];
int sel_value = [[dict valueForKey:[dict keyAtIndex:[indexPath row]]] intValue];
// update selection index and params value
[_cur_selections replaceObjectAtIndex:[indexPath section]
withObject:[NSNumber numberWithInt:[indexPath row]]];
[_params setInt:sel_value forKeyPath:[_entries objectAtIndex:[indexPath section]]];
}
}
#pragma mark - Convenience functions
- (OrderedDictionary *)selectionForIndex:(int)index
{
return (OrderedDictionary *)[_selections objectAtIndex:index];
}
@end

View File

@@ -0,0 +1,25 @@
/*
Password Encryption Controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import <Foundation/Foundation.h>
#import "Encryptor.h"
@interface EncryptionController : NSObject
{
Encryptor *_shared_encryptor;
}
+ (EncryptionController *)sharedEncryptionController;
// Return a Encryptor suitable for encrypting or decrypting with the master password
- (Encryptor *)decryptor;
- (Encryptor *)encryptor;
@end

View File

@@ -0,0 +1,155 @@
/*
Password Encryption Controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "EncryptionController.h"
#import "SFHFKeychainUtils.h"
#import "TSXAdditions.h"
@interface EncryptionController (Private)
- (BOOL)verifyPassword:(Encryptor *)decryptor;
- (NSData *)encryptedVerificationData;
- (void)setEncryptedVerificationData:(Encryptor *)encryptor;
- (NSString *)keychainServerName;
- (NSString *)keychainUsername;
- (void)setKeychainPassword:(NSString *)password;
- (NSString *)keychainPassword;
- (NSString *)keychainDefaultPassword;
@end
static EncryptionController *_shared_encryption_controller = nil;
#pragma mark -
@implementation EncryptionController
+ (EncryptionController *)sharedEncryptionController
{
@synchronized(self)
{
if (_shared_encryption_controller == nil)
_shared_encryption_controller = [[EncryptionController alloc] init];
}
return _shared_encryption_controller;
}
#pragma mark Getting an encryptor or decryptor
- (Encryptor *)encryptor
{
if (_shared_encryptor)
return _shared_encryptor;
NSString *saved_password = [self keychainPassword];
if (saved_password == nil)
{
saved_password = [self keychainDefaultPassword];
Encryptor *encryptor = [[[Encryptor alloc] initWithPassword:saved_password] autorelease];
[self setEncryptedVerificationData:encryptor];
_shared_encryptor = [encryptor retain];
}
else
{
Encryptor *encryptor = [[[Encryptor alloc] initWithPassword:saved_password] autorelease];
if ([self verifyPassword:encryptor])
_shared_encryptor = [encryptor retain];
}
return _shared_encryptor;
}
// For the current implementation, decryptors and encryptors are equivalent.
- (Encryptor *)decryptor
{
return [self encryptor];
}
@end
#pragma mark -
@implementation EncryptionController (Private)
#pragma mark -
#pragma mark Keychain password storage
- (NSString *)keychainServerName
{
return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
}
- (NSString *)keychainUsername
{
return @"master.password";
}
- (void)setKeychainPassword:(NSString *)password
{
NSError *error;
if (password == nil)
{
[SFHFKeychainUtils deleteItemForUsername:[self keychainUsername]
andServerName:[self keychainServerName]
error:&error];
return;
}
[SFHFKeychainUtils storeUsername:[self keychainUsername]
andPassword:password
forServerName:[self keychainServerName]
updateExisting:YES
error:&error];
}
- (NSString *)keychainPassword
{
NSError *error;
return [SFHFKeychainUtils getPasswordForUsername:[self keychainUsername]
andServerName:[self keychainServerName]
error:&error];
}
- (NSString *)keychainDefaultPassword
{
NSString *password = [[NSUserDefaults standardUserDefaults] stringForKey:@"UUID"];
if ([password length] == 0)
{
password = [NSString stringWithUUID];
[[NSUserDefaults standardUserDefaults] setObject:password forKey:@"UUID"];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"TSXMasterPasswordVerification"];
}
return password;
}
#pragma mark -
#pragma mark Verification of encryption key against verification data
- (BOOL)verifyPassword:(Encryptor *)decryptor
{
return [[decryptor plaintextPassword]
isEqualToString:[decryptor decryptString:[self encryptedVerificationData]]];
}
- (NSData *)encryptedVerificationData
{
return [[NSUserDefaults standardUserDefaults] dataForKey:@"TSXMasterPasswordVerification"];
}
- (void)setEncryptedVerificationData:(Encryptor *)encryptor
{
[[NSUserDefaults standardUserDefaults]
setObject:[encryptor encryptString:[encryptor plaintextPassword]]
forKey:@"TSXMasterPasswordVerification"];
}
@end

View File

@@ -0,0 +1,17 @@
/*
Application help controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import <UIKit/UIKit.h>
@interface HelpController : UIViewController <UIWebViewDelegate>
{
UIWebView *webView;
}
@end

View File

@@ -0,0 +1,76 @@
/*
Application help controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "HelpController.h"
#import "Utils.h"
@implementation HelpController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// set title and tab-bar image
[self setTitle:NSLocalizedString(@"Help", @"Help Controller title")];
UIImage *tabBarIcon = [UIImage
imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tabbar_icon_help"
ofType:@"png"]];
[self setTabBarItem:[[[UITabBarItem alloc]
initWithTitle:NSLocalizedString(@"Help", @"Tabbar item help")
image:tabBarIcon
tag:0] autorelease]];
}
return self;
}
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
webView = [[[UIWebView alloc] initWithFrame:CGRectZero] autorelease];
[webView
setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
[webView setAutoresizesSubviews:YES];
[webView setDelegate:self];
[webView setDataDetectorTypes:UIDataDetectorTypeNone];
[self setView:webView];
}
- (void)dealloc
{
[super dealloc];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *filename = (IsPhone() ? @"gestures_phone" : @"gestures");
NSString *htmlString = [[[NSString alloc]
initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:filename
ofType:@"html"
inDirectory:@"help_page"]
encoding:NSUTF8StringEncoding
error:nil] autorelease];
[webView
loadHTMLString:htmlString
baseURL:[NSURL fileURLWithPath:[[[NSBundle mainBundle] bundlePath]
stringByAppendingPathComponent:@"help_page"]]];
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
@end

View File

@@ -0,0 +1,18 @@
/*
main tabbar controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface MainTabBarController : UITabBarController
{
}
@end

View File

@@ -0,0 +1,20 @@
/*
main tabbar controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "MainTabBarController.h"
@implementation MainTabBarController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
@end

View File

@@ -0,0 +1,25 @@
/*
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "EditorBaseController.h"
@class ConnectionParams;
@interface PerformanceEditorController : EditorBaseController
{
@private
ConnectionParams *_params;
NSString *_keyPath;
}
- (id)initWithConnectionParams:(ConnectionParams *)params;
- (id)initWithConnectionParams:(ConnectionParams *)params keyPath:(NSString *)keyPath;
@end

View File

@@ -0,0 +1,244 @@
/*
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "PerformanceEditorController.h"
#import "ConnectionParams.h"
#import "Utils.h"
@interface PerformanceEditorController (Private)
- (NSString *)keyPathForKey:(NSString *)key;
@end
@implementation PerformanceEditorController
- (id)initWithConnectionParams:(ConnectionParams *)params
{
return [self initWithConnectionParams:params keyPath:nil];
}
- (id)initWithConnectionParams:(ConnectionParams *)params keyPath:(NSString *)keyPath;
{
self = [super initWithStyle:UITableViewStyleGrouped];
if (self)
{
_params = [params retain];
_keyPath = (keyPath != nil ? [keyPath retain] : nil);
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (NSString *)keyPathForKey:(NSString *)key
{
if (_keyPath)
return [_keyPath stringByAppendingFormat:@".%@", key];
return key;
}
- (void)dealloc
{
[super dealloc];
[_params release];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 7;
}
// set section headers
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
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;
}
case 1:
{
[[cell label] setText:NSLocalizedString(@"GFX", @"GFX performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_gfx"]]];
break;
}
case 2:
{
[[cell label] setText:NSLocalizedString(@"H264", @"H264 performance setting")];
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_h264"]]];
break;
}
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 -
#pragma mark Action Handlers
- (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;
case GET_TAG(0, 1):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_gfx"]];
break;
case GET_TAG(0, 2):
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_h264"]];
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

@@ -0,0 +1,75 @@
/*
RDP Session View Controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import <UIKit/UIKit.h>
#import "RDPSession.h"
#import "RDPKeyboard.h"
#import "RDPSessionView.h"
#import "TouchPointerView.h"
#import "AdvancedKeyboardView.h"
@interface RDPSessionViewController
: UIViewController <RDPSessionDelegate, TouchPointerDelegate, AdvancedKeyboardDelegate,
RDPKeyboardDelegate, UIScrollViewDelegate, UITextFieldDelegate>
{
// scrollview that hosts the rdp session view
IBOutlet UIScrollView *_session_scrollview;
// rdp session view
IBOutlet RDPSessionView *_session_view;
// touch pointer view
IBOutlet TouchPointerView *_touchpointer_view;
BOOL _autoscroll_with_touchpointer;
BOOL _is_autoscrolling;
// rdp session toolbar
IBOutlet UIToolbar *_session_toolbar;
BOOL _session_toolbar_visible;
// dummy text field used to display the keyboard
IBOutlet UITextField *_dummy_textfield;
// connecting view and the controls within that view
IBOutlet UIView *_connecting_view;
IBOutlet UILabel *_lbl_connecting;
IBOutlet UIActivityIndicatorView *_connecting_indicator_view;
IBOutlet UIButton *_cancel_connect_button;
// extended keyboard toolbar
UIToolbar *_keyboard_toolbar;
// rdp session
RDPSession *_session;
BOOL _session_initilized;
// flag that indicates whether the keyboard is visible or not
BOOL _keyboard_visible;
// flag to switch between left/right mouse button mode
BOOL _toggle_mouse_button;
// keyboard extension view
AdvancedKeyboardView *_advanced_keyboard_view;
BOOL _advanced_keyboard_visible;
BOOL _requesting_advanced_keyboard;
CGFloat _keyboard_last_height;
// delayed mouse move event sending
NSTimer *_mouse_move_event_timer;
int _mouse_move_events_skipped;
CGPoint _prev_long_press_position;
}
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
session:(RDPSession *)session;
@end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,34 @@
/*
controller for screen 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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "EditorBaseController.h"
@class ConnectionParams;
@class OrderedDictionary;
@interface ScreenSelectionController : EditorBaseController
{
@private
NSString *_keyPath;
ConnectionParams *_params;
// available options
OrderedDictionary *_color_options;
NSArray *_resolution_modes;
// current selections
int _selection_color;
int _selection_resolution;
}
- (id)initWithConnectionParams:(ConnectionParams *)params;
- (id)initWithConnectionParams:(ConnectionParams *)params keyPath:(NSString *)keyPath;
@end

View File

@@ -0,0 +1,253 @@
/*
controller for screen 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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "ScreenSelectionController.h"
#import "Utils.h"
#import "OrderedDictionary.h"
#import "ConnectionParams.h"
@interface ScreenSelectionController (Private)
- (NSString *)keyPathForKey:(NSString *)key;
@end
@implementation ScreenSelectionController
- (id)initWithConnectionParams:(ConnectionParams *)params
{
return [self initWithConnectionParams:params keyPath:nil];
}
- (id)initWithConnectionParams:(ConnectionParams *)params keyPath:(NSString *)keyPath
{
self = [super initWithStyle:UITableViewStyleGrouped];
if (self)
{
_params = [params retain];
_keyPath = (keyPath != nil ? [keyPath retain] : nil);
_color_options = (OrderedDictionary *)[SelectionForColorSetting() retain];
_resolution_modes = [ResolutionModes() retain];
// init current selections
NSUInteger idx = [_color_options
indexForValue:[NSNumber
numberWithInt:[_params
intForKeyPath:[self keyPathForKey:@"colors"]]]];
_selection_color = (idx != NSNotFound) ? idx : 0;
idx = [_resolution_modes
indexOfObject:ScreenResolutionDescription(
[_params
intForKeyPath:[self keyPathForKey:@"screen_resolution_type"]],
[_params intForKeyPath:[self keyPathForKey:@"width"]],
[_params intForKeyPath:[self keyPathForKey:@"height"]])];
_selection_resolution = (idx != NSNotFound) ? idx : 0;
}
return self;
}
- (void)dealloc
{
[super dealloc];
[_params autorelease];
[_keyPath autorelease];
[_color_options autorelease];
[_resolution_modes autorelease];
}
- (NSString *)keyPathForKey:(NSString *)key
{
if (_keyPath)
return [_keyPath stringByAppendingFormat:@".%@", key];
return key;
}
#pragma mark - View lifecycle
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
if (section == 0)
return [_color_options count];
return [_resolution_modes count] + 2; // +2 for custom width/height input fields
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
switch ([indexPath section])
{
case 0:
cell = [self tableViewCellFromIdentifier:TableCellIdentifierMultiChoice];
[[cell textLabel] setText:[_color_options keyAtIndex:[indexPath row]]];
break;
case 1:
if ([indexPath row] < [_resolution_modes count])
{
cell = [self tableViewCellFromIdentifier:TableCellIdentifierMultiChoice];
[[cell textLabel] setText:[_resolution_modes objectAtIndex:[indexPath row]]];
}
else
cell = [self tableViewCellFromIdentifier:TableCellIdentifierText];
break;
default:
break;
}
if ([indexPath section] == 1)
{
BOOL enabled = ([_params intForKeyPath:[self keyPathForKey:@"screen_resolution_type"]] ==
TSXScreenOptionCustom);
if ([indexPath row] == [_resolution_modes count])
{
int value = [_params intForKeyPath:[self keyPathForKey:@"width"]];
EditTextTableViewCell *textCell = (EditTextTableViewCell *)cell;
[[textCell label] setText:NSLocalizedString(@"Width", @"Custom Screen Width")];
[[textCell textfield] setText:[NSString stringWithFormat:@"%d", value ? value : 800]];
[[textCell textfield] setKeyboardType:UIKeyboardTypeNumberPad];
[[textCell label] setEnabled:enabled];
[[textCell textfield] setEnabled:enabled];
[[textCell textfield] setTag:1];
}
else if ([indexPath row] == ([_resolution_modes count] + 1))
{
int value = [_params intForKeyPath:[self keyPathForKey:@"height"]];
EditTextTableViewCell *textCell = (EditTextTableViewCell *)cell;
[[textCell label] setText:NSLocalizedString(@"Height", @"Custom Screen Height")];
[[textCell textfield] setText:[NSString stringWithFormat:@"%d", value ? value : 600]];
[[textCell textfield] setKeyboardType:UIKeyboardTypeNumberPad];
[[textCell label] setEnabled:enabled];
[[textCell textfield] setEnabled:enabled];
[[textCell textfield] setTag:2];
}
}
// set default checkmark
if ([indexPath row] == ([indexPath section] == 0 ? _selection_color : _selection_resolution))
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
else
[cell setAccessoryType:UITableViewCellAccessoryNone];
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// custom width/height cells are not selectable
if ([indexPath section] == 1 && [indexPath row] >= [_resolution_modes count])
return;
// has selection change?
int cur_selection = ([indexPath section] == 0 ? _selection_color : _selection_resolution);
if ([indexPath row] != cur_selection)
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
NSIndexPath *oldIndexPath = [NSIndexPath indexPathForRow:cur_selection
inSection:[indexPath section]];
// clear old checkmark
UITableViewCell *old_sel_cell = [tableView cellForRowAtIndexPath:oldIndexPath];
old_sel_cell.accessoryType = UITableViewCellAccessoryNone;
// set new checkmark
UITableViewCell *new_sel_cell = [tableView cellForRowAtIndexPath:indexPath];
new_sel_cell.accessoryType = UITableViewCellAccessoryCheckmark;
if ([indexPath section] == 0)
{
// get value from color dictionary
int sel_value =
[[_color_options valueForKey:[_color_options keyAtIndex:[indexPath row]]] intValue];
// update selection index and params value
[_params setInt:sel_value forKeyPath:[self keyPathForKey:@"colors"]];
_selection_color = [indexPath row];
}
else
{
// update selection index and params value
int width, height;
TSXScreenOptions mode;
ScanScreenResolution([_resolution_modes objectAtIndex:[indexPath row]], &width, &height,
&mode);
[_params setInt:mode forKeyPath:[self keyPathForKey:@"screen_resolution_type"]];
if (mode != TSXScreenOptionCustom)
{
[_params setInt:width forKeyPath:[self keyPathForKey:@"width"]];
[_params setInt:height forKeyPath:[self keyPathForKey:@"height"]];
}
_selection_resolution = [indexPath row];
// refresh width/height edit fields if custom selection changed
NSArray *indexPaths = [NSArray
arrayWithObjects:[NSIndexPath indexPathForRow:[_resolution_modes count]
inSection:1],
[NSIndexPath indexPathForRow:([_resolution_modes count] + 1)
inSection:1],
nil];
[[self tableView] reloadRowsAtIndexPaths:indexPaths
withRowAnimation:UITableViewRowAnimationNone];
}
}
}
#pragma mark -
#pragma mark Text Field delegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return NO;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
switch ([textField tag])
{
// update resolution settings (and check for invalid input)
case 1:
if ([[textField text] intValue] < 640)
[textField setText:@"640"];
[_params setInt:[[textField text] intValue] forKeyPath:[self keyPathForKey:@"width"]];
break;
case 2:
if ([[textField text] intValue] < 480)
[textField setText:@"480"];
[_params setInt:[[textField text] intValue] forKeyPath:[self keyPathForKey:@"height"]];
break;
default:
break;
}
return YES;
}
@end

View File

@@ -0,0 +1,33 @@
/*
Certificate verification controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import <UIKit/UIKit.h>
@class RDPSession;
@interface VerifyCertificateController : UIViewController
{
@private
IBOutlet UILabel *_label_issuer;
IBOutlet UIButton *_btn_accept;
IBOutlet UIButton *_btn_decline;
IBOutlet UILabel *_label_message;
IBOutlet UILabel *_label_for_issuer;
RDPSession *_session;
NSMutableDictionary *_params;
}
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
session:(RDPSession *)session
params:(NSMutableDictionary *)params;
@end

View File

@@ -0,0 +1,86 @@
/*
Certificate verification controller
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.
If a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.
*/
#import "VerifyCertificateController.h"
#import "RDPSession.h"
@implementation VerifyCertificateController
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
session:(RDPSession *)session
params:(NSMutableDictionary *)params
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
_session = session;
_params = params;
[self setModalPresentationStyle:UIModalPresentationFormSheet];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *message = NSLocalizedString(
@"The identity of the remote computer cannot be verified. Do you want to connect anyway?",
@"Verify certificate view message");
// init strings
[_label_message setText:message];
[_label_for_issuer
setText:NSLocalizedString(@"Issuer:", @"Verify certificate view issuer label")];
[_btn_accept setTitle:NSLocalizedString(@"Yes", @"Yes Button") forState:UIControlStateNormal];
[_btn_decline setTitle:NSLocalizedString(@"No", @"No Button") forState:UIControlStateNormal];
[_label_issuer setText:[_params valueForKey:@"issuer"]];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
// set signal
[[_session uiRequestCompleted] signal];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#pragma mark - Action handlers
- (IBAction)acceptPressed:(id)sender
{
[_params setValue:[NSNumber numberWithBool:YES] forKey:@"result"];
// dismiss controller
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)declinePressed:(id)sender
{
[_params setValue:[NSNumber numberWithBool:NO] forKey:@"result"];
// dismiss controller
[self dismissModalViewControllerAnimated:YES];
}
@end