iOS web browser with a focus on security and privacy
1/*
2 * Endless
3 * Copyright (c) 2015 joshua stein <jcs@jcs.org>
4 *
5 * See LICENSE file for redistribution terms.
6 */
7
8#import "AppDelegate.h"
9#import "Bookmark.h"
10
11@implementation Bookmark
12
13static AppDelegate *appDelegate;
14static NSMutableArray *_list;
15
16NSString * const BOOKMARK_KEY_NAME = @"name";
17NSString * const BOOKMARK_KEY_URL = @"url";
18
19NSString * const BOOKMARK_KEY_VERSION = @"version";
20NSString * const BOOKMARK_KEY_LIST = @"bookmarks";
21
22const int BOOKMARK_FILE_VERSION = 1;
23
24+ (NSString *)bookmarksPath
25{
26 NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
27 return [path stringByAppendingPathComponent:@"bookmarks.plist"];
28}
29
30+ (void)retrieveList
31{
32 appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
33 _list = nil;
34
35 NSFileManager *fileManager = [NSFileManager defaultManager];
36 if ([fileManager fileExistsAtPath:[self bookmarksPath]]) {
37 NSDictionary *bookmarks = [[NSDictionary alloc] initWithContentsOfFile:[self bookmarksPath]];
38
39 NSNumber *v = [bookmarks objectForKey:BOOKMARK_KEY_VERSION];
40 if (v != nil) {
41 if ([v intValue] != BOOKMARK_FILE_VERSION)
42 NSLog(@"need to handle bookmark list migration from version %d to %d", [v intValue], BOOKMARK_FILE_VERSION);
43
44 NSArray *tlist = [bookmarks objectForKey:BOOKMARK_KEY_LIST];
45 _list = [[NSMutableArray alloc] initWithCapacity:MIN(tlist.count, 5)];
46 for (int i = 0; i < [tlist count]; i++)
47 [_list addObject:[self unmarshall:tlist[i]]];
48 }
49 }
50
51 if (_list == nil)
52 _list = [[NSMutableArray alloc] initWithCapacity:5];
53}
54
55+ (NSMutableArray *)list
56{
57 return _list;
58}
59
60+ (void)persistList
61{
62 NSMutableDictionary *d = [[NSMutableDictionary alloc] init];
63
64 NSMutableArray *t = [[NSMutableArray alloc] initWithCapacity:[_list count]];
65 for (int i = 0; i < [_list count]; i++)
66 [t addObject:((Bookmark *)_list[i]).marshallable];
67
68 [d setObject:t forKey:BOOKMARK_KEY_LIST];
69 [d setObject:[NSNumber numberWithInt:BOOKMARK_FILE_VERSION] forKey:BOOKMARK_KEY_VERSION];
70
71 if ([d writeToFile:[self bookmarksPath] atomically:YES] == false)
72 NSLog(@"failed writing bookmarks to %@", [self bookmarksPath]);
73}
74
75+ (Bookmark *)unmarshall:(NSDictionary *)marshalled
76{
77 Bookmark *b = [[Bookmark alloc] init];
78 b.name = [marshalled objectForKey:BOOKMARK_KEY_NAME];
79 b.url = [NSURL URLWithString:[marshalled objectForKey:BOOKMARK_KEY_URL]];
80 return b;
81}
82
83+ (void)addBookmarkForURLString:(NSString *)urls withName:(NSString *)name;
84{
85 Bookmark *b = [[Bookmark alloc] init];
86
87 NSURL *furl = [NSURL URLWithString:urls];
88 if (![furl scheme] || [[furl scheme] isEqualToString:@""])
89 furl = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@", urls]];
90
91 if (![furl path] || [[furl path] isEqualToString:@""])
92 furl = [NSURL URLWithString:[NSString stringWithFormat:@"%@/", [furl absoluteString]]];
93
94 b.url = furl;
95
96 if (name && ![name isEqualToString:@""])
97 b.name = name;
98 else
99 b.name = [NSString stringWithFormat:@"%@%@", [furl host], [[furl path] isEqualToString:@"/"] ? @"" : [furl path]];
100
101 [[self list] addObject:b];
102 [self persistList];
103}
104
105+ (BOOL)isURLBookmarked:(NSURL *)url
106{
107 for (int i = 0; i < [[Bookmark list] count]; i++) {
108 Bookmark *b = [Bookmark list][i];
109
110 if ([[[[b url] absoluteString] lowercaseString] isEqualToString:[[url absoluteString] lowercaseString]])
111 return YES;
112 }
113
114 return NO;
115}
116
117+ (UIAlertController *)addBookmarkDialogWithOkCallback:(void (^)(void))callback
118{
119 WebViewTab *wvt = [[appDelegate webViewController] curWebViewTab];
120
121 UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Add Bookmark", nil) message:NSLocalizedString(@"Enter the details of the URL to bookmark:", nil) preferredStyle:UIAlertControllerStyleAlert];
122 [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
123 textField.placeholder = NSLocalizedString(@"URL", nil);
124
125 if (wvt && [wvt url])
126 textField.text = [[wvt url] absoluteString];
127 }];
128 [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
129 textField.placeholder = NSLocalizedString(@"Page Name (leave blank to use URL)", nil);
130
131 if (wvt && [wvt url])
132 textField.text = [[wvt title] text];
133 }];
134
135 UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK action") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
136 UITextField *url = alertController.textFields[0];
137 UITextField *name = alertController.textFields[1];
138
139 if (url && ![[url text] isEqualToString:@""]) {
140 [Bookmark addBookmarkForURLString:[url text] withName:[name text]];
141
142 if (callback != nil)
143 callback();
144 }
145 }];
146
147 UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel action") style:UIAlertActionStyleCancel handler:nil];
148 [alertController addAction:cancelAction];
149 [alertController addAction:okAction];
150
151 return alertController;
152}
153
154
155- (NSDictionary *)marshallable
156{
157 /* can only have basic things like NSArray, NSString, etc. or writing will fail */
158
159 return @{
160 BOOKMARK_KEY_NAME: self.name,
161 BOOKMARK_KEY_URL: self.url.absoluteString,
162 };
163}
164
165- (NSString *)urlString
166{
167 return [self.url absoluteString];
168}
169
170- (void)setUrlString:(NSString *)urls
171{
172 self.url = [NSURL URLWithString:urls];
173}
174
175@end