11#import "BookmarkListController.h"
13#import "BookmarkEditorController.h"
14#import "RDPSessionViewController.h"
15#import "Toast+UIView.h"
16#import "Reachability.h"
17#import "GlobalDefaults.h"
20#define SHOW_SESSIONS_SECTION 0
22#define SECTION_SESSIONS 0
23#define SECTION_BOOKMARKS 1
26@interface BookmarkListController (Private)
27#pragma mark misc functions
28- (void)performSearch:(NSString *)searchText;
29- (void)askToSaveTemporaryBookmark;
30#pragma mark Persisting bookmarks
31- (void)scheduleWriteBookmarksToDataStore;
32- (void)writeBookmarksToDataStore;
33- (void)scheduleWriteManualBookmarksToDataStore;
34- (void)writeManualBookmarksToDataStore;
35- (void)readManualBookmarksFromDataStore;
36- (void)writeArray:(NSArray *)bookmarks toDataStoreURL:(NSURL *)url;
37- (NSMutableArray *)arrayFromDataStoreURL:(NSURL *)url;
38- (NSURL *)manualBookmarksDataStoreURL;
39- (NSURL *)connectionHistoryDataStoreURL;
44@synthesize searchBar = _searchBar, tableView = _tableView, sessTableCell = _sessTableCell;
48- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
50 if ((
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]))
53 [
self readManualBookmarksFromDataStore];
56 [
self readConnectionHistoryFromDataStore];
59 _manual_search_result = nil;
62 [[NSNotificationCenter defaultCenter] addObserver:self
63 selector:@selector(sessionDisconnected:)
64 name:TSXSessionDidDisconnectNotification
66 [[NSNotificationCenter defaultCenter] addObserver:self
67 selector:@selector(sessionFailedToConnect:)
68 name:TSXSessionDidFailToConnectNotification
72 [
self setTitle:NSLocalizedString(@"Connections",
73 @"'Connections': bookmark controller title")];
74 [
self setTabBarItem:[[[UITabBarItem alloc]
75 initWithTabBarSystemItem:UITabBarSystemItemBookmarks
79 [[NSNotificationCenter defaultCenter] addObserver:self
80 selector:@selector(reachabilityChanged:)
81 name:kReachabilityChangedNotification
85 _active_sessions = [[NSMutableArray alloc] init];
86 _temporary_bookmark = nil;
102 [[
self navigationItem] setRightBarButtonItem:[
self editButtonItem]];
105 [_tableView setPreservesSuperviewLayoutMargins:YES];
106 [_searchBar setPreservesSuperviewLayoutMargins:YES];
109 [_tableView setEstimatedRowHeight:UITableViewAutomaticDimension];
112- (void)viewWillAppear:(BOOL)animated
114 [
super viewWillAppear:animated];
117 if ([[_searchBar text] length] > 0)
118 [
self performSearch:[_searchBar text]];
121 [_tableView reloadData];
124- (void)viewDidAppear:(BOOL)animated
126 [
super viewDidAppear:animated];
129 if (_temporary_bookmark)
130 [
self askToSaveTemporaryBookmark];
134- (void)viewSafeAreaInsetsDidChange
136 [
super viewSafeAreaInsetsDidChange];
137 [[
self view] setNeedsLayout];
140- (void)viewDidLayoutSubviews
142 [
super viewDidLayoutSubviews];
144 const CGRect bounds = [[
self view] bounds];
145 const UIEdgeInsets safe = [[
self view] safeAreaInsets];
146 const CGFloat x = safe.left;
147 const CGFloat w = bounds.size.width - safe.left - safe.right;
148 CGFloat searchH = CGRectGetHeight([_searchBar frame]);
150 [_searchBar setFrame:CGRectMake(x, safe.top, w, searchH)];
152 setFrame:CGRectMake(x, safe.top + searchH, w, bounds.size.height - safe.top - searchH)];
155- (void)viewWillDisappear:(BOOL)animated
157 [
super viewWillDisappear:animated];
160 [_searchBar setText:@""];
161 [_searchBar resignFirstResponder];
162 [
self performSearch:@""];
166- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
172- (void)didReceiveMemoryWarning
175 [
super didReceiveMemoryWarning];
182 [
super viewDidUnload];
189 [[NSNotificationCenter defaultCenter] removeObserver:self];
191 [_temporary_bookmark release];
192 [_connection_history release];
193 [_active_sessions release];
194 [_manual_search_result release];
195 [_history_search_result release];
196 [_manual_bookmarks release];
202#pragma mark Table view data source
204- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
210- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
215 case SECTION_SESSIONS:
219 case SECTION_BOOKMARKS:
222 if (_manual_search_result != nil)
223 return ([_manual_search_result count] + [_history_search_result count] + 1);
224 return ([_manual_bookmarks count] + 1);
234- (UITableViewCell *)cellForGenericListEntry
236 static NSString *CellIdentifier =
@"BookmarkListCell";
237 UITableViewCell *cell = [[
self tableView] dequeueReusableCellWithIdentifier:CellIdentifier];
240 cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
241 reuseIdentifier:CellIdentifier] autorelease];
242 [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
243 [cell setAccessoryType:UITableViewCellAccessoryDetailButton];
249- (void)setText:(NSString *)text forGenericListEntry:(UITableViewCell *)cell
251 UIListContentConfiguration *content = [cell defaultContentConfiguration];
252 [content setText:text];
253 [cell setContentConfiguration:content];
258 static NSString *BookmarkCellIdentifier =
@"BookmarkCell";
260 dequeueReusableCellWithIdentifier:BookmarkCellIdentifier];
264 reuseIdentifier:BookmarkCellIdentifier] autorelease];
271- (UITableViewCell *)tableView:(UITableView *)tableView
272 cellForRowAtIndexPath:(NSIndexPath *)indexPath
275 switch ([indexPath section])
277 case SECTION_SESSIONS:
280 static NSString *SessionCellIdentifier =
@"SessionCell";
282 dequeueReusableCellWithIdentifier:SessionCellIdentifier];
285 [[NSBundle mainBundle] loadNibNamed:@"SessionTableViewCell" owner:self options:nil];
286 cell = _sessTableCell;
287 _sessTableCell = nil;
291 RDPSession *session = [_active_sessions objectAtIndex:[indexPath row]];
292 [[cell title] setText:[session sessionName]];
293 [[cell server] setText:[[session params] StringForKey:@"hostname"]];
294 [[cell username] setText:[[session params] StringForKey:@"username"]];
296 setImage:[session getScreenshotWithSize:[[cell screenshot] bounds].size]];
297 [[cell disconnectButton] setTag:[indexPath row]];
301 case SECTION_BOOKMARKS:
304 if ([indexPath row] == 0)
308 UITableViewCell *cell = [
self cellForGenericListEntry];
309 if ([[_searchBar text] length] == 0)
311 [
self setText:NSLocalizedString(@"Add Connection",
312 @"'Add Connection': button label")
313 forGenericListEntry:cell];
314 [cell setAccessoryType:UITableViewCellAccessoryNone];
318 [
self setText:[_searchBar text] forGenericListEntry:cell];
319 [cell setAccessoryType:UITableViewCellAccessoryDetailButton];
327 if ([
self isIndexPathToHistoryItem:indexPath])
329 UITableViewCell *cell = [
self cellForGenericListEntry];
330 [
self setText:[_history_search_result
331 objectAtIndex:[
self historyIndexFromIndexPath:indexPath]]
332 forGenericListEntry:cell];
333 [cell setAccessoryType:UITableViewCellAccessoryDetailButton];
341 if (_manual_search_result == nil)
342 entry = [_manual_bookmarks
343 objectAtIndex:[
self bookmarkIndexFromIndexPath:indexPath]];
345 entry = [[_manual_search_result
346 objectAtIndex:[
self bookmarkIndexFromIndexPath:indexPath]]
347 valueForKey:@"bookmark"];
349 [cell setTitle:[entry label]];
350 [cell setSubTitle:[[entry params] StringForKey:@"hostname"]];
360 NSAssert(0,
@"Failed to create cell");
365- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
368 if ([indexPath section] == SECTION_SESSIONS)
370 if ([indexPath section] == SECTION_BOOKMARKS && [indexPath row] == 0)
376- (void)tableView:(UITableView *)tableView
377 commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
378 forRowAtIndexPath:(NSIndexPath *)indexPath
380 if (editingStyle == UITableViewCellEditingStyleDelete)
383 switch ([indexPath section])
385 case SECTION_BOOKMARKS:
387 if (_manual_search_result == nil)
389 removeObjectAtIndex:[
self bookmarkIndexFromIndexPath:indexPath]];
393 if ([
self isIndexPathToHistoryItem:indexPath])
397 [_history_search_result
398 objectAtIndex:[
self historyIndexFromIndexPath:indexPath]]];
399 [_history_search_result
400 removeObjectAtIndex:[
self historyIndexFromIndexPath:indexPath]];
401 [
self scheduleWriteConnectionHistoryToDataStore];
407 [[_manual_search_result
408 objectAtIndex:[
self bookmarkIndexFromIndexPath:indexPath]]
409 valueForKey:@"bookmark"]];
410 [_manual_search_result
411 removeObjectAtIndex:[
self bookmarkIndexFromIndexPath:indexPath]];
414 [
self scheduleWriteManualBookmarksToDataStore];
419 [tableView reloadSections:[NSIndexSet indexSetWithIndex:[indexPath section]]
420 withRowAnimation:UITableViewRowAnimationNone];
425- (void)tableView:(UITableView *)tableView
426 moveRowAtIndexPath:(NSIndexPath *)fromIndexPath
427 toIndexPath:(NSIndexPath *)toIndexPath
429 if ([fromIndexPath compare:toIndexPath] != NSOrderedSame)
431 switch ([fromIndexPath section])
433 case SECTION_BOOKMARKS:
435 NSInteger fromIdx = [
self bookmarkIndexFromIndexPath:fromIndexPath];
436 NSInteger toIdx = [
self bookmarkIndexFromIndexPath:toIndexPath];
438 [[_manual_bookmarks objectAtIndex:fromIdx] retain];
439 [_manual_bookmarks removeObjectAtIndex:fromIdx];
440 if (toIdx >= [_manual_bookmarks count])
441 [_manual_bookmarks addObject:temp_bookmark];
443 [_manual_bookmarks insertObject:temp_bookmark atIndex:toIdx];
444 [temp_bookmark release];
446 [
self scheduleWriteManualBookmarksToDataStore];
454- (NSIndexPath *)tableView:(UITableView *)tableView
455 targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath
456 toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
462 if ([proposedDestinationIndexPath row] == 0 ||
463 ([sourceIndexPath section] != [proposedDestinationIndexPath section]) ||
464 _manual_search_result != nil)
466 return sourceIndexPath;
470 return proposedDestinationIndexPath;
475- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
478 if ([indexPath section] == SECTION_BOOKMARKS && [indexPath row] == 0)
483- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
485 if (SHOW_SESSIONS_SECTION && section == SECTION_SESSIONS && [_active_sessions count] > 0)
486 return NSLocalizedString(
@"My Sessions",
@"'My Session': section sessions header");
487 if (section == SECTION_BOOKMARKS)
488 return NSLocalizedString(
@"Manual Connections",
489 @"'Manual Connections': section manual bookmarks header");
493- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
498- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
501 if (!SHOW_SESSIONS_SECTION && section == SECTION_SESSIONS)
503 return UITableViewAutomaticDimension;
506- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
509 if (!SHOW_SESSIONS_SECTION && section == SECTION_SESSIONS)
511 return [tableView sectionFooterHeight];
514- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
516 if ([indexPath section] == SECTION_SESSIONS)
519 return UITableViewAutomaticDimension;
523#pragma mark Table view delegate
525- (void)setEditing:(BOOL)editing animated:(BOOL)animated
527 [
super setEditing:editing animated:animated];
528 [[
self tableView] setEditing:editing animated:animated];
531- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
533 if ([indexPath section] == SECTION_SESSIONS)
536 RDPSession *session = [_active_sessions objectAtIndex:[indexPath row]];
537 UIViewController *ctrl =
540 session:session] autorelease];
541 [ctrl setHidesBottomBarWhenPushed:YES];
542 [[
self navigationController] pushViewController:ctrl animated:YES];
547 if ([indexPath section] == SECTION_BOOKMARKS)
550 if ([indexPath row] == 0)
552 if ([[_searchBar text] length] == 0)
559 [bookmarkEditorController
560 setTitle:NSLocalizedString(@"Add Connection", @"Add Connection title")];
561 [bookmarkEditorController setDelegate:self];
563 if ([[UIDevice currentDevice] userInterfaceIdiom] != UIUserInterfaceIdiomPad)
564 [bookmarkEditorController setHidesBottomBarWhenPushed:YES];
565 [[
self navigationController] pushViewController:bookmarkEditorController
572 bookmark = [
self bookmarkForQuickConnectTo:[_searchBar text]];
573 if (![_connection_history containsObject:[_searchBar text]])
575 [_connection_history addObject:[_searchBar text]];
576 [
self scheduleWriteConnectionHistoryToDataStore];
582 if (_manual_search_result != nil)
584 if ([
self isIndexPathToHistoryItem:indexPath])
587 NSString *item = [_history_search_result
588 objectAtIndex:[
self historyIndexFromIndexPath:indexPath]];
589 bookmark = [
self bookmarkForQuickConnectTo:item];
592 bookmark = [[_manual_search_result
593 objectAtIndex:[
self bookmarkIndexFromIndexPath:indexPath]]
594 valueForKey:@"bookmark"];
597 bookmark = [_manual_bookmarks
598 objectAtIndex:[
self bookmarkIndexFromIndexPath:
605 reachabilityWithHostName:[[bookmark params]
606 StringForKey:@"hostname"]]
607 currentReachabilityStatus] == ReachableViaWiFi];
614 UIViewController *ctrl =
617 session:session] autorelease];
618 [ctrl setHidesBottomBarWhenPushed:YES];
619 [[
self navigationController] pushViewController:ctrl animated:YES];
620 [_active_sessions addObject:session];
625- (void)tableView:(UITableView *)tableView
626 accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
629 NSString *bookmark_editor_title =
630 NSLocalizedString(
@"Edit Connection",
@"Edit Connection title");
632 if ([indexPath section] == SECTION_BOOKMARKS)
634 if ([indexPath row] == 0)
637 bookmark = [
self bookmarkForQuickConnectTo:[_searchBar text]];
638 bookmark_editor_title = NSLocalizedString(
@"Add Connection",
@"Add Connection title");
642 if (_manual_search_result != nil)
644 if ([
self isIndexPathToHistoryItem:indexPath])
647 NSString *item = [_history_search_result
648 objectAtIndex:[
self historyIndexFromIndexPath:indexPath]];
649 bookmark = [
self bookmarkForQuickConnectTo:item];
650 bookmark_editor_title =
651 NSLocalizedString(
@"Add Connection",
@"Add Connection title");
654 bookmark = [[_manual_search_result
655 objectAtIndex:[
self bookmarkIndexFromIndexPath:indexPath]]
656 valueForKey:@"bookmark"];
659 bookmark = [_manual_bookmarks
660 objectAtIndex:[
self bookmarkIndexFromIndexPath:indexPath]];
671 if ([[UIDevice currentDevice] userInterfaceIdiom] != UIUserInterfaceIdiomPad)
672 [editBookmarkController setHidesBottomBarWhenPushed:YES];
673 [editBookmarkController setTitle:bookmark_editor_title];
674 [editBookmarkController setDelegate:self];
675 [[
self navigationController] pushViewController:editBookmarkController animated:YES];
680#pragma mark Search Bar Delegates
682- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
685 [searchBar setShowsCancelButton:YES animated:YES];
689- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
692 [_manual_search_result release];
693 _manual_search_result = nil;
696 [searchBar setText:@""];
697 [searchBar resignFirstResponder];
700- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
702 [searchBar setShowsCancelButton:NO animated:YES];
705 [_tableView setAllowsSelection:YES];
710- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
712 [_searchBar resignFirstResponder];
715- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
717 [
self performSearch:searchText];
718 [_tableView reloadData];
721#pragma mark - Session handling
724- (void)sessionDisconnected:(NSNotification *)notification
728 [_active_sessions removeObject:session];
731 if ([[
self navigationController] visibleViewController] ==
self)
732 [_tableView reloadSections:[NSIndexSet indexSetWithIndex:SECTION_SESSIONS]
733 withRowAnimation:UITableViewRowAnimationNone];
737 if (![_manual_bookmarks containsObject:[session bookmark]])
739 if (_temporary_bookmark)
740 [_temporary_bookmark release];
745 _temporary_bookmark = [[session bookmark] retain];
749- (void)askToSaveTemporaryBookmark
752 NSLocalizedString(
@"Save Connection Settings?",
@"Save connection settings title");
753 NSString *message = NSLocalizedString(
754 @"Your Connection Settings have not been saved. Do you want to save them?",
755 @"Save connection settings message");
756 UIAlertController *alert =
757 [UIAlertController alertControllerWithTitle:title
759 preferredStyle:UIAlertControllerStyleAlert];
760 [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"No", @"No Button")
761 style:UIAlertActionStyleCancel
762 handler:^(UIAlertAction *action) {
763 [_temporary_bookmark autorelease];
764 _temporary_bookmark = nil;
767 addAction:[UIAlertAction
768 actionWithTitle:NSLocalizedString(@"Yes", @"Yes Button")
769 style:UIAlertActionStyleDefault
770 handler:^(UIAlertAction *action) {
771 if (_temporary_bookmark)
773 [_manual_bookmarks addObject:_temporary_bookmark];
775 reloadSections:[NSIndexSet
776 indexSetWithIndex:SECTION_BOOKMARKS]
777 withRowAnimation:UITableViewRowAnimationNone];
778 [
self scheduleWriteManualBookmarksToDataStore];
779 [_temporary_bookmark autorelease];
780 _temporary_bookmark = nil;
783 [
self presentViewController:alert animated:YES completion:nil];
786- (void)sessionFailedToConnect:(NSNotification *)notification
790 [_active_sessions removeObject:session];
793 [[
self view] makeToast:NSLocalizedString(@"Failed to connect to session!",
794 @"Failed to connect error message")
795 duration:ToastDurationNormal
799#pragma mark - Reachability notification
800- (void)reachabilityChanged:(NSNotification *)notification
804 if ([_active_sessions count] > 0)
806 RDPSession *session = [_active_sessions objectAtIndex:0];
807 [session disconnect];
811#pragma mark - BookmarkEditorController delegate
817 for (
int idx = 0; idx < [_manual_bookmarks count]; ++idx)
819 if ([[bookmark uuid] isEqualToString:[[_manual_bookmarks objectAtIndex:idx] uuid]])
821 [_manual_bookmarks replaceObjectAtIndex:idx withObject:bookmark];
827 [_manual_bookmarks addObject:bookmark];
830 NSString *hostname = [[bookmark params] StringForKey:@"hostname"];
831 if ([_connection_history containsObject:hostname])
833 [_connection_history removeObject:hostname];
834 [
self scheduleWriteConnectionHistoryToDataStore];
837 [
self scheduleWriteManualBookmarksToDataStore];
840- (IBAction)disconnectButtonPressed:(
id)sender
843 RDPSession *session = [_active_sessions objectAtIndex:[sender tag]];
844 [session disconnect];
847#pragma mark - Misc functions
849- (BOOL)hasNoBookmarks
851 return ([_manual_bookmarks count] == 0);
854- (void)performSearch:(NSString *)searchText
856 [_manual_search_result autorelease];
857 [_history_search_result autorelease];
859 if ([searchText length] > 0)
861 _manual_search_result = [FilterBookmarks(
863 [searchText componentsSeparatedByCharactersInSet:[NSCharacterSet
864 whitespaceAndNewlineCharacterSet]])
866 _history_search_result = [FilterHistory(_connection_history, searchText) retain];
870 _history_search_result = nil;
871 _manual_search_result = nil;
875- (NSInteger)bookmarkIndexFromIndexPath:(NSIndexPath *)indexPath
877 return [indexPath row] -
878 ((_history_search_result != nil) ? [_history_search_result count] : 0) - 1;
881- (NSInteger)historyIndexFromIndexPath:(NSIndexPath *)indexPath
883 return [indexPath row] - 1;
886- (BOOL)isIndexPathToHistoryItem:(NSIndexPath *)indexPath
888 return (([indexPath row] - 1) < [_history_search_result count]);
895 [bookmark setLabel:host];
896 [[bookmark params] setValue:host forKey:@"hostname"];
900#pragma mark - Persisting bookmarks
902- (void)scheduleWriteBookmarksToDataStore
904 [[NSOperationQueue mainQueue] addOperationWithBlock:^{
905 [
self writeBookmarksToDataStore];
909- (void)writeBookmarksToDataStore
911 [
self writeManualBookmarksToDataStore];
914- (void)scheduleWriteManualBookmarksToDataStore
916 [[NSOperationQueue mainQueue]
917 addOperation:[[[NSInvocationOperation alloc]
919 selector:@selector(writeManualBookmarksToDataStore)
920 object:nil] autorelease]];
923- (void)writeManualBookmarksToDataStore
925 [
self writeArray:_manual_bookmarks toDataStoreURL:[
self manualBookmarksDataStoreURL]];
928- (void)scheduleWriteConnectionHistoryToDataStore
930 [[NSOperationQueue mainQueue]
931 addOperation:[[[NSInvocationOperation alloc]
933 selector:@selector(writeConnectionHistoryToDataStore)
934 object:nil] autorelease]];
937- (void)writeConnectionHistoryToDataStore
939 [
self writeArray:_connection_history toDataStoreURL:[
self connectionHistoryDataStoreURL]];
942- (void)writeArray:(NSArray *)bookmarks toDataStoreURL:(NSURL *)url
944 NSError *error = nil;
945 NSData *archived_data = [NSKeyedArchiver archivedDataWithRootObject:bookmarks
946 requiringSecureCoding:YES
952 NSLog(
@"%s: failed to archive %@: %@", __func__, [url lastPathComponent], error);
956 [archived_data writeToURL:url atomically:YES];
959- (void)readManualBookmarksFromDataStore
961 [_manual_bookmarks autorelease];
962 _manual_bookmarks = [
self arrayFromDataStoreURL:[
self manualBookmarksDataStoreURL]];
964 if (_manual_bookmarks == nil)
966 _manual_bookmarks = [[NSMutableArray alloc] init];
970- (void)readConnectionHistoryFromDataStore
972 [_connection_history autorelease];
973 _connection_history = [
self arrayFromDataStoreURL:[
self connectionHistoryDataStoreURL]];
975 if (_connection_history == nil)
976 _connection_history = [[NSMutableArray alloc] init];
979- (NSMutableArray *)arrayFromDataStoreURL:(NSURL *)url
981 NSData *archived_data = [NSData dataWithContentsOfURL:url];
987 NSSet *classes = [NSSet setWithObjects:[NSArray class], [
ComputerBookmark class],
989 [NSString class], [NSNumber class], [NSData class], nil];
990 NSError *error = nil;
991 NSArray *decoded = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes
992 fromData:archived_data
997 NSLog(
@"%s: failed to unarchive %@: %@", __func__, [url lastPathComponent], error);
1002 return [[NSMutableArray alloc] initWithArray:decoded];
1005- (NSURL *)manualBookmarksDataStoreURL
1008 fileURLWithPath:[NSString stringWithFormat:@"%@/%@",
1009 [NSSearchPathForDirectoriesInDomains(
1010 NSDocumentDirectory, NSUserDomainMask, YES)
1012 @"com.freerdp.ifreerdp.bookmarks.plist"]];
1015- (NSURL *)connectionHistoryDataStoreURL
1018 fileURLWithPath:[NSString
1019 stringWithFormat:@"%@/%@",
1020 [NSSearchPathForDirectoriesInDomains(
1021 NSDocumentDirectory, NSUserDomainMask, YES)
1023 @"com.freerdp.ifreerdp.connection_history.plist"]];