root / pithos-macos / PithosAccount.m @ cb6abe72
History | View | Annotate | Download (17.7 kB)
1 |
// |
---|---|
2 |
// PithosAccount.m |
3 |
// pithos-macos |
4 |
// |
5 |
// Copyright 2012 GRNET S.A. All rights reserved. |
6 |
// |
7 |
// Redistribution and use in source and binary forms, with or |
8 |
// without modification, are permitted provided that the following |
9 |
// conditions are met: |
10 |
// |
11 |
// 1. Redistributions of source code must retain the above |
12 |
// copyright notice, this list of conditions and the following |
13 |
// disclaimer. |
14 |
// |
15 |
// 2. Redistributions in binary form must reproduce the above |
16 |
// copyright notice, this list of conditions and the following |
17 |
// disclaimer in the documentation and/or other materials |
18 |
// provided with the distribution. |
19 |
// |
20 |
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
21 |
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
22 |
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 |
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
24 |
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
25 |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
26 |
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
27 |
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
28 |
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
29 |
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
30 |
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 |
// POSSIBILITY OF SUCH DAMAGE. |
32 |
// |
33 |
// The views and conclusions contained in the software and |
34 |
// documentation are those of the authors and should not be |
35 |
// interpreted as representing official policies, either expressed |
36 |
// or implied, of GRNET S.A. |
37 |
|
38 |
#import "PithosAccount.h" |
39 |
#import "PithosSyncDaemon.h" |
40 |
#import "ASIPithos.h" |
41 |
#import "PithosAccountNode.h" |
42 |
#import "PithosSharingAccountsNode.h" |
43 |
#import "pithos_macosAppDelegate.h" |
44 |
|
45 |
@interface PithosAccount (Internal) |
46 |
- (BOOL)urlIsValid:(NSString *)urlString; |
47 |
@end |
48 |
|
49 |
@implementation PithosAccount |
50 |
@synthesize uniqueName, active, name; |
51 |
@synthesize syncActive, syncDirectoryPath, syncAccountsDictionary, syncSkipHidden, syncLastCompleted, syncDaemon; |
52 |
@synthesize serverURL, versionResource, loginResource, publicResource; |
53 |
@synthesize authUser, authToken, storageURLPrefix, authURL, loginURLPrefix, publicURLPrefix; |
54 |
@synthesize pithos, accountNode, sharingAccountsNode; |
55 |
|
56 |
#pragma mark - |
57 |
#pragma mark Object Lifecycle |
58 |
|
59 |
+ (id)pithosAccount { |
60 |
PithosAccount *pithosAccount = [[self alloc] init]; |
61 |
pithosAccount.uniqueName = [NSString stringWithFormat:@"pithosAccount-%f", [NSDate timeIntervalSinceReferenceDate]]; |
62 |
pithosAccount.syncSkipHidden = YES; |
63 |
pithosAccount.versionResource = @"v1"; |
64 |
pithosAccount.loginResource = @"login"; |
65 |
return pithosAccount; |
66 |
} |
67 |
|
68 |
|
69 |
- (NSString *)description { |
70 |
return [NSString stringWithFormat:@"uniqueName: %@, active: %d, name: %@, syncActive: %d, syncDirectoryPath: %@, syncAccountsDictionary: %@, syncSkipHidden: %d, syncLastCompleted: %@, serverURL: %@, versionResource: %@, loginResource: %@, publicResource: %@, authUser: %@, authToken: %@, storageURLPrefix: %@, authURL: %@, loginURLPrefix: %@, publicURLPrefix: %@", |
71 |
uniqueName, active, name, syncActive, syncDirectoryPath, syncAccountsDictionary, syncSkipHidden, syncLastCompleted, serverURL, versionResource, loginResource, publicResource, authUser, authToken, storageURLPrefix, authURL, loginURLPrefix, publicURLPrefix]; |
72 |
} |
73 |
|
74 |
#pragma mark - |
75 |
#pragma mark Internal |
76 |
|
77 |
- (BOOL)urlIsValid:(NSString *)urlString { |
78 |
if (urlString) { |
79 |
NSURL *url = [NSURL URLWithString:urlString]; |
80 |
if (url && url.scheme && url.host) |
81 |
return YES; |
82 |
} |
83 |
return NO; |
84 |
} |
85 |
|
86 |
#pragma mark - |
87 |
#pragma mark Properties |
88 |
|
89 |
- (NSString *)name { |
90 |
if (![name length]) { |
91 |
NSDictionary *pithosAccountsDictionary = [(pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate] pithosAccountsDictionary]; |
92 |
NSString *namePrefix = @"okeanos"; |
93 |
NSUInteger nameSuffix = 1; |
94 |
name = @"okeanos"; |
95 |
NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; |
96 |
NSFileManager *fileManager = [NSFileManager defaultManager]; |
97 |
while ([pithosAccountsDictionary objectForKey:name] || |
98 |
[fileManager fileExistsAtPath:[documentsDirectoryPath stringByAppendingPathComponent:name]]) { |
99 |
name = [NSString stringWithFormat:@"%@%ld", namePrefix, ++nameSuffix]; |
100 |
} |
101 |
} |
102 |
return name; |
103 |
} |
104 |
|
105 |
- (void)setName:(NSString *)aName { |
106 |
NSMutableDictionary *pithosAccountsDictionary = [(pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate] pithosAccountsDictionary]; |
107 |
if (![self.name isEqualToString:aName] && [aName length] && ![pithosAccountsDictionary objectForKey:aName]) { |
108 |
[pithosAccountsDictionary setObject:self forKey:aName]; |
109 |
[pithosAccountsDictionary removeObjectForKey:name]; |
110 |
name = aName; |
111 |
} |
112 |
} |
113 |
|
114 |
- (BOOL)syncActive { |
115 |
if (active) |
116 |
return syncActive; |
117 |
else |
118 |
return NO; |
119 |
} |
120 |
|
121 |
- (void)setSyncActive:(BOOL)aSyncActive { |
122 |
syncActive = aSyncActive; |
123 |
if (syncDaemon && !self.syncActive) |
124 |
[syncDaemon resetDaemon]; |
125 |
} |
126 |
|
127 |
- (NSString *)syncDirectoryPath { |
128 |
if (![syncDirectoryPath length]) { |
129 |
syncDirectoryPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] |
130 |
stringByAppendingPathComponent:self.name]; |
131 |
} |
132 |
return syncDirectoryPath; |
133 |
} |
134 |
|
135 |
- (void)setSyncDirectoryPath:(NSString *)aSyncDirectoryPath { |
136 |
if (![self.syncDirectoryPath isEqualToString:aSyncDirectoryPath] && [aSyncDirectoryPath length]) { |
137 |
BOOL isDirectory; |
138 |
if (![[NSFileManager defaultManager] fileExistsAtPath:aSyncDirectoryPath isDirectory:&isDirectory] || isDirectory) { |
139 |
syncDirectoryPath = aSyncDirectoryPath; |
140 |
} else { |
141 |
return; |
142 |
} |
143 |
|
144 |
@synchronized(self) { |
145 |
resetSyncDaemonLocalState = YES; |
146 |
syncLastCompleted = nil; |
147 |
} |
148 |
} |
149 |
} |
150 |
|
151 |
- (NSMutableDictionary *)syncAccountsDictionary { |
152 |
if (!syncAccountsDictionary) { |
153 |
syncAccountsDictionary = [NSMutableDictionary dictionaryWithObject:[NSMutableDictionary dictionaryWithObject:[NSMutableSet set] |
154 |
forKey:@"pithos"] |
155 |
forKey:@""]; |
156 |
} |
157 |
return syncAccountsDictionary; |
158 |
} |
159 |
|
160 |
- (void)setSyncAccountsDictionary:(NSMutableDictionary *)aSyncAccountsDictionary { |
161 |
if (aSyncAccountsDictionary && ![self.syncAccountsDictionary isEqualToDictionary:aSyncAccountsDictionary]) { |
162 |
syncAccountsDictionary = [[NSMutableDictionary alloc] initWithCapacity:[aSyncAccountsDictionary count]]; |
163 |
for (NSString *accountName in aSyncAccountsDictionary) { |
164 |
NSDictionary *aSyncContainersDictionary = [aSyncAccountsDictionary objectForKey:accountName]; |
165 |
NSMutableDictionary *syncContainersDictionary = [NSMutableDictionary dictionary]; |
166 |
for (NSString *containerName in aSyncContainersDictionary) { |
167 |
if (![accountName isEqualToString:@""] || ![[containerName lowercaseString] isEqualToString:@"shared to me"]) |
168 |
[syncContainersDictionary setObject:[NSMutableSet setWithSet:[aSyncContainersDictionary objectForKey:containerName]] |
169 |
forKey:containerName]; |
170 |
} |
171 |
if ([syncContainersDictionary count]) |
172 |
[syncAccountsDictionary setObject:syncContainersDictionary forKey:accountName]; |
173 |
} |
174 |
|
175 |
@synchronized(self) { |
176 |
resetSyncDaemonLocalState = YES; |
177 |
syncLastCompleted = nil; |
178 |
} |
179 |
} |
180 |
} |
181 |
|
182 |
- (NSDate *)syncLastCompleted { |
183 |
if (self.syncDaemon.lastCompletedSync && ![self.syncDaemon.lastCompletedSync isEqualToDate:syncLastCompleted]) { |
184 |
syncLastCompleted = [self.syncDaemon.lastCompletedSync copy]; |
185 |
} |
186 |
return syncLastCompleted; |
187 |
} |
188 |
|
189 |
- (PithosSyncDaemon *)syncDaemon { |
190 |
@synchronized(self) { |
191 |
if (self.syncActive && !syncDaemon) |
192 |
syncDaemon = [[PithosSyncDaemon alloc] initWithDirectoryPath:self.syncDirectoryPath |
193 |
pithosAccount:self |
194 |
accountsDictionary:self.syncAccountsDictionary |
195 |
skipHidden:self.syncSkipHidden |
196 |
resetLocalState:resetSyncDaemonLocalState]; |
197 |
resetSyncDaemonLocalState = NO; |
198 |
} |
199 |
return syncDaemon; |
200 |
} |
201 |
|
202 |
- (NSString *)serverURL { |
203 |
if (![self urlIsValid:serverURL]) { |
204 |
serverURL = @"https://pithos.okeanos.grnet.gr"; |
205 |
} |
206 |
return serverURL; |
207 |
} |
208 |
|
209 |
- (void)setServerURL:(NSString *)aServerURL { |
210 |
if (![self.serverURL isEqualToString:aServerURL] && [self urlIsValid:aServerURL]) { |
211 |
serverURL = aServerURL; |
212 |
storageURLPrefix = nil; |
213 |
authURL = nil; |
214 |
publicURLPrefix = nil; |
215 |
loginURLPrefix = nil; |
216 |
|
217 |
@synchronized(self) { |
218 |
updatePithos = YES; |
219 |
resetSyncDaemonLocalState = YES; |
220 |
syncLastCompleted = nil; |
221 |
} |
222 |
} |
223 |
} |
224 |
|
225 |
- (void)setAuthUser:(NSString *)anAuthUser { |
226 |
if ([anAuthUser length] && ![anAuthUser isEqualToString:authUser]) { |
227 |
authUser = anAuthUser; |
228 |
|
229 |
@synchronized(self) { |
230 |
updatePithos = YES; |
231 |
resetSyncDaemonLocalState = YES; |
232 |
syncLastCompleted = nil; |
233 |
|
234 |
} |
235 |
} |
236 |
} |
237 |
|
238 |
- (void)setAuthToken:(NSString *)anAuthToken { |
239 |
if ([anAuthToken length] && ![anAuthToken isEqualToString:authToken]) { |
240 |
authToken = anAuthToken; |
241 |
|
242 |
@synchronized(self) { |
243 |
updatePithos = YES; |
244 |
} |
245 |
} |
246 |
} |
247 |
|
248 |
- (NSString *)storageURLPrefix { |
249 |
if (![self urlIsValid:storageURLPrefix]) { |
250 |
if (versionResource) |
251 |
storageURLPrefix = [self.serverURL stringByAppendingFormat:@"/%@", versionResource]; |
252 |
else |
253 |
storageURLPrefix = [self.serverURL copy]; |
254 |
} |
255 |
return storageURLPrefix; |
256 |
} |
257 |
|
258 |
- (void)setStorageURLPrefix:(NSString *)aStorageURLPrefix { |
259 |
if (![self.storageURLPrefix isEqualToString:aStorageURLPrefix] && [self urlIsValid:aStorageURLPrefix]) { |
260 |
storageURLPrefix = aStorageURLPrefix; |
261 |
} |
262 |
} |
263 |
|
264 |
- (NSString *)authURL { |
265 |
if (![self urlIsValid:authURL]) { |
266 |
if (versionResource) |
267 |
authURL = [self.serverURL stringByAppendingFormat:@"/%@", versionResource]; |
268 |
else |
269 |
authURL = [self.serverURL copy]; |
270 |
} |
271 |
return authURL; |
272 |
} |
273 |
|
274 |
- (void)setAuthURL:(NSString *)anAuthURL { |
275 |
if (![self.authURL isEqualToString:anAuthURL] && [self urlIsValid:anAuthURL]) { |
276 |
authURL = anAuthURL; |
277 |
} |
278 |
} |
279 |
|
280 |
- (NSString *)publicURLPrefix { |
281 |
if (![self urlIsValid:publicURLPrefix]) { |
282 |
if (publicResource) |
283 |
publicURLPrefix = [self.serverURL stringByAppendingFormat:@"/%@", publicResource]; |
284 |
else |
285 |
publicURLPrefix = [self.serverURL copy]; |
286 |
} |
287 |
return publicURLPrefix; |
288 |
} |
289 |
|
290 |
- (void)setPublicURLPrefix:(NSString *)aPublicURLPrefix { |
291 |
if (![self.publicURLPrefix isEqualToString:aPublicURLPrefix] && [self urlIsValid:aPublicURLPrefix]) { |
292 |
publicURLPrefix = aPublicURLPrefix; |
293 |
} |
294 |
} |
295 |
|
296 |
- (NSString *)loginURLPrefix { |
297 |
if (![self urlIsValid:loginURLPrefix]) { |
298 |
if (loginResource) |
299 |
loginURLPrefix = [self.serverURL stringByAppendingFormat:@"/%@", loginResource]; |
300 |
else |
301 |
loginURLPrefix = [self.serverURL copy]; |
302 |
} |
303 |
return loginURLPrefix; |
304 |
} |
305 |
|
306 |
- (void)setLoginURLPrefix:(NSString *)aLoginURLPrefix { |
307 |
if (![self.loginURLPrefix isEqualToString:aLoginURLPrefix] && [self urlIsValid:aLoginURLPrefix]) { |
308 |
loginURLPrefix = aLoginURLPrefix; |
309 |
} |
310 |
} |
311 |
|
312 |
- (ASIPithos *)pithos { |
313 |
@synchronized(self) { |
314 |
if (!pithos || updatePithos) { |
315 |
pithos = [ASIPithos pithos]; |
316 |
pithos.authUser = authUser; |
317 |
pithos.authToken = authToken; |
318 |
pithos.storageURLPrefix = self.storageURLPrefix; |
319 |
pithos.authURL = self.authURL; |
320 |
pithos.publicURLPrefix = self.publicURLPrefix; |
321 |
updatePithos = NO; |
322 |
} |
323 |
} |
324 |
return pithos; |
325 |
} |
326 |
|
327 |
- (PithosAccountNode *)accountNode { |
328 |
if (!accountNode) { |
329 |
accountNode = [[PithosAccountNode alloc] initWithPithos:self.pithos]; |
330 |
accountNode.childrenUpdatedNotificationName = nil; |
331 |
accountNode.inheritChildrenUpdatedNotificationName = YES; |
332 |
} |
333 |
return accountNode; |
334 |
} |
335 |
|
336 |
- (PithosSharingAccountsNode *)sharingAccountsNode { |
337 |
if (!sharingAccountsNode) { |
338 |
sharingAccountsNode = [[PithosSharingAccountsNode alloc] initWithPithos:self.pithos]; |
339 |
sharingAccountsNode.childrenUpdatedNotificationName = nil; |
340 |
sharingAccountsNode.inheritChildrenUpdatedNotificationName = YES; |
341 |
} |
342 |
return sharingAccountsNode; |
343 |
} |
344 |
|
345 |
#pragma mark - |
346 |
#pragma mark Actions |
347 |
|
348 |
- (void)authenticateWithServerURL:(NSString *)aServerURL authUser:(NSString *)anAuthUser authToken:(NSString *)anAuthToken { |
349 |
self.serverURL = aServerURL; |
350 |
self.authUser = anAuthUser; |
351 |
self.authToken = anAuthToken; |
352 |
DLog(@"Account: %@\nauthentication", self); |
353 |
if (![authUser length] || ![authToken length]) { |
354 |
self.active = NO; |
355 |
self.syncActive = NO; |
356 |
// XXX Show preferences with self as the selected account? |
357 |
} else { |
358 |
self.active = YES; |
359 |
if (syncDaemon) { |
360 |
self.syncDaemon.pithos = self.pithos; |
361 |
if (self.syncActive) |
362 |
[self.syncDaemon startDaemon]; |
363 |
} |
364 |
if (accountNode) |
365 |
self.accountNode.pithos = self.pithos; |
366 |
if (sharingAccountsNode) |
367 |
self.sharingAccountsNode.pithos = self.pithos; |
368 |
if (accountNode) { |
369 |
if (self.accountNode.children) { |
370 |
} |
371 |
[self.accountNode refreshInfo]; |
372 |
} |
373 |
if (sharingAccountsNode && self.sharingAccountsNode.children) { |
374 |
} |
375 |
} |
376 |
} |
377 |
|
378 |
- (void)loginWithServerURL:(NSString *)aServerURL { |
379 |
self.serverURL = aServerURL; |
380 |
NSProcessInfo *processInfo = [NSProcessInfo processInfo]; |
381 |
NSString *loginURL = [NSString stringWithFormat:@"%@?next=pithos://%d/%@&force=", |
382 |
self.loginURLPrefix, [processInfo processIdentifier], self.name]; |
383 |
DLog(@"Account: %@\nloginURL: %@", self, loginURL); |
384 |
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:loginURL]]; |
385 |
} |
386 |
|
387 |
- (void)updateSyncWithSyncActive:(BOOL)aSyncActive |
388 |
syncDirectoryPath:(NSString *)aSyncDirectoryPath |
389 |
syncAccountsDictionary:(NSMutableDictionary *)aSyncAccountsDictionary |
390 |
syncSkipHidden:(BOOL)aSyncSkipHidden { |
391 |
self.syncAccountsDictionary = aSyncAccountsDictionary; |
392 |
self.syncDirectoryPath = aSyncDirectoryPath; |
393 |
self.syncSkipHidden = aSyncSkipHidden; |
394 |
self.syncActive = aSyncActive; |
395 |
if (syncDaemon) { |
396 |
self.syncDaemon.accountsDictionary = self.syncAccountsDictionary; |
397 |
self.syncDaemon.directoryPath = self.syncDirectoryPath; |
398 |
self.syncDaemon.skipHidden = self.syncSkipHidden; |
399 |
if (self.syncActive) |
400 |
[self.syncDaemon startDaemon]; |
401 |
} |
402 |
} |
403 |
|
404 |
#pragma mark - |
405 |
#pragma mark NSCoding |
406 |
|
407 |
- (id)initWithCoder:(NSCoder *)decoder { |
408 |
if ((self = [super init])) { |
409 |
self.uniqueName = [decoder decodeObjectForKey:@"uniqueName"]; |
410 |
self.active = [decoder decodeBoolForKey:@"active"]; |
411 |
name = [decoder decodeObjectForKey:@"name"]; |
412 |
|
413 |
self.syncActive = [decoder decodeBoolForKey:@"syncActive"]; |
414 |
self.syncDirectoryPath = [decoder decodeObjectForKey:@"syncDirectoryPath"]; |
415 |
self.syncAccountsDictionary = [decoder decodeObjectForKey:@"syncAccountsDictionary"]; |
416 |
self.syncSkipHidden = [decoder decodeBoolForKey:@"syncSkipHidden"]; |
417 |
self.syncLastCompleted = [decoder decodeObjectForKey:@"syncLastCompleted"]; |
418 |
|
419 |
self.serverURL = [decoder decodeObjectForKey:@"serverURL"]; |
420 |
self.versionResource = [decoder decodeObjectForKey:@"versionResource"]; |
421 |
self.loginResource = [decoder decodeObjectForKey:@"loginResource"]; |
422 |
self.publicResource = [decoder decodeObjectForKey:@"publicResource"]; |
423 |
|
424 |
self.authUser = [decoder decodeObjectForKey:@"authUser"]; |
425 |
self.authToken = [decoder decodeObjectForKey:@"authToken"]; |
426 |
self.storageURLPrefix = [decoder decodeObjectForKey:@"storageURLPrefix"]; |
427 |
self.authURL = [decoder decodeObjectForKey:@"authURL"]; |
428 |
self.publicURLPrefix = [decoder decodeObjectForKey:@"publicURLPrefix"]; |
429 |
self.loginURLPrefix = [decoder decodeObjectForKey:@"loginURLPrefix"]; |
430 |
|
431 |
if (![authUser length] || ![authToken length] || ![self.storageURLPrefix length]) |
432 |
self.active = NO; |
433 |
|
434 |
resetSyncDaemonLocalState = NO; |
435 |
} |
436 |
return self; |
437 |
} |
438 |
|
439 |
- (void)encodeWithCoder:(NSCoder *)encoder { |
440 |
[encoder encodeObject:uniqueName forKey:@"uniqueName"]; |
441 |
[encoder encodeBool:active forKey:@"active"]; |
442 |
[encoder encodeObject:name forKey:@"name"]; |
443 |
|
444 |
[encoder encodeBool:syncActive forKey:@"syncActive"]; |
445 |
[encoder encodeObject:syncDirectoryPath forKey:@"syncDirectoryPath"]; |
446 |
[encoder encodeObject:syncAccountsDictionary forKey:@"syncAccountsDictionary"]; |
447 |
[encoder encodeBool:syncSkipHidden forKey:@"syncSkipHidden"]; |
448 |
[encoder encodeObject:self.syncLastCompleted forKey:@"syncLastCompleted"]; |
449 |
|
450 |
[encoder encodeObject:serverURL forKey:@"serverURL"]; |
451 |
[encoder encodeObject:versionResource forKey:@"versionResource"]; |
452 |
[encoder encodeObject:publicResource forKey:@"publicResource"]; |
453 |
[encoder encodeObject:loginResource forKey:@"loginResource"]; |
454 |
|
455 |
[encoder encodeObject:authUser forKey:@"authUser"]; |
456 |
[encoder encodeObject:authToken forKey:@"authToken"]; |
457 |
[encoder encodeObject:storageURLPrefix forKey:@"storageURLPrefix"]; |
458 |
[encoder encodeObject:authURL forKey:@"authURL"]; |
459 |
[encoder encodeObject:publicURLPrefix forKey:@"publicURLPrefix"]; |
460 |
[encoder encodeObject:loginURLPrefix forKey:@"loginURLPrefix"]; |
461 |
} |
462 |
|
463 |
@end |