Statistics
| Branch: | Tag: | Revision:

root / pithos-macos / pithos_macosAppDelegate.m @ fb27f368

History | View | Annotate | Download (26.5 kB)

1
//
2
//  pithos_macosAppDelegate.m
3
//  pithos-macos
4
//
5
// Copyright 2011-2013 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 "PithosUtilities.h"
46
#import "LastCompletedSyncTransformer.h"
47

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

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

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

    
83
    NSData *tmpData = [userDefaults objectForKey:@"pithosAccounts"];
84
    NSArray *tmpArray;
85
    if (tmpData && (tmpArray = [NSKeyedUnarchiver unarchiveObjectWithData:tmpData]))
86
        self.pithosAccounts = [NSMutableArray arrayWithArray:tmpArray];
87
    else
88
        self.pithosAccounts = [NSMutableArray array];
89
    
90
    if (![pithosAccounts count]) {
91
        [pithosAccounts addObject:[PithosAccount pithosAccount]];
92
        self.pithosAccounts = self.pithosAccounts;
93
    } else {
94
        self.activated = YES;
95
    }
96
    
97
    pithosAccountsDictionary = [[NSMutableDictionary alloc] initWithCapacity:[pithosAccounts count]];
98
    for (PithosAccount *pithosAccount in pithosAccounts) {
99
        [pithosAccountsDictionary setObject:pithosAccount forKey:pithosAccount.name];
100
        if (pithosAccount.active) {
101
            if (!pithosAccount.manual) {
102
                ASIPithosRequest *serviceCatalogRequest = [ASIPithosRequest serviceCatalogRequestWithPithos:pithosAccount.pithos];
103
                [PithosUtilities startAndWaitForRequest:serviceCatalogRequest];
104
                [pithosAccount updateServicesFromServiceCatalogRequest:serviceCatalogRequest];
105
            }
106
            if (!currentPithosAccount)
107
                self.currentPithosAccount = pithosAccount;
108
        }
109
    }
110
    if (!currentPithosAccount)
111
        self.currentPithosAccount = [pithosAccounts objectAtIndex:0];
112

    
113
    if (currentPithosAccount.active) {
114
        [self savePithosAccounts:self];
115
        [self showPithosBrowser:self];
116
        self.pithosBrowserController.pithosAccountManager = currentPithosAccount;
117
    } else {
118
        // XXX maybe call specifically to go to new account tab
119
        [self showPithosPreferences:self];
120
    }
121

    
122
    syncTimer = [NSTimer scheduledTimerWithTimeInterval:syncTimeInterval 
123
                                                  target:self 
124
                                                selector:@selector(sync) 
125
                                                userInfo:nil 
126
                                                 repeats:YES];
127
    [syncTimer fire];
128
    
129
    @synchronized(self) {
130
        self.checkForUpdatesNotRunning = YES;
131
    }
132
    [self checkForUpdates];
133
}
134

    
135
// Based on: http://cocoatutorial.grapewave.com/2010/01/creating-a-status-bar-application/
136
// and: http://www.cocoadev.com/index.pl?ThumbnailImages
137
- (void)awakeFromNib {
138
    NSImage *sourceImage = [NSImage imageNamed:@"pithos-large.png"];
139
    
140
    NSImage *smallImage = [[NSImage alloc] initWithSize:NSMakeSize(18, 18)];
141
    [smallImage lockFocus];
142
    [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
143
    [sourceImage setSize:NSMakeSize(18, 18)];
144
    [sourceImage drawAtPoint:NSZeroPoint fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
145
    [smallImage unlockFocus];
146
    
147
    statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
148
    [statusItem setMenu:statusMenu];
149
    [statusItem setImage:sourceImage];
150
    [statusItem setHighlightMode:YES];
151
    
152
    self.alwaysNo = NO;
153
}
154

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

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

    
228
#pragma mark -
229
#pragma mark Callbacks
230

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

    
255
void LSSharedFileListChanged(LSSharedFileListRef inList, void *context) {
256
    pithos_macosAppDelegate *self = (__bridge id)context;
257
    [self loginItemsChanged];
258
}
259

    
260
#pragma mark -
261
#pragma mark Properties
262

    
263
- (PithosBrowserController *)pithosBrowserController {
264
    if (!pithosBrowserController) {
265
        pithosBrowserController = [[PithosBrowserController alloc] init];
266
    }
267
    return pithosBrowserController;
268
}
269

    
270
- (PithosPreferencesController *)pithosPreferencesController {
271
    if (!pithosPreferencesController) {
272
        pithosPreferencesController = [[PithosPreferencesController alloc] init];
273
    }
274
    return pithosPreferencesController;
275
}
276

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

    
310
#pragma mark -
311
#pragma mark NSMenuDelegate
312

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

    
354
#pragma mark -
355
#pragma mark Actions
356

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

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

    
371
- (IBAction)showPithosAbout:(id)sender {
372
    [NSApp orderFrontStandardAboutPanel:sender];
373
    [NSApp activateIgnoringOtherApps:YES];
374
}
375

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

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

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

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

    
485
#pragma mark -
486
#pragma mark ASIHTTPRequestDelegate
487

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

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

    
543
#pragma mark -
544
#pragma mark Menu Actions
545

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

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

    
577
- (IBAction)menuCheckForUpdates:(NSMenuItem *)sender {
578
    @synchronized(self) {
579
        checkForUpdatesCalledFromMenu = YES;
580
    }
581
    [self checkForUpdates];
582
}
583

    
584
@end