2 // pithos_macosAppDelegate.m
5 // Copyright 2011 GRNET S.A. All rights reserved.
7 // Redistribution and use in source and binary forms, with or
8 // without modification, are permitted provided that the following
11 // 1. Redistributions of source code must retain the above
12 // copyright notice, this list of conditions and the following
15 // 2. Redistributions in binary form must reproduce the above
16 // copyright notice, this list of conditions and the following
17 // disclaimer in the documentation and/or other materials
18 // provided with the distribution.
20 // THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
21 // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
24 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27 // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
33 // The views and conclusions contained in the software and
34 // documentation are those of the authors and should not be
35 // interpreted as representing official policies, either expressed
36 // or implied, of GRNET S.A.
38 #import "pithos_macosAppDelegate.h"
39 #import "PithosBrowserController.h"
40 #import "PithosPreferencesController.h"
41 #import "PithosSyncDaemon.h"
42 #import "ASIPithosRequest.h"
43 #import "ASIDownloadCache.h"
45 @implementation pithos_macosAppDelegate
46 @synthesize storageURLPrefix, publicURLPrefix, loginURLPrefix, aboutURL;
47 @synthesize syncDirectoryPath, syncContainerName, syncTimeInterval, pithosSyncDaemon, alwaysNo;
49 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
51 storageURLPrefix = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"PithosStorageURLPrefix"];
52 if (!storageURLPrefix) {
53 storageURLPrefix = [NSString stringWithString:@"https://pithos.dev.grnet.gr/v1"];
55 testURL = [NSURL URLWithString:storageURLPrefix];
56 if (!testURL || !testURL.scheme || !testURL.host)
57 storageURLPrefix = [NSString stringWithString:@"https://pithos.dev.grnet.gr/v1"];
59 [storageURLPrefix retain];
61 publicURLPrefix = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"PithosPublicURLPrefix"];
62 if (!publicURLPrefix) {
63 publicURLPrefix = [NSString stringWithString:@"https://pithos.dev.grnet.gr"];
65 testURL = [NSURL URLWithString:publicURLPrefix];
66 if (!testURL || !testURL.scheme || !testURL.host)
67 publicURLPrefix = [NSString stringWithString:@"https://pithos.dev.grnet.gr"];
69 [publicURLPrefix retain];
71 loginURLPrefix = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"PithosLoginURLPrefix"];
72 if (!loginURLPrefix) {
73 loginURLPrefix = [NSString stringWithString:@"https://pithos.dev.grnet.gr/login"];
75 testURL = [NSURL URLWithString:loginURLPrefix];
76 if (!testURL || !testURL.scheme || !testURL.host)
77 loginURLPrefix = [NSString stringWithString:@"https://pithos.dev.grnet.gr/login"];
79 [loginURLPrefix retain];
81 aboutURL = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"PithosAboutURL"];
83 aboutURL = [NSString stringWithString:@"https://pithos.dev.grnet.gr/docs"];
85 testURL = [NSURL URLWithString:aboutURL];
86 if (!testURL || !testURL.scheme || !testURL.host)
87 aboutURL = [NSString stringWithString:@"https://pithos.dev.grnet.gr/docs"];
91 syncDirectoryPath = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"PithosSyncDirectoryPath"];
92 if (!syncDirectoryPath || ![syncDirectoryPath length]) {
93 syncDirectoryPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"Pithos"];
96 if ([[NSFileManager defaultManager] fileExistsAtPath:syncDirectoryPath isDirectory:&isDirectory] && !isDirectory)
97 syncDirectoryPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"Pithos"];
99 [syncDirectoryPath retain];
101 syncContainerName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"PithosSyncContainerName"];
102 if (!syncContainerName || ![syncContainerName length] || [syncContainerName isEqualToString:@"trash"]) {
103 syncContainerName = [NSString stringWithString:@"pithos"];
105 [syncContainerName retain];
107 syncTimeInterval = [[[[NSBundle mainBundle] infoDictionary] objectForKey:@"PithosSyncTimeInterval"] doubleValue];
108 if (syncTimeInterval <= 0) {
109 syncTimeInterval = 180.0;
112 [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self
113 andSelector:@selector(handleAppleEvent:withReplyEvent:)
114 forEventClass:kInternetEventClass
115 andEventID:kAEGetURL];
116 [self showPithosBrowser:self];
118 [self authenticateWithAuthUser:[[userDefaultsController values] valueForKey:@"authUser"]
119 authToken:[[userDefaultsController values] valueForKey:@"authToken"]];
122 // Based on: http://cocoatutorial.grapewave.com/2010/01/creating-a-status-bar-application/
123 // and: http://www.cocoadev.com/index.pl?ThumbnailImages
124 - (void)awakeFromNib {
125 NSImage *sourceImage = [NSImage imageNamed:NSImageNameFolder];
127 NSImage *smallImage = [[[NSImage alloc] initWithSize:NSMakeSize(18, 18)] autorelease];
128 [smallImage lockFocus];
129 [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
130 [sourceImage setSize:NSMakeSize(18, 18)];
131 [sourceImage compositeToPoint:NSZeroPoint operation:NSCompositeCopy];
132 [smallImage unlockFocus];
134 statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
135 [statusItem setMenu:statusMenu];
136 [statusItem setImage:sourceImage];
137 [statusItem setHighlightMode:YES];
142 - (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent: (NSAppleEventDescriptor *)replyEvent {
143 NSURL *url = [NSURL URLWithString:[[event paramDescriptorForKeyword:keyDirectObject] stringValue]];
144 NSString *host = [url host];
145 NSString *query = [url query];
146 NSLog(@"host : '%@', query: '%@'", host, query);
147 NSProcessInfo *processInfo = [NSProcessInfo processInfo];
148 if ([host isEqualToString:[NSString stringWithFormat:@"%@_%d", [processInfo processName], [processInfo processIdentifier]]] && query) {
151 NSRange userRange = [query rangeOfString:@"user=" options:NSCaseInsensitiveSearch];
152 if (userRange.length == 0)
153 // XXX maybe show an error message?
155 NSUInteger authUserStartLocation = userRange.location + userRange.length;
156 NSRange userEndRange = [query rangeOfString:@"&" options:NSCaseInsensitiveSearch
157 range:NSMakeRange(authUserStartLocation, [query length] - authUserStartLocation)];
158 if (userEndRange.length) {
159 authUser = [[query substringWithRange:NSMakeRange(authUserStartLocation, userEndRange.location - authUserStartLocation)]
160 stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
162 authUser = [[query substringFromIndex:authUserStartLocation]
163 stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
167 NSRange tokenRange = [query rangeOfString:@"token=" options:NSCaseInsensitiveSearch];
168 if (tokenRange.length == 0)
169 // XXX maybe show an error message?
171 NSUInteger authTokenStartLocation = tokenRange.location + tokenRange.length;
172 NSRange tokenEndRange = [query rangeOfString:@"&" options:NSCaseInsensitiveSearch
173 range:NSMakeRange(authTokenStartLocation, [query length] - authTokenStartLocation)];
174 if (tokenEndRange.length) {
175 authToken = [[query substringWithRange:NSMakeRange(authTokenStartLocation, tokenEndRange.location - authTokenStartLocation)]
176 stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
178 authToken = [[query substringFromIndex:authTokenStartLocation]
179 stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
182 NSLog(@"query authUser: '%@', authToken: '%@'", authUser, authToken);
183 if ([authUser length] && [authToken length]) {
184 [[userDefaultsController values] setValue:authUser forKey:@"authUser"];
185 [[userDefaultsController values] setValue:authToken forKey:@"authToken"];
187 [self authenticateWithAuthUser:authUser authToken:authToken];
189 // XXX else maybe show an error message?
191 // XXX else maybe show an error message?
197 - (IBAction)showPithosBrowser:(id)sender {
198 [pithosBrowserController showWindow:sender];
199 [[pithosBrowserController window] makeKeyAndOrderFront:sender];
200 [NSApp activateIgnoringOtherApps:YES];
203 - (IBAction)showPithosPreferences:(id)sender {
204 [pithosPreferencesController showWindow:sender];
205 [[pithosPreferencesController window] makeKeyAndOrderFront:sender];
206 [NSApp activateIgnoringOtherApps:YES];
209 - (IBAction)aboutPithos:(id)sender {
210 [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:self.aboutURL]];
213 - (IBAction)syncNow:(id)sender {
214 [pithosSyncDaemon sync];
218 #pragma Authentication
220 - (void)authenticateWithAuthUser:(NSString *)authUser authToken:(NSString *)authToken {
221 NSLog(@"Authentication - storageURLPrefix:%@, authUser:%@, authToken:%@", storageURLPrefix, authUser, authToken);
222 if ([authUser length] && [authToken length] &&
223 (![[ASIPithosRequest authUser] isEqualToString:authUser] || ![[ASIPithosRequest authToken] isEqualToString:authToken])) {
224 [[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
225 [[ASIPithosRequest sharedQueue] cancelAllOperations];
227 [ASIPithosRequest setAuthURL:storageURLPrefix];
228 [ASIPithosRequest setStorageURLPrefix:storageURLPrefix];
229 [ASIPithosRequest setAuthUser:authUser];
230 [ASIPithosRequest setAuthToken:authToken];
231 [ASIPithosRequest setPublicURLPrefix:publicURLPrefix];
233 [self startSyncWithDirectoryPath:syncDirectoryPath containerName:syncContainerName];
235 [[NSNotificationCenter defaultCenter] postNotificationName:@"PithosAuthenticationCredentialsUpdated" object:self];
239 - (void)startSyncWithDirectoryPath:(NSString *)directoryPath containerName:(NSString *)containerName {
240 self.pithosSyncDaemon = [[PithosSyncDaemon alloc] initWithDirectoryPath:syncDirectoryPath
241 containerName:syncContainerName
242 timeInterval:syncTimeInterval];