Improve UUID translation in nodes
[pithos-macos] / pithos-macos / pithos_macosAppDelegate.m
index a03fd36..95d22ae 100644 (file)
 #import "PithosSyncDaemon.h"
 #import "ASIPithosRequest.h"
 #import "ASIPithos.h"
-#import "ASIDownloadCache.h"
 #import "LastCompletedSyncTransformer.h"
 
 @implementation pithos_macosAppDelegate
 @synthesize pithosBrowserController, pithosPreferencesController, alwaysNo, openAtLoginEnabled, openAtLogin, activated, 
-currentPithosAccount, pithosAccounts, pithosAccountsDictionary, syncPithosAccount, activityFacilityTimeInterval;
+currentPithosAccount, pithosAccounts, pithosAccountsDictionary, syncPithosAccount, activityFacilityTimeInterval, checkForUpdatesNotRunning;
 
 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
     [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self 
@@ -59,12 +58,12 @@ currentPithosAccount, pithosAccounts, pithosAccountsDictionary, syncPithosAccoun
     // and: http://cocoatutorial.grapewave.com/2010/02/creating-andor-removing-a-login-item/
     loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
     if (loginItems) {
-        LSSharedFileListAddObserver(loginItems, CFRunLoopGetMain(), (CFStringRef)NSDefaultRunLoopMode, LSSharedFileListChanged, self);
-        LSSharedFileListChanged(loginItems, self);
+        LSSharedFileListAddObserver(loginItems, CFRunLoopGetMain(), (CFStringRef)NSDefaultRunLoopMode, LSSharedFileListChanged, (__bridge void *)(self));
+        LSSharedFileListChanged(loginItems, (__bridge void *)(self));
         self.openAtLoginEnabled = YES;
     }
     
-    userDefaults = [[NSUserDefaults standardUserDefaults] retain];
+    userDefaults = [NSUserDefaults standardUserDefaults];
     
     syncTimeInterval = [userDefaults doubleForKey:@"syncTimeInterval"];
     if (syncTimeInterval <= 0.0) {
@@ -98,10 +97,11 @@ currentPithosAccount, pithosAccounts, pithosAccountsDictionary, syncPithosAccoun
     for (PithosAccount *pithosAccount in pithosAccounts) {
         [pithosAccountsDictionary setObject:pithosAccount forKey:pithosAccount.name];
         if (!currentPithosAccount && pithosAccount.active)
-            currentPithosAccount = [pithosAccount retain];
+            self.currentPithosAccount = pithosAccount;
     }
     if (!currentPithosAccount)
         self.currentPithosAccount = [pithosAccounts objectAtIndex:0];
+    self.pithosBrowserController.pithosAccountManager = currentPithosAccount;
     
     if (currentPithosAccount.active) {
         [self savePithosAccounts:self];
@@ -112,12 +112,17 @@ currentPithosAccount, pithosAccounts, pithosAccountsDictionary, syncPithosAccoun
         [self showPithosPreferences:self];
     }
 
-    syncTimer = [[NSTimer scheduledTimerWithTimeInterval:syncTimeInterval 
+    syncTimer = [NSTimer scheduledTimerWithTimeInterval:syncTimeInterval 
                                                   target:self 
                                                 selector:@selector(sync) 
                                                 userInfo:nil 
-                                                 repeats:YES] retain];
+                                                 repeats:YES];
     [syncTimer fire];
+    
+    @synchronized(self) {
+        self.checkForUpdatesNotRunning = YES;
+    }
+    [self checkForUpdates];
 }
 
 // Based on: http://cocoatutorial.grapewave.com/2010/01/creating-a-status-bar-application/
@@ -125,14 +130,14 @@ currentPithosAccount, pithosAccounts, pithosAccountsDictionary, syncPithosAccoun
 - (void)awakeFromNib {
     NSImage *sourceImage = [NSImage imageNamed:@"pithos-large.png"];
     
-    NSImage *smallImage = [[[NSImage alloc] initWithSize:NSMakeSize(18, 18)] autorelease];
+    NSImage *smallImage = [[NSImage alloc] initWithSize:NSMakeSize(18, 18)];
     [smallImage lockFocus];
     [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
     [sourceImage setSize:NSMakeSize(18, 18)];
-    [sourceImage compositeToPoint:NSZeroPoint operation:NSCompositeCopy];
+    [sourceImage drawAtPoint:NSZeroPoint fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
     [smallImage unlockFocus];
     
-    statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
+    statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
     [statusItem setMenu:statusMenu];
     [statusItem setImage:sourceImage];
     [statusItem setHighlightMode:YES];
@@ -144,7 +149,7 @@ currentPithosAccount, pithosAccounts, pithosAccountsDictionary, syncPithosAccoun
     NSURL *url = [NSURL URLWithString:[[event paramDescriptorForKeyword:keyDirectObject] stringValue]];
     NSString *host = [url host];
        NSString *query = [url query];
-    PithosAccount *pithosAccount = [pithosAccountsDictionary objectForKey:[url lastPathComponent]];
+    PithosAccount *pithosAccount = [pithosAccountsDictionary objectForKey:[ASIPithosRequest decodeFromPercentEscape:[url lastPathComponent]]];
     NSProcessInfo *processInfo = [NSProcessInfo processInfo];
     if ([host isEqualToString:[NSString stringWithFormat:@"%d", [processInfo processIdentifier]]] && pithosAccount && query) {
         // user=
@@ -180,7 +185,7 @@ currentPithosAccount, pithosAccounts, pithosAccountsDictionary, syncPithosAccoun
                          stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
         }
         
-        NSLog(@"query authUser: '%@', authToken: '%@'", authUser, authToken);
+        DLog(@"query authUser: '%@', authToken: '%@'", authUser, authToken);
         if ([authUser length] && [authToken length]) {
             [pithosAccount authenticateWithServerURL:nil authUser:authUser authToken:authToken];
             [self savePithosAccounts:self];
@@ -202,7 +207,7 @@ currentPithosAccount, pithosAccounts, pithosAccountsDictionary, syncPithosAccoun
 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
     [self savePithosAccounts:self];
     if ([self.pithosBrowserController operationsPending]) {
-        NSAlert *alert = [[[NSAlert alloc] init] autorelease];
+        NSAlert *alert = [[NSAlert alloc] init];
         [alert setMessageText:@"Pending Operations"];
         [alert setInformativeText:@"There are pending operations in the browser, do you want to quit and cancel them?"];
         [alert addButtonWithTitle:@"OK"];
@@ -212,7 +217,7 @@ currentPithosAccount, pithosAccounts, pithosAccountsDictionary, syncPithosAccoun
             return NSTerminateCancel;
     }
     if (loginItems) {
-        LSSharedFileListRemoveObserver(loginItems, CFRunLoopGetMain(), (CFStringRef)NSDefaultRunLoopMode, LSSharedFileListChanged, self);
+        LSSharedFileListRemoveObserver(loginItems, CFRunLoopGetMain(), (CFStringRef)NSDefaultRunLoopMode, LSSharedFileListChanged, (__bridge void *)(self));
         CFRelease(loginItems);
     }
     return NSTerminateNow;
@@ -224,13 +229,13 @@ currentPithosAccount, pithosAccounts, pithosAccountsDictionary, syncPithosAccoun
 - (void)loginItemsChanged {
     NSURL *appURL = [[NSBundle mainBundle] bundleURL];
     LSSharedFileListItemRef appItem = NULL;
-    NSArray *snapshot = [NSMakeCollectable(LSSharedFileListCopySnapshot(loginItems, NULL)) autorelease];
+    NSArray *snapshot = (__bridge_transfer NSArray *)(LSSharedFileListCopySnapshot(loginItems, NULL));
     for (id itemObject in snapshot) {
-        LSSharedFileListItemRef item = (LSSharedFileListItemRef)itemObject;
+        LSSharedFileListItemRef item = (__bridge LSSharedFileListItemRef)itemObject;
         UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
         CFURLRef currentItemURL = NULL;
         LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, NULL);
-        if (currentItemURL && CFEqual(currentItemURL, appURL)) {
+        if (currentItemURL && CFEqual(currentItemURL, (__bridge CFTypeRef)(appURL))) {
             CFRelease(currentItemURL);
             appItem = item;
             break;
@@ -246,7 +251,7 @@ currentPithosAccount, pithosAccounts, pithosAccountsDictionary, syncPithosAccoun
 }
 
 void LSSharedFileListChanged(LSSharedFileListRef inList, void *context) {
-    pithos_macosAppDelegate *self = (id)context;
+    pithos_macosAppDelegate *self = (__bridge id)context;
     [self loginItemsChanged];
 }
 
@@ -273,13 +278,13 @@ void LSSharedFileListChanged(LSSharedFileListRef inList, void *context) {
     } else if (anOpenAtLogin != openAtLogin) {
         NSURL *appURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
         LSSharedFileListItemRef appItem = NULL;
-        NSArray *snapshot = [NSMakeCollectable(LSSharedFileListCopySnapshot(loginItems, NULL)) autorelease];
+        NSArray *snapshot = (__bridge_transfer NSArray *)(LSSharedFileListCopySnapshot(loginItems, NULL));
         for (id itemObject in snapshot) {
-            LSSharedFileListItemRef item = (LSSharedFileListItemRef)itemObject;
+            LSSharedFileListItemRef item = (__bridge LSSharedFileListItemRef)itemObject;
             UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
             CFURLRef currentItemURL = NULL;
             LSSharedFileListItemResolve(item, resolutionFlags, &currentItemURL, NULL);
-            if (currentItemURL && CFEqual(currentItemURL, appURL)) {
+            if (currentItemURL && CFEqual(currentItemURL, (__bridge CFTypeRef)(appURL))) {
                 CFRelease(currentItemURL);
                 appItem = item;
                 break;
@@ -290,7 +295,7 @@ void LSSharedFileListChanged(LSSharedFileListRef inList, void *context) {
         
         if (anOpenAtLogin) {
             if (!appItem)
-                LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, NULL, NULL, (CFURLRef)appURL, NULL, NULL);
+                LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, NULL, NULL, (__bridge CFURLRef)appURL, NULL, NULL);
             openAtLogin = YES;
         } else {
             if (appItem)
@@ -309,9 +314,9 @@ void LSSharedFileListChanged(LSSharedFileListRef inList, void *context) {
     if ([menu isEqualTo:accountsMenu]) {
         [menu setAutoenablesItems:NO];
         for (PithosAccount *pithosAccount in pithosAccounts) {
-            menuItem = [[[NSMenuItem alloc] initWithTitle:pithosAccount.name 
+            menuItem = [[NSMenuItem alloc] initWithTitle:pithosAccount.name 
                                                    action:@selector(menuChangePithosAccount:) 
-                                            keyEquivalent:@""] autorelease];
+                                            keyEquivalent:@""];
             [menuItem setRepresentedObject:pithosAccount];
             [menuItem setEnabled:pithosAccount.active];
             [menuItem setState:((pithosAccount.active && [currentPithosAccount isEqualTo:pithosAccount]) ? NSOnState : NSOffState)];
@@ -323,7 +328,7 @@ void LSSharedFileListChanged(LSSharedFileListRef inList, void *context) {
         for (PithosAccount *pithosAccount in pithosAccounts) {
             menuItemTitle = [NSString stringWithFormat:@"%@: %@", 
                              pithosAccount.name, 
-                             [[[[LastCompletedSyncTransformer alloc] init] autorelease] transformedValue:pithosAccount.syncLastCompleted]];
+                             [[[LastCompletedSyncTransformer alloc] init] transformedValue:pithosAccount.syncLastCompleted]];
             if ([pithosAccount isEqualTo:syncPithosAccount] && [pithosAccount.syncDaemon isSyncing])
                 menuItemTitle = [menuItemTitle stringByAppendingString:@" (syncing)"];
 //            menuItem = [[[NSMenuItem alloc] initWithTitle:menuItemTitle 
@@ -332,15 +337,15 @@ void LSSharedFileListChanged(LSSharedFileListRef inList, void *context) {
 //            [menuItem setRepresentedObject:pithosAccount];
 //            [menuItem setEnabled:pithosAccount.active];
 //            [menuItem setState:((pithosAccount.active && pithosAccount.syncActive) ? NSOnState : NSOffState)];
-            menuItem = [[[NSMenuItem alloc] initWithTitle:menuItemTitle action:nil keyEquivalent:@""] autorelease];
+            menuItem = [[NSMenuItem alloc] initWithTitle:menuItemTitle action:nil keyEquivalent:@""];
             [menuItem setEnabled:NO];
             [menuItem setState:NO];
             [menu addItem:menuItem];
         }
         [menu addItem:[NSMenuItem separatorItem]];
-        [menu addItem:[[[NSMenuItem alloc] initWithTitle:@"Next Sync" 
+        [menu addItem:[[NSMenuItem alloc] initWithTitle:@"Next Sync" 
                                                   action:@selector(sync) 
-                                           keyEquivalent:@""] autorelease]];
+                                           keyEquivalent:@""]];
     }
 }
 
@@ -444,6 +449,7 @@ void LSSharedFileListChanged(LSSharedFileListRef inList, void *context) {
         for (PithosAccount *pithosAccount in pithosAccounts) {
             if (pithosAccount.active) {
                 self.currentPithosAccount = pithosAccount;
+                self.pithosBrowserController.pithosAccountManager = currentPithosAccount;
                 self.pithosBrowserController.pithos = currentPithosAccount.pithos;
                 break;
             }
@@ -453,12 +459,86 @@ void LSSharedFileListChanged(LSSharedFileListRef inList, void *context) {
             [self.pithosBrowserController.window close];
             [self.pithosBrowserController resetBrowser];
             self.currentPithosAccount = [pithosAccounts objectAtIndex:0];
+            self.pithosBrowserController.pithosAccountManager = currentPithosAccount;
         }
     }
     if ([self.syncPithosAccount isEqualTo:removedPithosAccount])
         self.syncPithosAccount = nil;
 }
 
+- (void)checkForUpdates {
+    @synchronized(self) {
+        if (!checkForUpdatesNotRunning)
+            return;
+        self.checkForUpdatesNotRunning = NO;
+    }
+    ASIHTTPRequest *checkForUpdatesRequest = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"https://code.grnet.gr/projects/pithos-macos/repository/revisions/master/raw/pithos-macos/pithos-macos-Info.plist"]];
+    checkForUpdatesRequest.delegate = self;
+    checkForUpdatesRequest.didFinishSelector = @selector(checkForUpdatesRequestFinished:);
+    checkForUpdatesRequest.didFailSelector = @selector(checkForUpdatesRequestFailed:);
+    checkForUpdatesRequest.timeOutSeconds = 60;
+    checkForUpdatesRequest.numberOfTimesToRetryOnTimeout = 10;
+    [checkForUpdatesRequest startAsynchronous];
+}
+
+#pragma mark -
+#pragma mark ASIHTTPRequestDelegate
+
+- (void)checkForUpdatesRequestFinished:(ASIHTTPRequest *)request {
+    if (request.responseStatusCode == 200) {
+        NSError *error = nil;
+        NSDictionary *plistDictionary = [NSPropertyListSerialization propertyListWithData:[request.responseString dataUsingEncoding:NSUTF8StringEncoding] 
+                                                                                  options:NSPropertyListImmutable 
+                                                                                   format:NULL 
+                                                                                    error:&error];
+        if (!error) {
+            NSString *currentVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
+            NSString *newVersion = [plistDictionary objectForKey:@"CFBundleVersion"];
+            NSURL *distributionURL = [NSURL URLWithString:[plistDictionary objectForKey:@"PithosDistributionURL"]];
+            if (newVersion && currentVersion && distributionURL && ([newVersion doubleValue] > [currentVersion doubleValue])) {
+                NSAlert *alert = [[NSAlert alloc] init];
+                [alert setMessageText:@"Updates Available"];
+                [alert setInformativeText:@"An updated version is available"];
+                [alert addButtonWithTitle:@"Download"];
+                [alert runModal];
+                [[NSWorkspace sharedWorkspace] openURL:distributionURL];
+            } else if (checkForUpdatesCalledFromMenu) {
+                NSAlert *alert = [[NSAlert alloc] init];
+                [alert setMessageText:@"No Updates Available"];
+                [alert setInformativeText:@"You are running the latest version"];
+                [alert addButtonWithTitle:@"OK"];
+                [alert runModal];
+                checkForUpdatesCalledFromMenu = NO;
+            }
+            [NSTimer scheduledTimerWithTimeInterval:86400 
+                                             target:self 
+                                           selector:@selector(checkForUpdates) 
+                                           userInfo:nil 
+                                            repeats:YES];
+            self.checkForUpdatesNotRunning = YES;
+            return;
+        }
+        DLog(@"Check for update plist error: %@", error);
+     }
+}
+
+- (void)checkForUpdatesRequestFailed:(ASIHTTPRequest *)request {
+    if (checkForUpdatesCalledFromMenu) {
+        NSAlert *alert = [[NSAlert alloc] init];
+        [alert setMessageText:@"Check for Updates Error"];
+        [alert setInformativeText:@"Cannot check for updates now, try again later"];
+        [alert addButtonWithTitle:@"OK"];
+        [alert runModal];
+        checkForUpdatesCalledFromMenu = NO;
+    }
+    [NSTimer scheduledTimerWithTimeInterval:600 
+                                     target:self 
+                                   selector:@selector(checkForUpdates) 
+                                   userInfo:nil 
+                                    repeats:YES];
+    self.checkForUpdatesNotRunning = YES;
+}
+
 #pragma mark -
 #pragma mark Menu Actions
 
@@ -468,7 +548,7 @@ void LSSharedFileListChanged(LSSharedFileListRef inList, void *context) {
         return;
     if (![currentPithosAccount isEqualTo:pithosAccount] && [pithosAccounts containsObject:pithosAccount]) {
         if ([self.pithosBrowserController operationsPending]) {
-            NSAlert *alert = [[[NSAlert alloc] init] autorelease];
+            NSAlert *alert = [[NSAlert alloc] init];
             [alert setMessageText:@"Pending Operations"];
             [alert setInformativeText:@"There are pending operations in the browser, do you want to change accounts and cancel them?"];
             [alert addButtonWithTitle:@"OK"];
@@ -478,6 +558,7 @@ void LSSharedFileListChanged(LSSharedFileListRef inList, void *context) {
                 return;
         }
         self.currentPithosAccount = pithosAccount;
+        self.pithosBrowserController.pithosAccountManager = currentPithosAccount;
         [self showPithosBrowser:self];
         self.pithosBrowserController.pithos = currentPithosAccount.pithos;
     }
@@ -493,4 +574,11 @@ void LSSharedFileListChanged(LSSharedFileListRef inList, void *context) {
 //    [self savePithosAccounts:self];
 //}
 
+- (IBAction)menuCheckForUpdates:(NSMenuItem *)sender {
+    @synchronized(self) {
+        checkForUpdatesCalledFromMenu = YES;
+    }
+    [self checkForUpdates];
+}
+
 @end