5 // Copyright 2012-2013 GRNET S.A. All rights reserved.
7 // Redistribution and use in source and binary forms, with or
8 // without modification, are permitted provided that the following
11 // 1. Redistributions of source code must retain the above
12 // copyright notice, this list of conditions and the following
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.
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.
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.
38 #import "PithosAccount.h"
39 #import "PithosSyncDaemon.h"
41 #import "ASIPithosRequest.h"
42 #import "PithosAccountNode.h"
43 #import "PithosSharingAccountsNode.h"
44 #import "PithosUtilities.h"
45 #import "pithos_macosAppDelegate.h"
47 static NSString *defaultAuthURLString = @"https://accounts.okeanos.grnet.gr/identity/v2.0";
48 static NSString *defaultManualURLString = @"https://pithos.okeanos.grnet.gr";
50 @interface NSString(Additions)
52 - (NSString *)stringByRemovingTrailingSlashes;
55 @implementation NSString(Additions)
57 NSURL *URL = [NSURL URLWithString:self];
58 return (URL && URL.scheme && URL.host);
61 - (NSString *)stringByRemovingTrailingSlashes {
62 return [self stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"/"]];
66 @implementation PithosAccount
67 @synthesize uniqueName, active, name, clientVersion;
68 @synthesize syncActive, syncDirectoryPath, syncAccountsDictionary, syncSkipHidden, syncLastCompleted, syncDaemon;
69 @synthesize authURLString, pithosObjectStoreURLString, astakosAccountURLString, astakosWebloginURLString, manual;
70 @synthesize authToken, authUser, userCatalog;
71 @synthesize ignoreSSLErrors;
72 @synthesize pithos, accountNode, sharingAccountsNode;
73 @synthesize tokensURL, storageURLPrefix, loginURL, userCatalogURL, publicURLPrefix;
76 #pragma mark Object Lifecycle
79 PithosAccount *pithosAccount = [[self alloc] init];
80 pithosAccount.uniqueName = [NSString stringWithFormat:@"pithosAccount-%f", [NSDate timeIntervalSinceReferenceDate]];
81 pithosAccount.clientVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
82 pithosAccount.syncSkipHidden = YES;
83 pithosAccount.authURLString = defaultAuthURLString;
87 - (NSString *)description {
88 return [NSString stringWithFormat:@"uniqueName: %@, active: %d, name: %@, clientVersion: %@, syncActive: %d, syncDirectoryPath: %@, syncAccountsDictionary: %@, syncSkipHidden: %d, syncLastCompleted: %@, authURLString: %@, pithosObjectStoreURLString:%@ , astakosAccountURLString: %@, astakosWebloginURLString: %@, manual: %d, authToken: %@, authUser: %@",
89 uniqueName, active, name, clientVersion, syncActive, syncDirectoryPath, syncAccountsDictionary, syncSkipHidden, syncLastCompleted, authURLString, pithosObjectStoreURLString, astakosAccountURLString, astakosWebloginURLString, manual, authToken, authUser];
93 #pragma mark Properties
97 NSDictionary *pithosAccountsDictionary = [(pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate] pithosAccountsDictionary];
98 NSString *namePrefix = @"okeanos";
99 NSUInteger nameSuffix = 1;
101 NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
102 NSFileManager *fileManager = [NSFileManager defaultManager];
103 while ([pithosAccountsDictionary objectForKey:name] ||
104 [fileManager fileExistsAtPath:[documentsDirectoryPath stringByAppendingPathComponent:name]]) {
105 name = [NSString stringWithFormat:@"%@%ld", namePrefix, ++nameSuffix];
111 - (void)setName:(NSString *)aName {
112 NSMutableDictionary *pithosAccountsDictionary = [(pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate] pithosAccountsDictionary];
113 if (![self.name isEqualToString:aName] && [aName length] && ![pithosAccountsDictionary objectForKey:aName]) {
114 [pithosAccountsDictionary setObject:self forKey:aName];
115 [pithosAccountsDictionary removeObjectForKey:name];
127 - (void)setSyncActive:(BOOL)aSyncActive {
128 syncActive = aSyncActive;
129 if (syncDaemon && !self.syncActive)
130 [syncDaemon resetDaemon];
133 - (NSString *)syncDirectoryPath {
134 if (![syncDirectoryPath length]) {
135 syncDirectoryPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
136 stringByAppendingPathComponent:self.name];
138 return syncDirectoryPath;
141 - (void)setSyncDirectoryPath:(NSString *)aSyncDirectoryPath {
142 if (![self.syncDirectoryPath isEqualToString:aSyncDirectoryPath] && [aSyncDirectoryPath length]) {
144 if (![[NSFileManager defaultManager] fileExistsAtPath:aSyncDirectoryPath isDirectory:&isDirectory] || isDirectory) {
145 syncDirectoryPath = aSyncDirectoryPath;
150 @synchronized(self) {
151 resetSyncDaemonLocalState = YES;
152 syncLastCompleted = nil;
157 - (NSMutableDictionary *)syncAccountsDictionary {
158 if (!syncAccountsDictionary) {
159 syncAccountsDictionary = [NSMutableDictionary dictionaryWithObject:[NSMutableDictionary dictionaryWithObject:[NSMutableSet set]
163 return syncAccountsDictionary;
166 - (void)setSyncAccountsDictionary:(NSMutableDictionary *)aSyncAccountsDictionary {
167 if (aSyncAccountsDictionary && ![self.syncAccountsDictionary isEqualToDictionary:aSyncAccountsDictionary]) {
168 syncAccountsDictionary = [[NSMutableDictionary alloc] initWithCapacity:[aSyncAccountsDictionary count]];
169 for (NSString *accountName in aSyncAccountsDictionary) {
170 NSDictionary *aSyncContainersDictionary = [aSyncAccountsDictionary objectForKey:accountName];
171 NSMutableDictionary *syncContainersDictionary = [NSMutableDictionary dictionary];
172 for (NSString *containerName in aSyncContainersDictionary) {
173 if (![accountName isEqualToString:@""] || ![[containerName lowercaseString] isEqualToString:@"shared with me"])
174 [syncContainersDictionary setObject:[NSMutableSet setWithSet:[aSyncContainersDictionary objectForKey:containerName]]
175 forKey:containerName];
177 if ([syncContainersDictionary count])
178 [syncAccountsDictionary setObject:syncContainersDictionary forKey:accountName];
181 @synchronized(self) {
182 resetSyncDaemonLocalState = YES;
183 syncLastCompleted = nil;
188 - (NSDate *)syncLastCompleted {
189 if (self.syncDaemon.lastCompletedSync && ![self.syncDaemon.lastCompletedSync isEqualToDate:syncLastCompleted]) {
190 syncLastCompleted = [self.syncDaemon.lastCompletedSync copy];
192 return syncLastCompleted;
195 - (PithosSyncDaemon *)syncDaemon {
196 @synchronized(self) {
197 if (self.syncActive && !syncDaemon)
198 syncDaemon = [[PithosSyncDaemon alloc] initWithDirectoryPath:self.syncDirectoryPath
200 accountsDictionary:self.syncAccountsDictionary
201 skipHidden:self.syncSkipHidden
202 resetLocalState:resetSyncDaemonLocalState];
203 resetSyncDaemonLocalState = NO;
208 - (void)setAuthURLString:(NSString *)anAuthURLString {
209 NSString *tmpURLString = [anAuthURLString stringByRemovingTrailingSlashes];
210 if (![authURLString isEqualToString:tmpURLString]) {
211 authURLString = tmpURLString;
213 @synchronized(self) {
215 resetSyncDaemonLocalState = YES;
216 syncLastCompleted = nil;
221 - (void)setPithosObjectStoreURLString:(NSString *)aPithosObjectStoreURLString {
222 NSString *tmpURLString = [aPithosObjectStoreURLString stringByRemovingTrailingSlashes];
223 if (![pithosObjectStoreURLString isEqualToString:tmpURLString]) {
224 pithosObjectStoreURLString = tmpURLString;
226 @synchronized(self) {
232 - (void)setAstakosAccountURLString:(NSString *)anAstakosAccountURLString {
233 NSString *tmpURLString = [anAstakosAccountURLString stringByRemovingTrailingSlashes];
234 if (![astakosAccountURLString isEqualToString:tmpURLString]) {
235 astakosAccountURLString = tmpURLString;
237 @synchronized(self) {
243 - (void)setAstakosWebloginURLString:(NSString *)anAstakosWebloginURLString {
244 NSString *tmpURLString = [anAstakosWebloginURLString stringByRemovingTrailingSlashes];
245 if (![astakosWebloginURLString isEqualToString:tmpURLString]) {
246 astakosWebloginURLString = tmpURLString;
250 - (void)setAuthToken:(NSString *)anAuthToken {
251 if (anAuthToken.length && ![anAuthToken isEqualToString:authToken]) {
252 authToken = anAuthToken;
254 @synchronized(self) {
260 - (void)setAuthUser:(NSString *)anAuthUser {
261 if (anAuthUser.length && ![anAuthUser isEqualToString:authUser]) {
262 authUser = anAuthUser;
264 @synchronized(self) {
266 resetSyncDaemonLocalState = YES;
267 syncLastCompleted = nil;
273 - (void)setIgnoreSSLErrors:(BOOL)anIgnoreSSLErrors {
274 if (anIgnoreSSLErrors != ignoreSSLErrors) {
275 ignoreSSLErrors = anIgnoreSSLErrors;
277 @synchronized(self) {
283 - (NSMutableDictionary *)userCatalog {
285 userCatalog = [NSMutableDictionary dictionary];
290 - (ASIPithos *)pithos {
291 @synchronized(self) {
292 if (!pithos || updatePithos) {
293 pithos = [ASIPithos pithos];
294 pithos.authToken = authToken;
295 pithos.authUser = authUser;
297 pithos.ignoreSSLErrors = ignoreSSLErrors;
299 pithos.tokensURL = self.tokensURL;
300 pithos.storageURLPrefix = self.storageURLPrefix;
301 pithos.userCatalogURL = self.userCatalogURL;
302 pithos.publicURLPrefix = self.publicURLPrefix;
309 - (PithosAccountNode *)accountNode {
311 accountNode = [[PithosAccountNode alloc] initWithPithosAccountManager:self];
312 accountNode.childrenUpdatedNotificationName = nil;
313 accountNode.inheritChildrenUpdatedNotificationName = YES;
318 - (PithosSharingAccountsNode *)sharingAccountsNode {
319 if (!sharingAccountsNode) {
320 sharingAccountsNode = [[PithosSharingAccountsNode alloc] initWithPithosAccountManager:self];
321 sharingAccountsNode.childrenUpdatedNotificationName = nil;
322 sharingAccountsNode.inheritChildrenUpdatedNotificationName = YES;
324 return sharingAccountsNode;
327 - (NSString *)tokensURL {
328 return [authURLString stringByAppendingString:@"/tokens"];
331 - (NSString *)storageURLPrefix {
332 return [pithosObjectStoreURLString copy];
335 - (NSString *)loginURL {
336 return [astakosWebloginURLString stringByAppendingString:@"/login"];
339 - (NSString *)publicURLPrefix {
340 return [pithosObjectStoreURLString copy];
343 - (NSString *)userCatalogURL {
344 return [astakosAccountURLString stringByAppendingString:@"/user_catalogs"];
350 - (void)updateWithAuthURLString:(NSString *)anAuthURLString
351 pithosObjectStoreURLString:(NSString *)aPithosObjectStoreURLString
352 astakosAccountURLString:(NSString *)anAstakosAccountURLString
353 astakosWebloginURLString:(NSString *)anAstakosWebloginURLString
355 authToken:(NSString *)anAuthToken
356 authUser:(NSString *)anAuthUser
357 ignoreSSLErrors:(BOOL)anIgnoreSSLErrors
358 resetNodes:(BOOL)resetNodes {
359 BOOL pithosUpdated = (![authURLString isEqualToString:[anAuthURLString stringByRemovingTrailingSlashes]] ||
360 ![pithosObjectStoreURLString isEqualToString:[aPithosObjectStoreURLString stringByRemovingTrailingSlashes]] ||
361 ![astakosAccountURLString isEqualToString:[anAstakosAccountURLString stringByRemovingTrailingSlashes]] ||
362 ![authToken isEqualToString:anAuthToken] || ![authUser isEqualToString:anAuthUser] ||
363 (ignoreSSLErrors != anIgnoreSSLErrors));
364 self.authURLString = anAuthURLString;
365 self.pithosObjectStoreURLString = aPithosObjectStoreURLString;
366 self.astakosAccountURLString = anAstakosAccountURLString;
367 self.astakosWebloginURLString = anAstakosWebloginURLString;
368 self.manual = aManual;
369 self.authToken = anAuthToken;
370 self.authUser = anAuthUser;
371 self.ignoreSSLErrors = anIgnoreSSLErrors;
372 DLog(@"Account updated: %@", self);
373 if (!authToken.length || !authUser.length) {
375 self.syncActive = NO;
377 [self updateUserCatalogForDisplaynames:nil UUIDs:[NSArray arrayWithObject:authUser]];
382 // For the sync daemon we keep using a separate pithos object.
383 self.syncDaemon.pithos = self.pithos;
385 [self.syncDaemon startDaemon];
389 [accountNode refreshInfo];
390 [sharingAccountsNode reset];
392 [[NSNotificationCenter defaultCenter] postNotificationName:@"PithosAccountPithosChanged" object:self];
398 - (void)updateWithAuthURLString:(NSString *)anAuthURLString
399 pithosObjectStoreURLString:(NSString *)aPithosObjectStoreURLString
400 astakosAccountURLString:(NSString *)anAstakosAccountURLString
401 astakosWebloginURLString:(NSString *)anAstakosWebloginURLString
403 authToken:(NSString *)anAuthToken
404 authUser:(NSString *)anAuthUser
405 ignoreSSLErrors:(BOOL)anIgnoreSSLErrors {
406 [self updateWithAuthURLString:anAuthURLString
407 pithosObjectStoreURLString:aPithosObjectStoreURLString
408 astakosAccountURLString:anAstakosAccountURLString
409 astakosWebloginURLString:anAstakosWebloginURLString
411 authToken:anAuthToken
413 ignoreSSLErrors:anIgnoreSSLErrors
417 - (void)updateSyncWithSyncActive:(BOOL)aSyncActive
418 syncDirectoryPath:(NSString *)aSyncDirectoryPath
419 syncAccountsDictionary:(NSMutableDictionary *)aSyncAccountsDictionary
420 syncSkipHidden:(BOOL)aSyncSkipHidden {
421 self.syncAccountsDictionary = aSyncAccountsDictionary;
422 self.syncDirectoryPath = aSyncDirectoryPath;
423 self.syncSkipHidden = aSyncSkipHidden;
424 self.syncActive = aSyncActive;
426 self.syncDaemon.accountsDictionary = self.syncAccountsDictionary;
427 self.syncDaemon.directoryPath = self.syncDirectoryPath;
428 self.syncDaemon.skipHidden = self.syncSkipHidden;
430 [self.syncDaemon startDaemon];
434 - (NSMutableDictionary *)servicesFromServiceCatalogRequest:(ASIPithosRequest *)serviceCatalogRequest {
435 NSMutableDictionary *services = [NSMutableDictionary dictionary];
436 if (serviceCatalogRequest.responseStatusCode == 200) {
437 BOOL pithosObjectStoreFound = NO;
438 BOOL astakosAccountFound = NO;
439 BOOL astakosWebloginFound = NO;
440 NSArray *serviceCatalog = [serviceCatalogRequest serviceCatalog];
441 for (NSDictionary *service in serviceCatalog) {
442 NSString *serviceName = [service objectForKey:@"name"];
443 if (!pithosObjectStoreFound && [serviceName isEqualToString:@"pithos_object-store"]) {
444 [services setObject:[[[service objectForKey:@"endpoints"] objectAtIndex:0] objectForKey:@"publicURL"]
445 forKey:@"PithosObjectStoreURLString"];
446 pithosObjectStoreFound = YES;
447 } else if (!astakosAccountFound && [serviceName isEqualToString:@"astakos_account"]) {
448 [services setObject:[[[service objectForKey:@"endpoints"] objectAtIndex:0] objectForKey:@"publicURL"]
449 forKey:@"AstakosAccountURLString"];
450 astakosAccountFound = YES;
451 } else if (!astakosWebloginFound && [serviceName isEqualToString:@"astakos_weblogin"]) {
452 [services setObject:[[[service objectForKey:@"endpoints"] objectAtIndex:0] objectForKey:@"SNF:webloginURL"]
453 forKey:@"AstakosWebloginURLString"];
454 astakosWebloginFound = YES;
456 if (pithosObjectStoreFound && astakosAccountFound && astakosWebloginFound)
463 - (void)updateServicesFromServiceCatalogRequest:(ASIPithosRequest *)serviceCatalogRequest {
464 if (serviceCatalogRequest.responseStatusCode == 200) {
465 NSMutableDictionary *services = [self servicesFromServiceCatalogRequest:serviceCatalogRequest];
466 NSString *newAuthToken = nil;
467 NSString *newAuthUser = nil;
468 if (authToken.length) {
469 NSDictionary *token = [serviceCatalogRequest token];
470 newAuthToken = [token objectForKey:@"id"];
471 newAuthUser = [[token objectForKey:@"tenant"] objectForKey:@"id"];
473 [self updateWithAuthURLString:authURLString
474 pithosObjectStoreURLString:[services objectForKey:@"PithosObjectStoreURLString"]
475 astakosAccountURLString:[services objectForKey:@"AstakosAccountURLString"]
476 astakosWebloginURLString:[services objectForKey:@"AstakosWebloginURLString"]
478 authToken:(newAuthToken ? newAuthToken : authToken)
479 authUser:(newAuthUser ? newAuthUser : authUser)
480 ignoreSSLErrors:ignoreSSLErrors
482 } else if (serviceCatalogRequest.responseStatusCode == 404) {
483 [self updateWithAuthURLString:authURLString
484 pithosObjectStoreURLString:[[[NSURL URLWithString:authURLString] URLByAppendingPathComponent:@"v1"] description]
485 astakosAccountURLString:[authURLString copy]
486 astakosWebloginURLString:[authURLString copy]
490 ignoreSSLErrors:ignoreSSLErrors
495 - (ASIPithosRequest *)updateUserCatalogForDisplaynames:(NSArray *)displaynames UUIDs:(NSArray *)UUIDs {
496 ASIPithosRequest *userCatalogRequest = [ASIPithosRequest userCatalogRequestWithPithos:self.pithos
497 displaynames:displaynames
499 [PithosUtilities startAndWaitForRequest:userCatalogRequest];
500 if (userCatalogRequest.error || ((userCatalogRequest.responseStatusCode != 200) && (userCatalogRequest.responseStatusCode != 404))) {
501 // Don't show alert on 404, since it can be a pre-UUID server.
502 [PithosUtilities httpRequestErrorAlertWithRequest:userCatalogRequest];
503 } else if (userCatalogRequest.responseStatusCode == 200) {
504 NSDictionary *catalogs = [userCatalogRequest catalogs];
505 NSDictionary *displaynameCatalog = [catalogs objectForKey:@"displayname_catalog"];
506 for (NSString *displayname in displaynameCatalog) {
507 [self.userCatalog setObject:displayname forKey:[displaynameCatalog objectForKey:displayname]];
510 NSDictionary *UUIDCatalog = [catalogs objectForKey:@"uuid_catalog"];
511 for (NSString *UUID in UUIDs) {
512 NSString *displayname = [UUIDCatalog objectForKey:UUID];
514 [self.userCatalog setObject:displayname forKey:UUID];
516 [self.userCatalog removeObjectForKey:UUID];
521 return userCatalogRequest;
524 - (NSString *)displaynameForUUID:(NSString *)UUID safe:(BOOL)safe {
525 NSString *displayName = [userCatalog objectForKey:UUID];
526 if (safe && !displayName) {
533 - (NSString *)displaynameForUUID:(NSString *)UUID {
534 return [self displaynameForUUID:UUID safe:NO];
538 #pragma mark NSCoding
540 - (id)initWithCoder:(NSCoder *)decoder {
541 if ((self = [super init])) {
542 self.uniqueName = [decoder decodeObjectForKey:@"uniqueName"];
543 self.active = [decoder decodeBoolForKey:@"active"];
544 name = [decoder decodeObjectForKey:@"name"];
545 self.clientVersion = [decoder decodeObjectForKey:@"clientVersion"];
547 self.syncActive = [decoder decodeBoolForKey:@"syncActive"];
548 self.syncDirectoryPath = [decoder decodeObjectForKey:@"syncDirectoryPath"];
549 self.syncAccountsDictionary = [decoder decodeObjectForKey:@"syncAccountsDictionary"];
550 self.syncSkipHidden = [decoder decodeBoolForKey:@"syncSkipHidden"];
551 self.syncLastCompleted = [decoder decodeObjectForKey:@"syncLastCompleted"];
553 self.authURLString = [decoder decodeObjectForKey:@"authURLString"];
554 self.pithosObjectStoreURLString = [decoder decodeObjectForKey:@"pithosObjectStoreURLString"];
555 self.astakosAccountURLString = [decoder decodeObjectForKey:@"astakosAccountURLString"];
556 self.astakosWebloginURLString = [decoder decodeObjectForKey:@"astakosWebloginURLString"];
557 self.manual = [decoder decodeBoolForKey:@"manual"];
559 self.ignoreSSLErrors = [decoder decodeBoolForKey:@"ignoreSSLErrors"];
561 // Support for older versions.
562 if (!authURLString && !pithosObjectStoreURLString && !astakosAccountURLString && !astakosWebloginURLString) {
563 NSString *tmpURLString = [decoder decodeObjectForKey:@"serverURL"];
565 [[[NSURL URLWithString:tmpURLString] URLByAppendingPathComponent:@""] isEqual:[[NSURL URLWithString:defaultManualURLString] URLByAppendingPathComponent:@""]]) {
566 self.authURLString = defaultAuthURLString;
569 self.pithosObjectStoreURLString = [tmpURLString stringByAppendingString:@"/v1"];
570 self.astakosAccountURLString = tmpURLString;
571 self.astakosWebloginURLString = tmpURLString;
576 self.authToken = [decoder decodeObjectForKey:@"authToken"];
577 self.authUser = [decoder decodeObjectForKey:@"authUser"];
578 self.userCatalog = [decoder decodeObjectForKey:@"userCatalog"];
580 if (![authUser length] || ![authToken length])
583 NSString *currentVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
584 if (!clientVersion || ![clientVersion isEqualToString:currentVersion]) {
585 resetSyncDaemonLocalState = YES;
586 self.clientVersion = currentVersion;
588 resetSyncDaemonLocalState = NO;
594 - (void)encodeWithCoder:(NSCoder *)encoder {
595 [encoder encodeObject:uniqueName forKey:@"uniqueName"];
596 [encoder encodeBool:active forKey:@"active"];
597 [encoder encodeObject:name forKey:@"name"];
598 [encoder encodeObject:clientVersion forKey:@"clientVersion"];
600 [encoder encodeBool:syncActive forKey:@"syncActive"];
601 [encoder encodeObject:syncDirectoryPath forKey:@"syncDirectoryPath"];
602 [encoder encodeObject:syncAccountsDictionary forKey:@"syncAccountsDictionary"];
603 [encoder encodeBool:syncSkipHidden forKey:@"syncSkipHidden"];
604 [encoder encodeObject:self.syncLastCompleted forKey:@"syncLastCompleted"];
606 [encoder encodeObject:authURLString forKey:@"authURLString"];
607 [encoder encodeObject:pithosObjectStoreURLString forKey:@"pithosObjectStoreURLString"];
608 [encoder encodeObject:astakosAccountURLString forKey:@"astakosAccountURLString"];
609 [encoder encodeObject:astakosWebloginURLString forKey:@"astakosWebloginURLString"];
610 [encoder encodeBool:manual forKey:@"manual"];
612 [encoder encodeObject:authToken forKey:@"authToken"];
613 [encoder encodeObject:authUser forKey:@"authUser"];
614 [encoder encodeObject:userCatalog forKey:@"userCatalog"];
616 [encoder encodeBool:ignoreSSLErrors forKey:@"ignoreSSLErrors"];