-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathQSFirefoxPlugIn.m
More file actions
239 lines (194 loc) · 7.56 KB
/
QSFirefoxPlugIn.m
File metadata and controls
239 lines (194 loc) · 7.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
//
// QSFirefoxPlugIn.m
// QSFirefoxPlugIn
//
#import "QSFirefoxPlugIn.h"
#import "lz4firefox.h"
@implementation QSFirefoxPlugIn
- (void)performJavaScript:(NSString *)jScript {
//NSLog(@"JAVASCRIPT perform: %@",jScript);
NSDictionary *errorDict=nil;
NSAppleScript *script=[[[NSAppleScript alloc]initWithSource:[NSString stringWithFormat:@"tell application \"Firefox\" to Get URL \"%@\"",jScript]]autorelease];
if (errorDict) NSLog(@"Load Script: %@",[errorDict objectForKey:@"NSAppleScriptErrorMessage"]);
else [script executeAndReturnError:&errorDict];
if (errorDict) NSLog(@"Run Script: %@",[errorDict objectForKey:@"NSAppleScriptErrorMessage"]);
}
- (id)resolveProxyObject:(id)proxy {
// reading Firefox's sessionsstore.js
static NSString *path = nil;
if (!path) {
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *fs = @[@"~/Library/Application Support/Firefox/Profiles/*/sessionstore-backups/recovery.jsonlz4",
@"~/Library/Application Support/Firefox/Profiles/*/sessionstore.js",
@"~/Library/Application Support/Firefox/Profiles/*/sessionstore-backups/recovery.js"];
for (NSString *p in fs) {
NSString *resolved = [p stringByResolvingWildcardsInPath];
if ([fm fileExistsAtPath:resolved]) {
path = [resolved retain];
break;
}
}
}
if (!path) {
QSShowAppNotifWithAttributes(@"QSFirefoxPlugin", NSLocalizedStringForThisBundle(@"Unable to locate Session Store", @"notif title"), NSLocalizedStringForThisBundle(@"Unable to locate the Session Store file for Firefox", @"notif message"));
return nil;
}
NSData *jsonData = nil;
NSError *err = nil;
if ([[path pathExtension] isEqualToString:@"jsonlz4"]) {
jsonData = readlz4(path);
} else {
jsonData = [NSData dataWithContentsOfFile:path];
}
if (!jsonData) {
NSLog(@"Error when reading file: %@", err);
}
// parsing JSON
NSDictionary *sessionstore = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&err];
// traversing JSON path to current web page
NSArray *windows = [sessionstore objectForKey:@"windows"];
int selectedWindow =[[sessionstore objectForKey:@"selectedWindow"] intValue];
NSDictionary *window = [windows objectAtIndex:selectedWindow-1];
NSArray *tabs = [window objectForKey:@"tabs"];
int selectedTab =[[window objectForKey:@"selected"] intValue];
NSDictionary *tab = [tabs objectAtIndex:selectedTab-1];
NSArray *entries = [tab objectForKey:@"entries"];
NSDictionary *entry = [entries lastObject];
NSString *title = [entry objectForKey:@"title"];
NSString *url = [entry objectForKey:@"url"];
return [QSObject URLObjectWithURL:url title:title];
}
# pragma mark Firefox right arrow
- (BOOL)loadChildrenForObject:(QSObject *)object {
if ([object isProxyObject]) {
return NO;
}
// Right-arrowing into the Firefox application
if ([[object primaryType] isEqualToString:QSFilePathType] &&
[[[NSBundle bundleWithPath:[object singleFilePath]] bundleIdentifier] isEqualToString:@"org.mozilla.firefox"]) {
[object setChildren:[self firefoxObjects]];
return YES;
}
// Right-arrowing into a Firefox child (Bookmarks or History)
NSString *catalogID = [object objectForType:@"qs.firefox.source"];
if (catalogID) {
QSCatalogEntry *entry = [QSLib entryForID:catalogID];
if (entry) {
NSArray *children = [entry scanAndCache];
if (children) {
[object setChildren:children];
return YES;
}
}
return NO;
}
return NO;
}
- (BOOL)objectHasChildren:(QSObject *)object {
return YES;
}
- (NSArray *)firefoxObjects {
NSMutableArray *objects = [NSMutableArray arrayWithCapacity:3];
QSObject *history = [QSObject makeObjectWithIdentifier:@"QSFirefoxHistoryChild"];
[history setName:@"Firefox History"];
[history setPrimaryType:@"qs.firefox.source"];
[history setObject:@"QSPresetFirefoxHistory" forType:@"qs.firefox.source"];
[history setIcon:[QSResourceManager imageNamed:@"org.mozilla.firefox"]];
[objects addObject:history];
QSObject *bookmarks = [QSObject makeObjectWithIdentifier:@"QSFirefoxBookmarksChild"];
[bookmarks setName:@"Firefox Bookmarks"];
[bookmarks setPrimaryType:@"qs.firefox.source"];
[bookmarks setObject:@"QSPresetFirefoxBookmarks" forType:@"qs.firefox.source"];
[bookmarks setIcon:[QSResourceManager imageNamed:@"org.mozilla.firefox"]];
[objects addObject:bookmarks];
QSObject *currentPage = [QSProxyObject proxyWithIdentifier:@"QSFirefoxCurrentWebPageProxy"];
if (currentPage) {
[objects addObject:currentPage];
}
return objects;
}
@end
@implementation QSFirefoxBookmarksParser
- (BOOL)validParserForPath:(NSString *)path {
return [[path lastPathComponent] isEqualToString:@"places.sqlite"];
}
- (NSArray *)objectsFromPath:(NSString *)path withSettings:(NSDictionary *)settings {
NSString *query = @"SELECT "
"bookmarks.title AS title, "
"places.url AS url "
"FROM moz_bookmarks AS bookmarks "
"LEFT JOIN moz_places AS places ON places.id = bookmarks.fk "
"WHERE bookmarks.fk IS NOT NULL "
"AND bookmarks.title IS NOT NULL "
"ORDER BY bookmarks.title;";
return [QSFirefoxPlacesParser executeSql:query onFile:path];
}
@end
@implementation QSFirefoxHistoryParser
- (BOOL)validParserForPath:(NSString *)path {
return [[path lastPathComponent] isEqualToString:@"places.sqlite"];
}
- (NSArray *)objectsFromPath:(NSString *)path withSettings:(NSDictionary *)settings {
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
NSInteger limit = [[settings objectForKey:@"historySize"] intValue];
if ([ud integerForKey:@"FirefoxSearchHistoryLimit"] > 0) {
limit = [ud integerForKey:@"FirefoxSearchHistoryLimit"];
}
NSString *query = [NSString stringWithFormat:@"SELECT DISTINCT "
"places.title AS title, "
"places.url AS url "
"FROM moz_historyvisits AS history "
"LEFT JOIN moz_places AS places ON places.id = history.place_id "
"ORDER BY visit_date DESC "
"LIMIT %d;",
limit];
return [QSFirefoxPlacesParser executeSql:query onFile:path];
}
@end
@implementation QSFirefoxPlacesParser
+ (NSArray *) executeSql:(NSString *)query onFile:(NSString *)path {
NSMutableArray *objects=[NSMutableArray arrayWithCapacity:0];
NSFileManager *manager = [NSFileManager defaultManager];
NSString *tempPath = [NSTemporaryDirectory() stringByAppendingString:@"QSFirefoxPlaces.sqlite"];
NSError *err;
BOOL status;
// make sure tmp-copy of places.sqlite isn't there
status = [manager removeItemAtPath:tempPath error:&err];
// copy places.sqlite so it wont be locked when Firefox is running
status = [manager copyItemAtPath:path toPath:tempPath error:&err];
if (!status) {
NSLog(@"Error while copying Firefox places.sqlite: %@", err);
}
// open places.sqlite DB
FMDatabase *db = [FMDatabase databaseWithPath:tempPath];
if (![db openWithFlags:0x00000001]) { // 1 = SQLITE_OPEN_READONLY
NSLog(@"Could not open Firefox's places.sqlite DB.");
return objects;
}
[db goodConnection];
// execute SQL query
FMResultSet *rs = [db executeQuery:query];
if ([db hadError]) {
NSLog(@"Error while reading Firefox's places.sqlite DB. Error %d: %@", [db lastErrorCode], [db lastErrorMessage]);
return objects;
}
// build QSObjects
NSString *url, *title;
QSObject *newObject;
while ([rs next]) {
title = [rs stringForColumn:@"title"];
url = [rs stringForColumn:@"url"];
newObject = [[QSObject alloc] initWithURL:url title:title];
[objects addObject:newObject];
}
// close DB
[rs close];
[db close];
// delete tmp-copy of places.sqlite
status = [manager removeItemAtPath:tempPath error:&err];
if (!status) {
NSLog(@"Error while removing copy of Firefox places.sqlite: %@", err);
}
return objects;
}
@end