Statistics
| Branch: | Tag: | Revision:

root / pithos-macos / pithos_macosAppDelegate.m @ cb6abe72

History | View | Annotate | Download (26.2 kB)

1
//
2
//  pithos_macosAppDelegate.m
3
//  pithos-macos
4
//
5
// Copyright 2011-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 "pithos_macosAppDelegate.h"
39
#import "PithosAccount.h"
40
#import "PithosBrowserController.h"
41
#import "PithosPreferencesController.h"
42
#import "PithosSyncDaemon.h"
43
#import "ASIPithosRequest.h"
44
#import "ASIPithos.h"
45
#import "LastCompletedSyncTransformer.h"
46

    
47
@implementation pithos_macosAppDelegate
48
@synthesize pithosBrowserController, pithosPreferencesController, alwaysNo, openAtLoginEnabled, openAtLogin, activated, 
49
currentPithosAccount, pithosAccounts, pithosAccountsDictionary, syncPithosAccount, activityFacilityTimeInterval, checkForUpdatesNotRunning;
50

    
51
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
52
    [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self 
53
                                                       andSelector:@selector(handleAppleEvent:withReplyEvent:) 
54
                                                     forEventClass:kInternetEventClass 
55
                                                        andEventID:kAEGetURL];
56
    
57
    // Based on: https://github.com/Mozketo/LaunchAtLoginController
58
    // and: http://cocoatutorial.grapewave.com/2010/02/creating-andor-removing-a-login-item/
59
    loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
60
    if (loginItems) {
61
        LSSharedFileListAddObserver(loginItems, CFRunLoopGetMain(), (CFStringRef)NSDefaultRunLoopMode, LSSharedFileListChanged, (__bridge void *)(self));
62
        LSSharedFileListChanged(loginItems, (__bridge void *)(self));
63
        self.openAtLoginEnabled = YES;
64
    }
65
    
66
    userDefaults = [NSUserDefaults standardUserDefaults];
67
    
68
    syncTimeInterval = [userDefaults doubleForKey:@"syncTimeInterval"];
69
    if (syncTimeInterval <= 0.0) {
70
        syncTimeInterval = 180.0;
71
        [userDefaults setDouble:syncTimeInterval forKey:@"syncTimeInterval"];
72
        [userDefaults synchronize];
73
    }
74

    
75
    activityFacilityTimeInterval = [userDefaults doubleForKey:@"activityFacilityTimeInterval"];
76
    if (activityFacilityTimeInterval <= 0.0) {
77
        activityFacilityTimeInterval = 0.05;
78
        [userDefaults setDouble:activityFacilityTimeInterval forKey:@"activityFacilityTimeInterval"];
79
        [userDefaults synchronize];
80
    }
81

    
82
    NSData *tmpData = [userDefaults objectForKey:@"pithosAccounts"];
83
    NSArray *tmpArray;
84
    if (tmpData && (tmpArray = [NSKeyedUnarchiver unarchiveObjectWithData:tmpData]))
85
        self.pithosAccounts = [NSMutableArray arrayWithArray:tmpArray];
86
    else
87
        self.pithosAccounts = [NSMutableArray array];
88
    
89
    if (![pithosAccounts count]) {
90
        [pithosAccounts addObject:[PithosAccount pithosAccount]];
91
        self.pithosAccounts = self.pithosAccounts;
92
    } else {
93
        self.activated = YES;
94
    }
95
    
96
    pithosAccountsDictionary = [[NSMutableDictionary alloc] initWithCapacity:[pithosAccounts count]];
97
    for (PithosAccount *pithosAccount in pithosAccounts) {
98
        [pithosAccountsDictionary setObject:pithosAccount forKey:pithosAccount.name];
99
        if (!currentPithosAccount && pithosAccount.active)
100
            currentPithosAccount = pithosAccount;
101
    }
102
    if (!currentPithosAccount)
103
        self.currentPithosAccount = [pithosAccounts objectAtIndex:0];
104
    
105
    if (currentPithosAccount.active) {
106
        [self savePithosAccounts:self];
107
        [self showPithosBrowser:self];
108
        self.pithosBrowserController.pithos = currentPithosAccount.pithos;
109
    } else {
110
        // XXX maybe call specifically to go to new account tab
111
        [self showPithosPreferences:self];
112
    }
113

    
114
    syncTimer = [NSTimer scheduledTimerWithTimeInterval:syncTimeInterval 
115
                                                  target:self 
116
                                                selector:@selector(sync) 
117
                                                userInfo:nil 
118
                                                 repeats:YES];
119
    [syncTimer fire];
120
    
121
    @synchronized(self) {
122
        self.checkForUpdatesNotRunning = YES;
123
    }
124
    [self checkForUpdates];
125
}
126

    
127
// Based on: http://cocoatutorial.grapewave.com/2010/01/creating-a-status-bar-application/
128
// and: http://www.cocoadev.com/index.pl?ThumbnailImages
129
- (void)awakeFromNib {
130
    NSImage *sourceImage = [NSImage imageNamed:@"pithos-large.png"];
131
    
132
    NSImage *smallImage = [[NSImage alloc] initWithSize:NSMakeSize(18, 18)];
133
    [smallImage lockFocus];
134
    [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
135
    [sourceImage setSize:NSMakeSize(18, 18)];
136
    [sourceImage compositeToPoint:NSZeroPoint operation:NSCompositeCopy];
137
    [smallImage unlockFocus];
138
    
139
    statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
140
    [statusItem setMenu:statusMenu];
141
    [statusItem setImage:sourceImage];
142
    [statusItem setHighlightMode:YES];
143
    
144
    self.alwaysNo = NO;
145
}
146

    
147
- (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent {
148
    NSURL *url = [NSURL URLWithString:[[event paramDescriptorForKeyword:keyDirectObject] stringValue]];
149
    NSString *host = [url host];
150
	NSString *query = [url query];
151
    PithosAccount *pithosAccount = [pithosAccountsDictionary objectForKey:[url lastPathComponent]];
152
    NSProcessInfo *processInfo = [NSProcessInfo processInfo];
153
    if ([host isEqualToString:[NSString stringWithFormat:@"%d", [processInfo processIdentifier]]] && pithosAccount && query) {
154
        // user=
155
        NSString *authUser;
156
        NSRange userRange = [query rangeOfString:@"user=" options:NSCaseInsensitiveSearch];
157
        if (userRange.length == 0)
158
            // XXX maybe show an error message?
159
            return;
160
        NSUInteger authUserStartLocation = userRange.location + userRange.length;
161
        NSRange userEndRange = [query rangeOfString:@"&" options:NSCaseInsensitiveSearch 
162
                                              range:NSMakeRange(authUserStartLocation, [query length] - authUserStartLocation)];
163
        if (userEndRange.length) {
164
            authUser = [[query substringWithRange:NSMakeRange(authUserStartLocation, userEndRange.location - authUserStartLocation)]
165
                        stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
166
        } else {
167
            authUser = [[query substringFromIndex:authUserStartLocation]
168
                        stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
169
        }
170
        // token=
171
        NSString *authToken;
172
        NSRange tokenRange = [query rangeOfString:@"token=" options:NSCaseInsensitiveSearch];
173
        if (tokenRange.length == 0)
174
            // XXX maybe show an error message?
175
            return;
176
        NSUInteger authTokenStartLocation = tokenRange.location + tokenRange.length;
177
        NSRange tokenEndRange = [query rangeOfString:@"&" options:NSCaseInsensitiveSearch 
178
                                              range:NSMakeRange(authTokenStartLocation, [query length] - authTokenStartLocation)];
179
        if (tokenEndRange.length) {
180
            authToken = [[query substringWithRange:NSMakeRange(authTokenStartLocation, tokenEndRange.location - authTokenStartLocation)]
181
                         stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
182
        } else {
183
            authToken = [[query substringFromIndex:authTokenStartLocation]
184
                         stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
185
        }
186
        
187
        DLog(@"query authUser: '%@', authToken: '%@'", authUser, authToken);
188
        if ([authUser length] && [authToken length]) {
189
            [pithosAccount authenticateWithServerURL:nil authUser:authUser authToken:authToken];
190
            [self savePithosAccounts:self];
191
            if (self.pithosPreferencesController && [self.pithosPreferencesController.selectedPithosAccount isEqualTo:pithosAccount]) {
192
                self.pithosPreferencesController.authUser = pithosAccount.authUser;
193
                self.pithosPreferencesController.authToken = pithosAccount.authToken;
194
            }
195
            self.activated = YES;
196
            if ([pithosAccount isEqualTo:currentPithosAccount]) {
197
                [self showPithosBrowser:self];
198
                self.pithosBrowserController.pithos = pithosAccount.pithos;
199
            }
200
        }
201
        // XXX else maybe show an error message?
202
    }
203
    // XXX else maybe show an error message?
204
}
205

    
206
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
207
    [self savePithosAccounts:self];
208
    if ([self.pithosBrowserController operationsPending]) {
209
        NSAlert *alert = [[NSAlert alloc] init];
210
        [alert setMessageText:@"Pending Operations"];
211
        [alert setInformativeText:@"There are pending operations in the browser, do you want to quit and cancel them?"];
212
        [alert addButtonWithTitle:@"OK"];
213
        [alert addButtonWithTitle:@"Cancel"];
214
        NSInteger choice = [alert runModal];
215
        if (choice == NSAlertSecondButtonReturn) 
216
            return NSTerminateCancel;
217
    }
218
    if (loginItems) {
219
        LSSharedFileListRemoveObserver(loginItems, CFRunLoopGetMain(), (CFStringRef)NSDefaultRunLoopMode, LSSharedFileListChanged, (__bridge void *)(self));
220
        CFRelease(loginItems);
221
    }
222
    return NSTerminateNow;
223
}
224

    
225
#pragma mark -
226
#pragma mark Callbacks
227

    
228
- (void)loginItemsChanged {
229
    NSURL *appURL = [[NSBundle mainBundle] bundleURL];
230
    LSSharedFileListItemRef appItem = NULL;
231
    NSArray *snapshot = (__bridge_transfer NSArray *)(LSSharedFileListCopySnapshot(loginItems, NULL));
232
    for (id itemObject in snapshot) {
233
        LSSharedFileListItemRef item = (__bridge LSSharedFileListItemRef)itemObject;
234
        UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
235
        CFURLRef currentItemURL = NULL;
236
        LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, NULL);
237
        if (currentItemURL && CFEqual(currentItemURL, (__bridge CFTypeRef)(appURL))) {
238
            CFRelease(currentItemURL);
239
            appItem = item;
240
            break;
241
        }
242
        if (currentItemURL)
243
            CFRelease(currentItemURL);
244
    }
245
    
246
    if (appItem && (!openAtLogin || !openAtLoginEnabled))
247
        self.openAtLogin = YES;
248
    else if (!appItem && (openAtLogin || !openAtLoginEnabled))
249
        self.openAtLogin = NO;
250
}
251

    
252
void LSSharedFileListChanged(LSSharedFileListRef inList, void *context) {
253
    pithos_macosAppDelegate *self = (__bridge id)context;
254
    [self loginItemsChanged];
255
}
256

    
257
#pragma mark -
258
#pragma mark Properties
259

    
260
- (PithosBrowserController *)pithosBrowserController {
261
    if (!pithosBrowserController) {
262
        pithosBrowserController = [[PithosBrowserController alloc] init];
263
    }
264
    return pithosBrowserController;
265
}
266

    
267
- (PithosPreferencesController *)pithosPreferencesController {
268
    if (!pithosPreferencesController) {
269
        pithosPreferencesController = [[PithosPreferencesController alloc] init];
270
    }
271
    return pithosPreferencesController;
272
}
273

    
274
- (void)setOpenAtLogin:(BOOL)anOpenAtLogin {
275
    if (!openAtLoginEnabled) {
276
        openAtLogin = anOpenAtLogin;
277
    } else if (anOpenAtLogin != openAtLogin) {
278
        NSURL *appURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
279
        LSSharedFileListItemRef appItem = NULL;
280
        NSArray *snapshot = (__bridge_transfer NSArray *)(LSSharedFileListCopySnapshot(loginItems, NULL));
281
        for (id itemObject in snapshot) {
282
            LSSharedFileListItemRef item = (__bridge LSSharedFileListItemRef)itemObject;
283
            UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
284
            CFURLRef currentItemURL = NULL;
285
            LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, NULL);
286
            if (currentItemURL && CFEqual(currentItemURL, (__bridge CFTypeRef)(appURL))) {
287
                CFRelease(currentItemURL);
288
                appItem = item;
289
                break;
290
            }
291
            if (currentItemURL)
292
                CFRelease(currentItemURL);
293
        }
294
        
295
        if (anOpenAtLogin) {
296
            if (!appItem)
297
                LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, NULL, NULL, (__bridge CFURLRef)appURL, NULL, NULL);
298
            openAtLogin = YES;
299
        } else {
300
            if (appItem)
301
                LSSharedFileListItemRemove(loginItems, appItem);
302
            openAtLogin = NO;
303
        }
304
    }
305
}
306

    
307
#pragma mark -
308
#pragma mark NSMenuDelegate
309

    
310
- (void)menuNeedsUpdate:(NSMenu *)menu {
311
    NSMenuItem *menuItem;
312
    [menu removeAllItems];
313
    if ([menu isEqualTo:accountsMenu]) {
314
        [menu setAutoenablesItems:NO];
315
        for (PithosAccount *pithosAccount in pithosAccounts) {
316
            menuItem = [[NSMenuItem alloc] initWithTitle:pithosAccount.name 
317
                                                   action:@selector(menuChangePithosAccount:) 
318
                                            keyEquivalent:@""];
319
            [menuItem setRepresentedObject:pithosAccount];
320
            [menuItem setEnabled:pithosAccount.active];
321
            [menuItem setState:((pithosAccount.active && [currentPithosAccount isEqualTo:pithosAccount]) ? NSOnState : NSOffState)];
322
            [menu addItem:menuItem];
323
        }
324
    } else if ([menu isEqualTo:lastSyncMenu]) {
325
        NSString *menuItemTitle;
326
        [menu setAutoenablesItems:NO];
327
        for (PithosAccount *pithosAccount in pithosAccounts) {
328
            menuItemTitle = [NSString stringWithFormat:@"%@: %@", 
329
                             pithosAccount.name, 
330
                             [[[LastCompletedSyncTransformer alloc] init] transformedValue:pithosAccount.syncLastCompleted]];
331
            if ([pithosAccount isEqualTo:syncPithosAccount] && [pithosAccount.syncDaemon isSyncing])
332
                menuItemTitle = [menuItemTitle stringByAppendingString:@" (syncing)"];
333
//            menuItem = [[[NSMenuItem alloc] initWithTitle:menuItemTitle 
334
//                                                   action:@selector(menuChangeSyncActive:) 
335
//                                            keyEquivalent:@""] autorelease];
336
//            [menuItem setRepresentedObject:pithosAccount];
337
//            [menuItem setEnabled:pithosAccount.active];
338
//            [menuItem setState:((pithosAccount.active && pithosAccount.syncActive) ? NSOnState : NSOffState)];
339
            menuItem = [[NSMenuItem alloc] initWithTitle:menuItemTitle action:nil keyEquivalent:@""];
340
            [menuItem setEnabled:NO];
341
            [menuItem setState:NO];
342
            [menu addItem:menuItem];
343
        }
344
        [menu addItem:[NSMenuItem separatorItem]];
345
        [menu addItem:[[NSMenuItem alloc] initWithTitle:@"Next Sync" 
346
                                                  action:@selector(sync) 
347
                                           keyEquivalent:@""]];
348
    }
349
}
350

    
351
#pragma mark -
352
#pragma mark Actions
353

    
354
- (IBAction)showPithosBrowser:(id)sender {
355
    if (!activated)
356
        return;
357
    [self.pithosBrowserController showWindow:sender];
358
    [[self.pithosBrowserController window] makeKeyAndOrderFront:sender];
359
    [NSApp activateIgnoringOtherApps:YES];
360
}
361

    
362
- (IBAction)showPithosPreferences:(id)sender {
363
    [self.pithosPreferencesController showWindow:sender];
364
    [[self.pithosPreferencesController window] makeKeyAndOrderFront:sender];
365
    [NSApp activateIgnoringOtherApps:YES];
366
}
367

    
368
- (IBAction)showPithosAbout:(id)sender {
369
    [NSApp orderFrontStandardAboutPanel:sender];
370
    [NSApp activateIgnoringOtherApps:YES];
371
}
372

    
373
- (void)sync {
374
    if (!activated || ![pithosAccounts count])
375
        return;
376
    NSUInteger syncIndex;
377
    BOOL syncPithosAccountFound = [pithosAccounts containsObject:syncPithosAccount];
378
    if (syncPithosAccountFound)
379
         syncIndex = [pithosAccounts indexOfObject:syncPithosAccount];
380
    
381
    PithosAccount *singleSyncPithosAccount = nil;
382
    for (PithosAccount *pithosAccount in pithosAccounts) {
383
        if (!singleSyncPithosAccount && pithosAccount.active && pithosAccount.syncActive && pithosAccount.syncDaemon) {
384
            singleSyncPithosAccount = pithosAccount;
385
        } else if (singleSyncPithosAccount && pithosAccount.active && pithosAccount.syncActive && pithosAccount.syncDaemon) {
386
            singleSyncPithosAccount = nil;
387
            break;
388
        }
389
    }
390
    
391
    if (syncPithosAccount && syncPithosAccount.active && syncPithosAccount.syncActive && syncPithosAccount.syncDaemon) {
392
        // An active syncDaemon was previously syncing
393
        if (singleSyncPithosAccount && [singleSyncPithosAccount isEqualTo:syncPithosAccount]) {
394
            // It's the only one, sync again
395
            [syncPithosAccount.syncDaemon startDaemon];
396
            [syncPithosAccount.syncDaemon sync];
397
            return;
398
        } else if ([syncPithosAccount.syncDaemon isSyncing]) {
399
            // It's still syncing, mark it as late and return
400
            [syncPithosAccount.syncDaemon syncLate];
401
            return;
402
        }
403
    }
404
    PithosAccount *newSyncPithosAccount = nil;
405
    if (syncPithosAccountFound) {
406
        for (PithosAccount *pithosAccount in [pithosAccounts objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(syncIndex + 1, [pithosAccounts count] - syncIndex - 1)]]) {
407
            if (pithosAccount.active && pithosAccount.syncActive && pithosAccount.syncDaemon) {
408
                newSyncPithosAccount = pithosAccount;
409
                break;
410
            }
411
        }
412
        if (!newSyncPithosAccount) {
413
            for (PithosAccount *pithosAccount in [pithosAccounts objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, syncIndex)]]) {
414
                if (pithosAccount.active && pithosAccount.syncActive && pithosAccount.syncDaemon) {
415
                    newSyncPithosAccount = pithosAccount;
416
                    break;
417
                }
418
            }
419
        }
420
    } else {
421
        for (PithosAccount *pithosAccount in pithosAccounts) {
422
            if (pithosAccount.active && pithosAccount.syncActive && pithosAccount.syncDaemon) {
423
                newSyncPithosAccount = pithosAccount;
424
                break;
425
            }
426
        }
427
    }        
428
    if (newSyncPithosAccount) {
429
        // A different syncDaemon is found, sync it
430
        self.syncPithosAccount = newSyncPithosAccount;
431
        [syncPithosAccount.syncDaemon startDaemon];
432
        [syncPithosAccount.syncDaemon sync];
433
    } else if (syncPithosAccountFound && syncPithosAccount && syncPithosAccount.active && syncPithosAccount.syncActive && syncPithosAccount.syncDaemon) {
434
        [syncPithosAccount.syncDaemon startDaemon];
435
        [syncPithosAccount.syncDaemon sync];
436
    } else {
437
        self.syncPithosAccount = nil;
438
    }
439
}
440

    
441
- (void)savePithosAccounts:(id)sender {
442
    [userDefaults setObject:[NSKeyedArchiver archivedDataWithRootObject:pithosAccounts] forKey:@"pithosAccounts"];
443
    [userDefaults synchronize];
444
}
445

    
446
- (void)removedPithosAccount:(PithosAccount *)removedPithosAccount {
447
    if ([self.currentPithosAccount isEqualTo:removedPithosAccount]) {
448
        for (PithosAccount *pithosAccount in pithosAccounts) {
449
            if (pithosAccount.active) {
450
                self.currentPithosAccount = pithosAccount;
451
                self.pithosBrowserController.pithos = currentPithosAccount.pithos;
452
                break;
453
            }
454
        }
455
        if ([self.currentPithosAccount isEqualTo:removedPithosAccount]) {
456
            self.activated = NO;
457
            [self.pithosBrowserController.window close];
458
            [self.pithosBrowserController resetBrowser];
459
            self.currentPithosAccount = [pithosAccounts objectAtIndex:0];
460
        }
461
    }
462
    if ([self.syncPithosAccount isEqualTo:removedPithosAccount])
463
        self.syncPithosAccount = nil;
464
}
465

    
466
- (void)checkForUpdates {
467
    @synchronized(self) {
468
        if (!checkForUpdatesNotRunning)
469
            return;
470
        self.checkForUpdatesNotRunning = NO;
471
    }
472
    ASIHTTPRequest *checkForUpdatesRequest = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"https://code.grnet.gr/projects/pithos-macos/repository/revisions/master/raw/pithos-macos/pithos-macos-Info.plist"]];
473
    checkForUpdatesRequest.delegate = self;
474
    checkForUpdatesRequest.didFinishSelector = @selector(checkForUpdatesRequestFinished:);
475
    checkForUpdatesRequest.didFailSelector = @selector(checkForUpdatesRequestFailed:);
476
    checkForUpdatesRequest.timeOutSeconds = 60;
477
    checkForUpdatesRequest.numberOfTimesToRetryOnTimeout = 10;
478
    [checkForUpdatesRequest startAsynchronous];
479
}
480

    
481
#pragma mark -
482
#pragma mark ASIHTTPRequestDelegate
483

    
484
- (void)checkForUpdatesRequestFinished:(ASIHTTPRequest *)request {
485
    if (request.responseStatusCode == 200) {
486
        NSError *error = nil;
487
        NSDictionary *plistDictionary = [NSPropertyListSerialization propertyListWithData:[request.responseString dataUsingEncoding:NSUTF8StringEncoding] 
488
                                                                                  options:NSPropertyListImmutable 
489
                                                                                   format:NULL 
490
                                                                                    error:&error];
491
        if (!error) {
492
            NSString *currentVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
493
            NSString *newVersion = [plistDictionary objectForKey:@"CFBundleVersion"];
494
            NSURL *distributionURL = [NSURL URLWithString:[plistDictionary objectForKey:@"PithosDistributionURL"]];
495
            if (newVersion && currentVersion && distributionURL && ([newVersion doubleValue] > [currentVersion doubleValue])) {
496
                NSAlert *alert = [[NSAlert alloc] init];
497
                [alert setMessageText:@"Updates Available"];
498
                [alert setInformativeText:@"An updated version is available"];
499
                [alert addButtonWithTitle:@"Download"];
500
                [alert runModal];
501
                [[NSWorkspace sharedWorkspace] openURL:distributionURL];
502
            } else if (checkForUpdatesCalledFromMenu) {
503
                NSAlert *alert = [[NSAlert alloc] init];
504
                [alert setMessageText:@"No Updates Available"];
505
                [alert setInformativeText:@"You are running the latest version"];
506
                [alert addButtonWithTitle:@"OK"];
507
                [alert runModal];
508
                checkForUpdatesCalledFromMenu = NO;
509
            }
510
            [NSTimer scheduledTimerWithTimeInterval:86400 
511
                                             target:self 
512
                                           selector:@selector(checkForUpdates) 
513
                                           userInfo:nil 
514
                                            repeats:YES];
515
            self.checkForUpdatesNotRunning = YES;
516
            return;
517
        }
518
        DLog(@"Check for update plist error: %@", error);
519
     }
520
}
521

    
522
- (void)checkForUpdatesRequestFailed:(ASIHTTPRequest *)request {
523
    if (checkForUpdatesCalledFromMenu) {
524
        NSAlert *alert = [[NSAlert alloc] init];
525
        [alert setMessageText:@"Check for Updates Error"];
526
        [alert setInformativeText:@"Cannot check for updates now, try again later"];
527
        [alert addButtonWithTitle:@"OK"];
528
        [alert runModal];
529
        checkForUpdatesCalledFromMenu = NO;
530
    }
531
    [NSTimer scheduledTimerWithTimeInterval:600 
532
                                     target:self 
533
                                   selector:@selector(checkForUpdates) 
534
                                   userInfo:nil 
535
                                    repeats:YES];
536
    self.checkForUpdatesNotRunning = YES;
537
}
538

    
539
#pragma mark -
540
#pragma mark Menu Actions
541

    
542
- (void)menuChangePithosAccount:(NSMenuItem *)sender {
543
    PithosAccount *pithosAccount = (PithosAccount *)[sender representedObject];
544
    if (!pithosAccount.active)
545
        return;
546
    if (![currentPithosAccount isEqualTo:pithosAccount] && [pithosAccounts containsObject:pithosAccount]) {
547
        if ([self.pithosBrowserController operationsPending]) {
548
            NSAlert *alert = [[NSAlert alloc] init];
549
            [alert setMessageText:@"Pending Operations"];
550
            [alert setInformativeText:@"There are pending operations in the browser, do you want to change accounts and cancel them?"];
551
            [alert addButtonWithTitle:@"OK"];
552
            [alert addButtonWithTitle:@"Cancel"];
553
            NSInteger choice = [alert runModal];
554
            if (choice == NSAlertSecondButtonReturn) 
555
                return;
556
        }
557
        self.currentPithosAccount = pithosAccount;
558
        [self showPithosBrowser:self];
559
        self.pithosBrowserController.pithos = currentPithosAccount.pithos;
560
    }
561
}
562

    
563
//- (void)menuChangeSyncActive:(NSMenuItem *)sender {
564
//    PithosAccount *pithosAccount = (PithosAccount *)[sender representedObject];
565
//    if (!pithosAccount.active)
566
//        return;
567
//    pithosAccount.syncActive = !pithosAccount.syncActive;
568
//    if (self.pithosPreferencesController && [self.pithosPreferencesController.selectedPithosAccount isEqualTo:pithosAccount])
569
//        self.pithosPreferencesController.syncActive = pithosAccount.syncActive;
570
//    [self savePithosAccounts:self];
571
//}
572

    
573
- (IBAction)menuCheckForUpdates:(NSMenuItem *)sender {
574
    @synchronized(self) {
575
        checkForUpdatesCalledFromMenu = YES;
576
    }
577
    [self checkForUpdates];
578
}
579

    
580
@end