Statistics
| Branch: | Tag: | Revision:

root / pithos-macos / PithosAccount.m @ baaf1397

History | View | Annotate | Download (24.3 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 "ASIPithosRequest.h"
42
#import "PithosAccountNode.h"
43
#import "PithosSharingAccountsNode.h"
44
#import "PithosUtilities.h"
45
#import "pithos_macosAppDelegate.h"
46

    
47
static NSString *defaultAuthURLString = @"https://accounts.okeanos.grnet.gr/identity/v2.0";
48
static NSString *defaultManualURLString = @"https://pithos.okeanos.grnet.gr";
49

    
50
@interface NSString(Additions)
51
- (BOOL)isValidURL;
52
- (NSString *)stringByRemovingTrailingSlashes;
53
@end
54

    
55
@implementation NSString(Additions)
56
- (BOOL)isValidURL {
57
    NSURL *URL = [NSURL URLWithString:self];
58
    return (URL && URL.scheme && URL.host);
59
}
60

    
61
- (NSString *)stringByRemovingTrailingSlashes {
62
    NSString *stringWithRemovedTrailingSlashes = [self copy];
63
    while ([stringWithRemovedTrailingSlashes hasSuffix:@"/"]) {
64
        stringWithRemovedTrailingSlashes = [stringWithRemovedTrailingSlashes substringToIndex:(stringWithRemovedTrailingSlashes.length - 1)];
65
    }
66
    return stringWithRemovedTrailingSlashes;
67
}
68
@end
69

    
70
@implementation PithosAccount
71
@synthesize uniqueName, active, name, clientVersion;
72
@synthesize syncActive, syncDirectoryPath, syncAccountsDictionary, syncSkipHidden, syncLastCompleted, syncDaemon;
73
@synthesize authURLString, pithosObjectStoreURLString, astakosAccountURLString, astakosWebloginURLString, manual;
74
@synthesize authToken, authUser, userCatalog;
75
@synthesize ignoreSSLErrors;
76
@synthesize pithos, accountNode, sharingAccountsNode;
77
@synthesize tokensURL, storageURLPrefix, loginURL, userCatalogURL, publicURLPrefix;
78

    
79
#pragma mark -
80
#pragma mark Object Lifecycle
81

    
82
+ (id)pithosAccount {
83
    PithosAccount *pithosAccount = [[self alloc] init];
84
    pithosAccount.uniqueName = [NSString stringWithFormat:@"pithosAccount-%f", [NSDate timeIntervalSinceReferenceDate]];
85
    pithosAccount.clientVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
86
    pithosAccount.syncSkipHidden = YES;
87
    pithosAccount.authURLString = defaultAuthURLString;
88
    return pithosAccount;
89
}
90

    
91
- (NSString *)description {
92
    return [NSString stringWithFormat:@"uniqueName: %@, active: %d, name: %@, clientVersion: %@, syncActive: %d, syncDirectoryPath: %@, syncAccountsDictionary: %@, syncSkipHidden: %d, syncLastCompleted: %@, authURLString: %@, pithosObjectStoreURLString:%@ , astakosAccountURLString: %@, astakosWebloginURLString: %@, manual: %d, authToken: %@, authUser: %@",
93
            uniqueName, active, name, clientVersion, syncActive, syncDirectoryPath, syncAccountsDictionary, syncSkipHidden, syncLastCompleted, authURLString, pithosObjectStoreURLString, astakosAccountURLString, astakosWebloginURLString, manual, authToken, authUser];
94
}
95

    
96
#pragma mark -
97
#pragma mark Properties
98

    
99
- (NSString *)name {
100
    if (![name length]) {
101
        NSDictionary *pithosAccountsDictionary = [(pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate] pithosAccountsDictionary];
102
        NSString *namePrefix = @"okeanos";
103
        NSUInteger nameSuffix = 1;
104
        name = @"okeanos";
105
        NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
106
        NSFileManager *fileManager = [NSFileManager defaultManager];
107
        while ([pithosAccountsDictionary objectForKey:name] || 
108
               [fileManager fileExistsAtPath:[documentsDirectoryPath stringByAppendingPathComponent:name]]) {
109
            name = [NSString stringWithFormat:@"%@%ld", namePrefix, ++nameSuffix];
110
        }
111
    }
112
    return name;
113
}
114

    
115
- (void)setName:(NSString *)aName {
116
    NSMutableDictionary *pithosAccountsDictionary = [(pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate] pithosAccountsDictionary];
117
    if (![self.name isEqualToString:aName] && [aName length] && ![pithosAccountsDictionary objectForKey:aName]) {
118
        [pithosAccountsDictionary setObject:self forKey:aName];
119
        [pithosAccountsDictionary removeObjectForKey:name];
120
        name = aName;
121
    }
122
}
123

    
124
- (BOOL)syncActive {
125
    if (active)
126
        return syncActive;
127
    else
128
        return NO;
129
}
130

    
131
- (void)setSyncActive:(BOOL)aSyncActive {
132
    syncActive = aSyncActive;
133
    if (syncDaemon && !self.syncActive)
134
        [syncDaemon resetDaemon];
135
}
136

    
137
- (NSString *)syncDirectoryPath {
138
    if (![syncDirectoryPath length]) {
139
        syncDirectoryPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] 
140
                              stringByAppendingPathComponent:self.name];
141
    }
142
    return syncDirectoryPath;
143
}
144

    
145
- (void)setSyncDirectoryPath:(NSString *)aSyncDirectoryPath {
146
    if (![self.syncDirectoryPath isEqualToString:aSyncDirectoryPath] && [aSyncDirectoryPath length]) {
147
        BOOL isDirectory;
148
        if (![[NSFileManager defaultManager] fileExistsAtPath:aSyncDirectoryPath isDirectory:&isDirectory] || isDirectory) {
149
            syncDirectoryPath = aSyncDirectoryPath;
150
        } else {
151
            return;
152
        }
153

    
154
        @synchronized(self) {
155
            resetSyncDaemonLocalState = YES;
156
            syncLastCompleted = nil;
157
        }
158
    }
159
}
160

    
161
- (NSMutableDictionary *)syncAccountsDictionary {
162
    if (!syncAccountsDictionary) {
163
        syncAccountsDictionary = [NSMutableDictionary dictionaryWithObject:[NSMutableDictionary dictionaryWithObject:[NSMutableSet set] 
164
                                                                                                              forKey:@"pithos"]
165
                                                                    forKey:@""];
166
    }        
167
    return syncAccountsDictionary;
168
}
169

    
170
- (void)setSyncAccountsDictionary:(NSMutableDictionary *)aSyncAccountsDictionary {
171
    if (aSyncAccountsDictionary && ![self.syncAccountsDictionary isEqualToDictionary:aSyncAccountsDictionary]) {
172
        syncAccountsDictionary = [[NSMutableDictionary alloc] initWithCapacity:[aSyncAccountsDictionary count]];
173
        for (NSString *accountName in aSyncAccountsDictionary) {
174
            NSDictionary *aSyncContainersDictionary = [aSyncAccountsDictionary objectForKey:accountName];
175
            NSMutableDictionary *syncContainersDictionary = [NSMutableDictionary dictionary];
176
            for (NSString *containerName in aSyncContainersDictionary) {
177
                if (![accountName isEqualToString:@""] || ![[containerName lowercaseString] isEqualToString:@"shared with me"])
178
                    [syncContainersDictionary setObject:[NSMutableSet setWithSet:[aSyncContainersDictionary objectForKey:containerName]] 
179
                                                 forKey:containerName];
180
            }
181
            if ([syncContainersDictionary count])
182
                [syncAccountsDictionary setObject:syncContainersDictionary forKey:accountName];
183
        }
184
        
185
        @synchronized(self) {
186
            resetSyncDaemonLocalState = YES;
187
            syncLastCompleted = nil;
188
        }
189
    }
190
}
191

    
192
- (NSDate *)syncLastCompleted {
193
    if (self.syncDaemon.lastCompletedSync && ![self.syncDaemon.lastCompletedSync isEqualToDate:syncLastCompleted]) {
194
        syncLastCompleted = [self.syncDaemon.lastCompletedSync copy];
195
    }
196
    return syncLastCompleted;
197
}
198

    
199
- (PithosSyncDaemon *)syncDaemon {
200
    @synchronized(self) {
201
        if (self.syncActive && !syncDaemon)
202
            syncDaemon = [[PithosSyncDaemon alloc] initWithDirectoryPath:self.syncDirectoryPath 
203
                                                           pithosAccount:self 
204
                                                      accountsDictionary:self.syncAccountsDictionary 
205
                                                              skipHidden:self.syncSkipHidden 
206
                                                         resetLocalState:resetSyncDaemonLocalState];
207
        resetSyncDaemonLocalState = NO;
208
    }
209
    return syncDaemon;
210
}
211

    
212
- (void)setAuthURLString:(NSString *)anAuthURLString {
213
    NSString *tmpURLString = [anAuthURLString stringByRemovingTrailingSlashes];
214
    if (![authURLString isEqualToString:tmpURLString]) {
215
        authURLString = tmpURLString;
216

    
217
        @synchronized(self) {
218
            updatePithos = YES;
219
            resetSyncDaemonLocalState = YES;
220
            syncLastCompleted = nil;
221
        }
222
    }
223
}
224

    
225
- (void)setPithosObjectStoreURLString:(NSString *)aPithosObjectStoreURLString {
226
    NSString *tmpURLString = [aPithosObjectStoreURLString stringByRemovingTrailingSlashes];
227
    if (![pithosObjectStoreURLString isEqualToString:tmpURLString]) {
228
        pithosObjectStoreURLString = tmpURLString;
229

    
230
        @synchronized(self) {
231
            updatePithos = YES;
232
        }
233
    }
234
}
235

    
236
- (void)setAstakosAccountURLString:(NSString *)anAstakosAccountURLString {
237
    NSString *tmpURLString = [anAstakosAccountURLString stringByRemovingTrailingSlashes];
238
    if (![astakosAccountURLString isEqualToString:tmpURLString]) {
239
        astakosAccountURLString = tmpURLString;
240
        
241
        @synchronized(self) {
242
            updatePithos = YES;
243
        }
244
    }
245
}
246

    
247
- (void)setAstakosWebloginURLString:(NSString *)anAstakosWebloginURLString {
248
    NSString *tmpURLString = [anAstakosWebloginURLString stringByRemovingTrailingSlashes];
249
    if (![astakosWebloginURLString isEqualToString:tmpURLString]) {
250
        astakosWebloginURLString = tmpURLString;
251
    }
252
}
253

    
254
- (void)setAuthToken:(NSString *)anAuthToken {
255
    if (anAuthToken.length && ![anAuthToken isEqualToString:authToken]) {
256
        authToken = anAuthToken;
257
        
258
        @synchronized(self) {
259
            updatePithos = YES;
260
        }
261
    }
262
}
263

    
264
- (void)setAuthUser:(NSString *)anAuthUser {
265
    if (anAuthUser.length && ![anAuthUser isEqualToString:authUser]) {
266
        authUser = anAuthUser;
267
        
268
        @synchronized(self) {
269
            updatePithos = YES;
270
            resetSyncDaemonLocalState = YES;
271
            syncLastCompleted = nil;
272

    
273
        }
274
    }
275
}
276

    
277
- (void)setIgnoreSSLErrors:(BOOL)anIgnoreSSLErrors {
278
    if (anIgnoreSSLErrors != ignoreSSLErrors) {
279
        ignoreSSLErrors = anIgnoreSSLErrors;
280
        
281
        @synchronized(self) {
282
            updatePithos = YES;
283
        }
284
    }
285
}
286

    
287
- (NSMutableDictionary *)userCatalog {
288
    if (!userCatalog) {
289
        userCatalog = [NSMutableDictionary dictionary];
290
    }
291
    return userCatalog;
292
}
293

    
294
- (ASIPithos *)pithos {
295
    @synchronized(self) {
296
        if (!pithos || updatePithos) {
297
            pithos = [ASIPithos pithos];
298
            pithos.authToken = authToken;
299
            pithos.authUser = authUser;
300
            
301
            pithos.ignoreSSLErrors = ignoreSSLErrors;
302
            
303
            pithos.tokensURL = self.tokensURL;
304
            pithos.storageURLPrefix = self.storageURLPrefix;
305
            pithos.userCatalogURL = self.userCatalogURL;
306
            pithos.publicURLPrefix = self.publicURLPrefix;
307
            updatePithos = NO;
308
        }
309
    }
310
    return pithos;
311
}
312

    
313
- (PithosAccountNode *)accountNode {
314
    if (!accountNode) {
315
        accountNode = [[PithosAccountNode alloc] initWithPithosAccountManager:self andPithos:self.pithos];
316
        accountNode.childrenUpdatedNotificationName = nil;
317
        accountNode.inheritChildrenUpdatedNotificationName = YES;
318
    }
319
    return accountNode;
320
}
321

    
322
- (PithosSharingAccountsNode *)sharingAccountsNode {
323
    if (!sharingAccountsNode) {
324
        sharingAccountsNode = [[PithosSharingAccountsNode alloc] initWithPithosAccountManager:self andPithos:self.pithos];
325
        sharingAccountsNode.childrenUpdatedNotificationName = nil;
326
        sharingAccountsNode.inheritChildrenUpdatedNotificationName = YES;
327
    }
328
    return sharingAccountsNode;
329
}
330

    
331
- (NSString *)tokensURL {
332
    return [authURLString stringByAppendingString:@"/tokens"];
333
}
334

    
335
- (NSString *)storageURLPrefix {
336
    return [pithosObjectStoreURLString copy];
337
}
338

    
339
- (NSString *)loginURL {
340
    return [astakosWebloginURLString stringByAppendingString:@"/login"];
341
}
342

    
343
- (NSString *)publicURLPrefix {
344
    return [pithosObjectStoreURLString copy];
345
}
346

    
347
- (NSString *)userCatalogURL {
348
    return [astakosAccountURLString stringByAppendingString:@"/user_catalogs"];
349
}
350

    
351
#pragma mark -
352
#pragma mark Actions
353

    
354
- (void)updateWithAuthURLString:(NSString *)anAuthURLString
355
     pithosObjectStoreURLString:(NSString *)aPithosObjectStoreURLString
356
        astakosAccountURLString:(NSString *)anAstakosAccountURLString
357
       astakosWebloginURLString:(NSString *)anAstakosWebloginURLString
358
                         manual:(BOOL)aManual
359
                      authToken:(NSString *)anAuthToken
360
                      authUser:(NSString *)anAuthUser
361
                ignoreSSLErrors:(BOOL)anIgnoreSSLErrors {
362
    self.authURLString = anAuthURLString;
363
    self.pithosObjectStoreURLString = aPithosObjectStoreURLString;
364
    self.astakosAccountURLString = anAstakosAccountURLString;
365
    self.astakosWebloginURLString = anAstakosWebloginURLString;
366
    self.manual = aManual;
367
    self.authToken = anAuthToken;
368
    self.authUser = anAuthUser;
369
    self.ignoreSSLErrors = anIgnoreSSLErrors;
370
    DLog(@"Account updated: %@", self);
371
    if (!authToken.length || !authUser.length) {
372
        self.active = NO;
373
        self.syncActive = NO;
374
    } else  {
375
        [self updateUserCatalogForDisplaynames:nil UUIDs:[NSArray arrayWithObject:authUser]];
376

    
377
        self.active = YES;
378
        if (syncDaemon) {
379
            self.syncDaemon.pithos = self.pithos;
380
            if (self.syncActive)
381
                [self.syncDaemon startDaemon];
382
        }
383
        if (accountNode)
384
            self.accountNode.pithos = self.pithos;
385
        if (sharingAccountsNode)
386
            self.sharingAccountsNode.pithos = self.pithos;
387
        if (accountNode) {
388
            if (self.accountNode.children) {
389
            }
390
            [self.accountNode refreshInfo];
391
        }
392
        if (sharingAccountsNode && self.sharingAccountsNode.children) {
393
        }
394
    }
395
}
396

    
397
- (void)updateSyncWithSyncActive:(BOOL)aSyncActive 
398
               syncDirectoryPath:(NSString *)aSyncDirectoryPath 
399
          syncAccountsDictionary:(NSMutableDictionary *)aSyncAccountsDictionary 
400
                  syncSkipHidden:(BOOL)aSyncSkipHidden {
401
    self.syncAccountsDictionary = aSyncAccountsDictionary;
402
    self.syncDirectoryPath = aSyncDirectoryPath;
403
    self.syncSkipHidden = aSyncSkipHidden;
404
    self.syncActive = aSyncActive;
405
    if (syncDaemon) {
406
        self.syncDaemon.accountsDictionary = self.syncAccountsDictionary;
407
        self.syncDaemon.directoryPath = self.syncDirectoryPath;
408
        self.syncDaemon.skipHidden = self.syncSkipHidden;
409
        if (self.syncActive)
410
            [self.syncDaemon startDaemon];
411
    }    
412
}
413

    
414
- (NSMutableDictionary *)servicesFromServiceCatalogRequest:(ASIPithosRequest *)serviceCatalogRequest {
415
    NSMutableDictionary *services = [NSMutableDictionary dictionary];
416
    if (serviceCatalogRequest.responseStatusCode == 200) {
417
        BOOL pithosObjectStoreFound = NO;
418
        BOOL astakosAccountFound = NO;
419
        BOOL astakosWebloginFound = NO;
420
        NSArray *serviceCatalog = [serviceCatalogRequest serviceCatalog];
421
        for (NSDictionary *service in serviceCatalog) {
422
            NSString *serviceName = [service objectForKey:@"name"];
423
            if (!pithosObjectStoreFound && [serviceName isEqualToString:@"pithos_object-store"]) {
424
                [services setObject:[[[service objectForKey:@"endpoints"] objectAtIndex:0] objectForKey:@"publicURL"]
425
                             forKey:@"PithosObjectStoreURLString"];
426
                pithosObjectStoreFound = YES;
427
            } else if (!astakosAccountFound && [serviceName isEqualToString:@"astakos_account"]) {
428
                [services setObject:[[[service objectForKey:@"endpoints"] objectAtIndex:0] objectForKey:@"publicURL"]
429
                             forKey:@"AstakosAccountURLString"];
430
                astakosAccountFound = YES;
431
            } else if (!astakosWebloginFound && [serviceName isEqualToString:@"astakos_weblogin"]) {
432
                [services setObject:[[[service objectForKey:@"endpoints"] objectAtIndex:0] objectForKey:@"SNF:webloginURL"]
433
                             forKey:@"AstakosWebloginURLString"];
434
                astakosWebloginFound = YES;
435
            }
436
            if (pithosObjectStoreFound && astakosAccountFound && astakosWebloginFound)
437
                break;
438
        }
439
    }
440
    return services;
441
}
442

    
443
- (void)updateServicesFromServiceCatalogRequest:(ASIPithosRequest *)serviceCatalogRequest {
444
    if (serviceCatalogRequest.responseStatusCode == 200) {
445
        NSMutableDictionary *services = [self servicesFromServiceCatalogRequest:serviceCatalogRequest];
446
        self.pithosObjectStoreURLString = [services objectForKey:@"PithosObjectStoreURLString"];
447
        self.astakosAccountURLString = [services objectForKey:@"AstakosAccountURLString"];
448
        self.astakosWebloginURLString = [services objectForKey:@"AstakosWebloginURLString"];
449
        self.manual = NO;
450
        
451
        if (authToken.length) {
452
            NSDictionary *token = [serviceCatalogRequest token];
453
            self.authToken = [token objectForKey:@"id"];
454
            self.authUser = [[token objectForKey:@"tenant"] objectForKey:@"id"];
455
        }
456
    } else if (serviceCatalogRequest.responseStatusCode == 404) {
457
        self.pithosObjectStoreURLString = [[[NSURL URLWithString:authURLString] URLByAppendingPathComponent:@"v1"] description];
458
        self.astakosAccountURLString = [self.authURLString copy];
459
        self.astakosWebloginURLString = [self.authURLString copy];
460
        self.manual = YES;
461
    }
462
}
463

    
464
- (ASIPithosRequest *)updateUserCatalogForDisplaynames:(NSArray *)displaynames UUIDs:(NSArray *)UUIDs {
465
    ASIPithosRequest *userCatalogRequest = [ASIPithosRequest userCatalogRequestWithPithos:self.pithos
466
                                                                             displaynames:displaynames
467
                                                                                    UUIDs:UUIDs];
468
    [PithosUtilities startAndWaitForRequest:userCatalogRequest];
469
    if (userCatalogRequest.error || ((userCatalogRequest.responseStatusCode != 200) && (userCatalogRequest.responseStatusCode != 404))) {
470
        // Don't show alert on 404, since it can be a pre-UUID server.
471
        [PithosUtilities httpRequestErrorAlertWithRequest:userCatalogRequest];
472
    } else if (userCatalogRequest.responseStatusCode == 200) {
473
        NSDictionary *catalogs = [userCatalogRequest catalogs];
474
        NSDictionary *displaynameCatalog = [catalogs objectForKey:@"displayname_catalog"];
475
        for (NSString *displayname in displaynameCatalog) {
476
            [self.userCatalog setObject:displayname forKey:[displaynameCatalog objectForKey:displayname]];
477
        }
478
        if (UUIDs) {
479
            NSDictionary *UUIDCatalog = [catalogs objectForKey:@"uuid_catalog"];
480
            for (NSString *UUID in UUIDs) {
481
                NSString *displayname = [UUIDCatalog objectForKey:UUID];
482
                if (displayname) {
483
                    [self.userCatalog setObject:displayname forKey:UUID];
484
                } else {
485
                    [self.userCatalog removeObjectForKey:UUID];
486
                }
487
            }
488
        }
489
    }
490
    return userCatalogRequest;
491
}
492

    
493
- (NSString *)displaynameForUUID:(NSString *)UUID safe:(BOOL)safe {
494
    NSString *displayName = [userCatalog objectForKey:UUID];
495
    if (safe && !displayName) {
496
        return UUID;
497
    } else {
498
        return displayName;
499
    }
500
}
501

    
502
- (NSString *)displaynameForUUID:(NSString *)UUID {
503
    return [self displaynameForUUID:UUID safe:NO];
504
}
505

    
506
#pragma mark -
507
#pragma mark NSCoding
508

    
509
- (id)initWithCoder:(NSCoder *)decoder {
510
    if ((self = [super init])) {
511
        self.uniqueName = [decoder decodeObjectForKey:@"uniqueName"];
512
        self.active = [decoder decodeBoolForKey:@"active"];
513
        name = [decoder decodeObjectForKey:@"name"];
514
        self.clientVersion = [decoder decodeObjectForKey:@"clientVersion"];
515

    
516
        self.syncActive = [decoder decodeBoolForKey:@"syncActive"];
517
        self.syncDirectoryPath = [decoder decodeObjectForKey:@"syncDirectoryPath"];
518
        self.syncAccountsDictionary = [decoder decodeObjectForKey:@"syncAccountsDictionary"];
519
        self.syncSkipHidden = [decoder decodeBoolForKey:@"syncSkipHidden"];
520
        self.syncLastCompleted = [decoder decodeObjectForKey:@"syncLastCompleted"];
521
        
522
        self.authURLString = [decoder decodeObjectForKey:@"authURLString"];
523
        self.pithosObjectStoreURLString = [decoder decodeObjectForKey:@"pithosObjectStoreURLString"];
524
        self.astakosAccountURLString = [decoder decodeObjectForKey:@"astakosAccountURLString"];
525
        self.astakosWebloginURLString = [decoder decodeObjectForKey:@"astakosWebloginURLString"];
526
        self.manual = [decoder decodeBoolForKey:@"manual"];
527
        
528
        // Support for older versions.
529
        if (!authURLString && !pithosObjectStoreURLString && !astakosAccountURLString && !astakosWebloginURLString) {
530
            NSString *tmpURLString = [decoder decodeObjectForKey:@"serverURL"];
531
            if (!tmpURLString ||
532
                [[[NSURL URLWithString:tmpURLString] URLByAppendingPathComponent:@""] isEqual:[[NSURL URLWithString:defaultManualURLString] URLByAppendingPathComponent:@""]]) {
533
                self.authURLString = defaultAuthURLString;
534
                self.manual = NO;
535
            } else {
536
                self.pithosObjectStoreURLString = [tmpURLString stringByAppendingString:@"/v1"];
537
                self.astakosAccountURLString = tmpURLString;
538
                self.astakosWebloginURLString = tmpURLString;
539
                self.manual = YES;
540
            }
541
        }
542
        
543
        self.authToken = [decoder decodeObjectForKey:@"authToken"];
544
        self.authUser = [decoder decodeObjectForKey:@"authUser"];
545
        self.userCatalog = [decoder decodeObjectForKey:@"userCatalog"];
546
        
547
        if (![authUser length] || ![authToken length])
548
            self.active = NO;
549
        
550
        NSString *currentVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
551
        if (!clientVersion || ![clientVersion isEqualToString:currentVersion]) {
552
            resetSyncDaemonLocalState = YES;
553
            self.clientVersion = currentVersion;
554
        } else {
555
            resetSyncDaemonLocalState = NO;
556
        }
557
    }
558
    return self;
559
}
560

    
561
- (void)encodeWithCoder:(NSCoder *)encoder {
562
    [encoder encodeObject:uniqueName forKey:@"uniqueName"];
563
    [encoder encodeBool:active forKey:@"active"];
564
    [encoder encodeObject:name forKey:@"name"];
565
    [encoder encodeObject:clientVersion forKey:@"clientVersion"];
566
    
567
    [encoder encodeBool:syncActive forKey:@"syncActive"];
568
    [encoder encodeObject:syncDirectoryPath forKey:@"syncDirectoryPath"];
569
    [encoder encodeObject:syncAccountsDictionary forKey:@"syncAccountsDictionary"];
570
    [encoder encodeBool:syncSkipHidden forKey:@"syncSkipHidden"];
571
    [encoder encodeObject:self.syncLastCompleted forKey:@"syncLastCompleted"];
572

    
573
    [encoder encodeObject:authURLString forKey:@"authURLString"];
574
    [encoder encodeObject:pithosObjectStoreURLString forKey:@"pithosObjectStoreURLString"];
575
    [encoder encodeObject:astakosAccountURLString forKey:@"astakosAccountURLString"];
576
    [encoder encodeObject:astakosWebloginURLString forKey:@"astakosWebloginURLString"];
577
    [encoder encodeBool:manual forKey:@"manual"];
578
    
579
    [encoder encodeObject:authToken forKey:@"authToken"];
580
    [encoder encodeObject:authUser forKey:@"authUser"];
581
    [encoder encodeObject:userCatalog forKey:@"userCatalog"];
582
}
583

    
584
@end