dev.stuconnolly.com / svn / safaritabs

  1. /*
  2.  *  $Id: STUpdater.m 227 2011-08-14 12:17:49Z stuart $
  3.  *
  4.  *  SafariTabs
  5.  *  http://stuconnolly.com/projects/safaritabs/
  6.  *
  7.  *  Copyright (c) 2010 Stuart Connolly. All rights reserved.
  8.  *
  9.  *  This program is free software: you can redistribute it and/or modify
  10.  *  it under the terms of the GNU General Public License as published by
  11.  *  the Free Software Foundation, either version 3 of the License, or
  12.  *  (at your option) any later version.
  13.  *
  14.  *  This program is distributed in the hope that it will be useful,
  15.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17.  *  GNU General Public License for more details.
  18.  *
  19.  *  You should have received a copy of the GNU General Public License
  20.  *  along with this program. If not, see <http://www.gnu.org/licenses/>.
  21.  */
  22.  
  23. #import "STUpdater.h"
  24. #import "STUtilities.h"
  25. #import "STConstants.h"
  26. #import "STSafariPlugin.h"
  27. #import "STUpdaterProtocol.h"
  28.  
  29. const CGFloat STDownloadTimeout = 60.0f;
  30.  
  31. @interface STUpdater ()
  32.  
  33. - (void)_compareVersions;
  34. - (void)_extractUpdateInformation;
  35. - (void)_notifyDelegateOfUpdateError;
  36. - (void)_notifyDelegateOfDownloadError;
  37. - (NSString *)_downloadDestination;
  38. - (NSComparisonResult)_compareVersion:(NSString *)versionA toVersion:(NSString *)versionB;
  39.  
  40. @end
  41.  
  42. @implementation STUpdater
  43.  
  44. /*!
  45.  * Checks for SafariTabs updates by downloading the contents of the XML update file on the server.
  46.  *
  47.  * @param delegate     The delegate object that is to be used when checking for and downloading updates.
  48.  * @param inBackground Indicates whether the check should table place in the background (i.e. no user interaction).
  49.  */
  50. - (void)checkForUpdatesUsingDelegate:(id)delegate inBackground:(BOOL)inBackground
  51. {
  52.     _delegate = delegate;
  53.     _inBackground = inBackground;
  54.        
  55.     NSURLRequest *urlRequst = [NSURLRequest requestWithURL:[NSURL URLWithString:[[STPluginBundle() infoDictionary] objectForKey:STUpdateURL]] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0];
  56.    
  57.     _urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequst delegate:self];
  58.    
  59.     if (_urlConnection) {
  60.         _infoPlistData = [[NSMutableData data] retain];
  61.     }
  62.     else {
  63.         [self _notifyDelegateOfUpdateError];
  64.     }
  65. }
  66.  
  67. /*!
  68.  * Downloads the updated version of SafariTabs from the server.
  69.  */
  70. - (void)downloadUpdate
  71. {
  72.     NSURLRequest *urlRequst = [NSURLRequest requestWithURL:[NSURL URLWithString:_downloadURL] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:STDownloadTimeout];
  73.  
  74.     _urlDownload = [[NSURLDownload alloc] initWithRequest:urlRequst delegate:self];
  75.  
  76.     if (!_urlDownload) {
  77.         [self _notifyDelegateOfDownloadError];
  78.     }
  79. }
  80.  
  81. #pragma mark -
  82. #pragma mark NSURLConnection Delegate Methods
  83.  
  84. -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
  85. {
  86.     // Reset data length
  87.     [_infoPlistData setLength:0];
  88. }
  89.  
  90. - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
  91. {
  92.     // Append received data
  93.     [_infoPlistData appendData:data];
  94. }
  95.  
  96. - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
  97. {
  98.     [connection release];
  99.     [_infoPlistData release];
  100. }
  101.  
  102. -(void)connectionDidFinishLoading:(NSURLConnection *)connection
  103. {
  104.     NSString *error;
  105.     NSPropertyListFormat format;
  106.    
  107.     [connection release];
  108.    
  109.     _versionPlist = [NSPropertyListSerialization propertyListFromData:_infoPlistData mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
  110.    
  111.     if ([NSPropertyListSerialization propertyList:_versionPlist isValidForFormat:format]) {
  112.         [self _extractUpdateInformation];
  113.         [self _compareVersions];
  114.     }
  115.     else {
  116.         [self _notifyDelegateOfUpdateError];
  117.     }
  118. }
  119.  
  120. #pragma mark -
  121. #pragma mark NSURLDownload Delegate Methods
  122.  
  123. - (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
  124. {
  125.     [download setDestination:[[self _downloadDestination] stringByAppendingPathComponent:filename] allowOverwrite:YES];
  126. }
  127.  
  128. - (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error
  129. {
  130.     [download release];
  131. }
  132.  
  133. - (void)downloadDidFinish:(NSURLDownload *)download
  134. {
  135.     [download release];
  136.    
  137.     if ([_delegate respondsToSelector:@selector(updaterDownloadComplete:)]) {
  138.         [_delegate updaterDownloadComplete:self];
  139.     }
  140. }
  141.  
  142. /*!
  143.  * Extracts the current version of the plugin and the version from the downloaded from the XML and parses them
  144.  * as integers.
  145.  */
  146. - (void)_extractUpdateInformation
  147. {        
  148.     _currentVersionString = [[STPluginBundle() infoDictionary] objectForKey:@"CFBundleShortVersionString"];
  149.     _plistVersionString = [_versionPlist objectForKey:STUserVersionKey];
  150.    
  151.     _downloadURL = [_versionPlist objectForKey:STDownloadURLKey];
  152.    
  153.     if (!_downloadURL) {
  154.         [self _notifyDelegateOfUpdateError];
  155.     }
  156. }
  157.  
  158. /*!
  159.  * Compares the two plugin versions that were extracted using the extractUpdateInformation: method.
  160.  */
  161. - (void)_compareVersions
  162. {        
  163.     if ([self _compareVersion:_currentVersionString toVersion:_plistVersionString] == NSOrderedAscending) {
  164.         if ([_delegate respondsToSelector:@selector(updater:newVersionAvailable:)]) {
  165.             [_delegate updater:self newVersionAvailable:_plistVersionString];
  166.         }
  167.     }
  168.     else {
  169.         if ([_delegate respondsToSelector:@selector(updaterNoNewVersionAvailable:)] && (!_inBackground)) {
  170.             [_delegate updaterNoNewVersionAvailable:self];
  171.         }
  172.     }
  173. }
  174.  
  175. /*!
  176.  * Notifies the delegate that an error occurred whilst trying to check for updates.
  177.  */
  178. - (void)_notifyDelegateOfUpdateError
  179. {
  180.     if ([_delegate respondsToSelector:@selector(updaterCheckForUpdateError:)] && (!_inBackground)) {
  181.         [_delegate updaterCheckForUpdateError:self];
  182.     }
  183.    
  184.     _delegate = nil;
  185. }
  186.  
  187. /*!
  188.  * Notifies the delegate that an error occurred whilst trying to download the updated version.
  189.  */
  190. - (void)_notifyDelegateOfDownloadError
  191. {
  192.     if ([_delegate respondsToSelector:@selector(updaterDownloadUpdateError:)]) {
  193.         [_delegate updaterDownloadUpdateError:self];
  194.     }
  195.    
  196.     _delegate = nil;
  197. }
  198.  
  199. /*!
  200.  * Determines the download destination by searching for the user's Desktop path. A temporary directory is used
  201.  * if it is not found.
  202.  *
  203.  * @return The download path
  204.  */
  205. - (NSString *)_downloadDestination
  206. {
  207.     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES);
  208.    
  209.     return ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
  210. }
  211.  
  212. /*!
  213.  * Compares the two supplied version strings.
  214.  *
  215.  * @param versionA The first version string of the comparison
  216.  * @param versionB The second version string of the comparison
  217.  *
  218.  * @return An integer (one of NSComparisonResult constants) indicating the result of the comparison.
  219.  */
  220. - (NSComparisonResult)_compareVersion:(NSString *)versionA toVersion:(NSString *)versionB
  221. {    
  222.     NSUInteger i;
  223.    
  224.     NSArray *versionAComponents = [versionA componentsSeparatedByString:STVersionNumberSeparator];
  225.     NSArray *versionBComponents = [versionB componentsSeparatedByString:STVersionNumberSeparator];
  226.    
  227.     NSUInteger aCount = [versionAComponents count];
  228.     NSUInteger bCount = [versionBComponents count];
  229.    
  230.     if (aCount > bCount) {
  231.         return NSOrderedDescending;
  232.     }
  233.     else if (bCount > aCount) {
  234.         return NSOrderedAscending;
  235.     }
  236.    
  237.     // Compare each of the individual version components
  238.     for (i = 0; i < [versionAComponents count]; i++)
  239.     {
  240.         NSInteger intA = [[versionAComponents objectAtIndex:i] integerValue];
  241.         NSInteger intB = [[versionBComponents objectAtIndex:i] integerValue];
  242.        
  243.         if (intB > intA) {
  244.            return NSOrderedAscending;
  245.         }
  246.         else if (intB < intA) {
  247.             return NSOrderedDescending;
  248.         }
  249.     }
  250.    
  251.     // If we get here the versions are the same
  252.     return NSOrderedSame;
  253. }
  254.  
  255. @end
  256.