PageRenderTime 55ms CodeModel.GetById 13ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 0ms

/Source/EmUpAppController.m

http://google-email-uploader-mac.googlecode.com/
Objective C | 274 lines | 171 code | 53 blank | 50 comment | 34 complexity | 694cdff7759e057a124c6a09cfb26eae MD5 | raw file
  1/* Copyright (c) 2009 Google Inc.
  2 *
  3 * Licensed under the Apache License, Version 2.0 (the "License");
  4 * you may not use this file except in compliance with the License.
  5 * You may obtain a copy of the License at
  6 *
  7 *     http://www.apache.org/licenses/LICENSE-2.0
  8 *
  9 * Unless required by applicable law or agreed to in writing, software
 10 * distributed under the License is distributed on an "AS IS" BASIS,
 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12 * See the License for the specific language governing permissions and
 13 * limitations under the License.
 14 */
 15
 16//
 17//  EmUpAppController.m
 18//
 19
 20#import "GTMHTTPFetcherLogging.h"
 21
 22#import "EmUpAppController.h"
 23#import "EmUpWindowController.h"
 24
 25@interface EmUpAppController (PrivateMethods)
 26- (void)checkVersion;
 27@end
 28
 29@implementation EmUpAppController
 30
 31- (void)applicationWillFinishLaunching:(NSNotification *)notifcation {
 32
 33  EmUpWindowController* windowController = [EmUpWindowController sharedEmUpWindowController];
 34  [windowController showWindow:self];
 35
 36  [self checkVersion];
 37}
 38
 39- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
 40  return YES;
 41}
 42
 43- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
 44  EmUpWindowController* windowController = [EmUpWindowController sharedEmUpWindowController];
 45  return [windowController canAppQuitNow] ? NSTerminateNow : NSTerminateLater;
 46}
 47
 48- (void)applicationWillTerminate:(NSNotification *)note {
 49  EmUpWindowController* windowController = [EmUpWindowController sharedEmUpWindowController];
 50  [windowController deleteImportedEntourageArchive];
 51}
 52
 53#pragma mark -
 54
 55- (IBAction)showHelp:(id)sender {
 56  NSString *urlStr = @"http://code.google.com/p/google-email-uploader-mac/";
 57  NSURL *url = [NSURL URLWithString:urlStr];
 58  [[NSWorkspace sharedWorkspace] openURL:url];
 59}
 60
 61- (IBAction)showReleaseNotes:(id)sender {
 62  NSString *urlStr = @"http://google-email-uploader-mac.googlecode.com/svn/trunk/Source/ReleaseNotes.txt";
 63  NSURL *url = [NSURL URLWithString:urlStr];
 64  [[NSWorkspace sharedWorkspace] openURL:url];
 65}
 66
 67- (IBAction)importFromEntourage:(id)sender {
 68  EmUpWindowController* windowController = [EmUpWindowController sharedEmUpWindowController];
 69  [windowController importRGEArchiveFromEntourage:sender];
 70}
 71
 72- (IBAction)addMailboxes:(id)sender {
 73  EmUpWindowController* windowController = [EmUpWindowController sharedEmUpWindowController];
 74  [windowController addMailboxes:sender];
 75}
 76
 77- (IBAction)reloadMailboxes:(id)sender {
 78  EmUpWindowController* windowController = [EmUpWindowController sharedEmUpWindowController];
 79  [windowController reloadMailboxesClicked:sender];
 80}
 81
 82- (IBAction)loggingCheckboxClicked:(id)sender {
 83  // toggle the menu item's checkmark
 84  [loggingMenuItem_ setState:![loggingMenuItem_ state]];
 85  [GTMHTTPFetcher setLoggingEnabled:[loggingMenuItem_ state]];
 86}
 87
 88- (IBAction)simulateUploadsClicked:(id)sender {
 89  [simulateUploadsMenuItem_ setState:![simulateUploadsMenuItem_ state]];
 90
 91  EmUpWindowController* windowController = [EmUpWindowController sharedEmUpWindowController];
 92  [windowController setSimulateUploads:[simulateUploadsMenuItem_ state]];
 93}
 94
 95#pragma mark -
 96
 97// we'll check the version in our plist against the plist on the open
 98// source site
 99//
100// for testing, use
101//   defaults write com.google.EmailUploader ForceUpdate "1"
102//
103- (void)checkVersion {
104  NSString *const kLastCheckDateKey = @"LastVersionCheck";
105  NSString *const kForceUpdateKey = @"ForceUpdate";
106  NSString *const kSkipUpdateCheckKey = @"SkipUpdateCheck";
107
108  // determine if we've checked in the last 24 hours (or if the the preferences
109  // to force or skip an update are set)
110  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
111  BOOL shouldSkipUpdate = [defaults boolForKey:kSkipUpdateCheckKey];
112  if (shouldSkipUpdate) return;
113
114  NSDate *lastCheckDate = [defaults objectForKey:kLastCheckDateKey];
115  BOOL shouldForceUpdate = [defaults boolForKey:kForceUpdateKey];
116  if (lastCheckDate && !shouldForceUpdate) {
117    // if the time since the last check is under a day, bail
118    NSTimeInterval interval = - [lastCheckDate timeIntervalSinceNow];
119    if (interval < 24 * 60 * 60) {
120      return;
121    }
122  }
123
124  // set the last check date to now
125  [defaults setObject:[NSDate date]
126               forKey:kLastCheckDateKey];
127
128  // URL of our plist file in the sources online
129  NSString *urlStr = @"http://google-email-uploader-mac.googlecode.com/svn/trunk/Source/LatestVersion.plist";
130
131  GTMHTTPFetcher *fetcher = [GTMHTTPFetcher fetcherWithURLString:urlStr];
132  [fetcher setComment:@"plist fetch"];
133  [fetcher beginFetchWithDelegate:self
134                didFinishSelector:@selector(plistFetcher:finishedWithData:error:)];
135
136  [fetcher setUserData:[NSNumber numberWithBool:shouldForceUpdate]];
137}
138
139- (NSString *)appVersionForCurrentSystemVersionWithMap:(NSDictionary *)versionMap {
140  // using a dictionary mapping system version ranges to app versions, like
141  //  -10.4.11     : 1.1.2
142  //  10.5-10.5.8  : 1.1.3
143  //  10.6-        : 1.1.4
144  // find the latest app version for the current system
145  //
146  // note: the system ranges should have no holes or overlapping system
147  //       versions, and should not be order-dependent
148
149  SInt32 systemMajor = 0, systemMinor = 0, systemRelease = 0;
150  (void) Gestalt(gestaltSystemVersionMajor, &systemMajor);
151  (void) Gestalt(gestaltSystemVersionMinor, &systemMinor);
152  (void) Gestalt(gestaltSystemVersionBugFix, &systemRelease);
153
154  NSString *systemVersion = [NSString stringWithFormat:@"%d.%d.%d",
155                             (int)systemMajor, (int)systemMinor, (int)systemRelease];
156  for (NSString *versionRange in versionMap) {
157
158    NSString *lowSystemVersion = nil;
159    NSString *dash = nil;
160    NSString *highSystemVersion = nil;
161    NSComparisonResult comp1, comp2;
162
163    // parse "low", "low-", "low-high", or "-high"
164    NSScanner *scanner = [NSScanner scannerWithString:versionRange];
165    [scanner scanUpToString:@"-" intoString:&lowSystemVersion];
166    [scanner scanString:@"-" intoString:&dash];
167    [scanner scanUpToString:@"\r" intoString:&highSystemVersion];
168
169    BOOL doesMatchLow = YES;
170    BOOL doesMatchHigh = YES;
171
172    if (lowSystemVersion) {
173      comp1 = [GDataUtilities compareVersion:lowSystemVersion
174                                   toVersion:systemVersion];
175      doesMatchLow = (comp1 == NSOrderedSame
176                      || (dash != nil && comp1 == NSOrderedAscending));
177    }
178
179    if (highSystemVersion) {
180      comp2 = [GDataUtilities compareVersion:highSystemVersion
181                                   toVersion:systemVersion];
182      doesMatchHigh = (comp2 == NSOrderedSame
183                       || (dash != nil && comp2 == NSOrderedDescending));
184    }
185
186    if (doesMatchLow && doesMatchHigh) {
187      NSString *result = [versionMap objectForKey:versionRange];
188      return result;
189    }
190  }
191
192  return nil;
193}
194
195- (void)plistFetcher:(GTMHTTPFetcher *)fetcher
196    finishedWithData:(NSData *)data
197               error:(NSError *)error {
198  if (error) {
199    // nothing to do but report this on the console
200    NSLog(@"unable to fetch plist at %@, %@", [[fetcher mutableRequest] URL], error);
201    return;
202  }
203
204  // convert the returns data to a plist dictionary
205  NSString *errorStr = nil;
206  NSDictionary *plist;
207
208  plist = [NSPropertyListSerialization propertyListFromData:data
209                                           mutabilityOption:NSPropertyListImmutable
210                                                     format:NULL
211                                           errorDescription:&errorStr];
212
213  if ([plist isKindOfClass:[NSDictionary class]]) {
214
215    // get the map of system versions to app versions, and step through the
216    // system version ranges to find the latest app version for this system
217    NSString *latestVersion;
218    NSDictionary *versionMap = [plist objectForKey:@"SystemToVersionMap"];
219    if (versionMap) {
220      // new, with the map
221      latestVersion = [self appVersionForCurrentSystemVersionWithMap:versionMap];
222    } else {
223      // old, without the map
224      latestVersion = [plist objectForKey:@"CFBundleShortVersionString"];
225    }
226
227    // compare the short version string in this bundle to the one from the
228    // map
229    NSString *thisVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
230
231    NSComparisonResult result = [GDataUtilities compareVersion:thisVersion
232                                                     toVersion:latestVersion];
233
234    BOOL shouldForceUpdate = [[fetcher userData] boolValue];
235
236    if (result != NSOrderedAscending && !shouldForceUpdate) {
237      // we're current; do nothing
238    } else {
239      // show the user the "update now?" dialog
240      EmUpWindowController* windowController = [EmUpWindowController sharedEmUpWindowController];
241
242      NSString *title = NSLocalizedString(@"UpdateAvailable", nil);
243      NSString *msg = NSLocalizedString(@"UpdateAvailableMsg", nil);
244      NSString *updateBtn = NSLocalizedString(@"UpdateButton", nil); // "Update Now"
245      NSString *dontUpdateBtn = NSLocalizedString(@"DontUpdateButton", nil); // "Don't Update"
246      NSString *releaseNotesBtn = NSLocalizedString(@"ReleaseNotesButton", nil); // "Release Notes"
247
248      NSBeginAlertSheet(title, updateBtn, dontUpdateBtn, releaseNotesBtn,
249                        [windowController window], self,
250                        @selector(updateSheetDidEnd:returnCode:contextInfo:),
251                        nil, nil, msg, thisVersion, latestVersion);
252    }
253  } else {
254    NSLog(@"unable to parse plist, %@", errorStr);
255  }
256}
257
258- (void)updateSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo {
259
260  NSString *urlStr = nil;
261  if (returnCode == NSAlertDefaultReturn) {
262    // downloads page
263    urlStr = @"https://code.google.com/p/google-email-uploader-mac/downloads/list";
264  } else if (returnCode == NSAlertOtherReturn) {
265    // release notes file in the source tree
266    urlStr = @"http://code.google.com/p/google-email-uploader-mac/source/browse/trunk/Source/ReleaseNotes.txt";
267  }
268
269  if (urlStr) {
270    [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlStr]];
271  }
272}
273
274@end