Removed old Sparkle files

CQTexperiment
Chris Moeller 2014-08-01 03:55:30 -07:00
parent 41f6eb17bd
commit 3b5b53ca26
309 changed files with 0 additions and 100771 deletions

View File

@ -1,3 +0,0 @@
#include "ConfigFrameworkRelease.xcconfig"
GCC_ENABLE_OBJC_GC = supported

View File

@ -1,3 +0,0 @@
#include "ConfigTestAppRelease.xcconfig"
GCC_ENABLE_OBJC_GC = required

View File

@ -1,3 +0,0 @@
#include "ConfigUnitTestRelease.xcconfig"
GCC_ENABLE_OBJC_GC = required

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>org.andymatuschak.Sparkle</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.5</string>
<key>CFBundleShortVersionString</key>
<string>1.5 Beta (git)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -1,38 +0,0 @@
Copyright (c) 2006 Andy Matuschak
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=================
EXTERNAL LICENSES
=================
License for bspatch.c and bsdiff.c, from bsdiff 4.3 (<http://www.daemonology.net/bsdiff/>:
/*-
* Copyright 2003-2005 Colin Percival
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

View File

@ -1,36 +0,0 @@
//
// NTSynchronousTask.h
// CocoatechCore
//
// Created by Steve Gehrman on 9/29/05.
// Copyright 2005 Steve Gehrman. All rights reserved.
//
#ifndef NTSYNCHRONOUSTASK_H
#define NTSYNCHRONOUSTASK_H
@interface NTSynchronousTask : NSObject
{
@private
NSTask *mv_task;
NSPipe *mv_outputPipe;
NSPipe *mv_inputPipe;
NSData* mv_output;
BOOL mv_done;
int mv_result;
}
// pass nil for directory if not needed
// returns the result
+(int) task:(NSString*)toolPath directory:(NSString*)currentDirectory withArgs:(NSArray*)args input:(NSData*)input output: (NSData**)outData;
+(NSData*)task:(NSString*)toolPath directory:(NSString*)currentDirectory withArgs:(NSArray*)args input:(NSData*)input;
- (void)run:(NSString*)toolPath directory:(NSString*)currentDirectory withArgs:(NSArray*)args input:(NSData*)input;
- (int)result;
- (NSData *)output;
@end
#endif

View File

@ -1,268 +0,0 @@
//
// NTSynchronousTask.m
// CocoatechCore
//
// Created by Steve Gehrman on 9/29/05.
// Copyright 2005 Steve Gehrman. All rights reserved.
//
#import "SUUpdater.h"
#import "SUAppcast.h"
#import "SUAppcastItem.h"
#import "SUVersionComparisonProtocol.h"
#import "NTSynchronousTask.h"
@implementation NTSynchronousTask
//----------------------------------------------------------
// task
//----------------------------------------------------------
- (NSTask *)task
{
return mv_task;
}
- (void)setTask:(NSTask *)theTask
{
if (mv_task != theTask) {
[mv_task release];
mv_task = [theTask retain];
}
}
//----------------------------------------------------------
// outputPipe
//----------------------------------------------------------
- (NSPipe *)outputPipe
{
return mv_outputPipe;
}
- (void)setOutputPipe:(NSPipe *)theOutputPipe
{
if (mv_outputPipe != theOutputPipe) {
[mv_outputPipe release];
mv_outputPipe = [theOutputPipe retain];
}
}
//----------------------------------------------------------
// inputPipe
//----------------------------------------------------------
- (NSPipe *)inputPipe
{
return mv_inputPipe;
}
- (void)setInputPipe:(NSPipe *)theInputPipe
{
if (mv_inputPipe != theInputPipe) {
[mv_inputPipe release];
mv_inputPipe = [theInputPipe retain];
}
}
//----------------------------------------------------------
// output
//----------------------------------------------------------
- (NSData *)output
{
return mv_output;
}
- (void)setOutput:(NSData *)theOutput
{
if (mv_output != theOutput) {
[mv_output release];
mv_output = [theOutput retain];
}
}
//----------------------------------------------------------
// done
//----------------------------------------------------------
- (BOOL)done
{
return mv_done;
}
- (void)setDone:(BOOL)flag
{
mv_done = flag;
}
//----------------------------------------------------------
// result
//----------------------------------------------------------
- (int)result
{
return mv_result;
}
- (void)setResult:(int)theResult
{
mv_result = theResult;
}
- (void)taskOutputAvailable:(NSNotification*)note
{
[self setOutput:[[note userInfo] objectForKey:NSFileHandleNotificationDataItem]];
[self setDone:YES];
}
- (void)taskDidTerminate:(NSNotification*)note
{
[self setResult:[[self task] terminationStatus]];
}
- (id)init;
{
self = [super init];
if (self)
{
[self setTask:[[[NSTask alloc] init] autorelease]];
[self setOutputPipe:[[[NSPipe alloc] init] autorelease]];
[self setInputPipe:[[[NSPipe alloc] init] autorelease]];
[[self task] setStandardInput:[self inputPipe]];
[[self task] setStandardOutput:[self outputPipe]];
[[self task] setStandardError:[self outputPipe]];
}
return self;
}
//----------------------------------------------------------
// dealloc
//----------------------------------------------------------
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[mv_task release];
[mv_outputPipe release];
[mv_inputPipe release];
[mv_output release];
[super dealloc];
}
- (void)run:(NSString*)toolPath directory:(NSString*)currentDirectory withArgs:(NSArray*)args input:(NSData*)input
{
BOOL success = NO;
if (currentDirectory)
[[self task] setCurrentDirectoryPath: currentDirectory];
[[self task] setLaunchPath:toolPath];
[[self task] setArguments:args];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(taskOutputAvailable:)
name:NSFileHandleReadToEndOfFileCompletionNotification
object:[[self outputPipe] fileHandleForReading]];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(taskDidTerminate:)
name:NSTaskDidTerminateNotification
object:[self task]];
[[[self outputPipe] fileHandleForReading] readToEndOfFileInBackgroundAndNotifyForModes:[NSArray arrayWithObjects:NSDefaultRunLoopMode, NSModalPanelRunLoopMode, NSEventTrackingRunLoopMode, nil]];
@try
{
[[self task] launch];
success = YES;
}
@catch (NSException *localException) { }
if (success)
{
if (input)
{
// feed the running task our input
[[[self inputPipe] fileHandleForWriting] writeData:input];
[[[self inputPipe] fileHandleForWriting] closeFile];
}
// loop until we are done receiving the data
if (![self done])
{
double resolution = 1;
BOOL isRunning;
NSDate* next;
do {
next = [NSDate dateWithTimeIntervalSinceNow:resolution];
isRunning = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:next];
} while (isRunning && ![self done]);
}
}
}
+ (NSData*)task:(NSString*)toolPath directory:(NSString*)currentDirectory withArgs:(NSArray*)args input:(NSData*)input
{
// we need this wacky pool here, otherwise we run out of pipes, the pipes are internally autoreleased
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSData* result=nil;
@try
{
NTSynchronousTask* task = [[NTSynchronousTask alloc] init];
[task run:toolPath directory:currentDirectory withArgs:args input:input];
if ([task result] == 0)
result = [[task output] retain];
[task release];
}
@catch (NSException *localException) { }
[pool drain];
// retained above
[result autorelease];
return result;
}
+(int) task:(NSString*)toolPath directory:(NSString*)currentDirectory withArgs:(NSArray*)args input:(NSData*)input output: (NSData**)outData
{
// we need this wacky pool here, otherwise we run out of pipes, the pipes are internally autoreleased
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int taskResult = 0;
if( outData )
*outData = nil;
NS_DURING
{
NTSynchronousTask* task = [[NTSynchronousTask alloc] init];
[task run:toolPath directory:currentDirectory withArgs:args input:input];
taskResult = [task result];
if( outData )
*outData = [[task output] retain];
[task release];
}
NS_HANDLER;
taskResult = errCppGeneral;
NS_ENDHANDLER;
[pool drain];
// retained above
if( outData )
[*outData autorelease];
return taskResult;
}
@end

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>org.andymatuschak.Sparkle.relaunch</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.5</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSUIElement</key>
<string>1</string>
</dict>
</plist>

View File

@ -1,36 +0,0 @@
//
// SUAppcast.h
// Sparkle
//
// Created by Andy Matuschak on 3/12/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SUAPPCAST_H
#define SUAPPCAST_H
@class SUAppcastItem;
@interface SUAppcast : NSObject
{
@private
NSArray *items;
NSString *userAgentString;
id delegate;
NSString *downloadFilename;
NSURLDownload *download;
}
- (void)fetchAppcastFromURL:(NSURL *)url;
- (void)setDelegate:delegate;
- (void)setUserAgentString:(NSString *)userAgentString;
- (NSArray *)items;
@end
@interface NSObject (SUAppcastDelegate)
- (void)appcastDidFinishLoading:(SUAppcast *)appcast;
- (void)appcast:(SUAppcast *)appcast failedToLoadWithError:(NSError *)error;
@end
#endif

View File

@ -1,301 +0,0 @@
//
// SUAppcast.m
// Sparkle
//
// Created by Andy Matuschak on 3/12/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#import "SUUpdater.h"
#import "SUAppcast.h"
#import "SUAppcastItem.h"
#import "SUVersionComparisonProtocol.h"
#import "SUAppcast.h"
#import "SUConstants.h"
#import "SULog.h"
@interface NSXMLElement (SUAppcastExtensions)
- (NSDictionary *)attributesAsDictionary;
@end
@implementation NSXMLElement (SUAppcastExtensions)
- (NSDictionary *)attributesAsDictionary
{
NSEnumerator *attributeEnum = [[self attributes] objectEnumerator];
NSXMLNode *attribute;
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
while ((attribute = [attributeEnum nextObject]))
[dictionary setObject:[attribute stringValue] forKey:[attribute name]];
return dictionary;
}
@end
@interface SUAppcast () <NSURLDownloadDelegate>
- (void)reportError:(NSError *)error;
- (NSXMLNode *)bestNodeInNodes:(NSArray *)nodes;
@end
@implementation SUAppcast
- (void)dealloc
{
[items release];
items = nil;
[userAgentString release];
userAgentString = nil;
[downloadFilename release];
downloadFilename = nil;
[download release];
download = nil;
[super dealloc];
}
- (NSArray *)items
{
return items;
}
- (void)fetchAppcastFromURL:(NSURL *)url
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0];
if (userAgentString)
[request setValue:userAgentString forHTTPHeaderField:@"User-Agent"];
download = [[NSURLDownload alloc] initWithRequest:request delegate:self];
}
- (void)download:(NSURLDownload *)aDownload decideDestinationWithSuggestedFilename:(NSString *)filename
{
NSString* destinationFilename = NSTemporaryDirectory();
if (destinationFilename)
{
destinationFilename = [destinationFilename stringByAppendingPathComponent:filename];
[download setDestination:destinationFilename allowOverwrite:NO];
}
}
- (void)download:(NSURLDownload *)aDownload didCreateDestination:(NSString *)path
{
[downloadFilename release];
downloadFilename = [path copy];
}
- (void)downloadDidFinish:(NSURLDownload *)aDownload
{
NSError *error = nil;
NSXMLDocument *document = nil;
BOOL failed = NO;
NSArray *xmlItems = nil;
NSMutableArray *appcastItems = [NSMutableArray array];
if (downloadFilename)
{
NSUInteger options = 0;
if (NSAppKitVersionNumber < NSAppKitVersionNumber10_7) {
// In order to avoid including external entities when parsing the appcast (a potential security vulnerability; see https://github.com/andymatuschak/Sparkle/issues/169), we ask NSXMLDocument to "tidy" the XML first. This happens to remove these external entities; it wouldn't be a future-proof approach, but it worked in these historical versions of OS X, and we have a more rigorous approach for 10.7+.
options = NSXMLDocumentTidyXML;
} else {
// In 10.7 and later, there's a real option for the behavior we desire.
options = NSXMLNodeLoadExternalEntitiesSameOriginOnly;
}
document = [[[NSXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:downloadFilename] options:options error:&error] autorelease];
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
[[NSFileManager defaultManager] removeFileAtPath:downloadFilename handler:nil];
#else
[[NSFileManager defaultManager] removeItemAtPath:downloadFilename error:nil];
#endif
[downloadFilename release];
downloadFilename = nil;
}
else
{
failed = YES;
}
if (nil == document)
{
failed = YES;
}
else
{
xmlItems = [document nodesForXPath:@"/rss/channel/item" error:&error];
if (nil == xmlItems)
{
failed = YES;
}
}
if (failed == NO)
{
NSEnumerator *nodeEnum = [xmlItems objectEnumerator];
NSXMLNode *node;
NSMutableDictionary *nodesDict = [NSMutableDictionary dictionary];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
while (failed == NO && (node = [nodeEnum nextObject]))
{
// First, we'll "index" all the first-level children of this appcast item so we can pick them out by language later.
if ([[node children] count])
{
node = [node childAtIndex:0];
while (nil != node)
{
NSString *name = [node name];
if (name)
{
NSMutableArray *nodes = [nodesDict objectForKey:name];
if (nodes == nil)
{
nodes = [NSMutableArray array];
[nodesDict setObject:nodes forKey:name];
}
[nodes addObject:node];
}
node = [node nextSibling];
}
}
NSEnumerator *nameEnum = [nodesDict keyEnumerator];
NSString *name;
while ((name = [nameEnum nextObject]))
{
node = [self bestNodeInNodes:[nodesDict objectForKey:name]];
if ([name isEqualToString:@"enclosure"])
{
// enclosure is flattened as a separate dictionary for some reason
NSDictionary *encDict = [(NSXMLElement *)node attributesAsDictionary];
[dict setObject:encDict forKey:@"enclosure"];
}
else if ([name isEqualToString:@"pubDate"])
{
// pubDate is expected to be an NSDate by SUAppcastItem, but the RSS class was returning an NSString
NSDate *date = [NSDate dateWithNaturalLanguageString:[node stringValue]];
if (date)
[dict setObject:date forKey:name];
}
else if ([name isEqualToString:@"sparkle:deltas"])
{
NSMutableArray *deltas = [NSMutableArray array];
NSEnumerator *childEnum = [[node children] objectEnumerator];
NSXMLNode *child;
while ((child = [childEnum nextObject])) {
if ([[child name] isEqualToString:@"enclosure"])
[deltas addObject:[(NSXMLElement *)child attributesAsDictionary]];
}
[dict setObject:deltas forKey:@"deltas"];
}
else if (name != nil)
{
// add all other values as strings
[dict setObject:[[node stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] forKey:name];
}
}
NSString *errString;
SUAppcastItem *anItem = [[[SUAppcastItem alloc] initWithDictionary:dict failureReason:&errString] autorelease];
if (anItem)
{
[appcastItems addObject:anItem];
}
else
{
SULog(@"Sparkle Updater: Failed to parse appcast item: %@.\nAppcast dictionary was: %@", errString, dict);
}
[nodesDict removeAllObjects];
[dict removeAllObjects];
}
}
if ([appcastItems count])
{
NSSortDescriptor *sort = [[[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO] autorelease];
[appcastItems sortUsingDescriptors:[NSArray arrayWithObject:sort]];
items = [appcastItems copy];
}
if (failed)
{
[self reportError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUAppcastParseError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:SULocalizedString(@"An error occurred while parsing the update feed.", nil), NSLocalizedDescriptionKey, nil]]];
}
else if ([delegate respondsToSelector:@selector(appcastDidFinishLoading:)])
{
[delegate appcastDidFinishLoading:self];
}
}
- (void)download:(NSURLDownload *)aDownload didFailWithError:(NSError *)error
{
if (downloadFilename)
{
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
[[NSFileManager defaultManager] removeFileAtPath:downloadFilename handler:nil];
#else
[[NSFileManager defaultManager] removeItemAtPath:downloadFilename error:nil];
#endif
}
[downloadFilename release];
downloadFilename = nil;
[self reportError:error];
}
- (NSURLRequest *)download:(NSURLDownload *)aDownload willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
{
return request;
}
- (void)reportError:(NSError *)error
{
if ([delegate respondsToSelector:@selector(appcast:failedToLoadWithError:)])
{
[delegate appcast:self failedToLoadWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUAppcastError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:SULocalizedString(@"An error occurred in retrieving update information. Please try again later.", nil), NSLocalizedDescriptionKey, [error localizedDescription], NSLocalizedFailureReasonErrorKey, nil]]];
}
}
- (NSXMLNode *)bestNodeInNodes:(NSArray *)nodes
{
// We use this method to pick out the localized version of a node when one's available.
if ([nodes count] == 1)
return [nodes objectAtIndex:0];
else if ([nodes count] == 0)
return nil;
NSEnumerator *nodeEnum = [nodes objectEnumerator];
NSXMLElement *node;
NSMutableArray *languages = [NSMutableArray array];
NSString *lang;
NSUInteger i;
while ((node = [nodeEnum nextObject]))
{
lang = [[node attributeForName:@"xml:lang"] stringValue];
[languages addObject:(lang ? lang : @"")];
}
lang = [[NSBundle preferredLocalizationsFromArray:languages] objectAtIndex:0];
i = [languages indexOfObject:([languages containsObject:lang] ? lang : @"")];
if (i == NSNotFound)
i = 0;
return [nodes objectAtIndex:i];
}
- (void)setUserAgentString:(NSString *)uas
{
if (uas != userAgentString)
{
[userAgentString release];
userAgentString = [uas copy];
}
}
- (void)setDelegate:del
{
delegate = del;
}
@end

View File

@ -1,60 +0,0 @@
//
// SUAppcastItem.h
// Sparkle
//
// Created by Andy Matuschak on 3/12/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SUAPPCASTITEM_H
#define SUAPPCASTITEM_H
@interface SUAppcastItem : NSObject
{
@private
NSString *title;
NSDate *date;
NSString *itemDescription;
NSURL *releaseNotesURL;
NSString *DSASignature;
NSString *minimumSystemVersion;
NSString *maximumSystemVersion;
NSURL *fileURL;
NSString *versionString;
NSString *displayVersionString;
NSDictionary *deltaUpdates;
NSDictionary *propertiesDictionary;
NSURL *infoURL; // UK 2007-08-31
}
// Initializes with data from a dictionary provided by the RSS class.
- initWithDictionary:(NSDictionary *)dict;
- initWithDictionary:(NSDictionary *)dict failureReason:(NSString**)error;
- (NSString *)title;
- (NSString *)versionString;
- (NSString *)displayVersionString;
- (NSDate *)date;
- (NSString *)itemDescription;
- (NSURL *)releaseNotesURL;
- (NSURL *)fileURL;
- (NSString *)DSASignature;
- (NSString *)minimumSystemVersion;
- (NSString *)maximumSystemVersion;
- (NSDictionary *)deltaUpdates;
- (BOOL)isDeltaUpdate;
// Returns the dictionary provided in initWithDictionary; this might be useful later for extensions.
- (NSDictionary *)propertiesDictionary;
- (NSURL *)infoURL; // UK 2007-08-31
@end
#endif

View File

@ -1,284 +0,0 @@
//
// SUAppcastItem.m
// Sparkle
//
// Created by Andy Matuschak on 3/12/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#import "SUUpdater.h"
#import "SUAppcast.h"
#import "SUAppcastItem.h"
#import "SUVersionComparisonProtocol.h"
#import "SUAppcastItem.h"
#import "SULog.h"
@implementation SUAppcastItem
// Attack of accessors!
- (NSString *)title { return [[title retain] autorelease]; }
- (void)setTitle:(NSString *)aTitle
{
if (title == aTitle) return;
[title release];
title = [aTitle copy];
}
- (NSDate *)date { return [[date retain] autorelease]; }
- (void)setDate:(NSDate *)aDate
{
if (date == aDate) return;
[date release];
date = [aDate copy];
}
- (NSString *)itemDescription { return [[itemDescription retain] autorelease]; }
- (void)setItemDescription:(NSString *)anItemDescription
{
if (itemDescription == anItemDescription) return;
[itemDescription release];
itemDescription = [anItemDescription copy];
}
- (NSURL *)releaseNotesURL { return [[releaseNotesURL retain] autorelease]; }
- (void)setReleaseNotesURL:(NSURL *)aReleaseNotesURL
{
if (releaseNotesURL == aReleaseNotesURL) return;
[releaseNotesURL release];
releaseNotesURL = [aReleaseNotesURL copy];
}
- (NSString *)DSASignature { return [[DSASignature retain] autorelease]; }
- (void)setDSASignature:(NSString *)aDSASignature
{
if (DSASignature == aDSASignature) return;
[DSASignature release];
DSASignature = [aDSASignature copy];
}
- (NSURL *)fileURL { return [[fileURL retain] autorelease]; }
- (void)setFileURL:(NSURL *)aFileURL
{
if (fileURL == aFileURL) return;
[fileURL release];
fileURL = [aFileURL copy];
}
- (NSString *)versionString { return [[versionString retain] autorelease]; }
- (void)setVersionString:(NSString *)s
{
if (versionString == s) return;
[versionString release];
versionString = [s copy];
}
- (NSString *)displayVersionString { return [[displayVersionString retain] autorelease]; }
- (void)setDisplayVersionString:(NSString *)s
{
if (displayVersionString == s) return;
[displayVersionString release];
displayVersionString = [s copy];
}
- (NSString *)minimumSystemVersion { return [[minimumSystemVersion retain] autorelease]; }
- (void)setMinimumSystemVersion:(NSString *)systemVersionString
{
if (minimumSystemVersion == systemVersionString) return;
[minimumSystemVersion release];
minimumSystemVersion = [systemVersionString copy];
}
- (NSString *)maximumSystemVersion { return [[maximumSystemVersion retain] autorelease]; }
- (void)setMaximumSystemVersion:(NSString *)systemVersionString
{
if (maximumSystemVersion == systemVersionString) return;
[maximumSystemVersion release];
maximumSystemVersion = [systemVersionString copy];
}
- (NSURL *)infoURL { return [[infoURL retain] autorelease]; } // UK 2007-08-31 (whole method)
- (void)setInfoURL:(NSURL *)aFileURL // UK 2007-08-31 (whole method)
{
if( aFileURL == infoURL ) return;
[infoURL release];
infoURL = [aFileURL copy];
}
- (NSDictionary *)deltaUpdates { return [[deltaUpdates retain] autorelease]; }
- (void)setDeltaUpdates:(NSDictionary *)updates
{
if (deltaUpdates == updates) return;
[deltaUpdates release];
deltaUpdates = [updates copy];
}
- (BOOL)isDeltaUpdate
{
return [[propertiesDictionary objectForKey:@"enclosure"] objectForKey:@"sparkle:deltaFrom"] != nil;
}
- initWithDictionary:(NSDictionary *)dict
{
return [self initWithDictionary:dict failureReason:nil];
}
- initWithDictionary:(NSDictionary *)dict failureReason:(NSString**)error
{
self = [super init];
if (self)
{
id enclosure = [dict objectForKey:@"enclosure"];
// Try to find a version string.
// Finding the new version number from the RSS feed is a little bit hacky. There are two ways:
// 1. A "sparkle:version" attribute on the enclosure tag, an extension from the RSS spec.
// 2. If there isn't a version attribute, Sparkle will parse the path in the enclosure, expecting
// that it will look like this: http://something.com/YourApp_0.5.zip. It'll read whatever's between the last
// underscore and the last period as the version number. So name your packages like this: APPNAME_VERSION.extension.
// The big caveat with this is that you can't have underscores in your version strings, as that'll confuse Sparkle.
// Feel free to change the separator string to a hyphen or something more suited to your needs if you like.
NSString *newVersion = [enclosure objectForKey:@"sparkle:version"];
if( newVersion == nil )
newVersion = [dict objectForKey:@"sparkle:version"]; // UK 2007-08-31 Get version from the item, in case it's a download-less item (i.e. paid upgrade).
if (newVersion == nil) // no sparkle:version attribute anywhere?
{
// Separate the url by underscores and take the last component, as that'll be closest to the end,
// then we remove the extension. Hopefully, this will be the version.
NSArray *fileComponents = [[enclosure objectForKey:@"url"] componentsSeparatedByString:@"_"];
if ([fileComponents count] > 1)
newVersion = [[fileComponents lastObject] stringByDeletingPathExtension];
}
if(!newVersion )
{
if (error)
*error = @"Feed item lacks sparkle:version attribute, and version couldn't be deduced from file name (would have used last component of a file name like AppName_1.3.4.zip)";
[self release];
return nil;
}
propertiesDictionary = [[NSMutableDictionary alloc] initWithDictionary:dict];
[self setTitle:[dict objectForKey:@"title"]];
[self setDate:[dict objectForKey:@"pubDate"]];
[self setItemDescription:[dict objectForKey:@"description"]];
NSString* theInfoURL = [dict objectForKey:@"link"];
if( theInfoURL )
{
if( ![theInfoURL isKindOfClass: [NSString class]] )
SULog(@"SUAppcastItem -initWithDictionary: Info URL is not of valid type.");
else
[self setInfoURL:[NSURL URLWithString:theInfoURL]];
}
// Need an info URL or an enclosure URL. Former to show "More Info"
// page, latter to download & install:
if( !enclosure && !theInfoURL )
{
if (error)
*error = @"No enclosure in feed item";
[self release];
return nil;
}
NSString* enclosureURLString = [enclosure objectForKey:@"url"];
if( !enclosureURLString && !theInfoURL )
{
if (error)
*error = @"Feed item's enclosure lacks URL";
[self release];
return nil;
}
if( enclosureURLString )
[self setFileURL: [NSURL URLWithString: [enclosureURLString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
if( enclosure )
[self setDSASignature:[enclosure objectForKey:@"sparkle:dsaSignature"]];
[self setVersionString: newVersion];
[self setMinimumSystemVersion: [dict objectForKey:@"sparkle:minimumSystemVersion"]];
[self setMaximumSystemVersion: [dict objectForKey:@"sparkle:maximumSystemVersion"]];
NSString *shortVersionString = [enclosure objectForKey:@"sparkle:shortVersionString"];
if (nil == shortVersionString)
shortVersionString = [dict objectForKey:@"sparkle:shortVersionString"]; // fall back on the <item>
if (shortVersionString)
[self setDisplayVersionString: shortVersionString];
else
[self setDisplayVersionString: [self versionString]];
// Find the appropriate release notes URL.
if ([dict objectForKey:@"sparkle:releaseNotesLink"])
[self setReleaseNotesURL:[NSURL URLWithString:[dict objectForKey:@"sparkle:releaseNotesLink"]]];
else if ([[self itemDescription] hasPrefix:@"http://"] || [[self itemDescription] hasPrefix:@"https://"]) // if the description starts with http:// or https:// use that.
[self setReleaseNotesURL:[NSURL URLWithString:[self itemDescription]]];
else
[self setReleaseNotesURL:nil];
if ([dict objectForKey:@"deltas"])
{
NSMutableDictionary *deltas = [NSMutableDictionary dictionary];
NSArray *deltaDictionaries = [dict objectForKey:@"deltas"];
NSEnumerator *deltaDictionariesEnum = [deltaDictionaries objectEnumerator];
NSDictionary *deltaDictionary;
while ((deltaDictionary = [deltaDictionariesEnum nextObject]))
{
NSMutableDictionary *fakeAppCastDict = [dict mutableCopy];
[fakeAppCastDict removeObjectForKey:@"deltas"];
[fakeAppCastDict setObject:deltaDictionary forKey:@"enclosure"];
SUAppcastItem *deltaItem = [[[self class] alloc] initWithDictionary:fakeAppCastDict];
[fakeAppCastDict release];
[deltas setObject:deltaItem forKey:[deltaDictionary objectForKey:@"sparkle:deltaFrom"]];
[deltaItem release];
}
[self setDeltaUpdates:deltas];
}
}
return self;
}
- (void)dealloc
{
[self setTitle:nil];
[self setDate:nil];
[self setItemDescription:nil];
[self setReleaseNotesURL:nil];
[self setDSASignature:nil];
[self setMinimumSystemVersion: nil];
[self setFileURL:nil];
[self setVersionString:nil];
[self setDisplayVersionString:nil];
[self setInfoURL:nil];
[propertiesDictionary release];
[super dealloc];
}
- (NSDictionary *)propertiesDictionary
{
return propertiesDictionary;
}
@end

View File

@ -1,39 +0,0 @@
//
// SUAutomaticUpdateAlert.h
// Sparkle
//
// Created by Andy Matuschak on 3/18/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SUAUTOMATICUPDATEALERT_H
#define SUAUTOMATICUPDATEALERT_H
#import "SUWindowController.h"
typedef enum
{
SUInstallNowChoice,
SUInstallLaterChoice,
SUDoNotInstallChoice
} SUAutomaticInstallationChoice;
@class SUAppcastItem, SUHost;
@interface SUAutomaticUpdateAlert : SUWindowController {
SUAppcastItem *updateItem;
id delegate;
SUHost *host;
}
- (id)initWithAppcastItem:(SUAppcastItem *)item host:(SUHost *)hostBundle delegate:delegate;
- (IBAction)installNow:sender;
- (IBAction)installLater:sender;
- (IBAction)doNotInstall:sender;
@end
@interface NSObject (SUAutomaticUpdateAlertDelegateProtocol)
- (void)automaticUpdateAlert:(SUAutomaticUpdateAlert *)aua finishedWithChoice:(SUAutomaticInstallationChoice)choice;
@end
#endif

View File

@ -1,71 +0,0 @@
//
// SUAutomaticUpdateAlert.m
// Sparkle
//
// Created by Andy Matuschak on 3/18/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#import "SUAutomaticUpdateAlert.h"
#import "SUHost.h"
@implementation SUAutomaticUpdateAlert
- (id)initWithAppcastItem:(SUAppcastItem *)item host:(SUHost *)aHost delegate:del;
{
self = [super initWithHost:aHost windowNibName:@"SUAutomaticUpdateAlert"];
if (self)
{
updateItem = [item retain];
delegate = del;
host = [aHost retain];
[self setShouldCascadeWindows:NO];
[[self window] center];
}
return self;
}
- (void)dealloc
{
[host release];
[updateItem release];
[super dealloc];
}
- (NSString *)description { return [NSString stringWithFormat:@"%@ <%@, %@>", [self class], [host bundlePath], [host installationPath]]; }
- (IBAction)installNow:sender
{
[self close];
[delegate automaticUpdateAlert:self finishedWithChoice:SUInstallNowChoice];
}
- (IBAction)installLater:sender
{
[self close];
[delegate automaticUpdateAlert:self finishedWithChoice:SUInstallLaterChoice];
}
- (IBAction)doNotInstall:sender
{
[self close];
[delegate automaticUpdateAlert:self finishedWithChoice:SUDoNotInstallChoice];
}
- (NSImage *)applicationIcon
{
return [host icon];
}
- (NSString *)titleText
{
return [NSString stringWithFormat:SULocalizedString(@"A new version of %@ is ready to install!", nil), [host name]];
}
- (NSString *)descriptionText
{
return [NSString stringWithFormat:SULocalizedString(@"%1$@ %2$@ has been downloaded and is ready to use! Would you like to install it and relaunch %1$@ now?", nil), [host name], [updateItem displayVersionString]];
}
@end

View File

@ -1,25 +0,0 @@
//
// SUAutomaticUpdateDriver.h
// Sparkle
//
// Created by Andy Matuschak on 5/6/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUAUTOMATICUPDATEDRIVER_H
#define SUAUTOMATICUPDATEDRIVER_H
#import <Cocoa/Cocoa.h>
#import "SUBasicUpdateDriver.h"
@class SUAutomaticUpdateAlert;
@interface SUAutomaticUpdateDriver : SUBasicUpdateDriver
{
@private
BOOL postponingInstallation, showErrors;
SUAutomaticUpdateAlert *alert;
}
@end
#endif

View File

@ -1,83 +0,0 @@
//
// SUAutomaticUpdateDriver.m
// Sparkle
//
// Created by Andy Matuschak on 5/6/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUAutomaticUpdateDriver.h"
#import "SUAutomaticUpdateAlert.h"
#import "SUHost.h"
#import "SUConstants.h"
@implementation SUAutomaticUpdateDriver
- (void)unarchiverDidFinish:(SUUnarchiver *)ua
{
alert = [[SUAutomaticUpdateAlert alloc] initWithAppcastItem:updateItem host:host delegate:self];
// If the app is a menubar app or the like, we need to focus it first and alter the
// update prompt to behave like a normal window. Otherwise if the window were hidden
// there may be no way for the application to be activated to make it visible again.
if ([host isBackgroundApplication])
{
[[alert window] setHidesOnDeactivate:NO];
[NSApp activateIgnoringOtherApps:YES];
}
if ([NSApp isActive])
[[alert window] makeKeyAndOrderFront:self];
else
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:NSApplicationDidBecomeActiveNotification object:NSApp];
}
- (void)applicationDidBecomeActive:(NSNotification *)aNotification
{
[[alert window] makeKeyAndOrderFront:self];
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSApplicationDidBecomeActiveNotification" object:NSApp];
}
- (void)automaticUpdateAlert:(SUAutomaticUpdateAlert *)aua finishedWithChoice:(SUAutomaticInstallationChoice)choice;
{
switch (choice)
{
case SUInstallNowChoice:
[self installWithToolAndRelaunch:YES];
break;
case SUInstallLaterChoice:
postponingInstallation = YES;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:NSApplicationWillTerminateNotification object:nil];
break;
case SUDoNotInstallChoice:
[host setObject:[updateItem versionString] forUserDefaultsKey:SUSkippedVersionKey];
[self abortUpdate];
break;
}
}
- (BOOL)shouldInstallSynchronously { return postponingInstallation; }
- (void)installWithToolAndRelaunch:(BOOL)relaunch
{
showErrors = YES;
[super installWithToolAndRelaunch:relaunch];
}
- (void)applicationWillTerminate:(NSNotification *)note
{
[self installWithToolAndRelaunch:NO];
}
- (void)abortUpdateWithError:(NSError *)error
{
if (showErrors)
[super abortUpdateWithError:error];
else
[self abortUpdate];
}
@end

View File

@ -1,60 +0,0 @@
//
// SUBasicUpdateDriver.h
// Sparkle,
//
// Created by Andy Matuschak on 4/23/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUBASICUPDATEDRIVER_H
#define SUBASICUPDATEDRIVER_H
#import <Cocoa/Cocoa.h>
#import "SUUpdateDriver.h"
@class SUAppcastItem, SUUnarchiver, SUAppcast, SUUnarchiver, SUHost;
@interface SUBasicUpdateDriver : SUUpdateDriver {
SUAppcastItem *updateItem;
SUAppcastItem *nonDeltaUpdateItem;
NSURLDownload *download;
NSString *downloadPath;
NSString *tempDir;
NSString *relaunchPath;
}
- (void)checkForUpdatesAtURL:(NSURL *)URL host:(SUHost *)host;
- (void)appcastDidFinishLoading:(SUAppcast *)ac;
- (void)appcast:(SUAppcast *)ac failedToLoadWithError:(NSError *)error;
- (BOOL)isItemNewer:(SUAppcastItem *)ui;
- (BOOL)hostSupportsItem:(SUAppcastItem *)ui;
- (BOOL)itemContainsSkippedVersion:(SUAppcastItem *)ui;
- (BOOL)itemContainsValidUpdate:(SUAppcastItem *)ui;
- (void)didFindValidUpdate;
- (void)didNotFindUpdate;
- (void)downloadUpdate;
- (void)download:(NSURLDownload *)d decideDestinationWithSuggestedFilename:(NSString *)name;
- (void)downloadDidFinish:(NSURLDownload *)d;
- (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error;
- (void)extractUpdate;
- (void)unarchiverDidFinish:(SUUnarchiver *)ua;
- (void)unarchiverDidFail:(SUUnarchiver *)ua;
- (void)failedToApplyDeltaUpdate;
- (void)installWithToolAndRelaunch:(BOOL)relaunch;
- (void)installerForHost:(SUHost *)host failedWithError:(NSError *)error;
- (void)installWithToolAndRelaunch:(BOOL)relaunch;
- (void)cleanUpDownload;
- (void)abortUpdate;
- (void)abortUpdateWithError:(NSError *)error;
@end
#endif

View File

@ -1,413 +0,0 @@
//
// SUBasicUpdateDriver.m
// Sparkle
//
// Created by Andy Matuschak on 4/23/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUBasicUpdateDriver.h"
#import "SUHost.h"
#import "SUDSAVerifier.h"
#import "SUInstaller.h"
#import "SUStandardVersionComparator.h"
#import "SUUnarchiver.h"
#import "SUConstants.h"
#import "SULog.h"
#import "SUPlainInstaller.h"
#import "SUPlainInstallerInternals.h"
#import "SUBinaryDeltaCommon.h"
#import "SUCodeSigningVerifier.h"
#import "SUUpdater_Private.h"
@interface SUBasicUpdateDriver () <NSURLDownloadDelegate>; @end
@implementation SUBasicUpdateDriver
- (void)checkForUpdatesAtURL:(NSURL *)URL host:(SUHost *)aHost
{
[super checkForUpdatesAtURL:URL host:aHost];
if ([aHost isRunningOnReadOnlyVolume])
{
[self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SURunningFromDiskImageError userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:SULocalizedString(@"%1$@ can't be updated when it's running from a read-only volume like a disk image or an optical drive. Move %1$@ to your Applications folder, relaunch it from there, and try again.", nil), [aHost name]] forKey:NSLocalizedDescriptionKey]]];
return;
}
SUAppcast *appcast = [[SUAppcast alloc] init];
CFRetain(appcast); // We'll manage the appcast's memory ourselves so we don't have to make it an IV to support GC.
[appcast release];
[appcast setDelegate:self];
[appcast setUserAgentString:[updater userAgentString]];
[appcast fetchAppcastFromURL:URL];
}
- (id <SUVersionComparison>)versionComparator
{
id <SUVersionComparison> comparator = nil;
// Give the delegate a chance to provide a custom version comparator
if ([[updater delegate] respondsToSelector:@selector(versionComparatorForUpdater:)])
comparator = [[updater delegate] versionComparatorForUpdater:updater];
// If we don't get a comparator from the delegate, use the default comparator
if (!comparator)
comparator = [SUStandardVersionComparator defaultComparator];
return comparator;
}
- (BOOL)isItemNewer:(SUAppcastItem *)ui
{
return [[self versionComparator] compareVersion:[host version] toVersion:[ui versionString]] == NSOrderedAscending;
}
- (BOOL)hostSupportsItem:(SUAppcastItem *)ui
{
if (([ui minimumSystemVersion] == nil || [[ui minimumSystemVersion] isEqualToString:@""]) &&
([ui maximumSystemVersion] == nil || [[ui maximumSystemVersion] isEqualToString:@""])) { return YES; }
BOOL minimumVersionOK = TRUE;
BOOL maximumVersionOK = TRUE;
// Check minimum and maximum System Version
if ([ui minimumSystemVersion] != nil && ![[ui minimumSystemVersion] isEqualToString:@""]) {
minimumVersionOK = [[SUStandardVersionComparator defaultComparator] compareVersion:[ui minimumSystemVersion] toVersion:[SUHost systemVersionString]] != NSOrderedDescending;
}
if ([ui maximumSystemVersion] != nil && ![[ui maximumSystemVersion] isEqualToString:@""]) {
maximumVersionOK = [[SUStandardVersionComparator defaultComparator] compareVersion:[ui maximumSystemVersion] toVersion:[SUHost systemVersionString]] != NSOrderedAscending;
}
return minimumVersionOK && maximumVersionOK;
}
- (BOOL)itemContainsSkippedVersion:(SUAppcastItem *)ui
{
NSString *skippedVersion = [host objectForUserDefaultsKey:SUSkippedVersionKey];
if (skippedVersion == nil) { return NO; }
return [[self versionComparator] compareVersion:[ui versionString] toVersion:skippedVersion] != NSOrderedDescending;
}
- (BOOL)itemContainsValidUpdate:(SUAppcastItem *)ui
{
return [self hostSupportsItem:ui] && [self isItemNewer:ui] && ![self itemContainsSkippedVersion:ui];
}
- (void)appcastDidFinishLoading:(SUAppcast *)ac
{
if ([[updater delegate] respondsToSelector:@selector(updater:didFinishLoadingAppcast:)])
[[updater delegate] updater:updater didFinishLoadingAppcast:ac];
SUAppcastItem *item = nil;
// Now we have to find the best valid update in the appcast.
if ([[updater delegate] respondsToSelector:@selector(bestValidUpdateInAppcast:forUpdater:)]) // Does the delegate want to handle it?
{
item = [[updater delegate] bestValidUpdateInAppcast:ac forUpdater:updater];
}
else // If not, we'll take care of it ourselves.
{
// Find the first update we can actually use.
NSEnumerator *updateEnumerator = [[ac items] objectEnumerator];
do {
item = [updateEnumerator nextObject];
} while (item && ![self hostSupportsItem:item]);
if (binaryDeltaSupported()) {
SUAppcastItem *deltaUpdateItem = [[item deltaUpdates] objectForKey:[host version]];
if (deltaUpdateItem && [self hostSupportsItem:deltaUpdateItem]) {
nonDeltaUpdateItem = [item retain];
item = deltaUpdateItem;
}
}
}
updateItem = [item retain];
if (ac) { CFRelease(ac); } // Remember that we're explicitly managing the memory of the appcast.
if (updateItem == nil) { [self didNotFindUpdate]; return; }
if ([self itemContainsValidUpdate:updateItem])
[self didFindValidUpdate];
else
[self didNotFindUpdate];
}
- (void)appcast:(SUAppcast *)ac failedToLoadWithError:(NSError *)error
{
if (ac) { CFRelease(ac); } // Remember that we're explicitly managing the memory of the appcast.
[self abortUpdateWithError:error];
}
- (void)didFindValidUpdate
{
if ([[updater delegate] respondsToSelector:@selector(updater:didFindValidUpdate:)])
[[updater delegate] updater:updater didFindValidUpdate:updateItem];
[self downloadUpdate];
}
- (void)didNotFindUpdate
{
if ([[updater delegate] respondsToSelector:@selector(updaterDidNotFindUpdate:)])
[[updater delegate] updaterDidNotFindUpdate:updater];
[self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUNoUpdateError userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:SULocalizedString(@"You already have the newest version of %@.", nil), [host name]] forKey:NSLocalizedDescriptionKey]]];
}
- (void)downloadUpdate
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[updateItem fileURL]];
[request setValue:[updater userAgentString] forHTTPHeaderField:@"User-Agent"];
download = [[NSURLDownload alloc] initWithRequest:request delegate:self];
}
- (void)download:(NSURLDownload *)d decideDestinationWithSuggestedFilename:(NSString *)name
{
// If name ends in .txt, the server probably has a stupid MIME configuration. We'll give the developer the benefit of the doubt and chop that off.
if ([[name pathExtension] isEqualToString:@"txt"])
name = [name stringByDeletingPathExtension];
NSString *downloadFileName = [NSString stringWithFormat:@"%@ %@", [host name], [updateItem versionString]];
[tempDir release];
tempDir = [[[host appSupportPath] stringByAppendingPathComponent:downloadFileName] retain];
int cnt=1;
while ([[NSFileManager defaultManager] fileExistsAtPath:tempDir] && cnt <= 999)
{
[tempDir release];
tempDir = [[[host appSupportPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@ %d", downloadFileName, cnt++]] retain];
}
// Create the temporary directory if necessary.
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
BOOL success = YES;
NSEnumerator *pathComponentEnumerator = [[tempDir pathComponents] objectEnumerator];
NSString *pathComponentAccumulator = @"";
NSString *currentPathComponent;
while ((currentPathComponent = [pathComponentEnumerator nextObject])) {
pathComponentAccumulator = [pathComponentAccumulator stringByAppendingPathComponent:currentPathComponent];
if ([[NSFileManager defaultManager] fileExistsAtPath:pathComponentAccumulator]) continue;
success &= [[NSFileManager defaultManager] createDirectoryAtPath:pathComponentAccumulator attributes:nil];
}
#else
BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:tempDir withIntermediateDirectories:YES attributes:nil error:NULL];
#endif
if (!success)
{
// Okay, something's really broken with this user's file structure.
[download cancel];
[self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUTemporaryDirectoryError userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Can't make a temporary directory for the update download at %@.",tempDir] forKey:NSLocalizedDescriptionKey]]];
}
downloadPath = [[tempDir stringByAppendingPathComponent:name] retain];
[download setDestination:downloadPath allowOverwrite:YES];
}
- (BOOL)validateUpdateDownloadedToPath:(NSString *)downloadedPath extractedToPath:(NSString *)extractedPath DSASignature:(NSString *)DSASignature publicDSAKey:(NSString *)publicDSAKey
{
NSString *newBundlePath = [SUInstaller appPathInUpdateFolder:extractedPath forHost:host];
if (newBundlePath)
{
NSError *error = nil;
if ([SUCodeSigningVerifier codeSignatureIsValidAtPath:newBundlePath error:&error]) {
return YES;
} else {
SULog(@"Code signature check on update failed: %@", error);
}
}
return [SUDSAVerifier validatePath:downloadedPath withEncodedDSASignature:DSASignature withPublicDSAKey:publicDSAKey];
}
- (void)downloadDidFinish:(NSURLDownload *)d
{
[self extractUpdate];
}
- (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error
{
[self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SURelaunchError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:SULocalizedString(@"An error occurred while downloading the update. Please try again later.", nil), NSLocalizedDescriptionKey, [error localizedDescription], NSLocalizedFailureReasonErrorKey, nil]]];
}
- (BOOL)download:(NSURLDownload *)download shouldDecodeSourceDataOfMIMEType:(NSString *)encodingType
{
// We don't want the download system to extract our gzips.
// Note that we use a substring matching here instead of direct comparison because the docs say "application/gzip" but the system *uses* "application/x-gzip". This is a documentation bug.
return ([encodingType rangeOfString:@"gzip"].location == NSNotFound);
}
- (void)extractUpdate
{
SUUnarchiver *unarchiver = [SUUnarchiver unarchiverForPath:downloadPath updatingHost:host];
if (!unarchiver)
{
SULog(@"Sparkle Error: No valid unarchiver for %@!", downloadPath);
[self unarchiverDidFail:nil];
return;
}
CFRetain(unarchiver); // Manage this memory manually so we don't have to make it an IV.
[unarchiver setDelegate:self];
[unarchiver start];
}
- (void)failedToApplyDeltaUpdate
{
// When a delta update fails to apply we fall back on updating via a full install.
[updateItem release];
updateItem = nonDeltaUpdateItem;
nonDeltaUpdateItem = nil;
[self downloadUpdate];
}
- (void)unarchiverDidFinish:(SUUnarchiver *)ua
{
if (ua) { CFRelease(ua); }
[self installWithToolAndRelaunch:YES];
}
- (void)unarchiverDidFail:(SUUnarchiver *)ua
{
if (ua) { CFRelease(ua); }
if ([updateItem isDeltaUpdate]) {
[self failedToApplyDeltaUpdate];
return;
}
[self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUUnarchivingError userInfo:[NSDictionary dictionaryWithObject:SULocalizedString(@"An error occurred while extracting the archive. Please try again later.", nil) forKey:NSLocalizedDescriptionKey]]];
}
- (BOOL)shouldInstallSynchronously { return NO; }
- (void)installWithToolAndRelaunch:(BOOL)relaunch
{
#if !ENDANGER_USERS_WITH_INSECURE_UPDATES
if (![self validateUpdateDownloadedToPath:downloadPath extractedToPath:tempDir DSASignature:[updateItem DSASignature] publicDSAKey:[host publicDSAKey]])
{
[self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUSignatureError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:SULocalizedString(@"An error occurred while extracting the archive. Please try again later.", nil), NSLocalizedDescriptionKey, @"The update is improperly signed.", NSLocalizedFailureReasonErrorKey, nil]]];
return;
}
#endif
if (![updater mayUpdateAndRestart])
{
[self abortUpdate];
return;
}
// Give the host app an opportunity to postpone the install and relaunch.
static BOOL postponedOnce = NO;
if (!postponedOnce && [[updater delegate] respondsToSelector:@selector(updater:shouldPostponeRelaunchForUpdate:untilInvoking:)])
{
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[self class] instanceMethodSignatureForSelector:@selector(installWithToolAndRelaunch:)]];
[invocation setSelector:@selector(installWithToolAndRelaunch:)];
[invocation setArgument:&relaunch atIndex:2];
[invocation setTarget:self];
postponedOnce = YES;
if ([[updater delegate] updater:updater shouldPostponeRelaunchForUpdate:updateItem untilInvoking:invocation])
return;
}
if ([[updater delegate] respondsToSelector:@selector(updater:willInstallUpdate:)])
[[updater delegate] updater:updater willInstallUpdate:updateItem];
// Copy the relauncher into a temporary directory so we can get to it after the new version's installed.
NSString *relaunchPathToCopy = [SPARKLE_BUNDLE pathForResource:@"finish_installation" ofType:@"app"];
NSString *targetPath = [[host appSupportPath] stringByAppendingPathComponent:[relaunchPathToCopy lastPathComponent]];
// Only the paranoid survive: if there's already a stray copy of relaunch there, we would have problems.
NSError *error = nil;
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
[[NSFileManager defaultManager] createDirectoryAtPath: [targetPath stringByDeletingLastPathComponent] attributes: [NSDictionary dictionary]];
#else
[[NSFileManager defaultManager] createDirectoryAtPath: [targetPath stringByDeletingLastPathComponent] withIntermediateDirectories: YES attributes: [NSDictionary dictionary] error: &error];
#endif
// Only the paranoid survive: if there's already a stray copy of relaunch there, we would have problems.
if( [SUPlainInstaller copyPathWithAuthentication: relaunchPathToCopy overPath: targetPath temporaryName: nil error: &error] )
relaunchPath = [targetPath retain];
else
[self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SURelaunchError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:SULocalizedString(@"An error occurred while extracting the archive. Please try again later.", nil), NSLocalizedDescriptionKey, [NSString stringWithFormat:@"Couldn't copy relauncher (%@) to temporary path (%@)! %@", relaunchPathToCopy, targetPath, (error ? [error localizedDescription] : @"")], NSLocalizedFailureReasonErrorKey, nil]]];
[[NSNotificationCenter defaultCenter] postNotificationName:SUUpdaterWillRestartNotification object:self];
if ([[updater delegate] respondsToSelector:@selector(updaterWillRelaunchApplication:)])
[[updater delegate] updaterWillRelaunchApplication:updater];
if(!relaunchPath || ![[NSFileManager defaultManager] fileExistsAtPath:relaunchPath])
{
// Note that we explicitly use the host app's name here, since updating plugin for Mail relaunches Mail, not just the plugin.
[self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SURelaunchError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:SULocalizedString(@"An error occurred while relaunching %1$@, but the new version will be available next time you run %1$@.", nil), [host name]], NSLocalizedDescriptionKey, [NSString stringWithFormat:@"Couldn't find the relauncher (expected to find it at %@)", relaunchPath], NSLocalizedFailureReasonErrorKey, nil]]];
// We intentionally don't abandon the update here so that the host won't initiate another.
return;
}
NSString *pathToRelaunch = [host bundlePath];
if ([[updater delegate] respondsToSelector:@selector(pathToRelaunchForUpdater:)])
pathToRelaunch = [[updater delegate] pathToRelaunchForUpdater:updater];
NSString *relaunchToolPath = [relaunchPath stringByAppendingPathComponent: @"/Contents/MacOS/finish_installation"];
[NSTask launchedTaskWithLaunchPath: relaunchToolPath arguments:[NSArray arrayWithObjects:[host bundlePath], pathToRelaunch, [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]], tempDir, relaunch ? @"1" : @"0", nil]];
[NSApp terminate:self];
}
- (void)cleanUpDownload
{
if (tempDir != nil) // tempDir contains downloadPath, so we implicitly delete both here.
{
BOOL success = NO;
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
success = [[NSFileManager defaultManager] removeFileAtPath: tempDir handler: nil]; // Clean up the copied relauncher
#else
NSError * error = nil;
success = [[NSFileManager defaultManager] removeItemAtPath: tempDir error: &error]; // Clean up the copied relauncher
#endif
if( !success )
[[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:[tempDir stringByDeletingLastPathComponent] destination:@"" files:[NSArray arrayWithObject:[tempDir lastPathComponent]] tag:NULL];
}
}
- (void)installerForHost:(SUHost *)aHost failedWithError:(NSError *)error
{
if (aHost != host) { return; }
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
[[NSFileManager defaultManager] removeFileAtPath: relaunchPath handler: nil]; // Clean up the copied relauncher
#else
NSError * dontThrow = nil;
[[NSFileManager defaultManager] removeItemAtPath: relaunchPath error: &dontThrow]; // Clean up the copied relauncher
#endif
[self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUInstallationError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:SULocalizedString(@"An error occurred while installing the update. Please try again later.", nil), NSLocalizedDescriptionKey, [error localizedDescription], NSLocalizedFailureReasonErrorKey, nil]]];
}
- (void)abortUpdate
{
[[self retain] autorelease]; // In case the notification center was the last one holding on to us.
[self cleanUpDownload];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super abortUpdate];
}
- (void)abortUpdateWithError:(NSError *)error
{
if ([error code] != SUNoUpdateError) // Let's not bother logging this.
SULog(@"Sparkle Error: %@", [error localizedDescription]);
if ([error localizedFailureReason])
SULog(@"Sparkle Error (continued): %@", [error localizedFailureReason]);
if (download)
[download cancel];
[self abortUpdate];
}
- (void)dealloc
{
[updateItem release];
[nonDeltaUpdateItem release];
[download release];
[downloadPath release];
[tempDir release];
[relaunchPath release];
[super dealloc];
}
@end

View File

@ -1,15 +0,0 @@
//
// SUBinaryDeltaApply.h
// Sparkle
//
// Created by Mark Rowe on 2009-06-01.
// Copyright 2009 Mark Rowe. All rights reserved.
//
#ifndef SUBINARYDELTAAPPLY_H
#define SUBINARYDELTAAPPLY_H
@class NSString;
int applyBinaryDelta(NSString *source, NSString *destination, NSString *patchFile);
#endif

View File

@ -1,101 +0,0 @@
//
// SUBinaryDeltaApply.m
// Sparkle
//
// Created by Mark Rowe on 2009-06-01.
// Copyright 2009 Mark Rowe. All rights reserved.
//
#import "SUBinaryDeltaApply.h"
#import "SUBinaryDeltaCommon.h"
#import <CommonCrypto/CommonDigest.h>
#import <Foundation/Foundation.h>
#import <bspatch.h>
#import <stdio.h>
#import <stdlib.h>
#import <xar/xar.h>
static void applyBinaryDeltaToFile(xar_t x, xar_file_t file, NSString *sourceFilePath, NSString *destinationFilePath)
{
NSString *patchFile = temporaryFilename(@"apply-binary-delta");
xar_extract_tofile(x, file, [patchFile fileSystemRepresentation]);
const char *argv[] = {"/usr/bin/bspatch", [sourceFilePath fileSystemRepresentation], [destinationFilePath fileSystemRepresentation], [patchFile fileSystemRepresentation]};
bspatch(4, (char **)argv);
unlink([patchFile fileSystemRepresentation]);
}
int applyBinaryDelta(NSString *source, NSString *destination, NSString *patchFile)
{
xar_t x = xar_open([patchFile UTF8String], READ);
if (!x) {
fprintf(stderr, "Unable to open %s. Giving up.\n", [patchFile UTF8String]);
return 1;
}
NSString *expectedBeforeHash = nil;
NSString *expectedAfterHash = nil;
xar_subdoc_t subdoc;
for (subdoc = xar_subdoc_first(x); subdoc; subdoc = xar_subdoc_next(subdoc)) {
if (!strcmp(xar_subdoc_name(subdoc), "binary-delta-attributes")) {
const char *value = 0;
xar_subdoc_prop_get(subdoc, "before-sha1", &value);
if (value)
expectedBeforeHash = [NSString stringWithUTF8String:value];
xar_subdoc_prop_get(subdoc, "after-sha1", &value);
if (value)
expectedAfterHash = [NSString stringWithUTF8String:value];
}
}
if (!expectedBeforeHash || !expectedAfterHash) {
fprintf(stderr, "Unable to find before-sha1 or after-sha1 metadata in delta. Giving up.\n");
return 1;
}
fprintf(stderr, "Verifying source... ");
NSString *beforeHash = hashOfTree(source);
if (![beforeHash isEqualToString:expectedBeforeHash]) {
fprintf(stderr, "Source doesn't have expected hash (%s != %s). Giving up.\n", [expectedBeforeHash UTF8String], [beforeHash UTF8String]);
return 1;
}
fprintf(stderr, "\nCopying files... ");
removeTree(destination);
copyTree(source, destination);
fprintf(stderr, "\nPatching... ");
xar_file_t file;
xar_iter_t iter = xar_iter_new();
for (file = xar_file_first(x, iter); file; file = xar_file_next(iter)) {
NSString *path = [NSString stringWithUTF8String:xar_get_path(file)];
NSString *sourceFilePath = [source stringByAppendingPathComponent:path];
NSString *destinationFilePath = [destination stringByAppendingPathComponent:path];
const char *value;
if (!xar_prop_get(file, "delete", &value) || !xar_prop_get(file, "delete-then-extract", &value)) {
removeTree(destinationFilePath);
if (!xar_prop_get(file, "delete", &value))
continue;
}
if (!xar_prop_get(file, "binary-delta", &value))
applyBinaryDeltaToFile(x, file, sourceFilePath, destinationFilePath);
else
xar_extract_tofile(x, file, [destinationFilePath fileSystemRepresentation]);
}
xar_close(x);
fprintf(stderr, "\nVerifying destination... ");
NSString *afterHash = hashOfTree(destination);
if (![afterHash isEqualToString:expectedAfterHash]) {
fprintf(stderr, "Destination doesn't have expected hash (%s != %s). Giving up.\n", [expectedAfterHash UTF8String], [afterHash UTF8String]);
removeTree(destination);
return 1;
}
fprintf(stderr, "\nDone!\n");
return 0;
}

View File

@ -1,26 +0,0 @@
//
// SUBinaryDeltaCommon.h
// Sparkle
//
// Created by Mark Rowe on 2009-06-01.
// Copyright 2009 Mark Rowe. All rights reserved.
//
#ifndef SUBINARYDELTACOMMON_H
#define SUBINARYDELTACOMMON_H
#include <fts.h>
@class NSString;
@class NSData;
extern int binaryDeltaSupported(void);
extern int compareFiles(const FTSENT **a, const FTSENT **b);
extern NSData *hashOfFile(FTSENT *ent);
extern NSString *hashOfTree(NSString *path);
extern void removeTree(NSString *path);
extern void copyTree(NSString *source, NSString *dest);
extern NSString *pathRelativeToDirectory(NSString *directory, NSString *path);
NSString *temporaryFilename(NSString *base);
#endif

View File

@ -1,165 +0,0 @@
//
// SUBinaryDeltaCommon.m
// Sparkle
//
// Created by Mark Rowe on 2009-06-01.
// Copyright 2009 Mark Rowe. All rights reserved.
//
#include "SUBinaryDeltaCommon.h"
#include <CommonCrypto/CommonDigest.h>
#include <Foundation/Foundation.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/stat.h>
extern int xar_close(void*) __attribute__((weak_import));
int binaryDeltaSupported(void)
{
// OS X 10.4 didn't include libxar, so we link against it weakly.
// This checks whether libxar is available at runtime.
return xar_close != 0;
}
int compareFiles(const FTSENT **a, const FTSENT **b)
{
return strcoll((*a)->fts_name, (*b)->fts_name);
}
NSString *pathRelativeToDirectory(NSString *directory, NSString *path)
{
NSUInteger directoryLength = [directory length];
if ([path hasPrefix:directory])
return [path substringFromIndex:directoryLength];
return path;
}
NSString *temporaryFilename(NSString *base)
{
NSString *template = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.XXXXXXXXXX", base]];
char buffer[MAXPATHLEN];
strcpy(buffer, [template fileSystemRepresentation]);
return [NSString stringWithUTF8String:mktemp(buffer)];
}
static void _hashOfBuffer(unsigned char *hash, const char* buffer, size_t bufferLength)
{
assert(bufferLength <= UINT32_MAX);
CC_SHA1_CTX hashContext;
CC_SHA1_Init(&hashContext);
CC_SHA1_Update(&hashContext, buffer, (CC_LONG)bufferLength);
CC_SHA1_Final(hash, &hashContext);
}
static void _hashOfFile(unsigned char* hash, FTSENT *ent)
{
if (ent->fts_info == FTS_SL) {
char linkDestination[MAXPATHLEN + 1];
ssize_t linkDestinationLength = readlink(ent->fts_path, linkDestination, MAXPATHLEN);
if (linkDestinationLength < 0) {
perror("readlink");
return;
}
_hashOfBuffer(hash, linkDestination, linkDestinationLength);
return;
}
if (ent->fts_info == FTS_F) {
int fileDescriptor = open(ent->fts_path, O_RDONLY);
if (fileDescriptor == -1) {
perror("open");
return;
}
size_t fileSize = (size_t)ent->fts_statp->st_size;
if (fileSize == 0) {
_hashOfBuffer(hash, NULL, 0);
close(fileDescriptor);
return;
}
void *buffer = mmap(0, fileSize, PROT_READ, MAP_FILE | MAP_PRIVATE, fileDescriptor, 0);
if (buffer == (void*)-1) {
close(fileDescriptor);
perror("mmap");
return;
}
_hashOfBuffer(hash, buffer, fileSize);
munmap(buffer, fileSize);
close(fileDescriptor);
return;
}
if (ent->fts_info == FTS_D)
memset(hash, 0xdd, CC_SHA1_DIGEST_LENGTH);
}
NSData *hashOfFile(FTSENT *ent)
{
unsigned char fileHash[CC_SHA1_DIGEST_LENGTH];
_hashOfFile(fileHash, ent);
return [NSData dataWithBytes:fileHash length:CC_SHA1_DIGEST_LENGTH];
}
NSString *hashOfTree(NSString *path)
{
const char *sourcePaths[] = {[path UTF8String], 0};
FTS *fts = fts_open((char* const*)sourcePaths, FTS_PHYSICAL | FTS_NOCHDIR, compareFiles);
if (!fts) {
perror("fts_open");
return nil;
}
CC_SHA1_CTX hashContext;
CC_SHA1_Init(&hashContext);
FTSENT *ent = 0;
while ((ent = fts_read(fts))) {
if (ent->fts_info != FTS_F && ent->fts_info != FTS_SL)
continue;
unsigned char fileHash[CC_SHA1_DIGEST_LENGTH];
_hashOfFile(fileHash, ent);
CC_SHA1_Update(&hashContext, fileHash, sizeof(fileHash));
NSString *relativePath = pathRelativeToDirectory(path, [NSString stringWithUTF8String:ent->fts_path]);
NSData *relativePathBytes = [relativePath dataUsingEncoding:NSUTF8StringEncoding];
CC_SHA1_Update(&hashContext, [relativePathBytes bytes], (uint32_t)[relativePathBytes length]);
}
fts_close(fts);
unsigned char hash[CC_SHA1_DIGEST_LENGTH];
CC_SHA1_Final(hash, &hashContext);
char hexHash[CC_SHA1_DIGEST_LENGTH * 2 + 1];
size_t i;
for (i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
sprintf(hexHash + i * 2, "%02x", hash[i]);
return [NSString stringWithUTF8String:hexHash];
}
void removeTree(NSString *path)
{
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
[[NSFileManager defaultManager] removeItemAtPath:path error:0];
#else
[[NSFileManager defaultManager] removeFileAtPath:path handler:nil];
#endif
}
void copyTree(NSString *source, NSString *dest)
{
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
[[NSFileManager defaultManager] copyItemAtPath:source toPath:dest error:0];
#else
[[NSFileManager defaultManager] copyPath:source toPath:dest handler:nil];
#endif
}

View File

@ -1,269 +0,0 @@
//
// SUBinaryDeltaTool.m
// Sparkle
//
// Created by Mark Rowe on 2009-06-01.
// Copyright 2009 Mark Rowe. All rights reserved.
//
#define _DARWIN_NO_64_BIT_INODE 1
#include "SUBinaryDeltaCommon.h"
#include "SUBinaryDeltaApply.h"
#include <CommonCrypto/CommonDigest.h>
#include <Foundation/Foundation.h>
#include <fcntl.h>
#include <fts.h>
#include <libgen.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <xar/xar.h>
extern int bsdiff(int argc, const char **argv);
@interface CreateBinaryDeltaOperation : NSOperation
{
NSString *_relativePath;
NSString *_fromPath;
NSString *_toPath;
NSString *_resultPath;
}
- (id)initWithRelativePath:(NSString *)relativePath oldTree:(NSString *)oldTree newTree:(NSString *)newTree;
- (NSString *)relativePath;
- (NSString *)resultPath;
@end
@implementation CreateBinaryDeltaOperation
- (id)initWithRelativePath:(NSString *)relativePath oldTree:(NSString *)oldTree newTree:(NSString *)newTree
{
if ((self = [super init])) {
_relativePath = [relativePath copy];
_fromPath = [[oldTree stringByAppendingPathComponent:relativePath] retain];
_toPath = [[newTree stringByAppendingPathComponent:relativePath] retain];
}
return self;
}
- (NSString *)relativePath
{
return [[_relativePath retain] autorelease];
}
- (NSString *)resultPath
{
return [[_resultPath retain] autorelease];
}
- (void)main
{
NSString *temporaryFile = temporaryFilename(@"BinaryDelta");
const char *argv[] = {"/usr/bin/bsdiff", [_fromPath fileSystemRepresentation], [_toPath fileSystemRepresentation], [temporaryFile fileSystemRepresentation]};
int result = bsdiff(4, argv);
if (!result)
_resultPath = [temporaryFile retain];
}
@end
static NSDictionary *infoForFile(FTSENT *ent)
{
NSData *hash = hashOfFile(ent);
NSNumber *size = nil;
if (ent->fts_info != FTS_D)
size = [NSNumber numberWithUnsignedLongLong:ent->fts_statp->st_size];
return [NSDictionary dictionaryWithObjectsAndKeys:hash, @"hash", [NSNumber numberWithUnsignedShort:ent->fts_info], @"type", size, @"size", nil];
}
static NSString *absolutePath(NSString *path)
{
NSURL *url = [[[NSURL alloc] initFileURLWithPath:path] autorelease];
return [[url absoluteURL] path];
}
static NSString *temporaryPatchFile(NSString *patchFile)
{
NSString *path = absolutePath(patchFile);
NSString *directory = [path stringByDeletingLastPathComponent];
NSString *file = [path lastPathComponent];
return [NSString stringWithFormat:@"%@/.%@.tmp", directory, file];
}
static BOOL shouldSkipDeltaCompression(NSString *key, NSDictionary* originalInfo, NSDictionary *newInfo)
{
unsigned long long fileSize = [[newInfo objectForKey:@"size"] unsignedLongLongValue];
if (fileSize < 4096)
return YES;
if (!originalInfo)
return YES;
if ([[originalInfo objectForKey:@"type"] unsignedShortValue] != [[newInfo objectForKey:@"type"] unsignedShortValue])
return YES;
return NO;
}
static BOOL shouldDeleteThenExtract(NSString *key, NSDictionary* originalInfo, NSDictionary *newInfo)
{
if (!originalInfo)
return NO;
if ([[originalInfo objectForKey:@"type"] unsignedShortValue] != [[newInfo objectForKey:@"type"] unsignedShortValue])
return YES;
return NO;
}
int main(int argc, char **argv)
{
if (argc != 5) {
usage:
fprintf(stderr, "Usage: BinaryDelta [create | apply] before-tree after-tree patch-file\n");
exit(1);
}
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *command = [NSString stringWithUTF8String:argv[1]];
NSString *oldPath = [NSString stringWithUTF8String:argv[2]];
NSString *newPath = [NSString stringWithUTF8String:argv[3]];
NSString *patchFile = [NSString stringWithUTF8String:argv[4]];
if ([command isEqualToString:@"apply"]) {
int result = applyBinaryDelta(oldPath, newPath, patchFile);
[pool drain];
return result;
}
if (![command isEqualToString:@"create"]) {
[pool drain];
goto usage;
}
NSMutableDictionary *originalTreeState = [NSMutableDictionary dictionary];
const char *sourcePaths[] = {[oldPath fileSystemRepresentation], 0};
FTS *fts = fts_open((char* const*)sourcePaths, FTS_PHYSICAL | FTS_NOCHDIR, compareFiles);
if (!fts) {
[pool drain];
perror("fts_open");
return 1;
}
fprintf(stderr, "Processing %s...", [oldPath UTF8String]);
FTSENT *ent = 0;
while ((ent = fts_read(fts))) {
if (ent->fts_info != FTS_F && ent->fts_info != FTS_SL && ent->fts_info != FTS_D)
continue;
NSString *key = pathRelativeToDirectory(oldPath, [NSString stringWithUTF8String:ent->fts_path]);
if (![key length])
continue;
NSDictionary *info = infoForFile(ent);
[originalTreeState setObject:info forKey:key];
}
fts_close(fts);
NSString *beforeHash = hashOfTree(oldPath);
NSMutableDictionary *newTreeState = [NSMutableDictionary dictionary];
for (NSString *key in originalTreeState)
{
[newTreeState setObject:[NSNull null] forKey:key];
}
fprintf(stderr, "\nProcessing %s... ", [newPath UTF8String]);
sourcePaths[0] = [newPath fileSystemRepresentation];
fts = fts_open((char* const*)sourcePaths, FTS_PHYSICAL | FTS_NOCHDIR, compareFiles);
if (!fts) {
[pool drain];
perror("fts_open");
return 1;
}
while ((ent = fts_read(fts))) {
if (ent->fts_info != FTS_F && ent->fts_info != FTS_SL && ent->fts_info != FTS_D)
continue;
NSString *key = pathRelativeToDirectory(newPath, [NSString stringWithUTF8String:ent->fts_path]);
if (![key length])
continue;
NSDictionary *info = infoForFile(ent);
NSDictionary *oldInfo = [originalTreeState objectForKey:key];
if ([info isEqual:oldInfo])
[newTreeState removeObjectForKey:key];
else
[newTreeState setObject:info forKey:key];
}
fts_close(fts);
NSString *afterHash = hashOfTree(newPath);
fprintf(stderr, "\nGenerating delta... ");
NSString *temporaryFile = temporaryPatchFile(patchFile);
xar_t x = xar_open([temporaryFile fileSystemRepresentation], WRITE);
xar_opt_set(x, XAR_OPT_COMPRESSION, "bzip2");
xar_subdoc_t attributes = xar_subdoc_new(x, "binary-delta-attributes");
xar_subdoc_prop_set(attributes, "before-sha1", [beforeHash UTF8String]);
xar_subdoc_prop_set(attributes, "after-sha1", [afterHash UTF8String]);
NSOperationQueue *deltaQueue = [[NSOperationQueue alloc] init];
NSMutableArray *deltaOperations = [NSMutableArray array];
NSArray *keys = [[newTreeState allKeys] sortedArrayUsingSelector:@selector(compare:)];
for (NSString* key in keys) {
id value = [newTreeState valueForKey:key];
if ([value isEqual:[NSNull null]]) {
xar_file_t newFile = xar_add_frombuffer(x, 0, [key fileSystemRepresentation], (char *)"", 1);
assert(newFile);
xar_prop_set(newFile, "delete", "true");
continue;
}
NSDictionary *originalInfo = [originalTreeState objectForKey:key];
NSDictionary *newInfo = [newTreeState objectForKey:key];
if (shouldSkipDeltaCompression(key, originalInfo, newInfo)) {
NSString *path = [newPath stringByAppendingPathComponent:key];
xar_file_t newFile = xar_add_frompath(x, 0, [key fileSystemRepresentation], [path fileSystemRepresentation]);
assert(newFile);
if (shouldDeleteThenExtract(key, originalInfo, newInfo))
xar_prop_set(newFile, "delete-then-extract", "true");
} else {
CreateBinaryDeltaOperation *operation = [[CreateBinaryDeltaOperation alloc] initWithRelativePath:key oldTree:oldPath newTree:newPath];
[deltaQueue addOperation:operation];
[deltaOperations addObject:operation];
[operation release];
}
}
[deltaQueue waitUntilAllOperationsAreFinished];
[deltaQueue release];
for (CreateBinaryDeltaOperation *operation in deltaOperations) {
NSString *resultPath = [operation resultPath];
xar_file_t newFile = xar_add_frompath(x, 0, [[operation relativePath] fileSystemRepresentation], [resultPath fileSystemRepresentation]);
assert(newFile);
xar_prop_set(newFile, "binary-delta", "true");
unlink([resultPath fileSystemRepresentation]);
}
xar_close(x);
unlink([patchFile fileSystemRepresentation]);
link([temporaryFile fileSystemRepresentation], [patchFile fileSystemRepresentation]);
unlink([temporaryFile fileSystemRepresentation]);
fprintf(stderr, "Done!\n");
[pool drain];
return 0;
}

View File

@ -1,20 +0,0 @@
//
// SUBinaryDeltaUnarchiver.h
// Sparkle
//
// Created by Mark Rowe on 2009-06-03.
// Copyright 2009 Mark Rowe. All rights reserved.
//
#ifndef SUBINARYDELTAUNARCHIVER_H
#define SUBINARYDELTAUNARCHIVER_H
#import <Cocoa/Cocoa.h>
#import "SUUnarchiver.h"
@interface SUBinaryDeltaUnarchiver : SUUnarchiver {
}
@end
#endif

View File

@ -1,48 +0,0 @@
//
// SUBinaryDeltaUnarchiver.m
// Sparkle
//
// Created by Mark Rowe on 2009-06-03.
// Copyright 2009 Mark Rowe. All rights reserved.
//
#import "SUBinaryDeltaCommon.h"
#import "SUBinaryDeltaUnarchiver.h"
#import "SUBinaryDeltaApply.h"
#import "SUUnarchiver_Private.h"
#import "SUHost.h"
#import "NTSynchronousTask.h"
@implementation SUBinaryDeltaUnarchiver
+ (BOOL)canUnarchivePath:(NSString *)path
{
return binaryDeltaSupported() && [[path pathExtension] isEqualToString:@"delta"];
}
- (void)applyBinaryDelta
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *sourcePath = [[updateHost bundle] bundlePath];
NSString *targetPath = [[archivePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:[sourcePath lastPathComponent]];
int result = applyBinaryDelta(sourcePath, targetPath, archivePath);
if (!result)
[self performSelectorOnMainThread:@selector(notifyDelegateOfSuccess) withObject:nil waitUntilDone:NO];
else
[self performSelectorOnMainThread:@selector(notifyDelegateOfFailure) withObject:nil waitUntilDone:NO];
[pool drain];
}
- (void)start
{
[NSThread detachNewThreadSelector:@selector(applyBinaryDelta) toTarget:self withObject:nil];
}
+ (void)load
{
[self registerImplementation:self];
}
@end

View File

@ -1,19 +0,0 @@
//
// SUCodeSigningVerifier.h
// Sparkle
//
// Created by Andy Matuschak on 7/5/12.
//
//
#ifndef SUCODESIGNINGVERIFIER_H
#define SUCODESIGNINGVERIFIER_H
#import <Foundation/Foundation.h>
@interface SUCodeSigningVerifier : NSObject
+ (BOOL)codeSignatureIsValidAtPath:(NSString *)destinationPath error:(NSError **)error;
+ (BOOL)hostApplicationIsCodeSigned;
@end
#endif

View File

@ -1,86 +0,0 @@
//
// SUCodeSigningVerifier.m
// Sparkle
//
// Created by Andy Matuschak on 7/5/12.
//
//
#import <Security/CodeSigning.h>
#import "SUCodeSigningVerifier.h"
#import "SULog.h"
@implementation SUCodeSigningVerifier
extern OSStatus SecCodeCopySelf(SecCSFlags flags, SecCodeRef *self) __attribute__((weak_import));
extern OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef code, SecCSFlags flags, SecRequirementRef *requirement) __attribute__((weak_import));
extern OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticCodeRef *staticCode) __attribute__((weak_import));
extern OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCode, SecCSFlags flags, SecRequirementRef requirement, CFErrorRef *errors) __attribute__((weak_import));
+ (BOOL)codeSignatureIsValidAtPath:(NSString *)destinationPath error:(NSError **)error
{
// This API didn't exist prior to 10.6.
if (SecCodeCopySelf == NULL) return NO;
OSStatus result;
SecRequirementRef requirement = NULL;
SecStaticCodeRef staticCode = NULL;
SecCodeRef hostCode = NULL;
result = SecCodeCopySelf(kSecCSDefaultFlags, &hostCode);
if (result != 0) {
SULog(@"Failed to copy host code %d", result);
goto finally;
}
result = SecCodeCopyDesignatedRequirement(hostCode, kSecCSDefaultFlags, &requirement);
if (result != 0) {
SULog(@"Failed to copy designated requirement %d", result);
goto finally;
}
NSBundle *newBundle = [NSBundle bundleWithPath:destinationPath];
if (!newBundle) {
SULog(@"Failed to load NSBundle for update");
result = -1;
goto finally;
}
result = SecStaticCodeCreateWithPath((CFURLRef)[newBundle executableURL], kSecCSDefaultFlags, &staticCode);
if (result != 0) {
SULog(@"Failed to get static code %d", result);
goto finally;
}
result = SecStaticCodeCheckValidityWithErrors(staticCode, kSecCSDefaultFlags | kSecCSCheckAllArchitectures, requirement, (CFErrorRef *)error);
if (result != 0 && error) [*error autorelease];
finally:
if (hostCode) CFRelease(hostCode);
if (staticCode) CFRelease(staticCode);
if (requirement) CFRelease(requirement);
return (result == 0);
}
+ (BOOL)hostApplicationIsCodeSigned
{
// This API didn't exist prior to 10.6.
if (SecCodeCopySelf == NULL) return NO;
OSStatus result;
SecCodeRef hostCode = NULL;
result = SecCodeCopySelf(kSecCSDefaultFlags, &hostCode);
if (result != 0) return NO;
SecRequirementRef requirement = NULL;
result = SecCodeCopyDesignatedRequirement(hostCode, kSecCSDefaultFlags, &requirement);
if (hostCode) CFRelease(hostCode);
if (requirement) CFRelease(requirement);
return (result == 0);
}
@end

View File

@ -1,113 +0,0 @@
//
// SUConstants.h
// Sparkle
//
// Created by Andy Matuschak on 3/16/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SUCONSTANTS_H
#define SUCONSTANTS_H
// -----------------------------------------------------------------------------
// Preprocessor flags:
// -----------------------------------------------------------------------------
// Turn off DSA signature check (practically invites man-in-the-middle attacks):
#define ENDANGER_USERS_WITH_INSECURE_UPDATES 0
// Sparkle usually doesn't allow downgrades as they're usually accidental, but
// if your app has a downgrade function or URL handler, turn this on:
#define PERMIT_AUTOMATED_DOWNGRADES 0
// If your app file on disk is named "MyApp 1.1b4", Sparkle usually updates it
// in place, giving you an app named 1.1b4 that is actually 1.2. Turn the
// following on to always reset the name back to "MyApp":
#define NORMALIZE_INSTALLED_APP_NAME 0
#define TRY_TO_APPEND_VERSION_NUMBER 1
// -----------------------------------------------------------------------------
// Notifications:
// -----------------------------------------------------------------------------
extern NSString *const SUUpdaterWillRestartNotification;
extern NSString *const SUTechnicalErrorInformationKey;
// -----------------------------------------------------------------------------
// PList keys::
// -----------------------------------------------------------------------------
extern NSString *const SUFeedURLKey;
extern NSString *const SUHasLaunchedBeforeKey;
extern NSString *const SUShowReleaseNotesKey;
extern NSString *const SUSkippedVersionKey;
extern NSString *const SUScheduledCheckIntervalKey;
extern NSString *const SULastCheckTimeKey;
extern NSString *const SUPublicDSAKeyKey;
extern NSString *const SUPublicDSAKeyFileKey;
extern NSString *const SUAutomaticallyUpdateKey;
extern NSString *const SUAllowsAutomaticUpdatesKey;
extern NSString *const SUEnableAutomaticChecksKey;
extern NSString *const SUEnableAutomaticChecksKeyOld;
extern NSString *const SUEnableSystemProfilingKey;
extern NSString *const SUSendProfileInfoKey;
extern NSString *const SULastProfileSubmitDateKey;
extern NSString *const SUPromptUserOnFirstLaunchKey;
extern NSString *const SUFixedHTMLDisplaySizeKey;
extern NSString *const SUKeepDownloadOnFailedInstallKey;
extern NSString *const SUDefaultsDomainKey;
// -----------------------------------------------------------------------------
// Errors:
// -----------------------------------------------------------------------------
extern NSString *const SUSparkleErrorDomain;
// Appcast phase errors.
extern OSStatus SUAppcastParseError;
extern OSStatus SUNoUpdateError;
extern OSStatus SUAppcastError;
extern OSStatus SURunningFromDiskImageError;
// Downlaod phase errors.
extern OSStatus SUTemporaryDirectoryError;
// Extraction phase errors.
extern OSStatus SUUnarchivingError;
extern OSStatus SUSignatureError;
// Installation phase errors.
extern OSStatus SUFileCopyFailure;
extern OSStatus SUAuthenticationFailure;
extern OSStatus SUMissingUpdateError;
extern OSStatus SUMissingInstallerToolError;
extern OSStatus SURelaunchError;
extern OSStatus SUInstallationError;
extern OSStatus SUDowngradeError;
// -----------------------------------------------------------------------------
// NSInteger fixer-upper:
// -----------------------------------------------------------------------------
// NSInteger is a type that was added to Leopard.
// Here is some glue to ensure that NSInteger will work with pre-10.5 SDKs:
#ifndef NSINTEGER_DEFINED
#ifdef NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
#define NSIntegerMax LONG_MAX
#define NSIntegerMin LONG_MIN
#define NSUIntegerMax ULONG_MAX
#define NSINTEGER_DEFINED 1
#endif
#endif

View File

@ -1,57 +0,0 @@
//
// SUConstants.m
// Sparkle
//
// Created by Andy Matuschak on 3/16/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#import "SUUpdater.h"
#import "SUAppcast.h"
#import "SUAppcastItem.h"
#import "SUVersionComparisonProtocol.h"
#import "SUConstants.h"
NSString *const SUUpdaterWillRestartNotification = @"SUUpdaterWillRestartNotificationName";
NSString *const SUTechnicalErrorInformationKey = @"SUTechnicalErrorInformation";
NSString *const SUHasLaunchedBeforeKey = @"SUHasLaunchedBefore";
NSString *const SUFeedURLKey = @"SUFeedURL";
NSString *const SUShowReleaseNotesKey = @"SUShowReleaseNotes";
NSString *const SUSkippedVersionKey = @"SUSkippedVersion";
NSString *const SUScheduledCheckIntervalKey = @"SUScheduledCheckInterval";
NSString *const SULastCheckTimeKey = @"SULastCheckTime";
NSString *const SUExpectsDSASignatureKey = @"SUExpectsDSASignature";
NSString *const SUPublicDSAKeyKey = @"SUPublicDSAKey";
NSString *const SUPublicDSAKeyFileKey = @"SUPublicDSAKeyFile";
NSString *const SUAutomaticallyUpdateKey = @"SUAutomaticallyUpdate";
NSString *const SUAllowsAutomaticUpdatesKey = @"SUAllowsAutomaticUpdates";
NSString *const SUEnableSystemProfilingKey = @"SUEnableSystemProfiling";
NSString *const SUEnableAutomaticChecksKey = @"SUEnableAutomaticChecks";
NSString *const SUEnableAutomaticChecksKeyOld = @"SUCheckAtStartup";
NSString *const SUSendProfileInfoKey = @"SUSendProfileInfo";
NSString *const SULastProfileSubmitDateKey = @"SULastProfileSubmissionDate";
NSString *const SUPromptUserOnFirstLaunchKey = @"SUPromptUserOnFirstLaunch";
NSString *const SUFixedHTMLDisplaySizeKey = @"SUFixedHTMLDisplaySize";
NSString *const SUKeepDownloadOnFailedInstallKey = @"SUKeepDownloadOnFailedInstall";
NSString *const SUDefaultsDomainKey = @"SUDefaultsDomain";
NSString *const SUSparkleErrorDomain = @"SUSparkleErrorDomain";
OSStatus SUAppcastParseError = 1000;
OSStatus SUNoUpdateError = 1001;
OSStatus SUAppcastError = 1002;
OSStatus SURunningFromDiskImageError = 1003;
OSStatus SUTemporaryDirectoryError = 2000;
OSStatus SUUnarchivingError = 3000;
OSStatus SUSignatureError = 3001;
OSStatus SUFileCopyFailure = 4000;
OSStatus SUAuthenticationFailure = 4001;
OSStatus SUMissingUpdateError = 4002;
OSStatus SUMissingInstallerToolError = 4003;
OSStatus SURelaunchError = 4004;
OSStatus SUInstallationError = 4005;
OSStatus SUDowngradeError = 4006;

View File

@ -1,18 +0,0 @@
//
// SUDSAVerifier.h
// Sparkle
//
// Created by Andy Matuschak on 3/16/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SUDSAVERIFIER_H
#define SUDSAVERIFIER_H
#import <Cocoa/Cocoa.h>
@interface SUDSAVerifier : NSObject {}
+ (BOOL)validatePath:(NSString *)path withEncodedDSASignature:(NSString *)encodedSignature withPublicDSAKey:(NSString *)pkeyString;
@end
#endif

View File

@ -1,357 +0,0 @@
//
// SUDSAVerifier.m
// Sparkle
//
// Created by Andy Matuschak on 3/16/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#import "SUDSAVerifier.h"
#import <Cocoa/Cocoa.h>
#import <Security/cssm.h>
/* CDSA Specific */
static CSSM_CSP_HANDLE cdsaInit( void );
static void cdsaRelease( CSSM_CSP_HANDLE cspHandle );
static CSSM_KEY_PTR cdsaCreateKey( CFDataRef rawKey );
static void cdsaReleaseKey( CSSM_KEY_PTR key );
static BOOL cdsaVerifyKey( CSSM_CSP_HANDLE cspHandle, const CSSM_KEY_PTR key );
static BOOL cdsaVerifySignature( CSSM_CSP_HANDLE cspHandle, const CSSM_KEY_PTR key, const CFDataRef msg, const CFDataRef signature );
static CFDataRef cdsaCreateSHA1Digest( CSSM_CSP_HANDLE cspHandle, const CFDataRef bytes );
/* Helper Functions */
static NSData *b64decode( NSString *str );
static NSData *rawKeyData( NSString *str );
@implementation SUDSAVerifier
#pragma mark -
+ (BOOL)validatePath:(NSString *)path withEncodedDSASignature:(NSString *)encodedSignature withPublicDSAKey:(NSString *)pkeyString
{
if ( !encodedSignature || !pkeyString || !path ) return NO;
BOOL result = NO;
NSData *pathData = nil, *sigData = nil;
CFDataRef hashData = NULL;
CSSM_KEY_PTR pubKey = cdsaCreateKey((CFDataRef)rawKeyData(pkeyString)); // Create the DSA key
CSSM_CSP_HANDLE cspHandle = CSSM_INVALID_HANDLE;
if ( !pubKey ) return NO;
if ( (cspHandle = cdsaInit()) == CSSM_INVALID_HANDLE ) goto validate_end; // Init CDSA
if ( !cdsaVerifyKey(cspHandle, pubKey) ) goto validate_end; // Verify the key is valid
if ( (pathData = [NSData dataWithContentsOfFile:path]) == nil ) goto validate_end; // File data
if ( (hashData = cdsaCreateSHA1Digest(cspHandle, (CFDataRef)pathData)) == NULL ) goto validate_end; // Hash
// Remove any line feeds from end of signature
// (Not likely needed, but the verify _can_ fail if there is, so...)
if ( [encodedSignature characterAtIndex:[encodedSignature length] - 1] == '\n' ) {
NSMutableString *sig = [[encodedSignature mutableCopy] autorelease];
while ( [sig characterAtIndex:[sig length] - 1] == '\n' )
[sig deleteCharactersInRange:NSMakeRange([sig length] - 1, 1)];
encodedSignature = sig;
}
if ( (sigData = b64decode(encodedSignature)) == nil ) goto validate_end; // Decode signature
// Verify the signature on the file
result = cdsaVerifySignature( cspHandle, pubKey, hashData, (CFDataRef)sigData );
validate_end:
cdsaReleaseKey( pubKey );
cdsaRelease( cspHandle );
if ( hashData ) CFRelease( hashData );
return result;
}
@end
#pragma mark -
#pragma mark Misc Helper Functions
#pragma mark -
static NSData *b64decode( NSString *str )
{
if ( !str ) return nil;
NSMutableData *retval = nil;
NSData *input = [str dataUsingEncoding:NSUTF8StringEncoding];
UInt8 *ibuf = (UInt8 *)[input bytes], *buf = NULL, *a = NULL;
size_t len = [input length], i = 0, j = 0, size = ((len + 3) / 4) * 3;
static UInt8 table[256] = {
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* 00-0F */
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* 10-1F */
99,99,99,99,99,99,99,99,99,99,99,62,99,99,99,63, /* 20-2F */
52,53,54,55,56,57,58,59,60,61,99,99,99,99,99,99, /* 30-3F */
99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */
15,16,17,18,19,20,21,22,23,24,25,99,99,99,99,99, /* 50-5F */
99,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */
41,42,43,44,45,46,47,48,49,50,51,99,99,99,99,99, /* 70-7F */
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* 80-8F */
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* 90-9F */
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* A0-AF */
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* B0-BF */
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* C0-CF */
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* D0-DF */
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, /* E0-EF */
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99 /* F0-FF */
};
retval = [NSMutableData dataWithLength:size];
buf = [retval mutableBytes];
if ( (a = calloc(4, sizeof(UInt8))) == NULL ) return nil;
do {
size_t ai = 0;
a[0] = a[1] = a[2] = a[3] = 0;
do {
UInt8 d = table[ibuf[i++]];
if ( d != 99 ) {
a[ai] = d;
ai++;
if ( ai == 4 ) break;
}
} while ( i < len );
if ( ai >= 2 ) buf[j] = (a[0] << 2) | (a[1] >> 4);
if ( ai >= 3 ) buf[j+1] = (a[1] << 4) | (a[2] >> 2);
if ( ai >= 4 ) buf[j+2] = (a[2] << 6) | a[3];
j += ai-1;
} while ( i < len );
free( a );
if ( j < size ) [retval setLength:j];
return retval;
}
static NSData *rawKeyData( NSString *key )
{
if ( (key == nil) || ([key length] == 0) ) return nil;
NSMutableString *t = [[key mutableCopy] autorelease];
// Remove the PEM guards (if present)
[t replaceOccurrencesOfString:@"-" withString:@"" options:NSLiteralSearch range:NSMakeRange(0, [t length])];
[t replaceOccurrencesOfString:@"BEGIN PUBLIC KEY" withString:@"" options:NSLiteralSearch range:NSMakeRange(0, [t length])];
[t replaceOccurrencesOfString:@"END PUBLIC KEY" withString:@"" options:NSLiteralSearch range:NSMakeRange(0, [t length])];
// Remove any line feeds from the beginning of the key
while ( [t characterAtIndex:0] == '\n' ) {
[t deleteCharactersInRange:NSMakeRange(0, 1)];
}
// Remove any line feeds at the end of the key
while ( [t characterAtIndex:[t length] - 1] == '\n' ) {
[t deleteCharactersInRange:NSMakeRange([t length] - 1, 1)];
}
// Remove whitespace around each line of the key.
NSMutableArray *pkeyTrimmedLines = [NSMutableArray array];
NSEnumerator *pkeyLinesEnumerator = [[t componentsSeparatedByString:@"\n"] objectEnumerator];
NSCharacterSet *whiteSet = [NSCharacterSet whitespaceCharacterSet];
NSString *pkeyLine;
while ((pkeyLine = [pkeyLinesEnumerator nextObject]) != nil)
{
[pkeyTrimmedLines addObject:[pkeyLine stringByTrimmingCharactersInSet:whiteSet]];
}
key = [pkeyTrimmedLines componentsJoinedByString:@"\n"]; // Put them back together.
// Base64 decode to return the raw key bits (DER format rather than PEM)
return b64decode( key );
}
#pragma mark -
#pragma mark CDSA
#pragma mark -
/* Helper Functions */
static CSSM_DATA_PTR su_createData( CFDataRef bytes );
static void su_freeData( CSSM_DATA_PTR data, Boolean freeData );
static Boolean su_copyBytesToData( CSSM_DATA_PTR data, CSSM_SIZE size, const uint8 *bytes );
/* Memory functions */
static void *su_malloc( CSSM_SIZE size, void *ref );
static void su_free( void *ptr, void *ref );
static void *su_realloc( void *ptr, CSSM_SIZE size, void *ref );
static void *su_calloc( uint32 num, CSSM_SIZE size, void *ref );
/* Constants & Typedefs */
static CSSM_VERSION vers = { 2, 0 };
static const CSSM_GUID su_guid = { 'S', 'p', 'a', { 'r', 'k', 'l', 'e', 0, 0, 0, 0 } };
static CSSM_BOOL cssmInited = CSSM_FALSE;
static CSSM_API_MEMORY_FUNCS SU_MemFuncs = {
su_malloc,
su_free,
su_realloc,
su_calloc,
NULL
};
static CSSM_CSP_HANDLE cdsaInit( void )
{
CSSM_CSP_HANDLE cspHandle = CSSM_INVALID_HANDLE;
CSSM_RETURN crtn;
if ( !cssmInited ) {
CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
crtn = CSSM_Init( &vers, CSSM_PRIVILEGE_SCOPE_NONE, &su_guid, CSSM_KEY_HIERARCHY_NONE, &pvcPolicy, NULL );
if ( crtn ) return CSSM_INVALID_HANDLE;
cssmInited = CSSM_TRUE;
}
crtn = CSSM_ModuleLoad( &gGuidAppleCSP, CSSM_KEY_HIERARCHY_NONE, NULL, NULL );
if ( crtn ) return CSSM_INVALID_HANDLE;
crtn = CSSM_ModuleAttach( &gGuidAppleCSP, &vers, &SU_MemFuncs, 0, CSSM_SERVICE_CSP, 0, CSSM_KEY_HIERARCHY_NONE, NULL, 0, NULL, &cspHandle );
if ( crtn ) return CSSM_INVALID_HANDLE;
return cspHandle;
}
static void cdsaRelease( CSSM_CSP_HANDLE cspHandle )
{
if ( CSSM_ModuleDetach(cspHandle) != CSSM_OK ) return;
CSSM_ModuleUnload( &gGuidAppleCSP, NULL, NULL );
}
static CSSM_KEY_PTR cdsaCreateKey( CFDataRef rawKey )
{
CSSM_KEY_PTR retval = NULL;
if ( !rawKey || (CFDataGetLength(rawKey) == 0) ) return NULL;
if ( (retval = su_malloc(sizeof(CSSM_KEY), NULL)) == NULL ) return NULL;
if ( !su_copyBytesToData(&(retval->KeyData), CFDataGetLength(rawKey), CFDataGetBytePtr(rawKey)) ) {
su_free( retval, NULL );
return NULL;
}
CSSM_KEYHEADER_PTR hdr = &(retval->KeyHeader);
memset( hdr, 0, sizeof(CSSM_KEYHEADER) );
hdr->HeaderVersion = CSSM_KEYHEADER_VERSION;
hdr->CspId = su_guid;
hdr->BlobType = CSSM_KEYBLOB_RAW;
hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_X509;
hdr->AlgorithmId = CSSM_ALGID_DSA;
hdr->KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
hdr->KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
hdr->KeyUsage = CSSM_KEYUSE_ANY;
return retval;
}
static void cdsaReleaseKey( CSSM_KEY_PTR key )
{
if ( key ) {
if ( key->KeyData.Data ) su_free( key->KeyData.Data, NULL );
su_free( key, NULL );
}
}
BOOL cdsaVerifyKey( CSSM_CSP_HANDLE cspHandle, CSSM_KEY_PTR key )
{
if ( key->KeyHeader.LogicalKeySizeInBits == 0 ) {
CSSM_RETURN crtn;
CSSM_KEY_SIZE keySize;
/* This will fail if the key isn't valid */
crtn = CSSM_QueryKeySizeInBits( cspHandle, CSSM_INVALID_HANDLE, key, &keySize );
if ( crtn ) return NO;
key->KeyHeader.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits;
}
return YES;
}
static BOOL cdsaVerifySignature( CSSM_CSP_HANDLE cspHandle, const CSSM_KEY_PTR key, const CFDataRef msg, const CFDataRef signature )
{
CSSM_CC_HANDLE ccHandle = CSSM_INVALID_HANDLE;
CSSM_DATA_PTR plain = su_createData( msg ), cipher = su_createData( signature );
BOOL retval = NO;
if ( !plain || !cipher || (CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_SHA1WithDSA, NULL, key, &ccHandle) != CSSM_OK) )
goto verify_end;
retval = ( CSSM_VerifyData(ccHandle, plain, 1, CSSM_ALGID_NONE, cipher) == CSSM_OK );
verify_end:
su_freeData( plain, true );
su_freeData( cipher, true );
if ( ccHandle ) CSSM_DeleteContext( ccHandle );
return retval;
}
static CFDataRef cdsaCreateSHA1Digest( CSSM_CSP_HANDLE cspHandle, const CFDataRef bytes )
{
CSSM_CC_HANDLE ccHandle = CSSM_INVALID_HANDLE;
CSSM_DATA_PTR data = su_createData( bytes ), dgst = su_createData( NULL );
CFDataRef retval = NULL;
if ( !data || !dgst || (CSSM_CSP_CreateDigestContext(cspHandle, CSSM_ALGID_SHA1, &ccHandle) != CSSM_OK) )
goto digest_end;
if ( CSSM_DigestData(ccHandle, data, 1, dgst) == CSSM_OK )
retval = CFDataCreate( kCFAllocatorDefault, (const UInt8 *)dgst->Data, (CFIndex)dgst->Length );
digest_end:
su_freeData( data, true );
su_freeData( dgst, true );
if ( ccHandle ) CSSM_DeleteContext( ccHandle );
return retval;
}
/* Memory Functions */
static void *su_malloc( CSSM_SIZE size, void *ref )
{
return malloc( size );
}
static void su_free( void *ptr, void *ref )
{
free( ptr );
}
static void *su_realloc( void *ptr, CSSM_SIZE size, void *ref )
{
return realloc( ptr, size );
}
static void *su_calloc( uint32 num, CSSM_SIZE size, void *ref )
{
return calloc( num, size );
}
/* Helper Functions */
static CSSM_DATA_PTR su_createData( CFDataRef bytes )
{
CSSM_DATA_PTR data = su_malloc( sizeof(CSSM_DATA), NULL );
if ( !data ) return NULL;
data->Data = NULL;
data->Length = 0;
if ( bytes ) su_copyBytesToData( data, CFDataGetLength(bytes), CFDataGetBytePtr(bytes) );
return data;
}
static void su_freeData( CSSM_DATA_PTR data, Boolean freeData )
{
if ( data ) {
if ( freeData && data->Data ) su_free( data->Data, NULL );
su_free( data, NULL );
}
}
static Boolean su_copyBytesToData( CSSM_DATA_PTR data, CSSM_SIZE size, const uint8 *bytes )
{
Boolean retval = false;
if ( size && bytes ) {
if ( (data->Data = su_malloc(size, NULL)) ) {
memcpy( data->Data, bytes, size );
data->Length = size;
retval = true;
}
}
return retval;
}

View File

@ -1,20 +0,0 @@
//
// SUDiskImageUnarchiver.h
// Sparkle
//
// Created by Andy Matuschak on 6/16/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUDISKIMAGEUNARCHIVER_H
#define SUDISKIMAGEUNARCHIVER_H
#import <Cocoa/Cocoa.h>
#import "SUUnarchiver.h"
@interface SUDiskImageUnarchiver : SUUnarchiver {
}
@end
#endif

View File

@ -1,206 +0,0 @@
//
// SUDiskImageUnarchiver.m
// Sparkle
//
// Created by Andy Matuschak on 6/16/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUDiskImageUnarchiver.h"
#import "SUUnarchiver_Private.h"
#import "NTSynchronousTask.h"
#import "SULog.h"
#import <CoreServices/CoreServices.h>
@implementation SUDiskImageUnarchiver
+ (BOOL)canUnarchivePath:(NSString *)path
{
return [[path pathExtension] isEqualToString:@"dmg"];
}
// Called on a non-main thread.
- (void)extractDMG
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSData *result = [NTSynchronousTask task:@"/usr/bin/hdiutil" directory:@"/" withArgs:[NSArray arrayWithObjects: @"isencrypted", archivePath, nil] input:NULL];
if([self isEncrypted:result] && [delegate respondsToSelector:@selector(unarchiver:requiresPasswordReturnedViaInvocation:)]) {
[self performSelectorOnMainThread:@selector(requestPasswordFromDelegate) withObject:nil waitUntilDone:NO];
} else {
[self extractDMGWithPassword:nil];
}
[pool release];
}
// Called on a non-main thread.
- (void)extractDMGWithPassword:(NSString *)password
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
BOOL mountedSuccessfully = NO;
SULog(@"Extracting %@ as a DMG", archivePath);
// get a unique mount point path
NSString *mountPointName = nil;
NSString *mountPoint = nil;
FSRef tmpRef;
do
{
CFUUIDRef uuid = CFUUIDCreate(NULL);
if (uuid)
{
CFStringRef uuidString = CFUUIDCreateString(NULL, uuid);
if (uuidString)
{
mountPoint = [@"/Volumes" stringByAppendingPathComponent:(NSString*)uuidString];
CFRelease(uuidString);
}
CFRelease(uuid);
}
}
while (noErr == FSPathMakeRefWithOptions((UInt8 *)[mountPoint fileSystemRepresentation], kFSPathMakeRefDoNotFollowLeafSymlink, &tmpRef, NULL));
NSData *promptData = nil;
if (password) {
NSString *data = [NSString stringWithFormat:@"%@\nyes\n", password];
const char *bytes = [data cStringUsingEncoding:NSUTF8StringEncoding];
NSUInteger length = [data lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
promptData = [NSData dataWithBytes:bytes length:length];
}
else
promptData = [NSData dataWithBytes:"yes\n" length:4];
NSArray* arguments = [NSArray arrayWithObjects:@"attach", archivePath, @"-mountpoint", mountPoint, /*@"-noverify",*/ @"-nobrowse", @"-noautoopen", nil];
NSData *output = nil;
NSInteger taskResult = -1;
@try
{
NTSynchronousTask* task = [[NTSynchronousTask alloc] init];
[task run:@"/usr/bin/hdiutil" directory:@"/" withArgs:arguments input:promptData];
taskResult = [task result];
output = [[[task output] copy] autorelease];
[task release];
}
@catch (NSException *localException)
{
goto reportError;
}
if (taskResult != 0)
{
NSString* resultStr = output ? [[[NSString alloc] initWithData: output encoding: NSUTF8StringEncoding] autorelease] : nil;
if (password != nil && [resultStr rangeOfString:@"Authentication error"].location != NSNotFound && [delegate respondsToSelector:@selector(unarchiver:requiresPasswordReturnedViaInvocation:)]) {
[self performSelectorOnMainThread:@selector(requestPasswordFromDelegate) withObject:nil waitUntilDone:NO];
goto finally;
} else {
SULog( @"hdiutil failed with code: %d data: <<%@>>", taskResult, resultStr );
goto reportError;
}
}
mountedSuccessfully = YES;
// Now that we've mounted it, we need to copy out its contents.
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) {
// On 10.7 and later we don't want to use the File Manager API and instead want to use NSFileManager (fixes #827357).
NSFileManager *manager = [[[NSFileManager alloc] init] autorelease];
NSError *error = nil;
NSArray *contents = [manager contentsOfDirectoryAtPath:mountPoint error:&error];
if (error)
{
SULog(@"Couldn't enumerate contents of archive mounted at %@: %@", mountPoint, error);
goto reportError;
}
NSEnumerator *contentsEnumerator = [contents objectEnumerator];
NSString *item;
while ((item = [contentsEnumerator nextObject]))
{
NSString *fromPath = [mountPoint stringByAppendingPathComponent:item];
NSString *toPath = [[archivePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:item];
// We skip any files in the DMG which are not readable.
if (![manager isReadableFileAtPath:fromPath])
continue;
SULog(@"copyItemAtPath:%@ toPath:%@", fromPath, toPath);
if (![manager copyItemAtPath:fromPath toPath:toPath error:&error])
{
SULog(@"Couldn't copy item: %@ : %@", error, error.userInfo ? error.userInfo : @"");
goto reportError;
}
}
}
else {
FSRef srcRef, dstRef;
OSStatus err;
err = FSPathMakeRef((UInt8 *)[mountPoint fileSystemRepresentation], &srcRef, NULL);
if (err != noErr) goto reportError;
err = FSPathMakeRef((UInt8 *)[[archivePath stringByDeletingLastPathComponent] fileSystemRepresentation], &dstRef, NULL);
if (err != noErr) goto reportError;
err = FSCopyObjectSync(&srcRef, &dstRef, (CFStringRef)mountPointName, NULL, kFSFileOperationSkipSourcePermissionErrors);
if (err != noErr) goto reportError;
}
[self performSelectorOnMainThread:@selector(notifyDelegateOfSuccess) withObject:nil waitUntilDone:NO];
goto finally;
reportError:
[self performSelectorOnMainThread:@selector(notifyDelegateOfFailure) withObject:nil waitUntilDone:NO];
finally:
if (mountedSuccessfully)
[NSTask launchedTaskWithLaunchPath:@"/usr/bin/hdiutil" arguments:[NSArray arrayWithObjects:@"detach", mountPoint, @"-force", nil]];
else
SULog(@"Can't mount DMG %@",archivePath);
[pool drain];
}
- (void)start
{
[NSThread detachNewThreadSelector:@selector(extractDMG) toTarget:self withObject:nil];
}
+ (void)load
{
[self registerImplementation:self];
}
- (BOOL)isEncrypted:(NSData*)resultData
{
BOOL result = NO;
if(resultData)
{
NSString *data = [NSString stringWithCString:(char*)[resultData bytes] encoding:NSUTF8StringEncoding];
if (!NSEqualRanges([data rangeOfString:@"passphrase-count"], NSMakeRange(NSNotFound, 0)))
{
result = YES;
}
}
return result;
}
- (void)requestPasswordFromDelegate
{
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(continueWithPassword:)]];
[invocation setSelector:@selector(continueWithPassword:)];
[invocation setTarget:self];
[invocation retainArguments];
[delegate unarchiver:self requiresPasswordReturnedViaInvocation:invocation];
}
- (void)continueWithPassword:(NSString *)password
{
[NSThread detachNewThreadSelector:@selector(extractDMGWithPassword:) toTarget:self withObject:password];
}
@end

View File

@ -1,45 +0,0 @@
//
// SUHost.h
// Sparkle
//
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUUpdater.h"
#import "SUAppcast.h"
#import "SUAppcastItem.h"
#import "SUVersionComparisonProtocol.h"
@interface SUHost : NSObject
{
@private
NSBundle *bundle;
NSString *defaultsDomain;
BOOL usesStandardUserDefaults;
}
+ (NSString *)systemVersionString;
- (id)initWithBundle:(NSBundle *)aBundle;
- (NSBundle *)bundle;
- (NSString *)bundlePath;
- (NSString *)appSupportPath;
- (NSString *)installationPath;
- (NSString *)name;
- (NSString *)version;
- (NSString *)displayVersion;
- (NSImage *)icon;
- (BOOL)isRunningOnReadOnlyVolume;
- (BOOL)isBackgroundApplication;
- (NSString *)publicDSAKey;
- (NSArray *)systemProfile;
- (id)objectForInfoDictionaryKey:(NSString *)key;
- (BOOL)boolForInfoDictionaryKey:(NSString *)key;
- (id)objectForUserDefaultsKey:(NSString *)defaultName;
- (void)setObject:(id)value forUserDefaultsKey:(NSString *)defaultName;
- (BOOL)boolForUserDefaultsKey:(NSString *)defaultName;
- (void)setBool:(BOOL)value forUserDefaultsKey:(NSString *)defaultName;
- (id)objectForKey:(NSString *)key;
- (BOOL)boolForKey:(NSString *)key;
@end

View File

@ -1,270 +0,0 @@
//
// SUHost.m
// Sparkle
//
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUHost.h"
#import "SUConstants.h"
#import "SUSystemProfiler.h"
#import <sys/mount.h> // For statfs for isRunningOnReadOnlyVolume
#import "SULog.h"
@implementation SUHost
- (id)initWithBundle:(NSBundle *)aBundle
{
if ((self = [super init]))
{
if (aBundle == nil) aBundle = [NSBundle mainBundle];
bundle = [aBundle retain];
if (![bundle bundleIdentifier])
SULog(@"Sparkle Error: the bundle being updated at %@ has no CFBundleIdentifier! This will cause preference read/write to not work properly.", bundle);
defaultsDomain = [[bundle objectForInfoDictionaryKey:SUDefaultsDomainKey] retain];
if (!defaultsDomain)
defaultsDomain = [[bundle bundleIdentifier] retain];
// If we're using the main bundle's defaults we'll use the standard user defaults mechanism, otherwise we have to get CF-y.
usesStandardUserDefaults = [defaultsDomain isEqualToString:[[NSBundle mainBundle] bundleIdentifier]];
}
return self;
}
- (void)dealloc
{
[defaultsDomain release];
[bundle release];
[super dealloc];
}
- (NSString *)description { return [NSString stringWithFormat:@"%@ <%@, %@>", [self class], [self bundlePath], [self installationPath]]; }
- (NSBundle *)bundle
{
return bundle;
}
- (NSString *)bundlePath
{
return [bundle bundlePath];
}
- (NSString *)appSupportPath
{
NSArray *appSupportPaths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *appSupportPath = nil;
if (!appSupportPaths || [appSupportPaths count] == 0)
{
SULog(@"Failed to find app support directory! Using ~/Library/Application Support...");
appSupportPath = [@"~/Library/Application Support" stringByExpandingTildeInPath];
}
else
appSupportPath = [appSupportPaths objectAtIndex:0];
appSupportPath = [appSupportPath stringByAppendingPathComponent:[self name]];
return appSupportPath;
}
- (NSString *)installationPath
{
#if NORMALIZE_INSTALLED_APP_NAME
// We'll install to "#{CFBundleName}.app", but only if that path doesn't already exist. If we're "Foo 4.2.app," and there's a "Foo.app" in this directory, we don't want to overwrite it! But if there's no "Foo.app," we'll take that name.
NSString *normalizedAppPath = [[[bundle bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent: [NSString stringWithFormat: @"%@.%@", [bundle objectForInfoDictionaryKey:@"CFBundleName"], [[bundle bundlePath] pathExtension]]];
if (![[NSFileManager defaultManager] fileExistsAtPath:[[[bundle bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent: [NSString stringWithFormat: @"%@.%@", [bundle objectForInfoDictionaryKey:@"CFBundleName"], [[bundle bundlePath] pathExtension]]]])
return normalizedAppPath;
#endif
return [bundle bundlePath];
}
- (NSString *)name
{
NSString *name = [bundle objectForInfoDictionaryKey:@"CFBundleDisplayName"];
if (name) return name;
name = [self objectForInfoDictionaryKey:@"CFBundleName"];
if (name) return name;
return [[[NSFileManager defaultManager] displayNameAtPath:[bundle bundlePath]] stringByDeletingPathExtension];
}
- (NSString *)version
{
NSString *version = [bundle objectForInfoDictionaryKey:@"CFBundleVersion"];
if (!version || [version isEqualToString:@""])
[NSException raise:@"SUNoVersionException" format:@"This host (%@) has no CFBundleVersion! This attribute is required.", [self bundlePath]];
return version;
}
- (NSString *)displayVersion
{
NSString *shortVersionString = [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
if (shortVersionString)
return shortVersionString;
else
return [self version]; // Fall back on the normal version string.
}
- (NSImage *)icon
{
// Cache the application icon.
NSString *iconPath = [bundle pathForResource:[bundle objectForInfoDictionaryKey:@"CFBundleIconFile"] ofType:@"icns"];
// According to the OS X docs, "CFBundleIconFile - This key identifies the file containing
// the icon for the bundle. The filename you specify does not need to include the .icns
// extension, although it may."
//
// However, if it *does* include the '.icns' the above method fails (tested on OS X 10.3.9) so we'll also try:
if (!iconPath)
iconPath = [bundle pathForResource:[bundle objectForInfoDictionaryKey:@"CFBundleIconFile"] ofType: nil];
NSImage *icon = [[[NSImage alloc] initWithContentsOfFile:iconPath] autorelease];
// Use a default icon if none is defined.
if (!icon) {
BOOL isMainBundle = (bundle == [NSBundle mainBundle]);
// Starting with 10.6, iconForFileType: accepts a UTI.
NSString *fileType = nil;
if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_5)
fileType = isMainBundle ? NSFileTypeForHFSTypeCode(kGenericApplicationIcon) : @".bundle";
else
fileType = isMainBundle ? (NSString*)kUTTypeApplication : (NSString*)kUTTypeBundle;
icon = [[NSWorkspace sharedWorkspace] iconForFileType:fileType];
}
return icon;
}
- (BOOL)isRunningOnReadOnlyVolume
{
struct statfs statfs_info;
statfs([[bundle bundlePath] fileSystemRepresentation], &statfs_info);
return (statfs_info.f_flags & MNT_RDONLY);
}
- (BOOL)isBackgroundApplication
{
ProcessSerialNumber PSN;
GetCurrentProcess(&PSN);
CFDictionaryRef processInfo = ProcessInformationCopyDictionary(&PSN, kProcessDictionaryIncludeAllInformationMask);
BOOL isElement = [[(NSDictionary *)processInfo objectForKey:@"LSUIElement"] boolValue];
if (processInfo)
CFRelease(processInfo);
return isElement;
}
- (NSString *)publicDSAKey
{
// Maybe the key is just a string in the Info.plist.
NSString *key = [bundle objectForInfoDictionaryKey:SUPublicDSAKeyKey];
if (key) { return key; }
// More likely, we've got a reference to a Resources file by filename:
NSString *keyFilename = [self objectForInfoDictionaryKey:SUPublicDSAKeyFileKey];
if (!keyFilename) { return nil; }
NSError *ignoreErr = nil;
return [NSString stringWithContentsOfFile:[bundle pathForResource:keyFilename ofType:nil] encoding:NSASCIIStringEncoding error: &ignoreErr];
}
- (NSArray *)systemProfile
{
return [[SUSystemProfiler sharedSystemProfiler] systemProfileArrayForHost:self];
}
- (id)objectForInfoDictionaryKey:(NSString *)key
{
return [bundle objectForInfoDictionaryKey:key];
}
- (BOOL)boolForInfoDictionaryKey:(NSString *)key
{
return [[self objectForInfoDictionaryKey:key] boolValue];
}
- (id)objectForUserDefaultsKey:(NSString *)defaultName
{
// Under Tiger, CFPreferencesCopyAppValue doesn't get values from NSRegistrationDomain, so anything
// passed into -[NSUserDefaults registerDefaults:] is ignored. The following line falls
// back to using NSUserDefaults, but only if the host bundle is the main bundle.
if (usesStandardUserDefaults)
return [[NSUserDefaults standardUserDefaults] objectForKey:defaultName];
CFPropertyListRef obj = CFPreferencesCopyAppValue((CFStringRef)defaultName, (CFStringRef)defaultsDomain);
return [(id)CFMakeCollectable(obj) autorelease];
}
- (void)setObject:(id)value forUserDefaultsKey:(NSString *)defaultName;
{
if (usesStandardUserDefaults)
{
[[NSUserDefaults standardUserDefaults] setObject:value forKey:defaultName];
}
else
{
CFPreferencesSetValue((CFStringRef)defaultName, value, (CFStringRef)defaultsDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
CFPreferencesSynchronize((CFStringRef)defaultsDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
}
}
- (BOOL)boolForUserDefaultsKey:(NSString *)defaultName
{
if (usesStandardUserDefaults)
return [[NSUserDefaults standardUserDefaults] boolForKey:defaultName];
BOOL value;
CFPropertyListRef plr = CFPreferencesCopyAppValue((CFStringRef)defaultName, (CFStringRef)defaultsDomain);
if (plr == NULL)
value = NO;
else
{
value = (BOOL)CFBooleanGetValue((CFBooleanRef)plr);
CFRelease(plr);
}
return value;
}
- (void)setBool:(BOOL)value forUserDefaultsKey:(NSString *)defaultName
{
if (usesStandardUserDefaults)
{
[[NSUserDefaults standardUserDefaults] setBool:value forKey:defaultName];
}
else
{
CFPreferencesSetValue((CFStringRef)defaultName, (CFBooleanRef)[NSNumber numberWithBool:value], (CFStringRef)defaultsDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
CFPreferencesSynchronize((CFStringRef)defaultsDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
}
}
- (id)objectForKey:(NSString *)key {
return [self objectForUserDefaultsKey:key] ? [self objectForUserDefaultsKey:key] : [self objectForInfoDictionaryKey:key];
}
- (BOOL)boolForKey:(NSString *)key {
return [self objectForUserDefaultsKey:key] ? [self boolForUserDefaultsKey:key] : [self boolForInfoDictionaryKey:key];
}
+ (NSString *)systemVersionString
{
// This returns a version string of the form X.Y.Z
// There may be a better way to deal with the problem that gestaltSystemVersionMajor
// et al. are not defined in 10.3, but this is probably good enough.
NSString* verStr = nil;
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4
SInt32 major, minor, bugfix;
OSErr err1 = Gestalt(gestaltSystemVersionMajor, &major);
OSErr err2 = Gestalt(gestaltSystemVersionMinor, &minor);
OSErr err3 = Gestalt(gestaltSystemVersionBugFix, &bugfix);
if (!err1 && !err2 && !err3)
{
verStr = [NSString stringWithFormat:@"%ld.%ld.%ld", (long)major, (long)minor, (long)bugfix];
}
else
#endif
{
NSString *versionPlistPath = @"/System/Library/CoreServices/SystemVersion.plist";
verStr = [[NSDictionary dictionaryWithContentsOfFile:versionPlistPath] objectForKey:@"ProductVersion"];
}
return verStr;
}
@end

View File

@ -1,29 +0,0 @@
//
// SUInstaller.h
// Sparkle
//
// Created by Andy Matuschak on 4/10/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUINSTALLER_H
#define SUINSTALLER_H
#import <Cocoa/Cocoa.h>
#import "SUVersionComparisonProtocol.h"
@class SUHost;
@interface SUInstaller : NSObject { }
+ (NSString *) appPathInUpdateFolder:(NSString *)updateFolder forHost:(SUHost *)host;
+ (void) installFromUpdateFolder:(NSString *)updateFolder overHost:(SUHost *)host installationPath:(NSString *)installationPath delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator;
+ (void) finishInstallationToPath:(NSString *)installationPath withResult:(BOOL)result host:(SUHost *)host error:(NSError *)error delegate:delegate;
+ (NSString*) updateFolder;
+ (void) notifyDelegateOfFailure: (NSDictionary*)dict;
@end
@interface NSObject (SUInstallerDelegateInformalProtocol)
- (void)installerFinishedForHost:(SUHost *)host;
- (void)installerForHost:(SUHost *)host failedWithError:(NSError *)error;
@end
#endif

View File

@ -1,182 +0,0 @@
//
// SUInstaller.m
// Sparkle
//
// Created by Andy Matuschak on 4/10/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUInstaller.h"
#import "SUPlainInstaller.h"
#import "SUPackageInstaller.h"
#import "SUHost.h"
#import "SUConstants.h"
#import "SULog.h"
@implementation SUInstaller
static NSString* sUpdateFolder = nil;
+(NSString*) updateFolder
{
return sUpdateFolder;
}
+ (BOOL)isAliasFolderAtPath:(NSString *)path
{
FSRef fileRef;
OSStatus err = noErr;
Boolean aliasFileFlag, folderFlag;
NSURL *fileURL = [NSURL fileURLWithPath:path];
if (FALSE == CFURLGetFSRef((CFURLRef)fileURL, &fileRef))
err = coreFoundationUnknownErr;
if (noErr == err)
err = FSIsAliasFile(&fileRef, &aliasFileFlag, &folderFlag);
if (noErr == err)
return (BOOL)(aliasFileFlag && folderFlag);
else
return NO;
}
+ (NSString *)installSourcePathInUpdateFolder:(NSString *)inUpdateFolder forHost:(SUHost *)host isPackage:(BOOL *)isPackagePtr
{
// Search subdirectories for the application
NSString *currentFile,
*newAppDownloadPath = nil,
*bundleFileName = [[host bundlePath] lastPathComponent],
*alternateBundleFileName = [[host name] stringByAppendingPathExtension:[[host bundlePath] pathExtension]];
BOOL isPackage = NO;
NSString *fallbackPackagePath = nil;
NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath: inUpdateFolder];
[sUpdateFolder release];
sUpdateFolder = [inUpdateFolder retain];
while ((currentFile = [dirEnum nextObject]))
{
NSString *currentPath = [inUpdateFolder stringByAppendingPathComponent:currentFile];
if ([[currentFile lastPathComponent] isEqualToString:bundleFileName] ||
[[currentFile lastPathComponent] isEqualToString:alternateBundleFileName]) // We found one!
{
isPackage = NO;
newAppDownloadPath = currentPath;
break;
}
else if ([[currentFile pathExtension] isEqualToString:@"pkg"] ||
[[currentFile pathExtension] isEqualToString:@"mpkg"])
{
if ([[[currentFile lastPathComponent] stringByDeletingPathExtension] isEqualToString:[bundleFileName stringByDeletingPathExtension]])
{
isPackage = YES;
newAppDownloadPath = currentPath;
break;
}
else
{
// Remember any other non-matching packages we have seen should we need to use one of them as a fallback.
fallbackPackagePath = currentPath;
}
}
else
{
// Try matching on bundle identifiers in case the user has changed the name of the host app
NSBundle *incomingBundle = [NSBundle bundleWithPath:currentPath];
if(incomingBundle && [[incomingBundle bundleIdentifier] isEqualToString:[[host bundle] bundleIdentifier]])
{
isPackage = NO;
newAppDownloadPath = currentPath;
break;
}
}
// Some DMGs have symlinks into /Applications! That's no good!
if ([self isAliasFolderAtPath:currentPath])
[dirEnum skipDescendents];
}
// We don't have a valid path. Try to use the fallback package.
if (newAppDownloadPath == nil && fallbackPackagePath != nil)
{
isPackage = YES;
newAppDownloadPath = fallbackPackagePath;
}
if (isPackagePtr) *isPackagePtr = isPackage;
return newAppDownloadPath;
}
+ (NSString *)appPathInUpdateFolder:(NSString *)updateFolder forHost:(SUHost *)host
{
BOOL isPackage = NO;
NSString *path = [self installSourcePathInUpdateFolder:updateFolder forHost:host isPackage:&isPackage];
return isPackage ? nil : path;
}
+ (void)installFromUpdateFolder:(NSString *)inUpdateFolder overHost:(SUHost *)host installationPath:(NSString *)installationPath delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator
{
BOOL isPackage = NO;
NSString *newAppDownloadPath = [self installSourcePathInUpdateFolder:inUpdateFolder forHost:host isPackage:&isPackage];
if (newAppDownloadPath == nil)
{
[self finishInstallationToPath:installationPath withResult:NO host:host error:[NSError errorWithDomain:SUSparkleErrorDomain code:SUMissingUpdateError userInfo:[NSDictionary dictionaryWithObject:@"Couldn't find an appropriate update in the downloaded package." forKey:NSLocalizedDescriptionKey]] delegate:delegate];
}
else
{
[(isPackage ? [SUPackageInstaller class] : [SUPlainInstaller class]) performInstallationToPath:installationPath fromPath:newAppDownloadPath host:host delegate:delegate synchronously:synchronously versionComparator:comparator];
}
}
+ (void)mdimportInstallationPath:(NSString *)installationPath
{
// *** GETS CALLED ON NON-MAIN THREAD!
SULog( @"mdimporting" );
NSTask *mdimport = [[[NSTask alloc] init] autorelease];
[mdimport setLaunchPath:@"/usr/bin/mdimport"];
[mdimport setArguments:[NSArray arrayWithObject:installationPath]];
@try
{
[mdimport launch];
[mdimport waitUntilExit];
}
@catch (NSException * launchException)
{
// No big deal.
SULog(@"Sparkle Error: %@", [launchException description]);
}
}
#define SUNotifyDictHostKey @"SUNotifyDictHost"
#define SUNotifyDictErrorKey @"SUNotifyDictError"
#define SUNotifyDictDelegateKey @"SUNotifyDictDelegate"
+ (void)finishInstallationToPath:(NSString *)installationPath withResult:(BOOL)result host:(SUHost *)host error:(NSError *)error delegate:delegate
{
if (result)
{
[self mdimportInstallationPath:installationPath];
if ([delegate respondsToSelector:@selector(installerFinishedForHost:)])
[delegate performSelectorOnMainThread: @selector(installerFinishedForHost:) withObject: host waitUntilDone: NO];
}
else
{
if ([delegate respondsToSelector:@selector(installerForHost:failedWithError:)])
[self performSelectorOnMainThread: @selector(notifyDelegateOfFailure:) withObject: [NSDictionary dictionaryWithObjectsAndKeys: host, SUNotifyDictHostKey, error, SUNotifyDictErrorKey, delegate, SUNotifyDictDelegateKey, nil] waitUntilDone: NO];
}
}
+(void) notifyDelegateOfFailure: (NSDictionary*)dict
{
[[dict objectForKey: SUNotifyDictDelegateKey] installerForHost: [dict objectForKey: SUNotifyDictHostKey] failedWithError: [dict objectForKey: SUNotifyDictErrorKey]];
}
@end

View File

@ -1,31 +0,0 @@
/*
* SULog.h
* EyeTV
*
* Created by Uli Kusterer on 12/03/2009.
* Copyright 2008 Elgato Systems GmbH. All rights reserved.
*
*/
/*
Log output for troubleshooting Sparkle failures on end-user machines.
Your tech support will hug you if you tell them about this.
*/
#pragma once
// -----------------------------------------------------------------------------
// Headers:
// -----------------------------------------------------------------------------
#include <Foundation/Foundation.h>
// -----------------------------------------------------------------------------
// Prototypes:
// -----------------------------------------------------------------------------
void SUClearLog( void );
void SULog( NSString* format, ... );

View File

@ -1,80 +0,0 @@
/*
* SULog.m
* EyeTV
*
* Created by Uli Kusterer on 12/03/2009.
* Copyright 2009 Elgato Systems GmbH. All rights reserved.
*
*/
// -----------------------------------------------------------------------------
// Headers:
// -----------------------------------------------------------------------------
#include "SULog.h"
// -----------------------------------------------------------------------------
// Constants:
// -----------------------------------------------------------------------------
#define LOG_FILE_PATH @"~/Library/Logs/SparkleUpdateLog.log"
// -----------------------------------------------------------------------------
// SUClearLog:
// Erase the log at the start of an update. We don't want to litter the
// user's hard disk with logging data that's mostly unused, so each app
// should clear the log before it starts updating, so only the most recent
// update is kept around.
//
// TAKES:
// sender - Object that sent this message, typically of type X.
//
// GIVES:
// param - who owns the returned value?
// result - same here.
// -----------------------------------------------------------------------------
void SUClearLog( void )
{
FILE* logfile = fopen([[LOG_FILE_PATH stringByExpandingTildeInPath] fileSystemRepresentation],"w");
if( logfile )
fclose(logfile);
else
NSLog(@"----- Sparkle Log -----");
}
// -----------------------------------------------------------------------------
// SULog:
// Like NSLog, but logs to one specific log file. Each line is prefixed
// with the current date and time, to help in regressing issues.
//
// TAKES:
// format - NSLog/printf-style format string.
// ... - More parameters depending on format string's contents.
// -----------------------------------------------------------------------------
void SULog( NSString* format, ... )
{
va_list ap;
va_start(ap, format);
NSString* theStr = [[[NSString alloc] initWithFormat: format arguments: ap] autorelease];
FILE* logfile = fopen([[LOG_FILE_PATH stringByExpandingTildeInPath] fileSystemRepresentation],"a");
if( !logfile )
NSLog( @"%@",theStr );
else
{
theStr = [NSString stringWithFormat: @"%@: %@", [NSDate date], theStr];
NSData* theData = [theStr dataUsingEncoding: NSUTF8StringEncoding];
char newlineChar = '\n';
fwrite( [theData bytes], 1, [theData length], logfile );
fwrite( &newlineChar, 1, 1, logfile ); // Append a newline.
fclose( logfile );
logfile = NULL;
}
va_end(ap);
}

View File

@ -1,182 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ADP2,1</key>
<string>Developer Transition Kit</string>
<key>iMac1,1</key>
<string>iMac G3 (Rev A-D)</string>
<key>iMac4,1</key>
<string>iMac (Core Duo)</string>
<key>iMac4,2</key>
<string>iMac for Education (17-inch, Core Duo)</string>
<key>iMac5,1</key>
<string>iMac (Core 2 Duo, 17 or 20 inch, SuperDrive)</string>
<key>iMac5,2</key>
<string>iMac (Core 2 Duo, 17 inch, Combo Drive)</string>
<key>iMac6,1</key>
<string>iMac (Core 2 Duo, 24 inch, SuperDrive)</string>
<key>iMac8,1</key>
<string>iMac (April 2008)</string>
<key>MacBook1,1</key>
<string>MacBook (Core Duo)</string>
<key>MacBook2,1</key>
<string>MacBook (Core 2 Duo)</string>
<key>MacBook4,1</key>
<string>MacBook (Core 2 Duo Feb 2008)</string>
<key>MacBookAir1,1</key>
<string>MacBook Air (January 2008)</string>
<key>MacBookAir2,1</key>
<string>MacBook Air (June 2009)</string>
<key>MacBookAir3,1</key>
<string>MacBook Air (October 2010)</string>
<key>MacBookPro1,1</key>
<string>MacBook Pro Core Duo (15-inch)</string>
<key>MacBookPro1,2</key>
<string>MacBook Pro Core Duo (17-inch)</string>
<key>MacBookPro2,1</key>
<string>MacBook Pro Core 2 Duo (17-inch)</string>
<key>MacBookPro2,2</key>
<string>MacBook Pro Core 2 Duo (15-inch)</string>
<key>MacBookPro3,1</key>
<string>MacBook Pro Core 2 Duo (15-inch LED, Core 2 Duo)</string>
<key>MacBookPro3,2</key>
<string>MacBook Pro Core 2 Duo (17-inch HD, Core 2 Duo)</string>
<key>MacBookPro4,1</key>
<string>MacBook Pro (Core 2 Duo Feb 2008)</string>
<key>Macmini1,1</key>
<string>Mac Mini (Core Solo/Duo)</string>
<key>MacPro1,1</key>
<string>Mac Pro (four-core)</string>
<key>MacPro2,1</key>
<string>Mac Pro (eight-core)</string>
<key>MacPro3,1</key>
<string>Mac Pro (January 2008 4- or 8- core &quot;Harpertown&quot;)</string>
<key>MacPro4,1</key>
<string>Mac Pro (March 2009)</string>
<key>MacPro5,1</key>
<string>Mac Pro (August 2010)</string>
<key>PowerBook1,1</key>
<string>PowerBook G3</string>
<key>PowerBook2,1</key>
<string>iBook G3</string>
<key>PowerBook2,2</key>
<string>iBook G3 (FireWire)</string>
<key>PowerBook2,3</key>
<string>iBook G3</string>
<key>PowerBook2,4</key>
<string>iBook G3</string>
<key>PowerBook3,1</key>
<string>PowerBook G3 (FireWire)</string>
<key>PowerBook3,2</key>
<string>PowerBook G4</string>
<key>PowerBook3,3</key>
<string>PowerBook G4 (Gigabit Ethernet)</string>
<key>PowerBook3,4</key>
<string>PowerBook G4 (DVI)</string>
<key>PowerBook3,5</key>
<string>PowerBook G4 (1GHz / 867MHz)</string>
<key>PowerBook4,1</key>
<string>iBook G3 (Dual USB, Late 2001)</string>
<key>PowerBook4,2</key>
<string>iBook G3 (16MB VRAM)</string>
<key>PowerBook4,3</key>
<string>iBook G3 Opaque 16MB VRAM, 32MB VRAM, Early 2003)</string>
<key>PowerBook5,1</key>
<string>PowerBook G4 (17 inch)</string>
<key>PowerBook5,2</key>
<string>PowerBook G4 (15 inch FW 800)</string>
<key>PowerBook5,3</key>
<string>PowerBook G4 (17-inch 1.33GHz)</string>
<key>PowerBook5,4</key>
<string>PowerBook G4 (15 inch 1.5/1.33GHz)</string>
<key>PowerBook5,5</key>
<string>PowerBook G4 (17-inch 1.5GHz)</string>
<key>PowerBook5,6</key>
<string>PowerBook G4 (15 inch 1.67GHz/1.5GHz)</string>
<key>PowerBook5,7</key>
<string>PowerBook G4 (17-inch 1.67GHz)</string>
<key>PowerBook5,8</key>
<string>PowerBook G4 (Double layer SD, 15 inch)</string>
<key>PowerBook5,9</key>
<string>PowerBook G4 (Double layer SD, 17 inch)</string>
<key>PowerBook6,1</key>
<string>PowerBook G4 (12 inch)</string>
<key>PowerBook6,2</key>
<string>PowerBook G4 (12 inch, DVI)</string>
<key>PowerBook6,3</key>
<string>iBook G4</string>
<key>PowerBook6,4</key>
<string>PowerBook G4 (12 inch 1.33GHz)</string>
<key>PowerBook6,5</key>
<string>iBook G4 (Early-Late 2004)</string>
<key>PowerBook6,7</key>
<string>iBook G4 (Mid 2005)</string>
<key>PowerBook6,8</key>
<string>PowerBook G4 (12 inch 1.5GHz)</string>
<key>PowerMac1,1</key>
<string>Power Macintosh G3 (Blue &amp; White)</string>
<key>PowerMac1,2</key>
<string>Power Macintosh G4 (PCI Graphics)</string>
<key>PowerMac10,1</key>
<string>Mac Mini G4</string>
<key>PowerMac10,2</key>
<string>Mac Mini (Late 2005)</string>
<key>PowerMac11,2</key>
<string>Power Macintosh G5 (Late 2005)</string>
<key>PowerMac12,1</key>
<string>iMac G5 (iSight)</string>
<key>PowerMac2,1</key>
<string>iMac G3 (Slot-loading CD-ROM)</string>
<key>PowerMac2,2</key>
<string>iMac G3 (Summer 2000)</string>
<key>PowerMac3,1</key>
<string>Power Macintosh G4 (AGP Graphics)</string>
<key>PowerMac3,2</key>
<string>Power Macintosh G4 (AGP Graphics)</string>
<key>PowerMac3,3</key>
<string>Power Macintosh G4 (Gigabit Ethernet)</string>
<key>PowerMac3,4</key>
<string>Power Macintosh G4 (Digital Audio)</string>
<key>PowerMac3,5</key>
<string>Power Macintosh G4 (Quick Silver)</string>
<key>PowerMac3,6</key>
<string>Power Macintosh G4 (Mirrored Drive Door)</string>
<key>PowerMac4,1</key>
<string>iMac G3 (Early/Summer 2001)</string>
<key>PowerMac4,2</key>
<string>iMac G4 (Flat Panel)</string>
<key>PowerMac4,4</key>
<string>eMac</string>
<key>PowerMac4,5</key>
<string>iMac G4 (17-inch Flat Panel)</string>
<key>PowerMac5,1</key>
<string>Power Macintosh G4 Cube</string>
<key>PowerMac6,1</key>
<string>iMac G4 (USB 2.0)</string>
<key>PowerMac6,3</key>
<string>iMac G4 (20-inch Flat Panel)</string>
<key>PowerMac6,4</key>
<string>eMac (USB 2.0, 2005)</string>
<key>PowerMac7,2</key>
<string>Power Macintosh G5</string>
<key>PowerMac7,3</key>
<string>Power Macintosh G5</string>
<key>PowerMac8,1</key>
<string>iMac G5</string>
<key>PowerMac8,2</key>
<string>iMac G5 (Ambient Light Sensor)</string>
<key>PowerMac9,1</key>
<string>Power Macintosh G5 (Late 2005)</string>
<key>RackMac1,1</key>
<string>Xserve G4</string>
<key>RackMac1,2</key>
<string>Xserve G4 (slot-loading, cluster node)</string>
<key>RackMac3,1</key>
<string>Xserve G5</string>
<key>Xserve1,1</key>
<string>Xserve (Intel Xeon)</string>
<key>Xserve2,1</key>
<string>Xserve (January 2008 quad-core)</string>
</dict>
</plist>

View File

@ -1,22 +0,0 @@
//
// SUPackageInstaller.h
// Sparkle
//
// Created by Andy Matuschak on 4/10/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUPACKAGEINSTALLER_H
#define SUPACKAGEINSTALLER_H
#import "SUUpdater.h"
#import "SUAppcast.h"
#import "SUAppcastItem.h"
#import "SUVersionComparisonProtocol.h"
#import "SUPlainInstaller.h"
@interface SUPackageInstaller : SUPlainInstaller { }
@end
#endif

View File

@ -1,72 +0,0 @@
//
// SUPackageInstaller.m
// Sparkle
//
// Created by Andy Matuschak on 4/10/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUPackageInstaller.h"
#import <Cocoa/Cocoa.h>
#import "SUConstants.h"
NSString *SUPackageInstallerCommandKey = @"SUPackageInstallerCommand";
NSString *SUPackageInstallerArgumentsKey = @"SUPackageInstallerArguments";
NSString *SUPackageInstallerHostKey = @"SUPackageInstallerHost";
NSString *SUPackageInstallerDelegateKey = @"SUPackageInstallerDelegate";
NSString *SUPackageInstallerInstallationPathKey = @"SUPackageInstallerInstallationPathKey";
@implementation SUPackageInstaller
+ (void)finishInstallationWithInfo:(NSDictionary *)info
{
[self finishInstallationToPath:[info objectForKey:SUPackageInstallerInstallationPathKey] withResult:YES host:[info objectForKey:SUPackageInstallerHostKey] error:nil delegate:[info objectForKey:SUPackageInstallerDelegateKey]];
}
+ (void)performInstallationWithInfo:(NSDictionary *)info
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSTask *installer = [NSTask launchedTaskWithLaunchPath:[info objectForKey:SUPackageInstallerCommandKey] arguments:[info objectForKey:SUPackageInstallerArgumentsKey]];
[installer waitUntilExit];
// Known bug: if the installation fails or is canceled, Sparkle goes ahead and restarts, thinking everything is fine.
[self performSelectorOnMainThread:@selector(finishInstallationWithInfo:) withObject:info waitUntilDone:NO];
[pool drain];
}
+ (void)performInstallationToPath:(NSString *)installationPath fromPath:(NSString *)path host:(SUHost *)host delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator
{
NSString *command;
NSArray *args;
if (floor(NSAppKitVersionNumber) == NSAppKitVersionNumber10_4) {
// 10.4 uses Installer.app because the "open" command in 10.4 doesn't support -W and -n
command = [[NSBundle bundleWithIdentifier:@"com.apple.installer"] executablePath];
args = [NSArray arrayWithObjects:path, nil];
} else {
// 10.5 and later. Run installer using the "open" command to ensure it is launched in front of current application.
// The -W and -n options were added to the 'open' command in 10.5
// -W = wait until the app has quit.
// -n = Open another instance if already open.
// -b = app bundle identifier
command = @"/usr/bin/open";
args = [NSArray arrayWithObjects:@"-W", @"-n", @"-b", @"com.apple.installer", path, nil];
}
if (![[NSFileManager defaultManager] fileExistsAtPath:command])
{
NSError *error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUMissingInstallerToolError userInfo:[NSDictionary dictionaryWithObject:@"Couldn't find Apple's installer tool!" forKey:NSLocalizedDescriptionKey]];
[self finishInstallationToPath:installationPath withResult:NO host:host error:error delegate:delegate];
}
else
{
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:command, SUPackageInstallerCommandKey, args, SUPackageInstallerArgumentsKey, host, SUPackageInstallerHostKey, delegate, SUPackageInstallerDelegateKey, installationPath, SUPackageInstallerInstallationPathKey, nil];
if (synchronously)
[self performInstallationWithInfo:info];
else
[NSThread detachNewThreadSelector:@selector(performInstallationWithInfo:) toTarget:self withObject:info];
}
}
@end

View File

@ -1,26 +0,0 @@
//
// SUPasswordPrompt.h
// Sparkle
//
// Created by rudy on 8/18/09.
// Copyright 2009 Ambrosia Software, Inc.. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "Sparkle/SUWindowController.h"
@interface SUPasswordPrompt : SUWindowController
{
IBOutlet NSImageView *mIconView;
IBOutlet NSTextField *mTextDescription;
IBOutlet NSSecureTextField *mPasswordField;
NSString *mPassword;
NSString *mName;
NSImage *mIcon;
}
- (id)initWithHost:(SUHost *)aHost;
- (NSInteger)run;
- (NSString *)password;
@end

View File

@ -1,86 +0,0 @@
//
// SUPasswordPrompt.m
// Sparkle
//
// Created by rudy on 8/18/09.
// Copyright 2009 Ambrosia Software, Inc.. All rights reserved.
//
#import "SUPasswordPrompt.h"
@implementation SUPasswordPrompt
- (id)initWithHost:(SUHost *)aHost
{
self = [super initWithHost:aHost windowNibName:@"SUPasswordPrompt"];
if (self)
{
[self setName:[aHost name]];
[self setIcon:[aHost icon]];
mPassword = nil;
[self setShouldCascadeWindows:NO];
}
return self;
}
- (void)awakeFromNib
{
[mIconView setImage:[self icon]];
}
- (void)setName:(NSString*)name
{
[mName release];
mName = [name retain];
}
- (NSString*)name
{
return mName;
}
- (void)setIcon:(NSImage*)icon
{
[mIcon release];
mIcon = [icon retain];
}
- (NSImage*)icon
{
return mIcon;
}
- (NSString *)password
{
return mPassword;
}
- (void)setPassword:(NSString*)password
{
[mPassword release];
mPassword = [password retain];
}
- (NSInteger)run
{
//modally run a password prompt
NSInteger result = [NSApp runModalForWindow:[self window]];
if(result)
[self setPassword:[mPasswordField stringValue]];
return result;
}
- (IBAction)accept:(id)sender
{
[[self window] orderOut:self];
[NSApp stopModalWithCode:1];
}
- (IBAction)cancel:(id)sender
{
[[self window] orderOut:self];
[NSApp stopModalWithCode:0];
}
@end

View File

@ -1,21 +0,0 @@
//
// SUPipedUnarchiver.h
// Sparkle
//
// Created by Andy Matuschak on 6/16/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUPIPEDUNARCHIVER_H
#define SUPIPEDUNARCHIVER_H
#import <Cocoa/Cocoa.h>
#import "SUUnarchiver.h"
@interface SUPipedUnarchiver : SUUnarchiver {
}
@end
#endif

View File

@ -1,144 +0,0 @@
//
// SUPipedUnarchiver.m
// Sparkle
//
// Created by Andy Matuschak on 6/16/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUPipedUnarchiver.h"
#import "SUUnarchiver_Private.h"
#import "SULog.h"
@implementation SUPipedUnarchiver
+ (SEL)selectorConformingToTypeOfPath:(NSString *)path
{
static NSDictionary *typeSelectorDictionary;
if (!typeSelectorDictionary)
typeSelectorDictionary = [[NSDictionary dictionaryWithObjectsAndKeys:@"extractZIP", @".zip", @"extractTAR", @".tar",
@"extractTGZ", @".tar.gz", @"extractTGZ", @".tgz",
@"extractTBZ", @".tar.bz2", @"extractTBZ", @".tbz", nil] retain];
NSString *lastPathComponent = [path lastPathComponent];
NSEnumerator *typeEnumerator = [typeSelectorDictionary keyEnumerator];
id currentType;
while ((currentType = [typeEnumerator nextObject]))
{
if ([currentType length] > [lastPathComponent length]) continue;
if ([[lastPathComponent substringFromIndex:[lastPathComponent length] - [currentType length]] isEqualToString:currentType])
return NSSelectorFromString([typeSelectorDictionary objectForKey:currentType]);
}
return NULL;
}
- (void)start
{
[NSThread detachNewThreadSelector:[[self class] selectorConformingToTypeOfPath:archivePath] toTarget:self withObject:nil];
}
+ (BOOL)canUnarchivePath:(NSString *)path
{
return ([self selectorConformingToTypeOfPath:path] != nil);
}
// This method abstracts the types that use a command line tool piping data from stdin.
- (void)extractArchivePipingDataToCommand:(NSString *)command
{
// *** GETS CALLED ON NON-MAIN THREAD!!!
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
FILE *fp = NULL, *cmdFP = NULL;
char *oldDestinationString = NULL;
SULog(@"Extracting %@ using '%@'",archivePath,command);
// Get the file size.
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
NSNumber *fs = [[[NSFileManager defaultManager] fileAttributesAtPath:archivePath traverseLink:NO] objectForKey:NSFileSize];
#else
NSNumber *fs = [[[NSFileManager defaultManager] attributesOfItemAtPath:archivePath error:nil] objectForKey:NSFileSize];
#endif
if (fs == nil) goto reportError;
// Thank you, Allan Odgaard!
// (who wrote the following extraction alg.)
fp = fopen([archivePath fileSystemRepresentation], "r");
if (!fp) goto reportError;
oldDestinationString = getenv("DESTINATION");
setenv("DESTINATION", [[archivePath stringByDeletingLastPathComponent] fileSystemRepresentation], 1);
cmdFP = popen([command fileSystemRepresentation], "w");
size_t written;
if (!cmdFP) goto reportError;
char buf[32*1024];
size_t len;
while((len = fread(buf, 1, 32*1024, fp)))
{
written = fwrite(buf, 1, len, cmdFP);
if( written < len )
{
pclose(cmdFP);
goto reportError;
}
[self performSelectorOnMainThread:@selector(notifyDelegateOfExtractedLength:) withObject:[NSNumber numberWithUnsignedLong:len] waitUntilDone:NO];
}
pclose(cmdFP);
if( ferror( fp ) )
goto reportError;
[self performSelectorOnMainThread:@selector(notifyDelegateOfSuccess) withObject:nil waitUntilDone:NO];
goto finally;
reportError:
[self performSelectorOnMainThread:@selector(notifyDelegateOfFailure) withObject:nil waitUntilDone:NO];
finally:
if (fp)
fclose(fp);
if (oldDestinationString)
setenv("DESTINATION", oldDestinationString, 1);
else
unsetenv("DESTINATION");
[pool release];
}
- (void)extractTAR
{
// *** GETS CALLED ON NON-MAIN THREAD!!!
return [self extractArchivePipingDataToCommand:@"tar -xC \"$DESTINATION\""];
}
- (void)extractTGZ
{
// *** GETS CALLED ON NON-MAIN THREAD!!!
return [self extractArchivePipingDataToCommand:@"tar -zxC \"$DESTINATION\""];
}
- (void)extractTBZ
{
// *** GETS CALLED ON NON-MAIN THREAD!!!
return [self extractArchivePipingDataToCommand:@"tar -jxC \"$DESTINATION\""];
}
- (void)extractZIP
{
// *** GETS CALLED ON NON-MAIN THREAD!!!
return [self extractArchivePipingDataToCommand:@"ditto -x -k - \"$DESTINATION\""];
}
+ (void)load
{
[self registerImplementation:self];
}
@end

View File

@ -1,26 +0,0 @@
//
// SUPlainInstaller.h
// Sparkle
//
// Created by Andy Matuschak on 4/10/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUPLAININSTALLER_H
#define SUPLAININSTALLER_H
#import "SUUpdater.h"
#import "SUAppcast.h"
#import "SUAppcastItem.h"
#import "SUVersionComparisonProtocol.h"
#import "SUInstaller.h"
#import "SUVersionComparisonProtocol.h"
@class SUHost;
@interface SUPlainInstaller : SUInstaller { }
+ (void)performInstallationToPath:(NSString *)installationPath fromPath:(NSString *)path host:(SUHost *)host delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator;
@end
#endif

View File

@ -1,83 +0,0 @@
//
// SUPlainInstaller.m
// Sparkle
//
// Created by Andy Matuschak on 4/10/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUPlainInstaller.h"
#import "SUPlainInstallerInternals.h"
#import "SUConstants.h"
#import "SUHost.h"
static NSString * const SUInstallerPathKey = @"SUInstallerPath";
static NSString * const SUInstallerTargetPathKey = @"SUInstallerTargetPath";
static NSString * const SUInstallerTempNameKey = @"SUInstallerTempName";
static NSString * const SUInstallerHostKey = @"SUInstallerHost";
static NSString * const SUInstallerDelegateKey = @"SUInstallerDelegate";
static NSString * const SUInstallerResultKey = @"SUInstallerResult";
static NSString * const SUInstallerErrorKey = @"SUInstallerError";
static NSString * const SUInstallerInstallationPathKey = @"SUInstallerInstallationPath";
@implementation SUPlainInstaller
+ (void)finishInstallationWithInfo:(NSDictionary *)info
{
// *** GETS CALLED ON NON-MAIN THREAD!
[self finishInstallationToPath:[info objectForKey:SUInstallerInstallationPathKey] withResult:[[info objectForKey:SUInstallerResultKey] boolValue] host:[info objectForKey:SUInstallerHostKey] error:[info objectForKey:SUInstallerErrorKey] delegate:[info objectForKey:SUInstallerDelegateKey]];
}
+ (void)performInstallationWithInfo:(NSDictionary *)info
{
// *** GETS CALLED ON NON-MAIN THREAD!
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSError *error = nil;
NSString * oldPath = [[info objectForKey:SUInstallerHostKey] bundlePath];
NSString * installationPath = [info objectForKey:SUInstallerInstallationPathKey];
BOOL result = [self copyPathWithAuthentication:[info objectForKey:SUInstallerPathKey] overPath: installationPath temporaryName:[info objectForKey:SUInstallerTempNameKey] error:&error];
if( result )
{
BOOL haveOld = [[NSFileManager defaultManager] fileExistsAtPath: oldPath];
BOOL differentFromNew = ![oldPath isEqualToString: installationPath];
if( haveOld && differentFromNew )
[self _movePathToTrash: oldPath]; // On success, trash old copy if there's still one due to renaming.
}
NSMutableDictionary *mutableInfo = [[info mutableCopy] autorelease];
[mutableInfo setObject:[NSNumber numberWithBool:result] forKey:SUInstallerResultKey];
[mutableInfo setObject:installationPath forKey:SUInstallerInstallationPathKey];
if (!result && error)
[mutableInfo setObject:error forKey:SUInstallerErrorKey];
[self performSelectorOnMainThread:@selector(finishInstallationWithInfo:) withObject:mutableInfo waitUntilDone:NO];
[pool drain];
}
+ (void)performInstallationToPath:(NSString *)installationPath fromPath:(NSString *)path host:(SUHost *)host delegate:delegate synchronously:(BOOL)synchronously versionComparator:(id <SUVersionComparison>)comparator
{
// Prevent malicious downgrades:
#if !PERMIT_AUTOMATED_DOWNGRADES
if ([comparator compareVersion:[host version] toVersion:[[NSBundle bundleWithPath:path] objectForInfoDictionaryKey:@"CFBundleVersion"]] == NSOrderedDescending)
{
NSString * errorMessage = [NSString stringWithFormat:@"Sparkle Updater: Possible attack in progress! Attempting to \"upgrade\" from %@ to %@. Aborting update.", [host version], [[NSBundle bundleWithPath:path] objectForInfoDictionaryKey:@"CFBundleVersion"]];
NSError *error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUDowngradeError userInfo:[NSDictionary dictionaryWithObject:errorMessage forKey:NSLocalizedDescriptionKey]];
[self finishInstallationToPath:installationPath withResult:NO host:host error:error delegate:delegate];
return;
}
#endif
NSString *targetPath = [host installationPath];
NSString *tempName = [self temporaryNameForPath:targetPath];
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:path, SUInstallerPathKey, targetPath, SUInstallerTargetPathKey, tempName, SUInstallerTempNameKey, host, SUInstallerHostKey, delegate, SUInstallerDelegateKey, installationPath, SUInstallerInstallationPathKey, nil];
if (synchronously)
[self performInstallationWithInfo:info];
else
[NSThread detachNewThreadSelector:@selector(performInstallationWithInfo:) toTarget:self withObject:info];
}
@end

View File

@ -1,22 +0,0 @@
//
// SUPlainInstallerInternals.m
// Sparkle
//
// Created by Andy Matuschak on 3/9/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SUPLAININSTALLERINTERNALS_H
#define SUPLAININSTALLERINTERNALS_H
#import "SUPlainInstaller.h"
@interface SUPlainInstaller (Internals)
+ (NSString *)temporaryNameForPath:(NSString *)path;
+ (BOOL)copyPathWithAuthentication:(NSString *)src overPath:(NSString *)dst temporaryName:(NSString *)tmp error:(NSError **)error;
+ (void)_movePathToTrash:(NSString *)path;
+ (BOOL)_removeFileAtPath:(NSString *)path error: (NSError**)error;
+ (BOOL)_removeFileAtPathWithForcedAuthentication:(NSString *)src error:(NSError **)error;
@end
#endif

View File

@ -1,618 +0,0 @@
//
// SUPlainInstallerInternals.m
// Sparkle
//
// Created by Andy Matuschak on 3/9/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#import "SUUpdater.h"
#import "SUAppcast.h"
#import "SUAppcastItem.h"
#import "SUVersionComparisonProtocol.h"
#import "SUPlainInstallerInternals.h"
#import "SUConstants.h"
#import "SULog.h"
#import <CoreServices/CoreServices.h>
#import <Security/Security.h>
#import <sys/stat.h>
#import <sys/wait.h>
#import <dirent.h>
#import <unistd.h>
#import <sys/param.h>
@interface SUPlainInstaller (MMExtendedAttributes)
// Removes the directory tree rooted at |root| from the file quarantine.
// The quarantine was introduced on Mac OS X 10.5 and is described at:
//
// http://developer.apple.com/releasenotes/Carbon/RN-LaunchServices/index.html
//#apple_ref/doc/uid/TP40001369-DontLinkElementID_2
//
// If |root| is not a directory, then it alone is removed from the quarantine.
// Symbolic links, including |root| if it is a symbolic link, will not be
// traversed.
//
// Ordinarily, the quarantine is managed by calling LSSetItemAttribute
// to set the kLSItemQuarantineProperties attribute to a dictionary specifying
// the quarantine properties to be applied. However, it does not appear to be
// possible to remove an item from the quarantine directly through any public
// Launch Services calls. Instead, this method takes advantage of the fact
// that the quarantine is implemented in part by setting an extended attribute,
// "com.apple.quarantine", on affected files. Removing this attribute is
// sufficient to remove files from the quarantine.
+ (void)releaseFromQuarantine:(NSString*)root;
@end
// Authorization code based on generous contribution from Allan Odgaard. Thanks, Allan!
static BOOL AuthorizationExecuteWithPrivilegesAndWait(AuthorizationRef authorization, const char* executablePath, AuthorizationFlags options, const char* const* arguments)
{
// *** MUST BE SAFE TO CALL ON NON-MAIN THREAD!
sig_t oldSigChildHandler = signal(SIGCHLD, SIG_DFL);
BOOL returnValue = YES;
if (AuthorizationExecuteWithPrivileges(authorization, executablePath, options, (char* const*)arguments, NULL) == errAuthorizationSuccess)
{
int status;
pid_t pid = wait(&status);
if (pid == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
returnValue = NO;
}
else
returnValue = NO;
signal(SIGCHLD, oldSigChildHandler);
return returnValue;
}
@implementation SUPlainInstaller (Internals)
+ (NSString *)temporaryNameForPath:(NSString *)path
{
// Let's try to read the version number so the filename will be more meaningful.
NSString *postFix;
NSString *version;
if ((version = [[NSBundle bundleWithPath:path] objectForInfoDictionaryKey:@"CFBundleVersion"]) && ![version isEqualToString:@""])
{
// We'll clean it up a little for safety.
// The cast is necessary because of a bug in the headers in pre-10.5 SDKs
NSMutableCharacterSet *validCharacters = (id)[NSMutableCharacterSet alphanumericCharacterSet];
[validCharacters formUnionWithCharacterSet:[NSCharacterSet characterSetWithCharactersInString:@".-()"]];
postFix = [version stringByTrimmingCharactersInSet:[validCharacters invertedSet]];
}
else
postFix = @"old";
NSString *prefix = [[path stringByDeletingPathExtension] stringByAppendingFormat:@" (%@)", postFix];
NSString *tempDir = [prefix stringByAppendingPathExtension:[path pathExtension]];
// Now let's make sure we get a unique path.
unsigned int cnt=2;
while ([[NSFileManager defaultManager] fileExistsAtPath:tempDir] && cnt <= 999)
tempDir = [NSString stringWithFormat:@"%@ %u.%@", prefix, cnt++, [path pathExtension]];
return [tempDir lastPathComponent];
}
+ (NSString *)_temporaryCopyNameForPath:(NSString *)path didFindTrash: (BOOL*)outDidFindTrash
{
// *** MUST BE SAFE TO CALL ON NON-MAIN THREAD!
NSString *tempDir = nil;
UInt8 trashPath[MAXPATHLEN +1] = { 0 };
FSRef trashRef, pathRef;
FSVolumeRefNum vSrcRefNum = kFSInvalidVolumeRefNum;
FSCatalogInfo catInfo;
memset( &catInfo, 0, sizeof(catInfo) );
OSStatus err = FSPathMakeRef( (UInt8*) [path fileSystemRepresentation], &pathRef, NULL );
if( err == noErr )
{
err = FSGetCatalogInfo( &pathRef, kFSCatInfoVolume, &catInfo, NULL, NULL, NULL );
vSrcRefNum = catInfo.volume;
}
if( err == noErr )
err = FSFindFolder( vSrcRefNum, kTrashFolderType, kCreateFolder, &trashRef );
if( err == noErr )
err = FSGetCatalogInfo( &trashRef, kFSCatInfoVolume, &catInfo, NULL, NULL, NULL );
if( err == noErr && vSrcRefNum != catInfo.volume )
err = nsvErr; // Couldn't find a trash folder on same volume as given path. Docs say this may happen in the future.
if( err == noErr )
err = FSRefMakePath( &trashRef, trashPath, MAXPATHLEN );
if( err == noErr )
tempDir = [[NSFileManager defaultManager] stringWithFileSystemRepresentation: (char*) trashPath length: strlen((char*) trashPath)];
if( outDidFindTrash )
*outDidFindTrash = (tempDir != nil);
if( !tempDir )
tempDir = [path stringByDeletingLastPathComponent];
// Let's try to read the version number so the filename will be more meaningful.
#if TRY_TO_APPEND_VERSION_NUMBER
NSString *postFix = nil;
NSString *version = nil;
if ((version = [[NSBundle bundleWithPath: path] objectForInfoDictionaryKey:@"CFBundleVersion"]) && ![version isEqualToString:@""])
{
// We'll clean it up a little for safety.
// The cast is necessary because of a bug in the headers in pre-10.5 SDKs
NSMutableCharacterSet *validCharacters = (id)[NSMutableCharacterSet alphanumericCharacterSet];
[validCharacters formUnionWithCharacterSet:[NSCharacterSet characterSetWithCharactersInString:@".-()"]];
postFix = [version stringByTrimmingCharactersInSet:[validCharacters invertedSet]];
}
else
postFix = @"old";
NSString *prefix = [NSString stringWithFormat: @"%@ (%@)", [[path lastPathComponent] stringByDeletingPathExtension], postFix];
#else
NSString *prefix = [[path lastPathComponent] stringByDeletingPathExtension];
#endif
NSString *tempName = [prefix stringByAppendingPathExtension: [path pathExtension]];
tempDir = [tempDir stringByAppendingPathComponent: tempName];
// Now let's make sure we get a unique path.
int cnt=2;
while ([[NSFileManager defaultManager] fileExistsAtPath:tempDir] && cnt <= 9999)
tempDir = [[tempDir stringByDeletingLastPathComponent] stringByAppendingPathComponent: [NSString stringWithFormat:@"%@ %d.%@", prefix, cnt++, [path pathExtension]]];
return tempDir;
}
+ (BOOL)_copyPathWithForcedAuthentication:(NSString *)src toPath:(NSString *)dst temporaryPath:(NSString *)tmp error:(NSError **)error
{
// *** MUST BE SAFE TO CALL ON NON-MAIN THREAD!
const char* srcPath = [src fileSystemRepresentation];
const char* tmpPath = [tmp fileSystemRepresentation];
const char* dstPath = [dst fileSystemRepresentation];
struct stat dstSB;
if( stat(dstPath, &dstSB) != 0 ) // Doesn't exist yet, try containing folder.
{
const char* dstDirPath = [[dst stringByDeletingLastPathComponent] fileSystemRepresentation];
if( stat(dstDirPath, &dstSB) != 0 )
{
NSString *errorMessage = [NSString stringWithFormat:@"Stat on %@ during authenticated file copy failed.", dst];
if (error != NULL)
*error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUFileCopyFailure userInfo:[NSDictionary dictionaryWithObject:errorMessage forKey:NSLocalizedDescriptionKey]];
return NO;
}
}
AuthorizationRef auth = NULL;
OSStatus authStat = errAuthorizationDenied;
while (authStat == errAuthorizationDenied) {
authStat = AuthorizationCreate(NULL,
kAuthorizationEmptyEnvironment,
kAuthorizationFlagDefaults,
&auth);
}
BOOL res = NO;
if (authStat == errAuthorizationSuccess) {
res = YES;
char uidgid[42];
snprintf(uidgid, sizeof(uidgid), "%u:%u",
dstSB.st_uid, dstSB.st_gid);
// If the currently-running application is trusted, the new
// version should be trusted as well. Remove it from the
// quarantine to avoid a delay at launch, and to avoid
// presenting the user with a confusing trust dialog.
//
// This needs to be done before "chown" changes ownership,
// because the ownership change will fail if the file is quarantined.
if (res)
{
SULog(@"releaseFromQuarantine");
[self performSelectorOnMainThread:@selector(releaseFromQuarantine:) withObject:src waitUntilDone:YES];
}
if( res ) // Set permissions while it's still in source, so we have it with working and correct perms when it arrives at destination.
{
const char* coParams[] = { "-R", uidgid, srcPath, NULL };
res = AuthorizationExecuteWithPrivilegesAndWait( auth, "/usr/sbin/chown", kAuthorizationFlagDefaults, coParams );
if( !res )
SULog( @"chown -R %s %s failed.", uidgid, srcPath );
}
BOOL haveDst = [[NSFileManager defaultManager] fileExistsAtPath: dst];
if( res && haveDst ) // If there's something at our tmp path (previous failed update or whatever) delete that first.
{
const char* rmParams[] = { "-rf", tmpPath, NULL };
res = AuthorizationExecuteWithPrivilegesAndWait( auth, "/bin/rm", kAuthorizationFlagDefaults, rmParams );
if( !res )
SULog( @"rm failed" );
}
if( res && haveDst ) // Move old exe to tmp path.
{
const char* mvParams[] = { "-f", dstPath, tmpPath, NULL };
res = AuthorizationExecuteWithPrivilegesAndWait( auth, "/bin/mv", kAuthorizationFlagDefaults, mvParams );
if( !res )
SULog( @"mv 1 failed" );
}
if( res ) // Move new exe to old exe's path.
{
const char* mvParams2[] = { "-f", srcPath, dstPath, NULL };
res = AuthorizationExecuteWithPrivilegesAndWait( auth, "/bin/mv", kAuthorizationFlagDefaults, mvParams2 );
if( !res )
SULog( @"mv 2 failed" );
}
// if( res && haveDst /*&& !foundTrash*/ ) // If we managed to put the old exe in the trash, leave it there for the user to delete or recover.
// { // ... Otherwise we better delete it, wouldn't want dozens of old versions lying around next to the new one.
// const char* rmParams2[] = { "-rf", tmpPath, NULL };
// res = AuthorizationExecuteWithPrivilegesAndWait( auth, "/bin/rm", kAuthorizationFlagDefaults, rmParams2 );
// }
AuthorizationFree(auth, 0);
// If the currently-running application is trusted, the new
// version should be trusted as well. Remove it from the
// quarantine to avoid a delay at launch, and to avoid
// presenting the user with a confusing trust dialog.
//
// This needs to be done after the application is moved to its
// new home with "mv" in case it's moved across filesystems: if
// that happens, "mv" actually performs a copy and may result
// in the application being quarantined.
if (res)
{
SULog(@"releaseFromQuarantine after installing");
[self performSelectorOnMainThread:@selector(releaseFromQuarantine:) withObject:dst waitUntilDone:YES];
}
if (!res)
{
// Something went wrong somewhere along the way, but we're not sure exactly where.
NSString *errorMessage = [NSString stringWithFormat:@"Authenticated file copy from %@ to %@ failed.", src, dst];
if (error != nil)
*error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUAuthenticationFailure userInfo:[NSDictionary dictionaryWithObject:errorMessage forKey:NSLocalizedDescriptionKey]];
}
}
else
{
if (error != nil)
*error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUAuthenticationFailure userInfo:[NSDictionary dictionaryWithObject:@"Couldn't get permission to authenticate." forKey:NSLocalizedDescriptionKey]];
}
return res;
}
+ (BOOL)_movePathWithForcedAuthentication:(NSString *)src toPath:(NSString *)dst error:(NSError **)error
{
// *** MUST BE SAFE TO CALL ON NON-MAIN THREAD!
const char* srcPath = [src fileSystemRepresentation];
const char* dstPath = [dst fileSystemRepresentation];
const char* dstContainerPath = [[dst stringByDeletingLastPathComponent] fileSystemRepresentation];
struct stat dstSB;
stat(dstContainerPath, &dstSB);
AuthorizationRef auth = NULL;
OSStatus authStat = errAuthorizationDenied;
while( authStat == errAuthorizationDenied )
{
authStat = AuthorizationCreate(NULL,
kAuthorizationEmptyEnvironment,
kAuthorizationFlagDefaults,
&auth);
}
BOOL res = NO;
if (authStat == errAuthorizationSuccess)
{
res = YES;
char uidgid[42];
snprintf(uidgid, sizeof(uidgid), "%d:%d",
dstSB.st_uid, dstSB.st_gid);
if( res ) // Set permissions while it's still in source, so we have it with working and correct perms when it arrives at destination.
{
const char* coParams[] = { "-R", uidgid, srcPath, NULL };
res = AuthorizationExecuteWithPrivilegesAndWait( auth, "/usr/sbin/chown", kAuthorizationFlagDefaults, coParams );
if( !res )
SULog(@"Can't set permissions");
}
BOOL haveDst = [[NSFileManager defaultManager] fileExistsAtPath: dst];
if( res && haveDst ) // If there's something at our tmp path (previous failed update or whatever) delete that first.
{
const char* rmParams[] = { "-rf", dstPath, NULL };
res = AuthorizationExecuteWithPrivilegesAndWait( auth, "/bin/rm", kAuthorizationFlagDefaults, rmParams );
if( !res )
SULog(@"Can't remove destination file");
}
if( res ) // Move!.
{
const char* mvParams[] = { "-f", srcPath, dstPath, NULL };
res = AuthorizationExecuteWithPrivilegesAndWait( auth, "/bin/mv", kAuthorizationFlagDefaults, mvParams );
if( !res )
SULog(@"Can't move source file");
}
AuthorizationFree(auth, 0);
if (!res)
{
// Something went wrong somewhere along the way, but we're not sure exactly where.
NSString *errorMessage = [NSString stringWithFormat:@"Authenticated file move from %@ to %@ failed.", src, dst];
if (error != NULL)
*error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUAuthenticationFailure userInfo:[NSDictionary dictionaryWithObject:errorMessage forKey:NSLocalizedDescriptionKey]];
}
}
else
{
if (error != NULL)
*error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUAuthenticationFailure userInfo:[NSDictionary dictionaryWithObject:@"Couldn't get permission to authenticate." forKey:NSLocalizedDescriptionKey]];
}
return res;
}
+ (BOOL)_removeFileAtPathWithForcedAuthentication:(NSString *)src error:(NSError **)error
{
// *** MUST BE SAFE TO CALL ON NON-MAIN THREAD!
const char* srcPath = [src fileSystemRepresentation];
AuthorizationRef auth = NULL;
OSStatus authStat = errAuthorizationDenied;
while( authStat == errAuthorizationDenied )
{
authStat = AuthorizationCreate(NULL,
kAuthorizationEmptyEnvironment,
kAuthorizationFlagDefaults,
&auth);
}
BOOL res = NO;
if (authStat == errAuthorizationSuccess)
{
res = YES;
if( res ) // If there's something at our tmp path (previous failed update or whatever) delete that first.
{
const char* rmParams[] = { "-rf", srcPath, NULL };
res = AuthorizationExecuteWithPrivilegesAndWait( auth, "/bin/rm", kAuthorizationFlagDefaults, rmParams );
if( !res )
SULog(@"Can't remove destination file");
}
AuthorizationFree(auth, 0);
if (!res)
{
// Something went wrong somewhere along the way, but we're not sure exactly where.
NSString *errorMessage = [NSString stringWithFormat:@"Authenticated file remove from %@ failed.", src];
if (error != NULL)
*error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUAuthenticationFailure userInfo:[NSDictionary dictionaryWithObject:errorMessage forKey:NSLocalizedDescriptionKey]];
}
}
else
{
if (error != NULL)
*error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUAuthenticationFailure userInfo:[NSDictionary dictionaryWithObject:@"Couldn't get permission to authenticate." forKey:NSLocalizedDescriptionKey]];
}
return res;
}
+ (BOOL)_removeFileAtPath:(NSString *)path error: (NSError**)error
{
BOOL success = YES;
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
if( ![[NSFileManager defaultManager] removeFileAtPath: path handler: nil] )
#else
if( ![[NSFileManager defaultManager] removeItemAtPath: path error: NULL] )
#endif
{
success = [self _removeFileAtPathWithForcedAuthentication: path error: error];
}
return success;
}
+ (void)_movePathToTrash:(NSString *)path
{
//SULog(@"Moving %@ to the trash.", path);
NSInteger tag = 0;
if (![[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:[path stringByDeletingLastPathComponent] destination:@"" files:[NSArray arrayWithObject:[path lastPathComponent]] tag:&tag])
{
BOOL didFindTrash = NO;
NSString* trashPath = [self _temporaryCopyNameForPath: path didFindTrash: &didFindTrash];
if( didFindTrash )
{
NSError *err = nil;
if( ![self _movePathWithForcedAuthentication: path toPath: trashPath error: &err] )
SULog(@"Sparkle error: couldn't move %@ to the trash (%@). %@", path, trashPath, err);
}
else
SULog(@"Sparkle error: couldn't move %@ to the trash. This is often a sign of a permissions error.", path);
}
else
;//SULog(@"Moved %@ to the trash.", path);
}
+ (BOOL)copyPathWithAuthentication:(NSString *)src overPath:(NSString *)dst temporaryName:(NSString *)tmp error:(NSError **)error
{
FSRef srcRef, dstRef, dstDirRef, movedRef, tmpDirRef;
OSStatus err;
BOOL hadFileAtDest = NO, didFindTrash = NO;
NSString *tmpPath = [self _temporaryCopyNameForPath: dst didFindTrash: &didFindTrash];
// Make FSRef for destination:
err = FSPathMakeRefWithOptions((UInt8 *)[dst fileSystemRepresentation], kFSPathMakeRefDoNotFollowLeafSymlink, &dstRef, NULL);
hadFileAtDest = (err == noErr); // There is a file at the destination, move it aside. If we normalized the name, we might not get here, so don't error.
if( hadFileAtDest )
{
if (0 != access([dst fileSystemRepresentation], W_OK) || 0 != access([[dst stringByDeletingLastPathComponent] fileSystemRepresentation], W_OK))
{
return [self _copyPathWithForcedAuthentication:src toPath:dst temporaryPath:tmpPath error:error];
}
}
else
{
if (0 != access([[dst stringByDeletingLastPathComponent] fileSystemRepresentation], W_OK)
|| 0 != access([[[dst stringByDeletingLastPathComponent] stringByDeletingLastPathComponent] fileSystemRepresentation], W_OK))
{
return [self _copyPathWithForcedAuthentication:src toPath:dst temporaryPath:tmpPath error:error];
}
}
if( hadFileAtDest )
{
err = FSPathMakeRef((UInt8 *)[[tmpPath stringByDeletingLastPathComponent] fileSystemRepresentation], &tmpDirRef, NULL);
if (err != noErr)
err = FSPathMakeRef((UInt8 *)[[dst stringByDeletingLastPathComponent] fileSystemRepresentation], &tmpDirRef, NULL);
}
err = FSPathMakeRef((UInt8 *)[[dst stringByDeletingLastPathComponent] fileSystemRepresentation], &dstDirRef, NULL);
if (err == noErr && hadFileAtDest)
{
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5)
{
NSFileManager *manager = [[[NSFileManager alloc] init] autorelease];
BOOL success = [manager moveItemAtPath:dst toPath:tmpPath error:error];
if (!success && hadFileAtDest)
{
if (error != NULL)
*error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUFileCopyFailure userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Couldn't move %@ to %@.", dst, tmpPath] forKey:NSLocalizedDescriptionKey]];
return NO;
}
} else {
err = FSMoveObjectSync(&dstRef, &tmpDirRef, (CFStringRef)[tmpPath lastPathComponent], &movedRef, 0);
if (err != noErr && hadFileAtDest)
{
if (error != NULL)
*error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUFileCopyFailure userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Couldn't move %@ to %@.", dst, tmpPath] forKey:NSLocalizedDescriptionKey]];
return NO;
}
}
}
err = FSPathMakeRef((UInt8 *)[src fileSystemRepresentation], &srcRef, NULL);
if (err == noErr)
{
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5)
{
NSFileManager *manager = [[[NSFileManager alloc] init] autorelease];
BOOL success = [manager copyItemAtPath:src toPath:dst error:error];
if (!success)
{
// We better move the old version back to its old location
if( hadFileAtDest )
success = [manager moveItemAtPath:tmpPath toPath:dst error:error];
if (error != NULL)
*error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUFileCopyFailure userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Couldn't move %@ to %@.", dst, tmpPath] forKey:NSLocalizedDescriptionKey]];
return NO;
}
} else {
err = FSCopyObjectSync(&srcRef, &dstDirRef, (CFStringRef)[dst lastPathComponent], NULL, 0);
if (err != noErr)
{
// We better move the old version back to its old location
if( hadFileAtDest )
FSMoveObjectSync(&movedRef, &dstDirRef, (CFStringRef)[dst lastPathComponent], &movedRef, 0);
if (error != NULL)
*error = [NSError errorWithDomain:SUSparkleErrorDomain code:SUFileCopyFailure userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Couldn't copy %@ to %@.", src, dst] forKey:NSLocalizedDescriptionKey]];
return NO;
}
}
}
// If the currently-running application is trusted, the new
// version should be trusted as well. Remove it from the
// quarantine to avoid a delay at launch, and to avoid
// presenting the user with a confusing trust dialog.
//
// This needs to be done after the application is moved to its
// new home in case it's moved across filesystems: if that
// happens, the move is actually a copy, and it may result
// in the application being quarantined.
[self performSelectorOnMainThread:@selector(releaseFromQuarantine:) withObject:dst waitUntilDone:YES];
return YES;
}
@end
#import <dlfcn.h>
#import <errno.h>
#import <sys/xattr.h>
@implementation SUPlainInstaller (MMExtendedAttributes)
+ (int)removeXAttr:(const char*)name
fromFile:(NSString*)file
options:(int)options
{
// *** MUST BE SAFE TO CALL ON NON-MAIN THREAD!
typedef int (*removexattr_type)(const char*, const char*, int);
// Reference removexattr directly, it's in the SDK.
static removexattr_type removexattr_func = removexattr;
// Make sure that the symbol is present. This checks the deployment
// target instead of the SDK so that it's able to catch dlsym failures
// as well as the null symbol that would result from building with the
// 10.4 SDK and a lower deployment target, and running on 10.3.
if (!removexattr_func) {
errno = ENOSYS;
return -1;
}
const char* path = NULL;
@try {
path = [file fileSystemRepresentation];
}
@catch (id exception) {
// -[NSString fileSystemRepresentation] throws an exception if it's
// unable to convert the string to something suitable. Map that to
// EDOM, "argument out of domain", which sort of conveys that there
// was a conversion failure.
errno = EDOM;
return -1;
}
return removexattr_func(path, name, options);
}
+ (void)releaseFromQuarantine:(NSString*)root
{
// *** MUST BE SAFE TO CALL ON NON-MAIN THREAD!
const char* quarantineAttribute = "com.apple.quarantine";
const int removeXAttrOptions = XATTR_NOFOLLOW;
[self removeXAttr:quarantineAttribute
fromFile:root
options:removeXAttrOptions];
// Only recurse if it's actually a directory. Don't recurse into a
// root-level symbolic link.
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
NSDictionary* rootAttributes = [[NSFileManager defaultManager] fileAttributesAtPath:root traverseLink:NO];
#else
NSDictionary* rootAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:root error:nil];
#endif
NSString* rootType = [rootAttributes objectForKey:NSFileType];
if (rootType == NSFileTypeDirectory) {
// The NSDirectoryEnumerator will avoid recursing into any contained
// symbolic links, so no further type checks are needed.
NSDirectoryEnumerator* directoryEnumerator = [[NSFileManager defaultManager] enumeratorAtPath:root];
NSString* file = nil;
while ((file = [directoryEnumerator nextObject])) {
[self removeXAttr:quarantineAttribute
fromFile:[root stringByAppendingPathComponent:file]
options:removeXAttrOptions];
}
}
}
@end

View File

@ -1,19 +0,0 @@
//
// SUProbingUpdateDriver.h
// Sparkle
//
// Created by Andy Matuschak on 5/7/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUPROBINGUPDATEDRIVER_H
#define SUPROBINGUPDATEDRIVER_H
#import <Cocoa/Cocoa.h>
#import "SUBasicUpdateDriver.h"
// This replaces the old SUStatusChecker.
@interface SUProbingUpdateDriver : SUBasicUpdateDriver { }
@end
#endif

View File

@ -1,30 +0,0 @@
//
// SUProbingUpdateDriver.m
// Sparkle
//
// Created by Andy Matuschak on 5/7/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUProbingUpdateDriver.h"
#import "SUUpdater.h"
@implementation SUProbingUpdateDriver
// Stop as soon as we have an answer! Since the superclass implementations are not called, we are responsible for notifying the delegate.
- (void)didFindValidUpdate
{
if ([[updater delegate] respondsToSelector:@selector(updater:didFindValidUpdate:)])
[[updater delegate] updater:updater didFindValidUpdate:updateItem];
[self abortUpdate];
}
- (void)didNotFindUpdate
{
if ([[updater delegate] respondsToSelector:@selector(updaterDidNotFindUpdate:)])
[[updater delegate] updaterDidNotFindUpdate:updater];
[self abortUpdate];
}
@end

View File

@ -1,23 +0,0 @@
//
// SUScheduledUpdateDriver.h
// Sparkle
//
// Created by Andy Matuschak on 5/6/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUSCHEDULEDUPDATEDRIVER_H
#define SUSCHEDULEDUPDATEDRIVER_H
#import <Cocoa/Cocoa.h>
#import "SUUIBasedUpdateDriver.h"
@interface SUScheduledUpdateDriver : SUUIBasedUpdateDriver
{
@private
BOOL showErrors;
}
@end
#endif

View File

@ -1,39 +0,0 @@
//
// SUScheduledUpdateDriver.m
// Sparkle
//
// Created by Andy Matuschak on 5/6/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUScheduledUpdateDriver.h"
#import "SUUpdater.h"
#import "SUAppcast.h"
#import "SUAppcastItem.h"
#import "SUVersionComparisonProtocol.h"
@implementation SUScheduledUpdateDriver
- (void)didFindValidUpdate
{
showErrors = YES; // We only start showing errors after we present the UI for the first time.
[super didFindValidUpdate];
}
- (void)didNotFindUpdate
{
if ([[updater delegate] respondsToSelector:@selector(updaterDidNotFindUpdate:)])
[[updater delegate] updaterDidNotFindUpdate:updater];
[self abortUpdate]; // Don't tell the user that no update was found; this was a scheduled update.
}
- (void)abortUpdateWithError:(NSError *)error
{
if (showErrors)
[super abortUpdateWithError:error];
else
[self abortUpdate];
}
@end

View File

@ -1,36 +0,0 @@
//
// SUStandardVersionComparator.h
// Sparkle
//
// Created by Andy Matuschak on 12/21/07.
// Copyright 2007 Andy Matuschak. All rights reserved.
//
#ifndef SUSTANDARDVERSIONCOMPARATOR_H
#define SUSTANDARDVERSIONCOMPARATOR_H
#import "SUVersionComparisonProtocol.h"
/*!
@class
@abstract Sparkle's default version comparator.
@discussion This comparator is adapted from MacPAD, by Kevin Ballard. It's "dumb" in that it does essentially string comparison, in components split by character type.
*/
@interface SUStandardVersionComparator : NSObject <SUVersionComparison> { }
/*!
@method
@abstract Returns a singleton instance of the comparator.
*/
+ (SUStandardVersionComparator *)defaultComparator;
/*!
@method
@abstract Compares version strings through textual analysis.
@discussion See the implementation for more details.
*/
- (NSComparisonResult)compareVersion:(NSString *)versionA toVersion:(NSString *)versionB;
@end
#endif

View File

@ -1,169 +0,0 @@
//
// SUStandardVersionComparator.m
// Sparkle
//
// Created by Andy Matuschak on 12/21/07.
// Copyright 2007 Andy Matuschak. All rights reserved.
//
#import "SUUpdater.h"
#import "SUAppcast.h"
#import "SUAppcastItem.h"
#import "SUVersionComparisonProtocol.h"
#import "SUStandardVersionComparator.h"
@implementation SUStandardVersionComparator
+ (SUStandardVersionComparator *)defaultComparator
{
static SUStandardVersionComparator *defaultComparator = nil;
if (defaultComparator == nil)
defaultComparator = [[SUStandardVersionComparator alloc] init];
return defaultComparator;
}
typedef enum {
kNumberType,
kStringType,
kSeparatorType,
} SUCharacterType;
- (SUCharacterType)typeOfCharacter:(NSString *)character
{
if ([character isEqualToString:@"."]) {
return kSeparatorType;
} else if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[character characterAtIndex:0]]) {
return kNumberType;
} else if ([[NSCharacterSet whitespaceAndNewlineCharacterSet] characterIsMember:[character characterAtIndex:0]]) {
return kSeparatorType;
} else if ([[NSCharacterSet punctuationCharacterSet] characterIsMember:[character characterAtIndex:0]]) {
return kSeparatorType;
} else {
return kStringType;
}
}
- (NSArray *)splitVersionString:(NSString *)version
{
NSString *character;
NSMutableString *s;
NSUInteger i, n;
SUCharacterType oldType, newType;
NSMutableArray *parts = [NSMutableArray array];
if ([version length] == 0) {
// Nothing to do here
return parts;
}
s = [[[version substringToIndex:1] mutableCopy] autorelease];
oldType = [self typeOfCharacter:s];
n = [version length] - 1;
for (i = 1; i <= n; ++i) {
character = [version substringWithRange:NSMakeRange(i, 1)];
newType = [self typeOfCharacter:character];
if (oldType != newType || oldType == kSeparatorType) {
// We've reached a new segment
NSString *aPart = [[[NSString alloc] initWithString:s] autorelease];
[parts addObject:aPart];
[s setString:character];
} else {
// Add character to string and continue
[s appendString:character];
}
oldType = newType;
}
// Add the last part onto the array
[parts addObject:[NSString stringWithString:s]];
return parts;
}
- (NSComparisonResult)compareVersion:(NSString *)versionA toVersion:(NSString *)versionB;
{
NSArray *partsA = [self splitVersionString:versionA];
NSArray *partsB = [self splitVersionString:versionB];
NSString *partA, *partB;
NSUInteger i, n;
long long valueA, valueB;
SUCharacterType typeA, typeB;
n = MIN([partsA count], [partsB count]);
for (i = 0; i < n; ++i) {
partA = [partsA objectAtIndex:i];
partB = [partsB objectAtIndex:i];
typeA = [self typeOfCharacter:partA];
typeB = [self typeOfCharacter:partB];
// Compare types
if (typeA == typeB) {
// Same type; we can compare
if (typeA == kNumberType) {
valueA = [partA longLongValue];
valueB = [partB longLongValue];
if (valueA > valueB) {
return NSOrderedDescending;
} else if (valueA < valueB) {
return NSOrderedAscending;
}
} else if (typeA == kStringType) {
NSComparisonResult result = [partA compare:partB];
if (result != NSOrderedSame) {
return result;
}
}
} else {
// Not the same type? Now we have to do some validity checking
if (typeA != kStringType && typeB == kStringType) {
// typeA wins
return NSOrderedDescending;
} else if (typeA == kStringType && typeB != kStringType) {
// typeB wins
return NSOrderedAscending;
} else {
// One is a number and the other is a period. The period is invalid
if (typeA == kNumberType) {
return NSOrderedDescending;
} else {
return NSOrderedAscending;
}
}
}
}
// The versions are equal up to the point where they both still have parts
// Lets check to see if one is larger than the other
if ([partsA count] != [partsB count]) {
// Yep. Lets get the next part of the larger
// n holds the index of the part we want.
NSString *missingPart;
SUCharacterType missingType;
NSComparisonResult shorterResult, largerResult;
if ([partsA count] > [partsB count]) {
missingPart = [partsA objectAtIndex:n];
shorterResult = NSOrderedAscending;
largerResult = NSOrderedDescending;
} else {
missingPart = [partsB objectAtIndex:n];
shorterResult = NSOrderedDescending;
largerResult = NSOrderedAscending;
}
missingType = [self typeOfCharacter:missingPart];
// Check the type
if (missingType == kStringType) {
// It's a string. Shorter version wins
return shorterResult;
} else {
// It's a number/period. Larger version wins
return largerResult;
}
}
// The 2 strings are identical
return NSOrderedSame;
}
@end

View File

@ -1,589 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
<data>
<int key="IBDocument.SystemTarget">1050</int>
<string key="IBDocument.SystemVersion">10D573</string>
<string key="IBDocument.InterfaceBuilderVersion">762</string>
<string key="IBDocument.AppKitVersion">1038.29</string>
<string key="IBDocument.HIToolboxVersion">460.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys" id="0">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
<integer value="6"/>
</object>
<reference key="IBDocument.PluginDependencies" ref="0"/>
<object class="NSMutableDictionary" key="IBDocument.Metadata">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference key="dict.sortedKeys" ref="0"/>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<object class="NSMutableArray" key="IBDocument.RootObjects" id="780577916">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSCustomObject" id="245526436">
<string key="NSClassName">SUStatusController</string>
</object>
<object class="NSCustomObject" id="879485556">
<string key="NSClassName">FirstResponder</string>
</object>
<object class="NSCustomObject" id="472338989">
<string key="NSClassName">NSApplication</string>
</object>
<object class="NSWindowTemplate" id="661323156">
<int key="NSWindowStyleMask">1</int>
<int key="NSWindowBacking">2</int>
<string key="NSWindowRect">{{200, 222}, {400, 107}}</string>
<int key="NSWTFlags">1886912512</int>
<string key="NSWindowTitle">Set in Code</string>
<object class="NSMutableString" key="NSWindowClass">
<characters key="NS.bytes">NSWindow</characters>
</object>
<object class="NSMutableString" key="NSViewClass">
<characters key="NS.bytes">View</characters>
</object>
<string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
<string key="NSWindowContentMinSize">{213, 107}</string>
<object class="NSView" key="NSWindowView" id="512815736">
<reference key="NSNextResponder"/>
<int key="NSvFlags">256</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSImageView" id="56655866">
<reference key="NSNextResponder" ref="512815736"/>
<int key="NSvFlags">268</int>
<object class="NSMutableSet" key="NSDragTypes">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="set.sortedObjects">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>Apple PDF pasteboard type</string>
<string>Apple PICT pasteboard type</string>
<string>Apple PNG pasteboard type</string>
<string>NSFilenamesPboardType</string>
<string>NeXT Encapsulated PostScript v1.2 pasteboard type</string>
<string>NeXT TIFF v4.0 pasteboard type</string>
</object>
</object>
<string key="NSFrame">{{24, 28}, {64, 64}}</string>
<reference key="NSSuperview" ref="512815736"/>
<bool key="NSEnabled">YES</bool>
<object class="NSImageCell" key="NSCell" id="381943368">
<int key="NSCellFlags">130560</int>
<int key="NSCellFlags2">33554432</int>
<object class="NSCustomResource" key="NSContents">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">NSApplicationIcon</string>
</object>
<int key="NSAlign">0</int>
<int key="NSScale">1</int>
<int key="NSStyle">0</int>
<bool key="NSAnimates">NO</bool>
</object>
<bool key="NSEditable">YES</bool>
</object>
<object class="NSTextField" id="692218720">
<reference key="NSNextResponder" ref="512815736"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{106, 75}, {277, 17}}</string>
<reference key="NSSuperview" ref="512815736"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="597081861">
<int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">272629760</int>
<string key="NSContents">Status Text (set by loc. string in code)</string>
<object class="NSFont" key="NSSupport">
<string key="NSName">LucidaGrande-Bold</string>
<double key="NSSize">13</double>
<int key="NSfFlags">2072</int>
</object>
<reference key="NSControlView" ref="692218720"/>
<object class="NSColor" key="NSBackgroundColor" id="747797151">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">controlColor</string>
<object class="NSColor" key="NSColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MC42NjY2NjY2ODY1AA</bytes>
</object>
</object>
<object class="NSColor" key="NSTextColor" id="640273742">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">controlTextColor</string>
<object class="NSColor" key="NSColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MAA</bytes>
</object>
</object>
</object>
</object>
<object class="NSProgressIndicator" id="454270533">
<reference key="NSNextResponder" ref="512815736"/>
<int key="NSvFlags">1280</int>
<object class="NSPSMatrix" key="NSDrawMatrix"/>
<string key="NSFrame">{{107, 47}, {275, 20}}</string>
<reference key="NSSuperview" ref="512815736"/>
<int key="NSpiFlags">16394</int>
<double key="NSMaxValue">100</double>
</object>
<object class="NSButton" id="566879706">
<reference key="NSNextResponder" ref="512815736"/>
<int key="NSvFlags">259</int>
<string key="NSFrame">{{272, 12}, {114, 32}}</string>
<reference key="NSSuperview" ref="512815736"/>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="130218013">
<int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">134217728</int>
<string key="NSContents">Button</string>
<object class="NSFont" key="NSSupport" id="531315841">
<string key="NSName">LucidaGrande</string>
<double key="NSSize">13</double>
<int key="NSfFlags">1044</int>
</object>
<reference key="NSControlView" ref="566879706"/>
<int key="NSButtonFlags">-2038284033</int>
<int key="NSButtonFlags2">1</int>
<reference key="NSAlternateImage" ref="531315841"/>
<string key="NSAlternateContents"/>
<object class="NSMutableString" key="NSKeyEquivalent">
<characters key="NS.bytes"/>
</object>
<int key="NSPeriodicDelay">200</int>
<int key="NSPeriodicInterval">25</int>
</object>
</object>
<object class="NSTextField" id="65200871">
<reference key="NSNextResponder" ref="512815736"/>
<int key="NSvFlags">256</int>
<string key="NSFrame">{{106, 22}, {167, 17}}</string>
<reference key="NSSuperview" ref="512815736"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="180962568">
<int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">272629760</int>
<string key="NSContents">Small System Font Text</string>
<reference key="NSSupport" ref="531315841"/>
<reference key="NSControlView" ref="65200871"/>
<reference key="NSBackgroundColor" ref="747797151"/>
<reference key="NSTextColor" ref="640273742"/>
</object>
</object>
</object>
<string key="NSFrameSize">{400, 107}</string>
<reference key="NSSuperview"/>
</object>
<string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string>
<string key="NSMinSize">{213, 129}</string>
<string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string>
</object>
</object>
<object class="IBObjectContainer" key="IBDocument.Objects">
<object class="NSMutableArray" key="connectionRecords">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBConnectionRecord">
<object class="IBBindingConnection" key="connection">
<string key="label">value: applicationIcon</string>
<reference key="source" ref="56655866"/>
<reference key="destination" ref="245526436"/>
<object class="NSNibBindingConnector" key="connector">
<reference key="NSSource" ref="56655866"/>
<reference key="NSDestination" ref="245526436"/>
<string key="NSLabel">value: applicationIcon</string>
<string key="NSBinding">value</string>
<string key="NSKeyPath">applicationIcon</string>
<int key="NSNibBindingConnectorVersion">2</int>
</object>
</object>
<int key="connectionID">9</int>
</object>
<object class="IBConnectionRecord">
<object class="IBBindingConnection" key="connection">
<string key="label">maxValue: maxProgressValue</string>
<reference key="source" ref="454270533"/>
<reference key="destination" ref="245526436"/>
<object class="NSNibBindingConnector" key="connector" id="110266706">
<reference key="NSSource" ref="454270533"/>
<reference key="NSDestination" ref="245526436"/>
<string key="NSLabel">maxValue: maxProgressValue</string>
<string key="NSBinding">maxValue</string>
<string key="NSKeyPath">maxProgressValue</string>
<int key="NSNibBindingConnectorVersion">2</int>
</object>
</object>
<int key="connectionID">13</int>
</object>
<object class="IBConnectionRecord">
<object class="IBBindingConnection" key="connection">
<string key="label">value: statusText</string>
<reference key="source" ref="65200871"/>
<reference key="destination" ref="245526436"/>
<object class="NSNibBindingConnector" key="connector">
<reference key="NSSource" ref="65200871"/>
<reference key="NSDestination" ref="245526436"/>
<string key="NSLabel">value: statusText</string>
<string key="NSBinding">value</string>
<string key="NSKeyPath">statusText</string>
<int key="NSNibBindingConnectorVersion">2</int>
</object>
</object>
<int key="connectionID">17</int>
</object>
<object class="IBConnectionRecord">
<object class="IBBindingConnection" key="connection">
<string key="label">title: buttonTitle</string>
<reference key="source" ref="566879706"/>
<reference key="destination" ref="245526436"/>
<object class="NSNibBindingConnector" key="connector">
<reference key="NSSource" ref="566879706"/>
<reference key="NSDestination" ref="245526436"/>
<string key="NSLabel">title: buttonTitle</string>
<string key="NSBinding">title</string>
<string key="NSKeyPath">buttonTitle</string>
<int key="NSNibBindingConnectorVersion">2</int>
</object>
</object>
<int key="connectionID">21</int>
</object>
<object class="IBConnectionRecord">
<object class="IBBindingConnection" key="connection">
<string key="label">title: windowTitle</string>
<reference key="source" ref="661323156"/>
<reference key="destination" ref="245526436"/>
<object class="NSNibBindingConnector" key="connector">
<reference key="NSSource" ref="661323156"/>
<reference key="NSDestination" ref="245526436"/>
<string key="NSLabel">title: windowTitle</string>
<string key="NSBinding">title</string>
<string key="NSKeyPath">windowTitle</string>
<int key="NSNibBindingConnectorVersion">2</int>
</object>
</object>
<int key="connectionID">24</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">window</string>
<reference key="source" ref="245526436"/>
<reference key="destination" ref="661323156"/>
</object>
<int key="connectionID">25</int>
</object>
<object class="IBConnectionRecord">
<object class="IBBindingConnection" key="connection">
<string key="label">value: title</string>
<reference key="source" ref="692218720"/>
<reference key="destination" ref="245526436"/>
<object class="NSNibBindingConnector" key="connector">
<reference key="NSSource" ref="692218720"/>
<reference key="NSDestination" ref="245526436"/>
<string key="NSLabel">value: title</string>
<string key="NSBinding">value</string>
<string key="NSKeyPath">title</string>
<int key="NSNibBindingConnectorVersion">2</int>
</object>
</object>
<int key="connectionID">26</int>
</object>
<object class="IBConnectionRecord">
<object class="IBBindingConnection" key="connection">
<string key="label">value: progressValue</string>
<reference key="source" ref="454270533"/>
<reference key="destination" ref="245526436"/>
<object class="NSNibBindingConnector" key="connector">
<reference key="NSSource" ref="454270533"/>
<reference key="NSDestination" ref="245526436"/>
<string key="NSLabel">value: progressValue</string>
<string key="NSBinding">value</string>
<string key="NSKeyPath">progressValue</string>
<reference key="NSPreviousConnector" ref="110266706"/>
<int key="NSNibBindingConnectorVersion">2</int>
</object>
</object>
<int key="connectionID">27</int>
</object>
<object class="IBConnectionRecord">
<object class="IBBindingConnection" key="connection">
<string key="label">hidden: statusText</string>
<reference key="source" ref="65200871"/>
<reference key="destination" ref="245526436"/>
<object class="NSNibBindingConnector" key="connector">
<reference key="NSSource" ref="65200871"/>
<reference key="NSDestination" ref="245526436"/>
<string key="NSLabel">hidden: statusText</string>
<string key="NSBinding">hidden</string>
<string key="NSKeyPath">statusText</string>
<object class="NSDictionary" key="NSOptions">
<string key="NS.key.0">NSValueTransformerName</string>
<string key="NS.object.0">NSIsNil</string>
</object>
<int key="NSNibBindingConnectorVersion">2</int>
</object>
</object>
<int key="connectionID">33</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">actionButton</string>
<reference key="source" ref="245526436"/>
<reference key="destination" ref="566879706"/>
</object>
<int key="connectionID">34</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">progressBar</string>
<reference key="source" ref="245526436"/>
<reference key="destination" ref="454270533"/>
</object>
<int key="connectionID">49</int>
</object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBObjectRecord">
<int key="objectID">0</int>
<reference key="object" ref="0"/>
<reference key="children" ref="780577916"/>
<nil key="parent"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">-2</int>
<reference key="object" ref="245526436"/>
<reference key="parent" ref="0"/>
<string key="objectName">File's Owner</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-1</int>
<reference key="object" ref="879485556"/>
<reference key="parent" ref="0"/>
<string key="objectName">First Responder</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-3</int>
<reference key="object" ref="472338989"/>
<reference key="parent" ref="0"/>
<string key="objectName">Application</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">5</int>
<reference key="object" ref="661323156"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="512815736"/>
</object>
<reference key="parent" ref="0"/>
<string key="objectName">Window</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">6</int>
<reference key="object" ref="512815736"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="56655866"/>
<reference ref="692218720"/>
<reference ref="454270533"/>
<reference ref="566879706"/>
<reference ref="65200871"/>
</object>
<reference key="parent" ref="661323156"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">7</int>
<reference key="object" ref="56655866"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="381943368"/>
</object>
<reference key="parent" ref="512815736"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">8</int>
<reference key="object" ref="692218720"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="597081861"/>
</object>
<reference key="parent" ref="512815736"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">11</int>
<reference key="object" ref="454270533"/>
<reference key="parent" ref="512815736"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">12</int>
<reference key="object" ref="566879706"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="130218013"/>
</object>
<reference key="parent" ref="512815736"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">16</int>
<reference key="object" ref="65200871"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="180962568"/>
</object>
<reference key="parent" ref="512815736"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">53</int>
<reference key="object" ref="381943368"/>
<reference key="parent" ref="56655866"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">54</int>
<reference key="object" ref="597081861"/>
<reference key="parent" ref="692218720"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">55</int>
<reference key="object" ref="130218013"/>
<reference key="parent" ref="566879706"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">56</int>
<reference key="object" ref="180962568"/>
<reference key="parent" ref="65200871"/>
</object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>-3.ImportedFromIB2</string>
<string>11.ImportedFromIB2</string>
<string>12.ImportedFromIB2</string>
<string>16.ImportedFromIB2</string>
<string>5.IBEditorWindowLastContentRect</string>
<string>5.IBWindowTemplateEditedContentRect</string>
<string>5.ImportedFromIB2</string>
<string>5.windowTemplate.hasMinSize</string>
<string>5.windowTemplate.minSize</string>
<string>6.ImportedFromIB2</string>
<string>7.ImportedFromIB2</string>
<string>8.ImportedFromIB2</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<boolean value="YES"/>
<boolean value="YES"/>
<boolean value="YES"/>
<boolean value="YES"/>
<string>{{294, 716}, {400, 107}}</string>
<string>{{294, 716}, {400, 107}}</string>
<boolean value="YES"/>
<boolean value="YES"/>
<string>{213, 107}</string>
<boolean value="YES"/>
<boolean value="YES"/>
<boolean value="YES"/>
</object>
</object>
<object class="NSMutableDictionary" key="unlocalizedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference key="dict.sortedKeys" ref="0"/>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<nil key="activeLocalization"/>
<object class="NSMutableDictionary" key="localizations">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference key="dict.sortedKeys" ref="0"/>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<nil key="sourceID"/>
<int key="maxID">56</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBPartialClassDescription">
<string key="className">FirstResponder</string>
<string key="superclassName">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">NSApplication</string>
<string key="superclassName">NSResponder</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">SUStatusController</string>
<string key="superclassName">SUWindowController</string>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>actionButton</string>
<string>progressBar</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>NSButton</string>
<string>NSProgressIndicator</string>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">SUWindowController</string>
<string key="superclassName">NSWindowController</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>
</object>
</object>
</object>
</object>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
<integer value="1050" key="NS.object.0"/>
</object>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
<integer value="3100" key="NS.object.0"/>
</object>
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
<string key="IBDocument.LastKnownRelativeProjectPath">Sparkle.xcodeproj</string>
<int key="IBDocument.defaultPropertyAccessControl">3</int>
<object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
<string key="NS.key.0">NSApplicationIcon</string>
<string key="NS.object.0">{128, 128}</string>
</object>
</data>
</archive>

View File

@ -1,44 +0,0 @@
//
// SUStatusController.h
// Sparkle
//
// Created by Andy Matuschak on 3/14/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SUSTATUSCONTROLLER_H
#define SUSTATUSCONTROLLER_H
#import "SUWindowController.h"
@class SUHost;
@interface SUStatusController : SUWindowController
{
@private
double progressValue, maxProgressValue;
NSString *title, *statusText, *buttonTitle;
IBOutlet NSButton *actionButton;
IBOutlet NSProgressIndicator* progressBar;
SUHost *host;
}
- (id)initWithHost:(SUHost *)host;
// Pass 0 for the max progress value to get an indeterminate progress bar.
// Pass nil for the status text to not show it.
- (void)beginActionWithTitle:(NSString *)title maxProgressValue:(double)maxProgressValue statusText:(NSString *)statusText;
// If isDefault is YES, the button's key equivalent will be \r.
- (void)setButtonTitle:(NSString *)buttonTitle target:target action:(SEL)action isDefault:(BOOL)isDefault;
- (void)setButtonEnabled:(BOOL)enabled;
- (double)progressValue;
- (void)setProgressValue:(double)value;
- (double)maxProgressValue;
- (void)setMaxProgressValue:(double)value;
- (void)setStatusText:(NSString *)statusText;
@end
#endif

View File

@ -1,144 +0,0 @@
//
// SUStatusController.m
// Sparkle
//
// Created by Andy Matuschak on 3/14/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#import "SUUpdater.h"
#import "SUAppcast.h"
#import "SUAppcastItem.h"
#import "SUVersionComparisonProtocol.h"
#import "SUStatusController.h"
#import "SUHost.h"
@implementation SUStatusController
- (id)initWithHost:(SUHost *)aHost
{
self = [super initWithHost:aHost windowNibName:@"SUStatus"];
if (self)
{
host = [aHost retain];
[self setShouldCascadeWindows:NO];
}
return self;
}
- (void)dealloc
{
[host release];
[title release];
[statusText release];
[buttonTitle release];
[super dealloc];
}
- (NSString *)description { return [NSString stringWithFormat:@"%@ <%@, %@>", [self class], [host bundlePath], [host installationPath]]; }
- (void)awakeFromNib
{
if ([host isBackgroundApplication]) {
[[self window] setLevel:NSFloatingWindowLevel];
}
[[self window] center];
[[self window] setFrameAutosaveName:@"SUStatusFrame"];
[progressBar setUsesThreadedAnimation:YES];
}
- (NSString *)windowTitle
{
return [NSString stringWithFormat:SULocalizedString(@"Updating %@", nil), [host name]];
}
- (NSImage *)applicationIcon
{
return [host icon];
}
- (void)beginActionWithTitle:(NSString *)aTitle maxProgressValue:(double)aMaxProgressValue statusText:(NSString *)aStatusText
{
[self willChangeValueForKey:@"title"];
title = [aTitle copy];
[self didChangeValueForKey:@"title"];
[self setMaxProgressValue:aMaxProgressValue];
[self setStatusText:aStatusText];
}
- (void)setButtonTitle:(NSString *)aButtonTitle target: (id)target action:(SEL)action isDefault:(BOOL)isDefault
{
[self willChangeValueForKey:@"buttonTitle"];
if (buttonTitle != aButtonTitle)
{
[buttonTitle release];
buttonTitle = [aButtonTitle copy];
}
[self didChangeValueForKey:@"buttonTitle"];
[self window];
[actionButton sizeToFit];
// Except we're going to add 15 px for padding.
[actionButton setFrameSize:NSMakeSize([actionButton frame].size.width + 15, [actionButton frame].size.height)];
// Now we have to move it over so that it's always 15px from the side of the window.
[actionButton setFrameOrigin:NSMakePoint([[self window] frame].size.width - 15 - [actionButton frame].size.width, [actionButton frame].origin.y)];
// Redisplay superview to clean up artifacts
[[actionButton superview] display];
[actionButton setTarget:target];
[actionButton setAction:action];
[actionButton setKeyEquivalent:isDefault ? @"\r" : @""];
// 06/05/2008 Alex: Avoid a crash when cancelling during the extraction
[self setButtonEnabled: (target != nil)];
}
- (BOOL)progressBarShouldAnimate
{
return YES;
}
- (void)setButtonEnabled:(BOOL)enabled
{
[actionButton setEnabled:enabled];
}
- (double)progressValue
{
return progressValue;
}
- (void)setProgressValue:(double)value
{
progressValue = value;
}
- (double)maxProgressValue
{
return maxProgressValue;
}
- (void)setMaxProgressValue:(double)value
{
if (value < 0.0) value = 0.0;
maxProgressValue = value;
[self setProgressValue:0.0];
[progressBar setIndeterminate:(value == 0.0)];
[progressBar startAnimation:self];
[progressBar setUsesThreadedAnimation: YES];
}
- (void)setStatusText:(NSString *)aStatusText
{
if (statusText != aStatusText)
{
[statusText release];
statusText = [aStatusText copy];
}
}
@end

View File

@ -1,20 +0,0 @@
//
// SUSystemProfiler.h
// Sparkle
//
// Created by Andy Matuschak on 12/22/07.
// Copyright 2007 Andy Matuschak. All rights reserved.
//
#ifndef SUSYSTEMPROFILER_H
#define SUSYSTEMPROFILER_H
#import <Cocoa/Cocoa.h>
@class SUHost;
@interface SUSystemProfiler : NSObject {}
+ (SUSystemProfiler *)sharedSystemProfiler;
- (NSMutableArray *)systemProfileArrayForHost:(SUHost *)host;
@end
#endif

View File

@ -1,140 +0,0 @@
//
// SUSystemProfiler.m
// Sparkle
//
// Created by Andy Matuschak on 12/22/07.
// Copyright 2007 Andy Matuschak. All rights reserved.
// Adapted from Sparkle+, by Tom Harrington.
//
#import "SUSystemProfiler.h"
#import "SUHost.h"
#import <sys/sysctl.h>
@implementation SUSystemProfiler
+ (SUSystemProfiler *)sharedSystemProfiler
{
static SUSystemProfiler *sharedSystemProfiler = nil;
if (!sharedSystemProfiler)
sharedSystemProfiler = [[self alloc] init];
return sharedSystemProfiler;
}
- (NSDictionary *)modelTranslationTable
{
NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"SUModelTranslation" ofType:@"plist"];
return [[[NSDictionary alloc] initWithContentsOfFile:path] autorelease];
}
- (NSMutableArray *)systemProfileArrayForHost:(SUHost *)host
{
NSDictionary *modelTranslation = [self modelTranslationTable];
// Gather profile information and append it to the URL.
NSMutableArray *profileArray = [NSMutableArray array];
NSArray *profileDictKeys = [NSArray arrayWithObjects:@"key", @"displayKey", @"value", @"displayValue", nil];
int error = 0;
int value = 0;
size_t length = sizeof(value);
// OS version
NSString *currentSystemVersion = [SUHost systemVersionString];
if (currentSystemVersion != nil)
[profileArray addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"osVersion",@"OS Version",currentSystemVersion,currentSystemVersion,nil] forKeys:profileDictKeys]];
// CPU type (decoder info for values found here is in mach/machine.h)
error = sysctlbyname("hw.cputype", &value, &length, NULL, 0);
int cpuType = -1;
if (error == 0) {
cpuType = value;
NSString *visibleCPUType;
switch(value) {
case CPU_TYPE_X86: visibleCPUType = @"Intel"; break;
case CPU_TYPE_POWERPC: visibleCPUType = @"PowerPC"; break;
default: visibleCPUType = @"Unknown"; break;
}
[profileArray addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"cputype",@"CPU Type", [NSNumber numberWithInt:value], visibleCPUType,nil] forKeys:profileDictKeys]];
}
error = sysctlbyname("hw.cpu64bit_capable", &value, &length, NULL, 0);
if(error != 0)
error = sysctlbyname("hw.optional.x86_64", &value, &length, NULL, 0); //x86 specific
if(error != 0)
error = sysctlbyname("hw.optional.64bitops", &value, &length, NULL, 0); //PPC specific
BOOL is64bit = NO;
if (error == 0) {
is64bit = value == 1;
[profileArray addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"cpu64bit", @"CPU is 64-Bit?", [NSNumber numberWithBool:is64bit], is64bit ? @"Yes" : @"No", nil] forKeys:profileDictKeys]];
}
error = sysctlbyname("hw.cpusubtype", &value, &length, NULL, 0);
if (error == 0) {
NSString *visibleCPUSubType;
if (cpuType == 7) {
// Intel
visibleCPUSubType = is64bit ? @"Intel Core 2" : @"Intel Core"; // If anyone knows how to tell a Core Duo from a Core Solo, please email tph@atomicbird.com
} else if (cpuType == 18) {
// PowerPC
switch(value) {
case 9: visibleCPUSubType=@"G3"; break;
case 10: case 11: visibleCPUSubType=@"G4"; break;
case 100: visibleCPUSubType=@"G5"; break;
default: visibleCPUSubType=@"Other"; break;
}
} else {
visibleCPUSubType = @"Other";
}
[profileArray addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"cpusubtype",@"CPU Subtype", [NSNumber numberWithInt:value], visibleCPUSubType,nil] forKeys:profileDictKeys]];
}
error = sysctlbyname("hw.model", NULL, &length, NULL, 0);
if (error == 0) {
char *cpuModel = (char *)malloc(sizeof(char) * length);
if (cpuModel != NULL) {
error = sysctlbyname("hw.model", cpuModel, &length, NULL, 0);
if (error == 0) {
NSString *rawModelName = [NSString stringWithUTF8String:cpuModel];
NSString *visibleModelName = [modelTranslation objectForKey:rawModelName];
if (visibleModelName == nil)
visibleModelName = rawModelName;
[profileArray addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"model",@"Mac Model", rawModelName, visibleModelName, nil] forKeys:profileDictKeys]];
}
free(cpuModel);
}
}
// Number of CPUs
error = sysctlbyname("hw.ncpu", &value, &length, NULL, 0);
if (error == 0)
[profileArray addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"ncpu",@"Number of CPUs", [NSNumber numberWithInt:value], [NSNumber numberWithInt:value],nil] forKeys:profileDictKeys]];
// User preferred language
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
NSArray *languages = [defs objectForKey:@"AppleLanguages"];
if ([languages count] > 0)
[profileArray addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"lang",@"Preferred Language", [languages objectAtIndex:0], [languages objectAtIndex:0],nil] forKeys:profileDictKeys]];
// Application sending the request
NSString *appName = [host name];
if (appName)
[profileArray addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"appName",@"Application Name", appName, appName,nil] forKeys:profileDictKeys]];
NSString *appVersion = [host version];
if (appVersion)
[profileArray addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"appVersion",@"Application Version", appVersion, appVersion,nil] forKeys:profileDictKeys]];
// Number of displays?
// CPU speed
SInt32 gestaltInfo;
OSErr err = Gestalt(gestaltProcClkSpeedMHz,&gestaltInfo);
if (err == noErr)
[profileArray addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"cpuFreqMHz",@"CPU Speed (GHz)", [NSNumber numberWithInt:gestaltInfo], [NSNumber numberWithDouble:gestaltInfo/1000.0],nil] forKeys:profileDictKeys]];
// amount of RAM
err = Gestalt(gestaltPhysicalRAMSizeInMegabytes,&gestaltInfo);
if (err == noErr)
[profileArray addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"ramMB",@"Memory (MB)", [NSNumber numberWithInt:gestaltInfo], [NSNumber numberWithInt:gestaltInfo],nil] forKeys:profileDictKeys]];
return profileArray;
}
@end

View File

@ -1,29 +0,0 @@
//
// SUUIBasedUpdateDriver.h
// Sparkle
//
// Created by Andy Matuschak on 5/5/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUUIBASEDUPDATEDRIVER_H
#define SUUIBASEDUPDATEDRIVER_H
#import <Cocoa/Cocoa.h>
#import "SUBasicUpdateDriver.h"
@class SUStatusController, SUUpdateAlert;
@interface SUUIBasedUpdateDriver : SUBasicUpdateDriver
{
SUStatusController *statusController;
SUUpdateAlert *updateAlert;
}
- (void)showModalAlert:(NSAlert *)alert;
- (IBAction)cancelDownload: (id)sender;
- (void)installAndRestart: (id)sender;
@end
#endif

View File

@ -1,236 +0,0 @@
//
// SUUIBasedUpdateDriver.m
// Sparkle
//
// Created by Andy Matuschak on 5/5/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUUIBasedUpdateDriver.h"
#import "SUUpdateAlert.h"
#import "SUUpdater_Private.h"
#import "SUHost.h"
#import "SUStatusController.h"
#import "SUConstants.h"
#import "SUPasswordPrompt.h"
@implementation SUUIBasedUpdateDriver
- (void)didFindValidUpdate
{
updateAlert = [[SUUpdateAlert alloc] initWithAppcastItem:updateItem host:host];
[updateAlert setDelegate:self];
id<SUVersionDisplay> versDisp = nil;
if ([[updater delegate] respondsToSelector:@selector(versionDisplayerForUpdater:)])
versDisp = [[updater delegate] versionDisplayerForUpdater: updater];
[updateAlert setVersionDisplayer: versDisp];
if ([[updater delegate] respondsToSelector:@selector(updater:didFindValidUpdate:)])
[[updater delegate] updater:updater didFindValidUpdate:updateItem];
// If the app is a menubar app or the like, we need to focus it first and alter the
// update prompt to behave like a normal window. Otherwise if the window were hidden
// there may be no way for the application to be activated to make it visible again.
if ([host isBackgroundApplication])
{
[[updateAlert window] setHidesOnDeactivate:NO];
[NSApp activateIgnoringOtherApps:YES];
}
// Only show the update alert if the app is active; otherwise, we'll wait until it is.
if ([NSApp isActive])
[[updateAlert window] makeKeyAndOrderFront:self];
else
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:NSApplicationDidBecomeActiveNotification object:NSApp];
}
- (void)didNotFindUpdate
{
if ([[updater delegate] respondsToSelector:@selector(updaterDidNotFindUpdate:)])
[[updater delegate] updaterDidNotFindUpdate:updater];
NSAlert *alert = [NSAlert alertWithMessageText:SULocalizedString(@"You're up-to-date!", nil) defaultButton:SULocalizedString(@"OK", nil) alternateButton:nil otherButton:nil informativeTextWithFormat:SULocalizedString(@"%@ %@ is currently the newest version available.", nil), [host name], [host displayVersion]];
[self showModalAlert:alert];
[self abortUpdate];
}
- (void)applicationDidBecomeActive:(NSNotification *)aNotification
{
[[updateAlert window] makeKeyAndOrderFront:self];
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSApplicationDidBecomeActiveNotification" object:NSApp];
}
- (void)updateAlert:(SUUpdateAlert *)alert finishedWithChoice:(SUUpdateAlertChoice)choice
{
[updateAlert release]; updateAlert = nil;
[host setObject:nil forUserDefaultsKey:SUSkippedVersionKey];
switch (choice)
{
case SUInstallUpdateChoice:
statusController = [[SUStatusController alloc] initWithHost:host];
[statusController beginActionWithTitle:SULocalizedString(@"Downloading update...", @"Take care not to overflow the status window.") maxProgressValue:0.0 statusText:nil];
[statusController setButtonTitle:SULocalizedString(@"Cancel", nil) target:self action:@selector(cancelDownload:) isDefault:NO];
[statusController showWindow:self];
[self downloadUpdate];
break;
case SUOpenInfoURLChoice:
[[NSWorkspace sharedWorkspace] openURL: [updateItem infoURL]];
[self abortUpdate];
break;
case SUSkipThisVersionChoice:
[host setObject:[updateItem versionString] forUserDefaultsKey:SUSkippedVersionKey];
[self abortUpdate];
break;
case SURemindMeLaterChoice:
[self abortUpdate];
break;
}
}
- (void)download:(NSURLDownload *)download didReceiveResponse:(NSURLResponse *)response
{
[statusController setMaxProgressValue:[response expectedContentLength]];
}
- (NSString *)humanReadableSizeFromDouble:(double)value
{
if (value < 1000)
return [NSString stringWithFormat:@"%.0lf %@", value, SULocalizedString(@"B", @"the unit for bytes")];
if (value < 1000 * 1000)
return [NSString stringWithFormat:@"%.0lf %@", value / 1000.0, SULocalizedString(@"KB", @"the unit for kilobytes")];
if (value < 1000 * 1000 * 1000)
return [NSString stringWithFormat:@"%.1lf %@", value / 1000.0 / 1000.0, SULocalizedString(@"MB", @"the unit for megabytes")];
return [NSString stringWithFormat:@"%.2lf %@", value / 1000.0 / 1000.0 / 1000.0, SULocalizedString(@"GB", @"the unit for gigabytes")];
}
- (void)download:(NSURLDownload *)download didReceiveDataOfLength:(NSUInteger)length
{
[statusController setProgressValue:[statusController progressValue] + (double)length];
if ([statusController maxProgressValue] > 0.0)
[statusController setStatusText:[NSString stringWithFormat:SULocalizedString(@"%@ of %@", nil), [self humanReadableSizeFromDouble:[statusController progressValue]], [self humanReadableSizeFromDouble:[statusController maxProgressValue]]]];
else
[statusController setStatusText:[NSString stringWithFormat:SULocalizedString(@"%@ downloaded", nil), [self humanReadableSizeFromDouble:[statusController progressValue]]]];
}
- (IBAction)cancelDownload: (id)sender
{
if (download)
[download cancel];
[self abortUpdate];
}
- (void)extractUpdate
{
// Now we have to extract the downloaded archive.
[statusController beginActionWithTitle:SULocalizedString(@"Extracting update...", @"Take care not to overflow the status window.") maxProgressValue:0.0 statusText:nil];
[statusController setButtonEnabled:NO];
[super extractUpdate];
}
- (void)unarchiver:(SUUnarchiver *)ua extractedLength:(unsigned long)length
{
// We do this here instead of in extractUpdate so that we only have a determinate progress bar for archives with progress.
if ([statusController maxProgressValue] == 0.0)
{
NSDictionary * attributes;
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
attributes = [[NSFileManager defaultManager] fileAttributesAtPath:downloadPath traverseLink:NO];
#else
attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:downloadPath error:nil];
#endif
[statusController setMaxProgressValue:[[attributes objectForKey:NSFileSize] doubleValue]];
}
[statusController setProgressValue:[statusController progressValue] + (double)length];
}
- (void)unarchiverDidFinish:(SUUnarchiver *)ua
{
[statusController beginActionWithTitle:SULocalizedString(@"Ready to Install", nil) maxProgressValue:1.0 statusText:nil];
[statusController setProgressValue:1.0]; // Fill the bar.
[statusController setButtonEnabled:YES];
[statusController setButtonTitle:SULocalizedString(@"Install and Relaunch", nil) target:self action:@selector(installAndRestart:) isDefault:YES];
[[statusController window] makeKeyAndOrderFront: self];
[NSApp requestUserAttention:NSInformationalRequest];
}
- (void)unarchiver:(SUUnarchiver *)unarchiver requiresPasswordReturnedViaInvocation:(NSInvocation *)invocation
{
SUPasswordPrompt *prompt = [[SUPasswordPrompt alloc] initWithHost:host];
NSString *password = nil;
if([prompt run])
{
password = [prompt password];
}
[prompt release];
[invocation setArgument:&password atIndex:2];
[invocation invoke];
}
- (void)installAndRestart: (id)sender
{
[self installWithToolAndRelaunch:YES];
}
- (void)installWithToolAndRelaunch:(BOOL)relaunch
{
[statusController beginActionWithTitle:SULocalizedString(@"Installing update...", @"Take care not to overflow the status window.") maxProgressValue:0.0 statusText:nil];
[statusController setButtonEnabled:NO];
[super installWithToolAndRelaunch:relaunch];
// if a user chooses to NOT relaunch the app (as is the case with WebKit
// when it asks you if you are sure you want to close the app with multiple
// tabs open), the status window still stays on the screen and obscures
// other windows; with this fix, it doesn't
if (statusController)
{
[statusController close];
[statusController autorelease];
statusController = nil;
}
}
- (void)abortUpdateWithError:(NSError *)error
{
NSAlert *alert = [NSAlert alertWithMessageText:SULocalizedString(@"Update Error!", nil) defaultButton:SULocalizedString(@"Cancel Update", nil) alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", [error localizedDescription]];
[self showModalAlert:alert];
[super abortUpdateWithError:error];
}
- (void)abortUpdate
{
if (statusController)
{
[statusController close];
[statusController autorelease];
statusController = nil;
}
[super abortUpdate];
}
- (void)showModalAlert:(NSAlert *)alert
{
if ([[updater delegate] respondsToSelector:@selector(updaterWillShowModalAlert:)])
[[updater delegate] updaterWillShowModalAlert: updater];
// When showing a modal alert we need to ensure that background applications
// are focused to inform the user since there is no dock icon to notify them.
if ([host isBackgroundApplication]) { [NSApp activateIgnoringOtherApps:YES]; }
[alert setIcon:[host icon]];
[alert runModal];
if ([[updater delegate] respondsToSelector:@selector(updaterDidShowModalAlert:)])
[[updater delegate] updaterDidShowModalAlert: updater];
}
@end

View File

@ -1,34 +0,0 @@
//
// SUUnarchiver.h
// Sparkle
//
// Created by Andy Matuschak on 3/16/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SUUNARCHIVER_H
#define SUUNARCHIVER_H
@class SUHost;
@interface SUUnarchiver : NSObject {
id delegate;
NSString *archivePath;
SUHost *updateHost;
}
+ (SUUnarchiver *)unarchiverForPath:(NSString *)path updatingHost:(SUHost *)host;
- (void)setDelegate:delegate;
- (void)start;
@end
@interface NSObject (SUUnarchiverDelegate)
- (void)unarchiver:(SUUnarchiver *)unarchiver extractedLength:(unsigned long)length;
- (void)unarchiverDidFinish:(SUUnarchiver *)unarchiver;
- (void)unarchiverDidFail:(SUUnarchiver *)unarchiver;
- (void)unarchiver:(SUUnarchiver *)unarchiver requiresPasswordReturnedViaInvocation:(NSInvocation *)invocation;
@end
#endif

View File

@ -1,44 +0,0 @@
//
// SUUnarchiver.m
// Sparkle
//
// Created by Andy Matuschak on 3/16/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#import "SUUpdater.h"
#import "SUAppcast.h"
#import "SUAppcastItem.h"
#import "SUVersionComparisonProtocol.h"
#import "SUUnarchiver.h"
#import "SUUnarchiver_Private.h"
@implementation SUUnarchiver
+ (SUUnarchiver *)unarchiverForPath:(NSString *)path updatingHost:(SUHost *)host
{
NSEnumerator *implementationEnumerator = [[self unarchiverImplementations] objectEnumerator];
id current;
while ((current = [implementationEnumerator nextObject]))
{
if ([current canUnarchivePath:path])
return [[[current alloc] initWithPath:path host:host] autorelease];
}
return nil;
}
- (NSString *)description { return [NSString stringWithFormat:@"%@ <%@>", [self class], archivePath]; }
- (void)setDelegate:del
{
delegate = del;
}
- (void)start
{
// No-op
}
@end

View File

@ -1,26 +0,0 @@
//
// SUUnarchiver_Private.h
// Sparkle
//
// Created by Andy Matuschak on 6/17/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUUNARCHIVER_PRIVATE_H
#define SUUNARCHIVER_PRIVATE_H
#import <Cocoa/Cocoa.h>
#import "SUUnarchiver.h"
@interface SUUnarchiver (Private)
+ (void)registerImplementation:(Class)implementation;
+ (NSArray *)unarchiverImplementations;
+ (BOOL)canUnarchivePath:(NSString *)path;
- (id)initWithPath:(NSString *)path host:(SUHost *)host;;
- (void)notifyDelegateOfExtractedLength:(NSNumber *)length;
- (void)notifyDelegateOfSuccess;
- (void)notifyDelegateOfFailure;
@end
#endif

View File

@ -1,67 +0,0 @@
//
// SUUnarchiver_Private.m
// Sparkle
//
// Created by Andy Matuschak on 6/17/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUUnarchiver_Private.h"
@implementation SUUnarchiver (Private)
- (id)initWithPath:(NSString *)path host:(SUHost *)host
{
if ((self = [super init]))
{
archivePath = [path copy];
updateHost = [host retain];
}
return self;
}
- (void)dealloc
{
[archivePath release];
[updateHost release];
[super dealloc];
}
+ (BOOL)canUnarchivePath:(NSString *)path
{
return NO;
}
- (void)notifyDelegateOfExtractedLength:(NSNumber *)length
{
if ([delegate respondsToSelector:@selector(unarchiver:extractedLength:)])
[delegate unarchiver:self extractedLength:[length unsignedLongValue]];
}
- (void)notifyDelegateOfSuccess
{
if ([delegate respondsToSelector:@selector(unarchiverDidFinish:)])
[delegate performSelector:@selector(unarchiverDidFinish:) withObject:self];
}
- (void)notifyDelegateOfFailure
{
if ([delegate respondsToSelector:@selector(unarchiverDidFail:)])
[delegate performSelector:@selector(unarchiverDidFail:) withObject:self];
}
static NSMutableArray *gUnarchiverImplementations;
+ (void)registerImplementation:(Class)implementation
{
if (!gUnarchiverImplementations)
gUnarchiverImplementations = [[NSMutableArray alloc] init];
[gUnarchiverImplementations addObject:implementation];
}
+ (NSArray *)unarchiverImplementations
{
return [NSArray arrayWithArray:gUnarchiverImplementations];
}
@end

View File

@ -1,56 +0,0 @@
//
// SUUpdateAlert.h
// Sparkle
//
// Created by Andy Matuschak on 3/12/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SUUPDATEALERT_H
#define SUUPDATEALERT_H
#import "SUWindowController.h"
#import "SUVersionDisplayProtocol.h"
typedef enum
{
SUInstallUpdateChoice,
SURemindMeLaterChoice,
SUSkipThisVersionChoice,
SUOpenInfoURLChoice
} SUUpdateAlertChoice;
@class WebView, SUAppcastItem, SUHost;
@interface SUUpdateAlert : SUWindowController {
SUAppcastItem *updateItem;
SUHost *host;
id delegate;
id<SUVersionDisplay> versionDisplayer;
IBOutlet WebView *releaseNotesView;
IBOutlet NSTextField *description;
IBOutlet NSButton *installButton; // UK 2007-08-31.
IBOutlet NSButton *skipButton;
IBOutlet NSButton *laterButton;
NSProgressIndicator *releaseNotesSpinner;
BOOL webViewFinishedLoading;
}
- (id)initWithAppcastItem:(SUAppcastItem *)item host:(SUHost *)host;
- (void)setDelegate:delegate;
- (IBAction)installUpdate:sender;
- (IBAction)skipThisVersion:sender;
- (IBAction)remindMeLater:sender;
- (void)setVersionDisplayer: (id<SUVersionDisplay>)disp;
@end
@interface NSObject (SUUpdateAlertDelegate)
- (void)updateAlert:(SUUpdateAlert *)updateAlert finishedWithChoice:(SUUpdateAlertChoice)updateChoice;
- (void)updateAlert:(SUUpdateAlert *)updateAlert shouldAllowAutoUpdate: (BOOL*)shouldAllowAutoUpdate;
@end
#endif

View File

@ -1,356 +0,0 @@
//
// SUUpdateAlert.m
// Sparkle
//
// Created by Andy Matuschak on 3/12/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
// -----------------------------------------------------------------------------
// Headers:
// -----------------------------------------------------------------------------
#import "SUUpdateAlert.h"
#import "SUHost.h"
#import <WebKit/WebKit.h>
#import "SUConstants.h"
@interface WebView (SUTenFiveProperty)
-(void) setDrawsBackground: (BOOL)state;
@end
@implementation SUUpdateAlert
- (id)initWithAppcastItem:(SUAppcastItem *)item host:(SUHost *)aHost
{
self = [super initWithHost:host windowNibName:@"SUUpdateAlert"];
if (self)
{
host = [aHost retain];
updateItem = [item retain];
[self setShouldCascadeWindows:NO];
// Alex: This dummy line makes sure that the binary is linked against WebKit.
// The SUUpdateAlert.xib file contains a WebView and if we don't link against WebKit,
// we will get a runtime crash when decoding the NIB. It is better to get a link error.
[WebView MIMETypesShownAsHTML];
}
return self;
}
- (NSString *)description { return [NSString stringWithFormat:@"%@ <%@>", [self class], [host bundlePath]]; }
- (void)dealloc
{
[updateItem release];
[host release];
[super dealloc];
}
- (void)setVersionDisplayer: (id<SUVersionDisplay>)disp
{
versionDisplayer = disp;
}
- (void)endWithSelection:(SUUpdateAlertChoice)choice
{
[releaseNotesView stopLoading:self];
[releaseNotesView setFrameLoadDelegate:nil];
[releaseNotesView setPolicyDelegate:nil];
[releaseNotesView removeFromSuperview]; // Otherwise it gets sent Esc presses (why?!) and gets very confused.
[self close];
if ([delegate respondsToSelector:@selector(updateAlert:finishedWithChoice:)])
[delegate updateAlert:self finishedWithChoice:choice];
}
- (IBAction)installUpdate: (id)sender
{
[self endWithSelection:SUInstallUpdateChoice];
}
- (IBAction)openInfoURL: (id)sender
{
[self endWithSelection:SUOpenInfoURLChoice];
}
- (IBAction)skipThisVersion: (id)sender
{
[self endWithSelection:SUSkipThisVersionChoice];
}
- (IBAction)remindMeLater: (id)sender
{
[self endWithSelection:SURemindMeLaterChoice];
}
- (void)displayReleaseNotes
{
// Set the default font
[releaseNotesView setPreferencesIdentifier:[SPARKLE_BUNDLE bundleIdentifier]];
[[releaseNotesView preferences] setStandardFontFamily:[[NSFont systemFontOfSize:8] familyName]];
[[releaseNotesView preferences] setDefaultFontSize:(int)[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
[releaseNotesView setFrameLoadDelegate:self];
[releaseNotesView setPolicyDelegate:self];
// Stick a nice big spinner in the middle of the web view until the page is loaded.
NSRect frame = [[releaseNotesView superview] frame];
releaseNotesSpinner = [[[NSProgressIndicator alloc] initWithFrame:NSMakeRect(NSMidX(frame)-16, NSMidY(frame)-16, 32, 32)] autorelease];
[releaseNotesSpinner setStyle:NSProgressIndicatorSpinningStyle];
[releaseNotesSpinner startAnimation:self];
webViewFinishedLoading = NO;
[[releaseNotesView superview] addSubview:releaseNotesSpinner];
// If there's a release notes URL, load it; otherwise, just stick the contents of the description into the web view.
if ([updateItem releaseNotesURL])
{
if ([[updateItem releaseNotesURL] isFileURL])
{
[[releaseNotesView mainFrame] loadHTMLString:@"Release notes with file:// URLs are not supported for security reasons&mdash;Javascript would be able to read files on your file system." baseURL:nil];
}
else
{
[[releaseNotesView mainFrame] loadRequest:[NSURLRequest requestWithURL:[updateItem releaseNotesURL] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30]];
}
}
else
{
[[releaseNotesView mainFrame] loadHTMLString:[updateItem itemDescription] baseURL:nil];
}
}
- (BOOL)showsReleaseNotes
{
NSNumber *shouldShowReleaseNotes = [host objectForInfoDictionaryKey:SUShowReleaseNotesKey];
if (shouldShowReleaseNotes == nil)
{
// UK 2007-09-18: Don't show release notes if RSS item contains no description and no release notes URL:
return( ([updateItem itemDescription] != nil
&& [[[updateItem itemDescription] stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]] length] > 0)
|| [updateItem releaseNotesURL] != nil );
}
else
return [shouldShowReleaseNotes boolValue];
}
- (BOOL)allowsAutomaticUpdates
{
BOOL allowAutoUpdates = YES; // Defaults to YES.
if( [host objectForInfoDictionaryKey:SUAllowsAutomaticUpdatesKey] )
allowAutoUpdates = [host boolForInfoDictionaryKey: SUAllowsAutomaticUpdatesKey];
// UK 2007-08-31: Give delegate a chance to modify this choice:
if( delegate && [delegate respondsToSelector: @selector(updateAlert:shouldAllowAutoUpdate:)] )
[delegate updateAlert: self shouldAllowAutoUpdate: &allowAutoUpdates];
return allowAutoUpdates;
}
- (void)awakeFromNib
{
NSString* sizeStr = [host objectForInfoDictionaryKey:SUFixedHTMLDisplaySizeKey];
if( [host isBackgroundApplication] )
[[self window] setLevel:NSFloatingWindowLevel]; // This means the window will float over all other apps, if our app is switched out ?! UK 2007-09-04
[[self window] setFrameAutosaveName: sizeStr ? @"" : @"SUUpdateAlertFrame"];
// We're gonna do some frame magic to match the window's size to the description field and the presence of the release notes view.
NSRect frame = [[self window] frame];
BOOL showReleaseNotes = [self showsReleaseNotes]; // UK 2007-09-18
if (!showReleaseNotes) // UK 2007-09-18
{
// Resize the window to be appropriate for not having a huge release notes view.
frame.size.height -= [releaseNotesView frame].size.height + 40; // Extra 40 is for the release notes label and margin.
if ([self allowsAutomaticUpdates])
frame.size.height += 10; // Make room for the check box.
// Hiding the resize handles is not enough on 10.5, you can still click
// where they would be, so we set the min/max sizes to be equal to
// inhibit resizing completely:
[[self window] setShowsResizeIndicator: NO];
[[self window] setMinSize: frame.size];
[[self window] setMaxSize: frame.size];
}
else if (![self allowsAutomaticUpdates])
{
NSRect boxFrame = [[[releaseNotesView superview] superview] frame];
boxFrame.origin.y -= 20;
boxFrame.size.height += 20;
[[[releaseNotesView superview] superview] setFrame:boxFrame];
}
if( [updateItem fileURL] == nil ) // UK 2007-08-31 (whole if clause)
{
[installButton setTitle: SULocalizedString( @"Learn More...", @"Alternate title for 'Install Update' button when there's no download in RSS feed." )];
[installButton setAction: @selector(openInfoURL:)];
}
// Make sure button widths are OK:
#define DISTANCE_BETWEEN_BUTTONS 3
#define DISTANCE_BETWEEN_BUTTON_GROUPS 12
CGFloat minimumWindowWidth = [[self window] frame].size.width -NSMaxX([installButton frame]) +NSMinX([skipButton frame]); // Distance between contents and left/right edge.
NSDictionary* attrs = [NSDictionary dictionaryWithObjectsAndKeys: [installButton font], NSFontAttributeName, nil];
NSSize titleSize = [[installButton title] sizeWithAttributes: attrs];
titleSize.width += (16 + 8) * 2; // 16 px for the end caps plus 8 px padding at each end or it'll look as ugly as calling -sizeToFit.
NSRect installBtnBox = [installButton frame];
installBtnBox.origin.x += installBtnBox.size.width -titleSize.width;
installBtnBox.size.width = titleSize.width;
[installButton setFrame: installBtnBox];
minimumWindowWidth += titleSize.width;
titleSize = [[laterButton title] sizeWithAttributes: attrs];
titleSize.width += (16 + 8) * 2; // 16 px for the end caps plus 8 px padding at each end or it'll look as ugly as calling -sizeToFit.
NSRect laterBtnBox = [installButton frame];
laterBtnBox.origin.x = installBtnBox.origin.x -DISTANCE_BETWEEN_BUTTONS -titleSize.width;
laterBtnBox.size.width = titleSize.width;
[laterButton setFrame: laterBtnBox];
minimumWindowWidth += DISTANCE_BETWEEN_BUTTONS +titleSize.width;
titleSize = [[skipButton title] sizeWithAttributes: attrs];
titleSize.width += (16 + 8) * 2; // 16 px for the end caps plus 8 px padding at each end or it'll look as ugly as calling -sizeToFit.
NSRect skipBtnBox = [skipButton frame];
skipBtnBox.size.width = titleSize.width;
[skipButton setFrame: skipBtnBox];
minimumWindowWidth += DISTANCE_BETWEEN_BUTTON_GROUPS +titleSize.width;
if( showReleaseNotes ) // UK 2007-09-18 (whole block)
{
if( sizeStr )
{
NSSize desiredSize = NSSizeFromString( sizeStr );
NSSize sizeDiff = NSZeroSize;
// NSBox* boxView = (NSBox*)[[releaseNotesView superview] superview];
//[boxView setBorderType: NSNoBorder];
[releaseNotesView setDrawsBackground: NO];
sizeDiff.width = desiredSize.width -[releaseNotesView frame].size.width;
sizeDiff.height = desiredSize.height -[releaseNotesView frame].size.height;
frame.size.width += sizeDiff.width;
frame.size.height += sizeDiff.height;
// No resizing:
[[self window] setShowsResizeIndicator:NO];
[[self window] setMinSize:frame.size];
[[self window] setMaxSize:frame.size];
}
}
if( frame.size.width < minimumWindowWidth )
frame.size.width = minimumWindowWidth;
[[self window] setFrame: frame display: NO];
[[self window] center];
if (showReleaseNotes) // UK 2007-09-18
{
[self displayReleaseNotes];
}
[[[releaseNotesView superview] superview] setHidden: !showReleaseNotes]; // UK 2007-09-18
}
-(BOOL)showsReleaseNotesText
{
return( [host objectForInfoDictionaryKey:SUFixedHTMLDisplaySizeKey] == nil );
}
- (BOOL)windowShouldClose:note
{
[self endWithSelection:SURemindMeLaterChoice];
return YES;
}
- (NSImage *)applicationIcon
{
return [host icon];
}
- (NSString *)titleText
{
return [NSString stringWithFormat:SULocalizedString(@"A new version of %@ is available!", nil), [host name]];
}
- (NSString *)descriptionText
{
NSString *updateItemVersion = [updateItem displayVersionString];
NSString *hostVersion = [host displayVersion];
// Display more info if the version strings are the same; useful for betas.
if( !versionDisplayer && [updateItemVersion isEqualToString:hostVersion] )
{
updateItemVersion = [updateItemVersion stringByAppendingFormat:@" (%@)", [updateItem versionString]];
hostVersion = [hostVersion stringByAppendingFormat:@" (%@)", [host version]];
}
else
[versionDisplayer formatVersion: &updateItemVersion andVersion: &hostVersion];
return [NSString stringWithFormat:SULocalizedString(@"%@ %@ is now available--you have %@. Would you like to download it now?", nil), [host name], updateItemVersion, hostVersion];
}
- (void)webView:(WebView *)sender didFinishLoadForFrame:frame
{
if ([frame parentFrame] == nil) {
webViewFinishedLoading = YES;
[releaseNotesSpinner setHidden:YES];
[sender display]; // necessary to prevent weird scroll bar artifacting
}
}
- (void)webView:sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:frame decisionListener:listener
{
if (webViewFinishedLoading) {
[[NSWorkspace sharedWorkspace] openURL:[request URL]];
[listener ignore];
}
else {
[listener use];
}
}
// Clean up the contextual menu.
- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems
{
NSMutableArray *webViewMenuItems = [[defaultMenuItems mutableCopy] autorelease];
if (webViewMenuItems)
{
NSEnumerator *itemEnumerator = [defaultMenuItems objectEnumerator];
NSMenuItem *menuItem = nil;
while ((menuItem = [itemEnumerator nextObject]))
{
NSInteger tag = [menuItem tag];
switch (tag)
{
case WebMenuItemTagOpenLinkInNewWindow:
case WebMenuItemTagDownloadLinkToDisk:
case WebMenuItemTagOpenImageInNewWindow:
case WebMenuItemTagDownloadImageToDisk:
case WebMenuItemTagOpenFrameInNewWindow:
case WebMenuItemTagGoBack:
case WebMenuItemTagGoForward:
case WebMenuItemTagStop:
case WebMenuItemTagReload:
[webViewMenuItems removeObjectIdenticalTo: menuItem];
}
}
}
return webViewMenuItems;
}
- (void)setDelegate:del
{
delegate = del;
}
@end

View File

@ -1,35 +0,0 @@
//
// SUUpdateDriver.h
// Sparkle
//
// Created by Andy Matuschak on 5/7/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUUPDATEDRIVER_H
#define SUUPDATEDRIVER_H
#import <Cocoa/Cocoa.h>
extern NSString * const SUUpdateDriverFinishedNotification;
@class SUHost, SUUpdater;
@interface SUUpdateDriver : NSObject
{
SUHost *host;
SUUpdater *updater;
NSURL *appcastURL;
BOOL finished;
}
- initWithUpdater:(SUUpdater *)updater;
- (void)checkForUpdatesAtURL:(NSURL *)URL host:(SUHost *)host;
- (void)abortUpdate;
- (BOOL)finished;
- (SUHost*)host;
- (void)setHost:(SUHost*)newHost;
@end
#endif

View File

@ -1,56 +0,0 @@
//
// SUUpdateDriver.m
// Sparkle
//
// Created by Andy Matuschak on 5/7/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUUpdateDriver.h"
#import "SUHost.h"
NSString * const SUUpdateDriverFinishedNotification = @"SUUpdateDriverFinished";
@implementation SUUpdateDriver
- initWithUpdater:(SUUpdater *)anUpdater
{
if ((self = [super init]))
updater = anUpdater;
return self;
}
- (NSString *)description { return [NSString stringWithFormat:@"%@ <%@, %@>", [self class], [host bundlePath], [host installationPath]]; }
- (void)checkForUpdatesAtURL:(NSURL *)URL host:(SUHost *)h
{
appcastURL = [URL copy];
host = [h retain];
}
- (void)abortUpdate
{
[self setValue:[NSNumber numberWithBool:YES] forKey:@"finished"];
[[NSNotificationCenter defaultCenter] postNotificationName:SUUpdateDriverFinishedNotification object:self];
}
- (BOOL)finished { return finished; }
- (void)dealloc
{
[host release];
[appcastURL release];
[super dealloc];
}
- (SUHost*)host
{
return host;
}
- (void)setHost:(SUHost*)newHost
{
[host release];
host = [newHost retain];
}
@end

View File

@ -1,39 +0,0 @@
//
// SUUpdatePermissionPrompt.h
// Sparkle
//
// Created by Andy Matuschak on 1/24/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUUPDATEPERMISSIONPROMPT_H
#define SUUPDATEPERMISSIONPROMPT_H
#import "SUWindowController.h"
typedef enum {
SUAutomaticallyCheck,
SUDoNotAutomaticallyCheck
} SUPermissionPromptResult;
@class SUHost;
@interface SUUpdatePermissionPrompt : SUWindowController {
SUHost *host;
NSArray *systemProfileInformationArray;
id delegate;
IBOutlet NSTextField *descriptionTextField;
IBOutlet NSView *moreInfoView;
IBOutlet NSButton *moreInfoButton;
IBOutlet NSTableView *profileTableView;
BOOL isShowingMoreInfo, shouldSendProfile;
}
+ (void)promptWithHost:(SUHost *)aHost systemProfile:(NSArray *)profile delegate:(id)d;
- (IBAction)toggleMoreInfo:(id)sender;
- (IBAction)finishPrompt:(id)sender;
@end
@interface NSObject (SUUpdatePermissionPromptDelegateInformalProtocol)
- (void)updatePermissionPromptFinishedWithResult:(SUPermissionPromptResult)result;
@end
#endif

View File

@ -1,136 +0,0 @@
//
// SUUpdatePermissionPrompt.m
// Sparkle
//
// Created by Andy Matuschak on 1/24/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUUpdatePermissionPrompt.h"
#import "SUHost.h"
#import "SUConstants.h"
@implementation SUUpdatePermissionPrompt
- (BOOL)shouldAskAboutProfile
{
return [[host objectForInfoDictionaryKey:SUEnableSystemProfilingKey] boolValue];
}
- (id)initWithHost:(SUHost *)aHost systemProfile:(NSArray *)profile delegate:(id)d
{
self = [super initWithHost:aHost windowNibName:@"SUUpdatePermissionPrompt"];
if (self)
{
host = [aHost retain];
delegate = d;
isShowingMoreInfo = NO;
shouldSendProfile = [self shouldAskAboutProfile];
systemProfileInformationArray = [profile retain];
[self setShouldCascadeWindows:NO];
}
return self;
}
+ (void)promptWithHost:(SUHost *)aHost systemProfile:(NSArray *)profile delegate:(id)d
{
// If this is a background application we need to focus it in order to bring the prompt
// to the user's attention. Otherwise the prompt would be hidden behind other applications and
// the user would not know why the application was paused.
if ([aHost isBackgroundApplication]) { [NSApp activateIgnoringOtherApps:YES]; }
id prompt = [[[[self class] alloc] initWithHost:aHost systemProfile:profile delegate:d] autorelease];
[NSApp runModalForWindow:[prompt window]];
}
- (NSString *)description { return [NSString stringWithFormat:@"%@ <%@>", [self class], [host bundlePath]]; }
- (void)awakeFromNib
{
if (![self shouldAskAboutProfile])
{
NSRect frame = [[self window] frame];
frame.size.height -= [moreInfoButton frame].size.height;
[[self window] setFrame:frame display:YES];
} else {
// Set the table view's delegate so we can disable row selection.
[profileTableView setDelegate:(id)self];
}
}
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row { return NO; }
- (void)dealloc
{
[host release];
[systemProfileInformationArray release];
[super dealloc];
}
- (NSImage *)icon
{
return [host icon];
}
- (NSString *)promptDescription
{
return [NSString stringWithFormat:SULocalizedString(@"Should %1$@ automatically check for updates? You can always check for updates manually from the %1$@ menu.", nil), [host name]];
}
- (IBAction)toggleMoreInfo:(id)sender
{
[self willChangeValueForKey:@"isShowingMoreInfo"];
isShowingMoreInfo = !isShowingMoreInfo;
[self didChangeValueForKey:@"isShowingMoreInfo"];
NSView *contentView = [[self window] contentView];
NSRect contentViewFrame = [contentView frame];
NSRect windowFrame = [[self window] frame];
NSRect profileMoreInfoViewFrame = [moreInfoView frame];
NSRect profileMoreInfoButtonFrame = [moreInfoButton frame];
NSRect descriptionFrame = [descriptionTextField frame];
if (isShowingMoreInfo)
{
// Add the subview
contentViewFrame.size.height += profileMoreInfoViewFrame.size.height;
profileMoreInfoViewFrame.origin.y = profileMoreInfoButtonFrame.origin.y - profileMoreInfoViewFrame.size.height;
profileMoreInfoViewFrame.origin.x = descriptionFrame.origin.x;
profileMoreInfoViewFrame.size.width = descriptionFrame.size.width;
windowFrame.size.height += profileMoreInfoViewFrame.size.height;
windowFrame.origin.y -= profileMoreInfoViewFrame.size.height;
[moreInfoView setFrame:profileMoreInfoViewFrame];
[moreInfoView setHidden:YES];
[contentView addSubview:moreInfoView
positioned:NSWindowBelow
relativeTo:moreInfoButton];
} else {
// Remove the subview
[moreInfoView setHidden:NO];
[moreInfoView removeFromSuperview];
contentViewFrame.size.height -= profileMoreInfoViewFrame.size.height;
windowFrame.size.height -= profileMoreInfoViewFrame.size.height;
windowFrame.origin.y += profileMoreInfoViewFrame.size.height;
}
[[self window] setFrame:windowFrame display:YES animate:YES];
[contentView setFrame:contentViewFrame];
[contentView setNeedsDisplay:YES];
[moreInfoView setHidden:(!isShowingMoreInfo)];
}
- (IBAction)finishPrompt:(id)sender
{
if (![delegate respondsToSelector:@selector(updatePermissionPromptFinishedWithResult:)])
[NSException raise:@"SUInvalidDelegate" format:@"SUUpdatePermissionPrompt's delegate (%@) doesn't respond to updatePermissionPromptFinishedWithResult:!", delegate];
[host setBool:shouldSendProfile forUserDefaultsKey:SUSendProfileInfoKey];
[delegate updatePermissionPromptFinishedWithResult:([sender tag] == 1 ? SUAutomaticallyCheck : SUDoNotAutomaticallyCheck)];
[[self window] close];
[NSApp stopModal];
}
@end

View File

@ -1,161 +0,0 @@
//
// SUUpdater.h
// Sparkle
//
// Created by Andy Matuschak on 1/4/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SUUPDATER_H
#define SUUPDATER_H
#import "SUVersionComparisonProtocol.h"
#import "SUVersionDisplayProtocol.h"
@class SUUpdateDriver, SUAppcastItem, SUHost, SUAppcast;
@interface SUUpdater : NSObject
{
@private
NSTimer *checkTimer;
SUUpdateDriver *driver;
NSString *customUserAgentString;
SUHost *host;
IBOutlet id delegate;
}
+ (SUUpdater *)sharedUpdater;
+ (SUUpdater *)updaterForBundle:(NSBundle *)bundle;
- (id)initForBundle:(NSBundle *)bundle;
- (NSBundle *)hostBundle;
- (void)setDelegate:(id)delegate;
- (id)delegate;
- (void)setAutomaticallyChecksForUpdates:(BOOL)automaticallyChecks;
- (BOOL)automaticallyChecksForUpdates;
- (void)setUpdateCheckInterval:(NSTimeInterval)interval;
- (NSTimeInterval)updateCheckInterval;
- (void)setFeedURL:(NSURL *)feedURL;
- (NSURL *)feedURL; // *** MUST BE CALLED ON MAIN THREAD ***
- (void)setUserAgentString:(NSString *)userAgent;
- (NSString *)userAgentString;
- (void)setSendsSystemProfile:(BOOL)sendsSystemProfile;
- (BOOL)sendsSystemProfile;
- (void)setAutomaticallyDownloadsUpdates:(BOOL)automaticallyDownloadsUpdates;
- (BOOL)automaticallyDownloadsUpdates;
// This IBAction is meant for a main menu item. Hook up any menu item to this action,
// and Sparkle will check for updates and report back its findings verbosely.
- (IBAction)checkForUpdates:(id)sender;
// This kicks off an update meant to be programmatically initiated. That is, it will display no UI unless it actually finds an update,
// in which case it proceeds as usual. If the fully automated updating is turned on, however, this will invoke that behavior, and if an
// update is found, it will be downloaded and prepped for installation.
- (void)checkForUpdatesInBackground;
// Date of last update check. Returns nil if no check has been performed.
- (NSDate*)lastUpdateCheckDate;
// This begins a "probing" check for updates which will not actually offer to update to that version. The delegate methods, though,
// (up to updater:didFindValidUpdate: and updaterDidNotFindUpdate:), are called, so you can use that information in your UI.
- (void)checkForUpdateInformation;
// Call this to appropriately schedule or cancel the update checking timer according to the preferences for time interval and automatic checks. This call does not change the date of the next check, but only the internal NSTimer.
- (void)resetUpdateCycle;
- (BOOL)updateInProgress;
@end
// -----------------------------------------------------------------------------
// SUUpdater Delegate:
// -----------------------------------------------------------------------------
@interface NSObject (SUUpdaterDelegateInformalProtocol)
// Use this to keep Sparkle from popping up e.g. while your setup assistant is showing:
- (BOOL)updaterMayCheckForUpdates:(SUUpdater *)bundle;
// This method allows you to add extra parameters to the appcast URL, potentially based on whether or not Sparkle will also be sending along the system profile. This method should return an array of dictionaries with keys: "key", "value", "displayKey", "displayValue", the latter two being specifically for display to the user.
- (NSArray *)feedParametersForUpdater:(SUUpdater *)updater sendingSystemProfile:(BOOL)sendingProfile;
// Override this to dynamically specify the entire URL.
- (NSString*)feedURLStringForUpdater:(SUUpdater*)updater;
// Use this to override the default behavior for Sparkle prompting the user about automatic update checks.
- (BOOL)updaterShouldPromptForPermissionToCheckForUpdates:(SUUpdater *)bundle;
// Implement this if you want to do some special handling with the appcast once it finishes loading.
- (void)updater:(SUUpdater *)updater didFinishLoadingAppcast:(SUAppcast *)appcast;
// If you're using special logic or extensions in your appcast, implement this to use your own logic for finding
// a valid update, if any, in the given appcast.
- (SUAppcastItem *)bestValidUpdateInAppcast:(SUAppcast *)appcast forUpdater:(SUUpdater *)bundle;
// Sent when a valid update is found by the update driver.
- (void)updater:(SUUpdater *)updater didFindValidUpdate:(SUAppcastItem *)update;
// Sent when a valid update is not found.
- (void)updaterDidNotFindUpdate:(SUUpdater *)update;
// Sent immediately before installing the specified update.
- (void)updater:(SUUpdater *)updater willInstallUpdate:(SUAppcastItem *)update;
// Return YES to delay the relaunch until you do some processing; invoke the given NSInvocation to continue.
// This is not called if the user didn't relaunch on the previous update, in that case it will immediately
// restart.
- (BOOL)updater:(SUUpdater *)updater shouldPostponeRelaunchForUpdate:(SUAppcastItem *)update untilInvoking:(NSInvocation *)invocation;
// Some apps *can not* be relaunched in certain circumstances. They can use this method
// to prevent a relaunch "hard":
- (BOOL)updaterShouldRelaunchApplication:(SUUpdater *)updater;
// Called immediately before relaunching.
- (void)updaterWillRelaunchApplication:(SUUpdater *)updater;
// This method allows you to provide a custom version comparator.
// If you don't implement this method or return nil, the standard version comparator will be used.
- (id <SUVersionComparison>)versionComparatorForUpdater:(SUUpdater *)updater;
// This method allows you to provide a custom version comparator.
// If you don't implement this method or return nil, the standard version displayer will be used.
- (id <SUVersionDisplay>)versionDisplayerForUpdater:(SUUpdater *)updater;
// Returns the path which is used to relaunch the client after the update is installed. By default, the path of the host bundle.
- (NSString *)pathToRelaunchForUpdater:(SUUpdater *)updater;
// Called before and after, respectively, an updater shows a modal alert window, to give the host
// the opportunity to hide attached windows etc. that may get in the way:
-(void) updaterWillShowModalAlert:(SUUpdater *)updater;
-(void) updaterDidShowModalAlert:(SUUpdater *)updater;
@end
// -----------------------------------------------------------------------------
// Constants:
// -----------------------------------------------------------------------------
// Define some minimum intervals to avoid DOS-like checking attacks. These are in seconds.
#if defined(DEBUG) && DEBUG && 0
#define SU_MIN_CHECK_INTERVAL 60
#else
#define SU_MIN_CHECK_INTERVAL 60*60
#endif
#if defined(DEBUG) && DEBUG && 0
#define SU_DEFAULT_CHECK_INTERVAL 60
#else
#define SU_DEFAULT_CHECK_INTERVAL 60*60*24
#endif
#endif

View File

@ -1,557 +0,0 @@
//
// SUUpdater.m
// Sparkle
//
// Created by Andy Matuschak on 1/4/06.
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#import "SUUpdater.h"
#import "SUHost.h"
#import "SUUpdatePermissionPrompt.h"
#import "SUAutomaticUpdateDriver.h"
#import "SUProbingUpdateDriver.h"
#import "SUUserInitiatedUpdateDriver.h"
#import "SUScheduledUpdateDriver.h"
#import "SUConstants.h"
#import "SULog.h"
#import "SUCodeSigningVerifier.h"
#include <SystemConfiguration/SystemConfiguration.h>
@interface SUUpdater (Private)
- (id)initForBundle:(NSBundle *)bundle;
- (void)startUpdateCycle;
- (void)checkForUpdatesWithDriver:(SUUpdateDriver *)updateDriver;
- (BOOL)automaticallyDownloadsUpdates;
- (void)scheduleNextUpdateCheck;
- (void)registerAsObserver;
- (void)unregisterAsObserver;
- (void)updateDriverDidFinish:(NSNotification *)note;
- (NSURL *)parameterizedFeedURL;
-(void) notifyWillShowModalAlert;
-(void) notifyDidShowModalAlert;
@end
@implementation SUUpdater
#pragma mark Initialization
static NSMutableDictionary *sharedUpdaters = nil;
static NSString * const SUUpdaterDefaultsObservationContext = @"SUUpdaterDefaultsObservationContext";
+ (SUUpdater *)sharedUpdater
{
return [self updaterForBundle:[NSBundle mainBundle]];
}
// SUUpdater has a singleton for each bundle. We use the fact that NSBundle instances are also singletons, so we can use them as keys. If you don't trust that you can also use the identifier as key
+ (SUUpdater *)updaterForBundle:(NSBundle *)bundle
{
if (bundle == nil) bundle = [NSBundle mainBundle];
id updater = [sharedUpdaters objectForKey:[NSValue valueWithNonretainedObject:bundle]];
if (updater == nil)
updater = [[[[self class] alloc] initForBundle:bundle] autorelease];
return updater;
}
// This is the designated initializer for SUUpdater, important for subclasses
- (id)initForBundle:(NSBundle *)bundle
{
self = [super init];
if (bundle == nil) bundle = [NSBundle mainBundle];
// Register as observer straight away to avoid exceptions on -dealloc when -unregisterAsObserver is called:
if (self)
[self registerAsObserver];
id updater = [sharedUpdaters objectForKey:[NSValue valueWithNonretainedObject:bundle]];
if (updater)
{
[self release];
self = [updater retain];
}
else if (self)
{
if (sharedUpdaters == nil)
sharedUpdaters = [[NSMutableDictionary alloc] init];
[sharedUpdaters setObject:self forKey:[NSValue valueWithNonretainedObject:bundle]];
host = [[SUHost alloc] initWithBundle:bundle];
#if !ENDANGER_USERS_WITH_INSECURE_UPDATES
// Saving-the-developer-from-a-stupid-mistake-check:
BOOL hasPublicDSAKey = [host publicDSAKey] != nil;
BOOL isMainBundle = [bundle isEqualTo:[NSBundle mainBundle]];
BOOL hostIsCodeSigned = [SUCodeSigningVerifier hostApplicationIsCodeSigned];
if (!isMainBundle && !hasPublicDSAKey) {
[self notifyWillShowModalAlert];
NSRunAlertPanel(@"Insecure update error!", @"For security reasons, you need to sign your updates with a DSA key. See Sparkle's documentation for more information.", @"OK", nil, nil);
[self notifyDidShowModalAlert];
} else if (isMainBundle && !(hasPublicDSAKey || hostIsCodeSigned)) {
[self notifyWillShowModalAlert];
NSRunAlertPanel(@"Insecure update error!", @"For security reasons, you need to code sign your application or sign your updates with a DSA key. See Sparkle's documentation for more information.", @"OK", nil, nil);
[self notifyDidShowModalAlert];
}
#endif
// This runs the permission prompt if needed, but never before the app has finished launching because the runloop won't run before that
[self performSelector:@selector(startUpdateCycle) withObject:nil afterDelay:0];
}
return self;
}
// This will be used when the updater is instantiated in a nib such as MainMenu
- (id)init
{
return [self initForBundle:[NSBundle mainBundle]];
}
- (NSString *)description { return [NSString stringWithFormat:@"%@ <%@, %@>", [self class], [host bundlePath], [host installationPath]]; }
-(void) notifyWillShowModalAlert
{
if( [delegate respondsToSelector: @selector(updaterWillShowModalAlert:)] )
[delegate updaterWillShowModalAlert: self];
}
-(void) notifyDidShowModalAlert
{
if( [delegate respondsToSelector: @selector(updaterDidShowModalAlert:)] )
[delegate updaterDidShowModalAlert: self];
}
- (void)startUpdateCycle
{
BOOL shouldPrompt = NO;
// If the user has been asked about automatic checks, don't bother prompting
if ([host objectForUserDefaultsKey:SUEnableAutomaticChecksKey])
{
shouldPrompt = NO;
}
// Does the delegate want to take care of the logic for when we should ask permission to update?
else if ([delegate respondsToSelector:@selector(updaterShouldPromptForPermissionToCheckForUpdates:)])
{
shouldPrompt = [delegate updaterShouldPromptForPermissionToCheckForUpdates:self];
}
// Has he been asked already? And don't ask if the host has a default value set in its Info.plist.
else if ([host objectForKey:SUEnableAutomaticChecksKey] == nil)
{
if ([host objectForUserDefaultsKey:SUEnableAutomaticChecksKeyOld])
[self setAutomaticallyChecksForUpdates:[host boolForUserDefaultsKey:SUEnableAutomaticChecksKeyOld]];
// Now, we don't want to ask the user for permission to do a weird thing on the first launch.
// We wait until the second launch, unless explicitly overridden via SUPromptUserOnFirstLaunchKey.
else if (![host objectForKey:SUPromptUserOnFirstLaunchKey])
{
if ([host boolForUserDefaultsKey:SUHasLaunchedBeforeKey] == NO)
[host setBool:YES forUserDefaultsKey:SUHasLaunchedBeforeKey];
else
shouldPrompt = YES;
}
else
shouldPrompt = YES;
}
if (shouldPrompt)
{
NSArray *profileInfo = [host systemProfile];
// Always say we're sending the system profile here so that the delegate displays the parameters it would send.
if ([delegate respondsToSelector:@selector(feedParametersForUpdater:sendingSystemProfile:)])
profileInfo = [profileInfo arrayByAddingObjectsFromArray:[delegate feedParametersForUpdater:self sendingSystemProfile:YES]];
[SUUpdatePermissionPrompt promptWithHost:host systemProfile:profileInfo delegate:self];
// We start the update checks and register as observer for changes after the prompt finishes
}
else
{
// We check if the user's said they want updates, or they haven't said anything, and the default is set to checking.
[self scheduleNextUpdateCheck];
}
}
- (void)updatePermissionPromptFinishedWithResult:(SUPermissionPromptResult)result
{
[self setAutomaticallyChecksForUpdates:(result == SUAutomaticallyCheck)];
// Schedule checks, but make sure we ignore the delayed call from KVO
[self resetUpdateCycle];
}
- (void)updateDriverDidFinish:(NSNotification *)note
{
if ([note object] == driver && [driver finished])
{
[driver release]; driver = nil;
[self scheduleNextUpdateCheck];
}
}
- (NSDate *)lastUpdateCheckDate
{
return [host objectForUserDefaultsKey:SULastCheckTimeKey];
}
- (void)scheduleNextUpdateCheck
{
if (checkTimer)
{
[checkTimer invalidate];
[checkTimer release]; // UK 2009-03-16 Timer is non-repeating, may have invalidated itself, so we had to retain it.
checkTimer = nil;
}
if (![self automaticallyChecksForUpdates]) return;
// How long has it been since last we checked for an update?
NSDate *lastCheckDate = [self lastUpdateCheckDate];
if (!lastCheckDate) { lastCheckDate = [NSDate distantPast]; }
NSTimeInterval intervalSinceCheck = [[NSDate date] timeIntervalSinceDate:lastCheckDate];
// Now we want to figure out how long until we check again.
NSTimeInterval delayUntilCheck, updateCheckInterval = [self updateCheckInterval];
if (updateCheckInterval < SU_MIN_CHECK_INTERVAL)
updateCheckInterval = SU_MIN_CHECK_INTERVAL;
if (intervalSinceCheck < updateCheckInterval)
delayUntilCheck = (updateCheckInterval - intervalSinceCheck); // It hasn't been long enough.
else
delayUntilCheck = 0; // We're overdue! Run one now.
checkTimer = [[NSTimer scheduledTimerWithTimeInterval:delayUntilCheck target:self selector:@selector(checkForUpdatesInBackground) userInfo:nil repeats:NO] retain]; // UK 2009-03-16 Timer is non-repeating, may have invalidated itself, so we had to retain it.
}
-(void) putFeedURLIntoDictionary: (NSMutableDictionary*)theDict // You release this.
{
[theDict setObject: [self feedURL] forKey: @"feedURL"];
}
-(void) checkForUpdatesInBgReachabilityCheckWithDriver: (SUUpdateDriver*)inDriver /* RUNS ON ITS OWN THREAD */
{
NS_DURING
// This method *must* be called on its own thread. SCNetworkReachabilityCheckByName
// can block, and it can be waiting a long time on slow networks, and we
// wouldn't want to beachball the main thread for a background operation.
// We could use asynchronous reachability callbacks, but those aren't
// reliable enough and can 'get lost' sometimes, which we don't want.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
SCNetworkConnectionFlags flags = 0;
BOOL isNetworkReachable = YES;
// Don't perform automatic checks on unconnected laptops or dial-up connections that aren't online:
NSMutableDictionary* theDict = [NSMutableDictionary dictionary];
[self performSelectorOnMainThread: @selector(putFeedURLIntoDictionary:) withObject: theDict waitUntilDone: YES]; // Get feed URL on main thread, it's not safe to call elsewhere.
const char *hostname = [[[theDict objectForKey: @"feedURL"] host] cStringUsingEncoding: NSUTF8StringEncoding];
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, hostname);
Boolean reachabilityResult = NO;
// If the feed's using a file:// URL, we won't be able to use reachability.
if (reachability != NULL) {
SCNetworkReachabilityGetFlags(reachability, &flags);
CFRelease(reachability);
}
if( reachabilityResult )
{
BOOL reachable = (flags & kSCNetworkFlagsReachable) == kSCNetworkFlagsReachable;
BOOL automatic = (flags & kSCNetworkFlagsConnectionAutomatic) == kSCNetworkFlagsConnectionAutomatic;
BOOL local = (flags & kSCNetworkFlagsIsLocalAddress) == kSCNetworkFlagsIsLocalAddress;
//NSLog(@"reachable = %s, automatic = %s, local = %s", (reachable?"YES":"NO"), (automatic?"YES":"NO"), (local?"YES":"NO"));
if( !(reachable || automatic || local) )
isNetworkReachable = NO;
}
// If the network's not reachable, we pass a nil driver into checkForUpdatesWithDriver, which will then reschedule the next update so we try again later.
[self performSelectorOnMainThread: @selector(checkForUpdatesWithDriver:) withObject: isNetworkReachable ? inDriver : nil waitUntilDone: NO];
[pool release];
NS_HANDLER
SULog(@"UNCAUGHT EXCEPTION IN UPDATE CHECK TIMER: %@",[localException reason]);
// Don't propagate the exception beyond here. In Carbon apps that would trash the stack.
NS_ENDHANDLER
}
- (void)checkForUpdatesInBackground
{
// Background update checks should only happen if we have a network connection.
// Wouldn't want to annoy users on dial-up by establishing a connection every
// hour or so:
SUUpdateDriver * theUpdateDriver = [[[([self automaticallyDownloadsUpdates] ? [SUAutomaticUpdateDriver class] : [SUScheduledUpdateDriver class]) alloc] initWithUpdater:self] autorelease];
[NSThread detachNewThreadSelector: @selector(checkForUpdatesInBgReachabilityCheckWithDriver:) toTarget: self withObject: theUpdateDriver];
}
- (BOOL)mayUpdateAndRestart
{
return( !delegate || ![delegate respondsToSelector: @selector(updaterShouldRelaunchApplication:)] || [delegate updaterShouldRelaunchApplication: self] );
}
- (IBAction)checkForUpdates: (id)sender
{
[self checkForUpdatesWithDriver:[[[SUUserInitiatedUpdateDriver alloc] initWithUpdater:self] autorelease]];
}
- (void)checkForUpdateInformation
{
[self checkForUpdatesWithDriver:[[[SUProbingUpdateDriver alloc] initWithUpdater:self] autorelease]];
}
- (void)checkForUpdatesWithDriver:(SUUpdateDriver *)d
{
if ([self updateInProgress]) { return; }
if (checkTimer) { [checkTimer invalidate]; [checkTimer release]; checkTimer = nil; } // UK 2009-03-16 Timer is non-repeating, may have invalidated itself, so we had to retain it.
SUClearLog();
SULog( @"===== %@ =====", [[NSFileManager defaultManager] displayNameAtPath: [[NSBundle mainBundle] bundlePath]] );
[self willChangeValueForKey:@"lastUpdateCheckDate"];
[host setObject:[NSDate date] forUserDefaultsKey:SULastCheckTimeKey];
[self didChangeValueForKey:@"lastUpdateCheckDate"];
if( [delegate respondsToSelector: @selector(updaterMayCheckForUpdates:)] && ![delegate updaterMayCheckForUpdates: self] )
{
[self scheduleNextUpdateCheck];
return;
}
driver = [d retain];
// If we're not given a driver at all, just schedule the next update check and bail.
if (!driver)
{
[self scheduleNextUpdateCheck];
return;
}
NSURL* theFeedURL = [self parameterizedFeedURL];
if( theFeedURL ) // Use a NIL URL to cancel quietly.
[driver checkForUpdatesAtURL: theFeedURL host:host];
else
[driver abortUpdate];
}
- (void)registerAsObserver
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateDriverDidFinish:) name:SUUpdateDriverFinishedNotification object:nil];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:[@"values." stringByAppendingString:SUScheduledCheckIntervalKey] options:0 context:SUUpdaterDefaultsObservationContext];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:[@"values." stringByAppendingString:SUEnableAutomaticChecksKey] options:0 context:SUUpdaterDefaultsObservationContext];
}
- (void)unregisterAsObserver
{
@try
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:[@"values." stringByAppendingString:SUScheduledCheckIntervalKey]];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:[@"values." stringByAppendingString:SUEnableAutomaticChecksKey]];
}
@catch (NSException *e)
{
NSLog(@"Sparkle Error: [SUUpdater unregisterAsObserver] called, but the updater wasn't registered as an observer.");
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == SUUpdaterDefaultsObservationContext)
{
// Allow a small delay, because perhaps the user or developer wants to change both preferences. This allows the developer to interpret a zero check interval as a sign to disable automatic checking.
// Or we may get this from the developer and from our own KVO observation, this will effectively coalesce them.
[[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(resetUpdateCycle) object:nil];
[self performSelector:@selector(resetUpdateCycle) withObject:nil afterDelay:1];
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)resetUpdateCycle
{
[[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(resetUpdateCycle) object:nil];
[self scheduleNextUpdateCheck];
}
- (void)setAutomaticallyChecksForUpdates:(BOOL)automaticallyCheckForUpdates
{
[host setBool:automaticallyCheckForUpdates forUserDefaultsKey:SUEnableAutomaticChecksKey];
// Hack to support backwards compatibility with older Sparkle versions, which supported
// disabling updates by setting the check interval to 0.
if (automaticallyCheckForUpdates && [self updateCheckInterval] == 0)
[self setUpdateCheckInterval:SU_DEFAULT_CHECK_INTERVAL];
[[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(resetUpdateCycle) object:nil];
// Provide a small delay in case multiple preferences are being updated simultaneously.
[self performSelector:@selector(resetUpdateCycle) withObject:nil afterDelay:1];
}
- (BOOL)automaticallyChecksForUpdates
{
// Don't automatically update when the check interval is 0, to be compatible with 1.1 settings.
if ([self updateCheckInterval] == 0)
return NO;
return [host boolForKey:SUEnableAutomaticChecksKey];
}
- (void)setAutomaticallyDownloadsUpdates:(BOOL)automaticallyUpdates
{
[host setBool:automaticallyUpdates forUserDefaultsKey:SUAutomaticallyUpdateKey];
}
- (BOOL)automaticallyDownloadsUpdates
{
// If the SUAllowsAutomaticUpdatesKey exists and is set to NO, return NO.
if ([host objectForInfoDictionaryKey:SUAllowsAutomaticUpdatesKey] && [host boolForInfoDictionaryKey:SUAllowsAutomaticUpdatesKey] == NO)
return NO;
// Otherwise, automatically downloading updates is allowed. Does the user want it?
return [host boolForUserDefaultsKey:SUAutomaticallyUpdateKey];
}
- (void)setFeedURL:(NSURL *)feedURL
{
[host setObject:[feedURL absoluteString] forUserDefaultsKey:SUFeedURLKey];
}
- (NSURL *)feedURL // *** MUST BE CALLED ON MAIN THREAD ***
{
// A value in the user defaults overrides one in the Info.plist (so preferences panels can be created wherein users choose between beta / release feeds).
NSString *appcastString = [host objectForKey:SUFeedURLKey];
if( [delegate respondsToSelector: @selector(feedURLStringForUpdater:)] )
appcastString = [delegate feedURLStringForUpdater: self];
if (!appcastString) // Can't find an appcast string!
[NSException raise:@"SUNoFeedURL" format:@"You must specify the URL of the appcast as the SUFeedURL key in either the Info.plist or the user defaults!"];
NSCharacterSet* quoteSet = [NSCharacterSet characterSetWithCharactersInString: @"\"\'"]; // Some feed publishers add quotes; strip 'em.
NSString* castUrlStr = [appcastString stringByTrimmingCharactersInSet:quoteSet];
if( !castUrlStr || [castUrlStr length] == 0 )
return nil;
else
return [NSURL URLWithString: castUrlStr];
}
- (void)setUserAgentString:(NSString *)userAgent
{
if (customUserAgentString == userAgent)
return;
[customUserAgentString release];
customUserAgentString = [userAgent copy];
}
- (NSString *)userAgentString
{
if (customUserAgentString)
return customUserAgentString;
NSString *version = [SPARKLE_BUNDLE objectForInfoDictionaryKey:@"CFBundleVersion"];
NSString *userAgent = [NSString stringWithFormat:@"%@/%@ Sparkle/%@", [host name], [host displayVersion], version ? version : @"?"];
NSData *cleanedAgent = [userAgent dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
return [[[NSString alloc] initWithData:cleanedAgent encoding:NSASCIIStringEncoding] autorelease];
}
- (void)setSendsSystemProfile:(BOOL)sendsSystemProfile
{
[host setBool:sendsSystemProfile forUserDefaultsKey:SUSendProfileInfoKey];
}
- (BOOL)sendsSystemProfile
{
return [host boolForUserDefaultsKey:SUSendProfileInfoKey];
}
- (NSURL *)parameterizedFeedURL
{
NSURL *baseFeedURL = [self feedURL];
// Determine all the parameters we're attaching to the base feed URL.
BOOL sendingSystemProfile = [self sendsSystemProfile];
// Let's only send the system profiling information once per week at most, so we normalize daily-checkers vs. biweekly-checkers and the such.
NSDate *lastSubmitDate = [host objectForUserDefaultsKey:SULastProfileSubmitDateKey];
if(!lastSubmitDate)
lastSubmitDate = [NSDate distantPast];
const NSTimeInterval oneWeek = 60 * 60 * 24 * 7;
sendingSystemProfile &= (-[lastSubmitDate timeIntervalSinceNow] >= oneWeek);
NSArray *parameters = [NSArray array];
if ([delegate respondsToSelector:@selector(feedParametersForUpdater:sendingSystemProfile:)])
parameters = [parameters arrayByAddingObjectsFromArray:[delegate feedParametersForUpdater:self sendingSystemProfile:sendingSystemProfile]];
if (sendingSystemProfile)
{
parameters = [parameters arrayByAddingObjectsFromArray:[host systemProfile]];
[host setObject:[NSDate date] forUserDefaultsKey:SULastProfileSubmitDateKey];
}
if ([parameters count] == 0) { return baseFeedURL; }
// Build up the parameterized URL.
NSMutableArray *parameterStrings = [NSMutableArray array];
NSEnumerator *profileInfoEnumerator = [parameters objectEnumerator];
NSDictionary *currentProfileInfo;
while ((currentProfileInfo = [profileInfoEnumerator nextObject]))
[parameterStrings addObject:[NSString stringWithFormat:@"%@=%@", [[[currentProfileInfo objectForKey:@"key"] description] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding], [[[currentProfileInfo objectForKey:@"value"] description] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
NSString *separatorCharacter = @"?";
if ([baseFeedURL query])
separatorCharacter = @"&"; // In case the URL is already http://foo.org/baz.xml?bat=4
NSString *appcastStringWithProfile = [NSString stringWithFormat:@"%@%@%@", [baseFeedURL absoluteString], separatorCharacter, [parameterStrings componentsJoinedByString:@"&"]];
// Clean it up so it's a valid URL
return [NSURL URLWithString:appcastStringWithProfile];
}
- (void)setUpdateCheckInterval:(NSTimeInterval)updateCheckInterval
{
[host setObject:[NSNumber numberWithDouble:updateCheckInterval] forUserDefaultsKey:SUScheduledCheckIntervalKey];
if (updateCheckInterval == 0) // For compatibility with 1.1's settings.
[self setAutomaticallyChecksForUpdates:NO];
[[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(resetUpdateCycle) object:nil];
// Provide a small delay in case multiple preferences are being updated simultaneously.
[self performSelector:@selector(resetUpdateCycle) withObject:nil afterDelay:1];
}
- (NSTimeInterval)updateCheckInterval
{
// Find the stored check interval. User defaults override Info.plist.
NSNumber *intervalValue = [host objectForKey:SUScheduledCheckIntervalKey];
if (intervalValue)
return [intervalValue doubleValue];
else
return SU_DEFAULT_CHECK_INTERVAL;
}
- (void)dealloc
{
[self unregisterAsObserver];
[host release];
if (checkTimer) { [checkTimer invalidate]; [checkTimer release]; checkTimer = nil; } // UK 2009-03-16 Timer is non-repeating, may have invalidated itself, so we had to retain it.
[super dealloc];
}
- (BOOL)validateMenuItem:(NSMenuItem *)item
{
if ([item action] == @selector(checkForUpdates:))
return ![self updateInProgress];
return YES;
}
- (void)setDelegate:aDelegate
{
delegate = aDelegate;
}
- (BOOL)updateInProgress
{
return driver && ([driver finished] == NO);
}
- (id)delegate { return delegate; }
- (NSBundle *)hostBundle { return [host bundle]; }
@end

View File

@ -1,15 +0,0 @@
//
// SUUpdater_Private.h
// Sparkle
//
// Created by Andy Matuschak on 5/9/11.
// Copyright 2011 Andy Matuschak. All rights reserved.
//
#import "SUUpdater.h"
@interface SUUpdater (Private)
- (BOOL)mayUpdateAndRestart;
@end

View File

@ -1,24 +0,0 @@
//
// SUUserInitiatedUpdateDriver.h
// Sparkle
//
// Created by Andy Matuschak on 5/30/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUUSERINITIATEDUPDATEDRIVER_H
#define SUUSERINITIATEDUPDATEDRIVER_H
#import <Cocoa/Cocoa.h>
#import "SUUIBasedUpdateDriver.h"
@interface SUUserInitiatedUpdateDriver : SUUIBasedUpdateDriver
{
@private
SUStatusController *checkingController;
BOOL isCanceled;
}
@end
#endif

View File

@ -1,88 +0,0 @@
//
// SUUserInitiatedUpdateDriver.m
// Sparkle
//
// Created by Andy Matuschak on 5/30/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUUserInitiatedUpdateDriver.h"
#import "SUStatusController.h"
#import "SUHost.h"
@implementation SUUserInitiatedUpdateDriver
- (void)closeCheckingWindow
{
if (checkingController)
{
[[checkingController window] close];
[checkingController release];
checkingController = nil;
}
}
- (void)cancelCheckForUpdates:sender
{
[self closeCheckingWindow];
isCanceled = YES;
}
- (void)checkForUpdatesAtURL:(NSURL *)URL host:(SUHost *)aHost
{
checkingController = [[SUStatusController alloc] initWithHost:aHost];
[[checkingController window] center]; // Force the checking controller to load its window.
[checkingController beginActionWithTitle:SULocalizedString(@"Checking for updates...", nil) maxProgressValue:0.0 statusText:nil];
[checkingController setButtonTitle:SULocalizedString(@"Cancel", nil) target:self action:@selector(cancelCheckForUpdates:) isDefault:NO];
[checkingController showWindow:self];
[super checkForUpdatesAtURL:URL host:aHost];
// For background applications, obtain focus.
// Useful if the update check is requested from another app like System Preferences.
if ([aHost isBackgroundApplication])
{
[NSApp activateIgnoringOtherApps:YES];
}
}
- (void)appcastDidFinishLoading:(SUAppcast *)ac
{
if (isCanceled)
{
[self abortUpdate];
return;
}
[self closeCheckingWindow];
[super appcastDidFinishLoading:ac];
}
- (void)abortUpdateWithError:(NSError *)error
{
[self closeCheckingWindow];
[super abortUpdateWithError:error];
}
- (void)abortUpdate
{
[self closeCheckingWindow];
[super abortUpdate];
}
- (void)appcast:(SUAppcast *)ac failedToLoadWithError:(NSError *)error
{
if (isCanceled)
{
[self abortUpdate];
return;
}
[super appcast:ac failedToLoadWithError:error];
}
- (BOOL)itemContainsValidUpdate:(SUAppcastItem *)ui
{
// We don't check to see if this update's been skipped, because the user explicitly *asked* if he had the latest version.
return [self hostSupportsItem:ui] && [self isItemNewer:ui];
}
@end

View File

@ -1,29 +0,0 @@
//
// SUVersionComparisonProtocol.h
// Sparkle
//
// Created by Andy Matuschak on 12/21/07.
// Copyright 2007 Andy Matuschak. All rights reserved.
//
#ifndef SUVERSIONCOMPARISONPROTOCOL_H
#define SUVERSIONCOMPARISONPROTOCOL_H
#import <Cocoa/Cocoa.h>
/*!
@protocol
@abstract Implement this protocol to provide version comparison facilities for Sparkle.
*/
@protocol SUVersionComparison
/*!
@method
@abstract An abstract method to compare two version strings.
@discussion Should return NSOrderedAscending if b > a, NSOrderedDescending if b < a, and NSOrderedSame if they are equivalent.
*/
- (NSComparisonResult)compareVersion:(NSString *)versionA toVersion:(NSString *)versionB; // *** MAY BE CALLED ON NON-MAIN THREAD!
@end
#endif

View File

@ -1,27 +0,0 @@
//
// SUVersionDisplayProtocol.h
// EyeTV
//
// Created by Uli Kusterer on 08.12.09.
// Copyright 2009 Elgato Systems GmbH. All rights reserved.
//
#import <Cocoa/Cocoa.h>
/*!
@protocol
@abstract Implement this protocol to apply special formatting to the two
version numbers.
*/
@protocol SUVersionDisplay
/*!
@method
@abstract An abstract method to format two version strings.
@discussion You get both so you can display important distinguishing
information, but leave out unnecessary/confusing parts.
*/
-(void) formatVersion: (NSString**)inOutVersionA andVersion: (NSString**)inOutVersionB;
@end

View File

@ -1,20 +0,0 @@
//
// SUWindowController.h
// Sparkle
//
// Created by Andy Matuschak on 2/13/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef SUWINDOWCONTROLLER_H
#define SUWINDOWCONTROLLER_H
#import <Cocoa/Cocoa.h>
@class SUHost;
@interface SUWindowController : NSWindowController { }
// We use this instead of plain old NSWindowController initWithWindowNibName so that we'll be able to find the right path when running in a bundle loaded from another app.
- (id)initWithHost:(SUHost *)host windowNibName:(NSString *)nibName;
@end
#endif

View File

@ -1,27 +0,0 @@
//
// SUWindowController.m
// Sparkle
//
// Created by Andy Matuschak on 2/13/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUWindowController.h"
#import "SUHost.h"
@implementation SUWindowController
- (id)initWithHost:(SUHost *)host windowNibName:(NSString *)nibName
{
NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:nibName ofType:@"nib"];
if (path == nil) // Slight hack to resolve issues with running Sparkle in debug configurations.
{
NSString *frameworkPath = [[[host bundle] sharedFrameworksPath] stringByAppendingPathComponent:@"Sparkle.framework"];
NSBundle *framework = [NSBundle bundleWithPath:frameworkPath];
path = [framework pathForResource:nibName ofType:@"nib"];
}
self = [super initWithWindowNibPath:path owner:self];
return self;
}
@end

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title>Your Great App's Changelog</title>
<link>http://you.com/app/appcast.xml</link>
<description>Most recent changes with links to updates.</description>
<language>en</language>
<item>
<title>Version 2.0 (2 bugs fixed; 3 new features)</title>
<sparkle:releaseNotesLink>
http://you.com/app/2.0.html
</sparkle:releaseNotesLink>
<pubDate>Wed, 09 Jan 2006 19:20:11 +0000</pubDate>
<enclosure url="http://you.com/app/Your Great App 2.0.zip" sparkle:version="2.0" length="1623481" type="application/octet-stream" sparkle:dsaSignature="BAFJW4B6B1K1JyW30nbkBwainOzrN6EQuAh" />
</item>
<item>
<title>Version 1.5 (8 bugs fixed; 2 new features)</title>
<sparkle:releaseNotesLink>
http://you.com/app/1.5.html
</sparkle:releaseNotesLink>
<pubDate>Wed, 01 Jan 2006 12:20:11 +0000</pubDate>
<enclosure url="http://you.com/app/Your Great App 1.5.zip" sparkle:version="1.5" length="1472893" type="application/octet-stream" sparkle:dsaSignature="234818feCa1JyW30nbkBwainOzrN6EQuAh" />
</item>
<!-- Now here's an example of a version with a weird internal version number (like an SVN revision) but a human-readable external one. -->
<item>
<title>Version 1.4 (5 bugs fixed; 2 new features)</title>
<sparkle:releaseNotesLink>
http://you.com/app/1.4.html
</sparkle:releaseNotesLink>
<pubDate>Wed, 25 Dec 2005 12:20:11 +0000</pubDate>
<enclosure url="http://you.com/app/Your Great App 1.4.zip" sparkle:version="241" sparkle:shortVersionString="1.4" sparkle:dsaSignature="MC0CFBfeCa1JyW30nbkBwainOzrN6EQuAh=" length="1472349" type="application/octet-stream" />
</item>
</channel>
</rss>

View File

@ -1,21 +0,0 @@
//
// Sparkle.h
// Sparkle
//
// Created by Andy Matuschak on 3/16/06. (Modified by CDHW on 23/12/07)
// Copyright 2006 Andy Matuschak. All rights reserved.
//
#ifndef SPARKLE_H
#define SPARKLE_H
// This list should include the shared headers. It doesn't matter if some of them aren't shared (unless
// there are name-space collisions) so we can list all of them to start with:
#import <Sparkle/SUUpdater.h>
#import <Sparkle/SUAppcast.h>
#import <Sparkle/SUAppcastItem.h>
#import <Sparkle/SUVersionComparisonProtocol.h>
#endif

Binary file not shown.

View File

@ -1,30 +0,0 @@
//
// Sparkle.pch
// Sparkle
//
// Created by Andy Matuschak on 7/23/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#ifndef NSAppKitVersionNumber10_4
#define NSAppKitVersionNumber10_4 824
#endif
#ifndef NSAppKitVersionNumber10_5
#define NSAppKitVersionNumber10_5 949
#endif
#ifndef NSAppKitVersionNumber10_6
#define NSAppKitVersionNumber10_6 1038
#endif
#ifdef __OBJC__
#define SPARKLE_BUNDLE [NSBundle bundleWithIdentifier:@"org.andymatuschak.Sparkle"]
#define SULocalizedString(key,comment) NSLocalizedStringFromTableInBundle(key, @"Sparkle", SPARKLE_BUNDLE, comment)
#define SUAbstractFail() NSAssert2(nil, @"Can't call %@ on an instance of %@; this is an abstract method!", __PRETTY_FUNCTION__, [self class]);
#import <Cocoa/Cocoa.h>
#import "SUConstants.h"
#endif

View File

@ -1,5 +0,0 @@
*.pbxuser
*.perspectivev3
*.mode1v3
project.xcworkspace/
xcuserdata/

View File

@ -1,43 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBClasses</key>
<array>
<dict>
<key>CLASS</key>
<string>FirstResponder</string>
<key>LANGUAGE</key>
<string>ObjC</string>
<key>SUPERCLASS</key>
<string>NSObject</string>
</dict>
<dict>
<key>CLASS</key>
<string>NSObject</string>
<key>LANGUAGE</key>
<string>ObjC</string>
</dict>
<dict>
<key>ACTIONS</key>
<dict>
<key>checkForUpdates</key>
<string>id</string>
</dict>
<key>CLASS</key>
<string>SUUpdater</string>
<key>LANGUAGE</key>
<string>ObjC</string>
<key>OUTLETS</key>
<dict>
<key>delegate</key>
<string>id</string>
</dict>
<key>SUPERCLASS</key>
<string>NSObject</string>
</dict>
</array>
<key>IBVersion</key>
<string>1</string>
</dict>
</plist>

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBFramework Version</key>
<string>667</string>
<key>IBLastKnownRelativeProjectPath</key>
<string>../../Sparkle.xcodeproj</string>
<key>IBOldestOS</key>
<integer>5</integer>
<key>IBOpenObjects</key>
<array>
<integer>2</integer>
<integer>57</integer>
</array>
<key>IBSystem Version</key>
<string>9D34</string>
<key>targetFramework</key>
<string>IBCocoaFramework</string>
</dict>
</plist>

View File

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string>Sparkle</string>
<key>CFBundleName</key>
<string>Sparkle Test App</string>
<key>CFBundleIdentifier</key>
<string>org.andymatuschak.SparkleTestApp</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.5</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>SUFeedURL</key>
<string>http://www.andymatuschak.org/files/sparkletestcast.xml</string>
<key>SUEnableSystemProfiling</key>
<true/>
<key>SUPublicDSAKeyFile</key>
<string>dsa_pub.pem</string>
</dict>
</plist>

View File

@ -1,20 +0,0 @@
-----BEGIN DSA PRIVATE KEY-----
MIIDPgIBAAKCAQEA9lmy8fAXdW9b6fBXQ6Us5B2dLZV+cR685tFlhPSKJDpicP1F
pNRkGESZwPFJbnxUyVeHWVS9yLeMcKqllhcjd+i1oEFKX7LPXk5+zO745OwVWHIe
0DLOIxhJ0mJHm7mH1YVGZYOVVYkPt+0Y/hDbQVK5DycSGAhgDiCZ+Obl+aDSD2xJ
RZGnVOpu83dYJ/CoUYCHqWtpN4gW5Bbgm8Uz0/2qiyPjFvJEeI1yE04AZA3sOg1y
1S/UrCbqeC3gBIs0xsskwWOW3zCWjvDWgfPrj65At0mVfq/yyGgXJlN71X5sONxR
swZSbRn5T2i/BJPZUStWks5Nxq+7T3WmnaPbTwIVAJp+BByoy95V3x8wZg0q66eR
ufiJAoIBABbxkX6C9Lt8zeDvvIpk8X4kmHBVIwVJcuICJTVzOAIBZsvFhPnYmUYe
v93oPgjtAdYqPrYZlNrExQG1e7B1bhmgaT8hbXL6whxhqRHKlsJsboVHNQs3qAbx
sOLvJnwgb3FD4xX4ZZSSRXSIGk62FxcaoLG+mSlirGM/SY4yZDpURSJUX6MHdUZa
qHWWGL3b31pz3d9h6SPYv6H4T3ZReVtn+dXYh/41SWkQqEyhAsHGBvqpDwuYJCCI
Mwuvwz0U/KcwiydDaFo900MC9S33zEpk/YUxgA9YsiY5+UvWSy5M/yvkKBkvkb+I
G6DAMWtApWu0fDcLV6jA9JKXmcAwAIECggEBAPC0OJEnLkOwU1Ehop7o2XJbWDKN
giFt44IO3l9gx1fu05HrieDbwAJTkRK7qNEA0yk1iMT2hMHHbwLRNddEsOJuUd7o
iyKwqwkmCQ2Q1zYPBR09wag9NEr8xLSTQJCw9CpxTRSH+9hc1DeuwkwAnTEn7JiW
WbcxVCRtmtaUlN7+dTozxqGJHpYF6WsqHMeuG7Ixnyf6he8Fz8mjxnrc7/l73gFL
Q+IZvUSjzh2zqtqaejtcmlNcT+fGmEFKxpcLB3JP3uu8PN8MbS/R6j191f1ovuM9
U4MO3RuT4xJF0OlwyWAnOEik1S1p+tNQciQ/Ipv8Ff3DDBct9YZPPlNGi+ICFHHD
tP5yX7hMTJIykGaMuM44KJMM
-----END DSA PRIVATE KEY-----

View File

@ -1,20 +0,0 @@
-----BEGIN PUBLIC KEY-----
MIIDOzCCAi0GByqGSM44BAEwggIgAoIBAQD2WbLx8Bd1b1vp8FdDpSzkHZ0tlX5x
Hrzm0WWE9IokOmJw/UWk1GQYRJnA8UlufFTJV4dZVL3It4xwqqWWFyN36LWgQUpf
ss9eTn7M7vjk7BVYch7QMs4jGEnSYkebuYfVhUZlg5VViQ+37Rj+ENtBUrkPJxIY
CGAOIJn45uX5oNIPbElFkadU6m7zd1gn8KhRgIepa2k3iBbkFuCbxTPT/aqLI+MW
8kR4jXITTgBkDew6DXLVL9SsJup4LeAEizTGyyTBY5bfMJaO8NaB8+uPrkC3SZV+
r/LIaBcmU3vVfmw43FGzBlJtGflPaL8Ek9lRK1aSzk3Gr7tPdaado9tPAhUAmn4E
HKjL3lXfHzBmDSrrp5G5+IkCggEAFvGRfoL0u3zN4O+8imTxfiSYcFUjBUly4gIl
NXM4AgFmy8WE+diZRh6/3eg+CO0B1io+thmU2sTFAbV7sHVuGaBpPyFtcvrCHGGp
EcqWwmxuhUc1CzeoBvGw4u8mfCBvcUPjFfhllJJFdIgaTrYXFxqgsb6ZKWKsYz9J
jjJkOlRFIlRfowd1RlqodZYYvdvfWnPd32HpI9i/ofhPdlF5W2f51diH/jVJaRCo
TKECwcYG+qkPC5gkIIgzC6/DPRT8pzCLJ0NoWj3TQwL1LffMSmT9hTGAD1iyJjn5
S9ZLLkz/K+QoGS+Rv4gboMAxa0Cla7R8NwtXqMD0kpeZwDAAgQOCAQYAAoIBAQDw
tDiRJy5DsFNRIaKe6NlyW1gyjYIhbeOCDt5fYMdX7tOR64ng28ACU5ESu6jRANMp
NYjE9oTBx28C0TXXRLDiblHe6IsisKsJJgkNkNc2DwUdPcGoPTRK/MS0k0CQsPQq
cU0Uh/vYXNQ3rsJMAJ0xJ+yYllm3MVQkbZrWlJTe/nU6M8ahiR6WBelrKhzHrhuy
MZ8n+oXvBc/Jo8Z63O/5e94BS0PiGb1Eo84ds6ramno7XJpTXE/nxphBSsaXCwdy
T97rvDzfDG0v0eo9fdX9aL7jPVODDt0bk+MSRdDpcMlgJzhIpNUtafrTUHIkPyKb
/BX9wwwXLfWGTz5TRovi
-----END PUBLIC KEY-----

View File

@ -1,14 +0,0 @@
//
// main.m
// Sparkle
//
// Created by Andy Matuschak on 3/12/06.
// Copyright Andy Matuschak 2006. All rights reserved.
//
#import <Cocoa/Cocoa.h>
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **) argv);
}

View File

@ -1,16 +0,0 @@
//
// SUVersionComparisonTest.h
// Sparkle
//
// Created by Andy Matuschak on 4/15/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import <SenTestingKit/SenTestingKit.h>
@interface SUVersionComparisonTest : SenTestCase {
}
@end

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
</dict>
</plist>

View File

@ -1,616 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
<data>
<int key="IBDocument.SystemTarget">1050</int>
<string key="IBDocument.SystemVersion">11C74</string>
<string key="IBDocument.InterfaceBuilderVersion">1938</string>
<string key="IBDocument.AppKitVersion">1138.23</string>
<string key="IBDocument.HIToolboxVersion">567.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="NS.object.0">1938</string>
</object>
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>NSTextField</string>
<string>NSView</string>
<string>NSWindowTemplate</string>
<string>NSUserDefaultsController</string>
<string>NSTextFieldCell</string>
<string>NSImageCell</string>
<string>NSButtonCell</string>
<string>NSImageView</string>
<string>NSButton</string>
<string>NSCustomObject</string>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
</object>
<object class="NSMutableDictionary" key="IBDocument.Metadata">
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
<integer value="1" key="NS.object.0"/>
</object>
<object class="NSMutableArray" key="IBDocument.RootObjects" id="703667931">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSCustomObject" id="1063113299">
<string key="NSClassName">SUAutomaticUpdateAlert</string>
</object>
<object class="NSCustomObject" id="980192062">
<string key="NSClassName">FirstResponder</string>
</object>
<object class="NSCustomObject" id="600560674">
<string key="NSClassName">NSApplication</string>
</object>
<object class="NSWindowTemplate" id="26497398">
<int key="NSWindowStyleMask">1</int>
<int key="NSWindowBacking">2</int>
<string key="NSWindowRect">{{114, 521}, {616, 152}}</string>
<int key="NSWTFlags">1886912512</int>
<string key="NSWindowTitle"/>
<object class="NSMutableString" key="NSWindowClass">
<characters key="NS.bytes">NSWindow</characters>
</object>
<object class="NSMutableString" key="NSViewClass">
<characters key="NS.bytes">View</characters>
</object>
<nil key="NSUserInterfaceItemIdentifier"/>
<string key="NSWindowContentMinSize">{511, 152}</string>
<object class="NSView" key="NSWindowView" id="683629094">
<reference key="NSNextResponder"/>
<int key="NSvFlags">256</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSImageView" id="684391777">
<reference key="NSNextResponder" ref="683629094"/>
<int key="NSvFlags">268</int>
<object class="NSMutableSet" key="NSDragTypes">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="set.sortedObjects">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>Apple PDF pasteboard type</string>
<string>Apple PICT pasteboard type</string>
<string>Apple PNG pasteboard type</string>
<string>NSFilenamesPboardType</string>
<string>NeXT Encapsulated PostScript v1.2 pasteboard type</string>
<string>NeXT TIFF v4.0 pasteboard type</string>
</object>
</object>
<string key="NSFrame">{{532, 73}, {64, 64}}</string>
<reference key="NSSuperview" ref="683629094"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="265767855"/>
<bool key="NSEnabled">YES</bool>
<object class="NSImageCell" key="NSCell" id="17541256">
<int key="NSCellFlags">130560</int>
<int key="NSCellFlags2">33554432</int>
<object class="NSCustomResource" key="NSContents">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">NSApplicationIcon</string>
</object>
<int key="NSAlign">0</int>
<int key="NSScale">0</int>
<int key="NSStyle">0</int>
<bool key="NSAnimates">NO</bool>
</object>
<bool key="NSEditable">YES</bool>
</object>
<object class="NSTextField" id="766768061">
<reference key="NSNextResponder" ref="683629094"/>
<int key="NSvFlags">270</int>
<string key="NSFrame">{{105, 120}, {497, 17}}</string>
<reference key="NSSuperview" ref="683629094"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="757978667"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="86959214">
<int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">272629760</int>
<string key="NSContents"/>
<object class="NSFont" key="NSSupport">
<string key="NSName">LucidaGrande-Bold</string>
<double key="NSSize">13</double>
<int key="NSfFlags">2072</int>
</object>
<reference key="NSControlView" ref="766768061"/>
<object class="NSColor" key="NSBackgroundColor" id="1051534986">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">controlColor</string>
<object class="NSColor" key="NSColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
</object>
</object>
<object class="NSColor" key="NSTextColor" id="953131030">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">controlTextColor</string>
<object class="NSColor" key="NSColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MAA</bytes>
</object>
</object>
</object>
</object>
<object class="NSTextField" id="757978667">
<reference key="NSNextResponder" ref="683629094"/>
<int key="NSvFlags">270</int>
<string key="NSFrame">{{17, 81}, {497, 31}}</string>
<reference key="NSSuperview" ref="683629094"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="649646560"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="7373583">
<int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">272629760</int>
<string key="NSContents"/>
<object class="NSFont" key="NSSupport" id="26">
<string key="NSName">LucidaGrande</string>
<double key="NSSize">11</double>
<int key="NSfFlags">3100</int>
</object>
<reference key="NSControlView" ref="757978667"/>
<reference key="NSBackgroundColor" ref="1051534986"/>
<reference key="NSTextColor" ref="953131030"/>
</object>
</object>
<object class="NSButton" id="265767855">
<reference key="NSNextResponder" ref="683629094"/>
<int key="NSvFlags">257</int>
<string key="NSFrame">{{14, 12}, {168, 32}}</string>
<reference key="NSSuperview" ref="683629094"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="389094888"/>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="5529083">
<int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">134217728</int>
<string key="NSContents">تثبيت وإعادة تشغيل التطبيق</string>
<object class="NSFont" key="NSSupport" id="957448308">
<string key="NSName">LucidaGrande</string>
<double key="NSSize">13</double>
<int key="NSfFlags">1044</int>
</object>
<reference key="NSControlView" ref="265767855"/>
<int key="NSButtonFlags">-2038284033</int>
<int key="NSButtonFlags2">1</int>
<reference key="NSAlternateImage" ref="957448308"/>
<string key="NSAlternateContents"/>
<string type="base64-UTF8" key="NSKeyEquivalent">DQ</string>
<int key="NSPeriodicDelay">200</int>
<int key="NSPeriodicInterval">25</int>
</object>
</object>
<object class="NSButton" id="389094888">
<reference key="NSNextResponder" ref="683629094"/>
<int key="NSvFlags">257</int>
<string key="NSFrame">{{182, 12}, {146, 32}}</string>
<reference key="NSSuperview" ref="683629094"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="689081238"/>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="285814029">
<int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">134217728</int>
<string key="NSContents">تثبيت عند إنهاء التطبيق</string>
<reference key="NSSupport" ref="957448308"/>
<reference key="NSControlView" ref="389094888"/>
<int key="NSButtonFlags">-2038284033</int>
<int key="NSButtonFlags2">1</int>
<reference key="NSAlternateImage" ref="957448308"/>
<string key="NSAlternateContents"/>
<string type="base64-UTF8" key="NSKeyEquivalent">Gw</string>
<int key="NSPeriodicDelay">200</int>
<int key="NSPeriodicInterval">25</int>
</object>
</object>
<object class="NSButton" id="689081238">
<reference key="NSNextResponder" ref="683629094"/>
<int key="NSvFlags">256</int>
<string key="NSFrame">{{438, 12}, {92, 32}}</string>
<reference key="NSSuperview" ref="683629094"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView"/>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="368800735">
<int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">134217728</int>
<string key="NSContents">عدم التثبيت</string>
<reference key="NSSupport" ref="957448308"/>
<reference key="NSControlView" ref="689081238"/>
<int key="NSButtonFlags">-2038284033</int>
<int key="NSButtonFlags2">1</int>
<reference key="NSAlternateImage" ref="957448308"/>
<string key="NSAlternateContents"/>
<object class="NSMutableString" key="NSKeyEquivalent">
<characters key="NS.bytes"/>
</object>
<int key="NSPeriodicDelay">200</int>
<int key="NSPeriodicInterval">25</int>
</object>
</object>
<object class="NSButton" id="649646560">
<reference key="NSNextResponder" ref="683629094"/>
<int key="NSvFlags">256</int>
<string key="NSFrame">{{-55, 58}, {581, 18}}</string>
<reference key="NSSuperview" ref="683629094"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="684391777"/>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="112350240">
<int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">67239936</int>
<string key="NSContents">تنزيل التحديثات وتثبيتها تلقائيًا في المستقبل</string>
<reference key="NSSupport" ref="26"/>
<reference key="NSControlView" ref="649646560"/>
<int key="NSButtonFlags">1210864127</int>
<int key="NSButtonFlags2">2</int>
<object class="NSButtonImageSource" key="NSAlternateImage">
<string key="NSImageName">NSSwitch</string>
</object>
<string key="NSAlternateContents"/>
<string key="NSKeyEquivalent"/>
<int key="NSPeriodicDelay">200</int>
<int key="NSPeriodicInterval">25</int>
</object>
</object>
</object>
<string key="NSFrameSize">{616, 152}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="766768061"/>
</object>
<string key="NSScreenRect">{{0, 0}, {1280, 778}}</string>
<string key="NSMinSize">{511, 174}</string>
<string key="NSMaxSize">{10000000000000, 10000000000000}</string>
<bool key="NSWindowIsRestorable">YES</bool>
</object>
<object class="NSUserDefaultsController" id="964078912">
<bool key="NSSharedInstance">YES</bool>
</object>
</object>
<object class="IBObjectContainer" key="IBDocument.Objects">
<object class="NSMutableArray" key="connectionRecords">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">window</string>
<reference key="source" ref="1063113299"/>
<reference key="destination" ref="26497398"/>
</object>
<int key="connectionID">22</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">installNow:</string>
<reference key="source" ref="1063113299"/>
<reference key="destination" ref="265767855"/>
</object>
<int key="connectionID">33</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">installLater:</string>
<reference key="source" ref="1063113299"/>
<reference key="destination" ref="389094888"/>
</object>
<int key="connectionID">34</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">doNotInstall:</string>
<reference key="source" ref="1063113299"/>
<reference key="destination" ref="689081238"/>
</object>
<int key="connectionID">35</int>
</object>
<object class="IBConnectionRecord">
<object class="IBBindingConnection" key="connection">
<string key="label">value: applicationIcon</string>
<reference key="source" ref="684391777"/>
<reference key="destination" ref="1063113299"/>
<object class="NSNibBindingConnector" key="connector">
<reference key="NSSource" ref="684391777"/>
<reference key="NSDestination" ref="1063113299"/>
<string key="NSLabel">value: applicationIcon</string>
<string key="NSBinding">value</string>
<string key="NSKeyPath">applicationIcon</string>
<int key="NSNibBindingConnectorVersion">2</int>
</object>
</object>
<int key="connectionID">10</int>
</object>
<object class="IBConnectionRecord">
<object class="IBBindingConnection" key="connection">
<string key="label">value: titleText</string>
<reference key="source" ref="766768061"/>
<reference key="destination" ref="1063113299"/>
<object class="NSNibBindingConnector" key="connector">
<reference key="NSSource" ref="766768061"/>
<reference key="NSDestination" ref="1063113299"/>
<string key="NSLabel">value: titleText</string>
<string key="NSBinding">value</string>
<string key="NSKeyPath">titleText</string>
<int key="NSNibBindingConnectorVersion">2</int>
</object>
</object>
<int key="connectionID">11</int>
</object>
<object class="IBConnectionRecord">
<object class="IBBindingConnection" key="connection">
<string key="label">value: descriptionText</string>
<reference key="source" ref="757978667"/>
<reference key="destination" ref="1063113299"/>
<object class="NSNibBindingConnector" key="connector">
<reference key="NSSource" ref="757978667"/>
<reference key="NSDestination" ref="1063113299"/>
<string key="NSLabel">value: descriptionText</string>
<string key="NSBinding">value</string>
<string key="NSKeyPath">descriptionText</string>
<int key="NSNibBindingConnectorVersion">2</int>
</object>
</object>
<int key="connectionID">14</int>
</object>
<object class="IBConnectionRecord">
<object class="IBBindingConnection" key="connection">
<string key="label">value: values.SUAutomaticallyUpdate</string>
<reference key="source" ref="649646560"/>
<reference key="destination" ref="964078912"/>
<object class="NSNibBindingConnector" key="connector">
<reference key="NSSource" ref="649646560"/>
<reference key="NSDestination" ref="964078912"/>
<string key="NSLabel">value: values.SUAutomaticallyUpdate</string>
<string key="NSBinding">value</string>
<string key="NSKeyPath">values.SUAutomaticallyUpdate</string>
<int key="NSNibBindingConnectorVersion">2</int>
</object>
</object>
<int key="connectionID">19</int>
</object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBObjectRecord">
<int key="objectID">0</int>
<object class="NSArray" key="object" id="0">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<reference key="children" ref="703667931"/>
<nil key="parent"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">-2</int>
<reference key="object" ref="1063113299"/>
<reference key="parent" ref="0"/>
<string key="objectName">File's Owner</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-1</int>
<reference key="object" ref="980192062"/>
<reference key="parent" ref="0"/>
<string key="objectName">First Responder</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-3</int>
<reference key="object" ref="600560674"/>
<reference key="parent" ref="0"/>
<string key="objectName">Application</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">5</int>
<reference key="object" ref="26497398"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="683629094"/>
</object>
<reference key="parent" ref="0"/>
<string key="objectName">Window</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">6</int>
<reference key="object" ref="683629094"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="684391777"/>
<reference ref="766768061"/>
<reference ref="757978667"/>
<reference ref="649646560"/>
<reference ref="265767855"/>
<reference ref="389094888"/>
<reference ref="689081238"/>
</object>
<reference key="parent" ref="26497398"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">7</int>
<reference key="object" ref="684391777"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="17541256"/>
</object>
<reference key="parent" ref="683629094"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">8</int>
<reference key="object" ref="766768061"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="86959214"/>
</object>
<reference key="parent" ref="683629094"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">9</int>
<reference key="object" ref="757978667"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="7373583"/>
</object>
<reference key="parent" ref="683629094"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">15</int>
<reference key="object" ref="265767855"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="5529083"/>
</object>
<reference key="parent" ref="683629094"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">16</int>
<reference key="object" ref="389094888"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="285814029"/>
</object>
<reference key="parent" ref="683629094"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">17</int>
<reference key="object" ref="649646560"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="112350240"/>
</object>
<reference key="parent" ref="683629094"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">30</int>
<reference key="object" ref="689081238"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="368800735"/>
</object>
<reference key="parent" ref="683629094"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">18</int>
<reference key="object" ref="964078912"/>
<reference key="parent" ref="0"/>
<string key="objectName">Shared Defaults</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">38</int>
<reference key="object" ref="17541256"/>
<reference key="parent" ref="684391777"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">39</int>
<reference key="object" ref="86959214"/>
<reference key="parent" ref="766768061"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">40</int>
<reference key="object" ref="7373583"/>
<reference key="parent" ref="757978667"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">41</int>
<reference key="object" ref="5529083"/>
<reference key="parent" ref="265767855"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">42</int>
<reference key="object" ref="285814029"/>
<reference key="parent" ref="389094888"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">43</int>
<reference key="object" ref="112350240"/>
<reference key="parent" ref="649646560"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">44</int>
<reference key="object" ref="368800735"/>
<reference key="parent" ref="689081238"/>
</object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>-1.IBPluginDependency</string>
<string>-2.IBPluginDependency</string>
<string>-3.IBPluginDependency</string>
<string>15.IBPluginDependency</string>
<string>16.IBPluginDependency</string>
<string>17.IBPluginDependency</string>
<string>18.IBPluginDependency</string>
<string>30.IBPluginDependency</string>
<string>38.IBPluginDependency</string>
<string>39.IBPluginDependency</string>
<string>40.IBPluginDependency</string>
<string>41.IBPluginDependency</string>
<string>42.IBPluginDependency</string>
<string>43.IBPluginDependency</string>
<string>44.IBPluginDependency</string>
<string>5.IBPluginDependency</string>
<string>5.IBWindowTemplateEditedContentRect</string>
<string>6.IBPluginDependency</string>
<string>7.IBPluginDependency</string>
<string>8.IBPluginDependency</string>
<string>9.IBPluginDependency</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>{{312, 947}, {743, 152}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
</object>
</object>
<object class="NSMutableDictionary" key="unlocalizedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference key="dict.sortedKeys" ref="0"/>
<reference key="dict.values" ref="0"/>
</object>
<nil key="activeLocalization"/>
<object class="NSMutableDictionary" key="localizations">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference key="dict.sortedKeys" ref="0"/>
<reference key="dict.values" ref="0"/>
</object>
<nil key="sourceID"/>
<int key="maxID">44</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes"/>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
<integer value="1050" key="NS.object.0"/>
</object>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
<integer value="3100" key="NS.object.0"/>
</object>
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
<int key="IBDocument.defaultPropertyAccessControl">3</int>
<object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
<string key="NS.key.0">NSApplicationIcon</string>
<string key="NS.object.0">{128, 128}</string>
</object>
</data>
</archive>

View File

@ -1,603 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
<data>
<int key="IBDocument.SystemTarget">1050</int>
<string key="IBDocument.SystemVersion">12B19</string>
<string key="IBDocument.InterfaceBuilderVersion">2549</string>
<string key="IBDocument.AppKitVersion">1187</string>
<string key="IBDocument.HIToolboxVersion">624.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="NS.object.0">2549</string>
</object>
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>NSButton</string>
<string>NSButtonCell</string>
<string>NSCustomObject</string>
<string>NSImageCell</string>
<string>NSImageView</string>
<string>NSSecureTextField</string>
<string>NSSecureTextFieldCell</string>
<string>NSTextField</string>
<string>NSTextFieldCell</string>
<string>NSView</string>
<string>NSWindowTemplate</string>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
</object>
<object class="NSMutableDictionary" key="IBDocument.Metadata">
<string key="NS.key.0">PluginDependencyRecalculationVersion</string>
<integer value="1" key="NS.object.0"/>
</object>
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSCustomObject" id="1001">
<string key="NSClassName">SUPasswordPrompt</string>
</object>
<object class="NSCustomObject" id="1003">
<string key="NSClassName">FirstResponder</string>
</object>
<object class="NSCustomObject" id="1004">
<string key="NSClassName">NSApplication</string>
</object>
<object class="NSWindowTemplate" id="1005">
<int key="NSWindowStyleMask">1</int>
<int key="NSWindowBacking">2</int>
<string key="NSWindowRect">{{196, 372}, {394, 118}}</string>
<int key="NSWTFlags">544736256</int>
<string key="NSWindowTitle">كلمة السر</string>
<string key="NSWindowClass">NSWindow</string>
<nil key="NSViewClass"/>
<nil key="NSUserInterfaceItemIdentifier"/>
<object class="NSView" key="NSWindowView" id="1006">
<reference key="NSNextResponder"/>
<int key="NSvFlags">256</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSSecureTextField" id="702493616">
<reference key="NSNextResponder" ref="1006"/>
<int key="NSvFlags">290</int>
<string key="NSFrame">{{20, 49}, {195, 22}}</string>
<reference key="NSSuperview" ref="1006"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="904376142"/>
<bool key="NSEnabled">YES</bool>
<object class="NSSecureTextFieldCell" key="NSCell" id="952445980">
<int key="NSCellFlags">342884416</int>
<int key="NSCellFlags2">272630784</int>
<string key="NSContents"/>
<object class="NSFont" key="NSSupport" id="761309253">
<string key="NSName">LucidaGrande</string>
<double key="NSSize">13</double>
<int key="NSfFlags">1044</int>
</object>
<reference key="NSControlView" ref="702493616"/>
<bool key="NSDrawsBackground">YES</bool>
<object class="NSColor" key="NSBackgroundColor">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">textBackgroundColor</string>
<object class="NSColor" key="NSColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MQA</bytes>
</object>
</object>
<object class="NSColor" key="NSTextColor">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">textColor</string>
<object class="NSColor" key="NSColor" id="1044763220">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MAA</bytes>
</object>
</object>
<object class="NSArray" key="NSAllowedInputLocales">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
</object>
</object>
<bool key="NSAllowsLogicalLayoutDirection">NO</bool>
</object>
<object class="NSTextField" id="904376142">
<reference key="NSNextResponder" ref="1006"/>
<int key="NSvFlags">292</int>
<string key="NSFrame">{{220, 51}, {68, 17}}</string>
<reference key="NSSuperview" ref="1006"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="17192395"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="561848322">
<int key="NSCellFlags">68157504</int>
<int key="NSCellFlags2">71304192</int>
<string key="NSContents">كلمة السر:</string>
<reference key="NSSupport" ref="761309253"/>
<reference key="NSControlView" ref="904376142"/>
<object class="NSColor" key="NSBackgroundColor" id="768468736">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">controlColor</string>
<object class="NSColor" key="NSColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
</object>
</object>
<object class="NSColor" key="NSTextColor" id="294895527">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">controlTextColor</string>
<reference key="NSColor" ref="1044763220"/>
</object>
</object>
<bool key="NSAllowsLogicalLayoutDirection">NO</bool>
</object>
<object class="NSButton" id="17192395">
<reference key="NSNextResponder" ref="1006"/>
<int key="NSvFlags">289</int>
<string key="NSFrame">{{14, 13}, {83, 32}}</string>
<reference key="NSSuperview" ref="1006"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="253260072"/>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="611796391">
<int key="NSCellFlags">67108864</int>
<int key="NSCellFlags2">134217728</int>
<string key="NSContents">فتح القفل</string>
<reference key="NSSupport" ref="761309253"/>
<reference key="NSControlView" ref="17192395"/>
<int key="NSButtonFlags">-2038284288</int>
<int key="NSButtonFlags2">129</int>
<string key="NSAlternateContents"/>
<string type="base64-UTF8" key="NSKeyEquivalent">DQ</string>
<int key="NSPeriodicDelay">200</int>
<int key="NSPeriodicInterval">25</int>
</object>
<bool key="NSAllowsLogicalLayoutDirection">NO</bool>
</object>
<object class="NSButton" id="253260072">
<reference key="NSNextResponder" ref="1006"/>
<int key="NSvFlags">289</int>
<string key="NSFrame">{{97, 13}, {82, 32}}</string>
<reference key="NSSuperview" ref="1006"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="470601067"/>
<bool key="NSEnabled">YES</bool>
<object class="NSButtonCell" key="NSCell" id="600635121">
<int key="NSCellFlags">67108864</int>
<int key="NSCellFlags2">134217728</int>
<string key="NSContents">إلغاء</string>
<reference key="NSSupport" ref="761309253"/>
<reference key="NSControlView" ref="253260072"/>
<int key="NSButtonFlags">-2038284288</int>
<int key="NSButtonFlags2">129</int>
<string key="NSAlternateContents"/>
<string type="base64-UTF8" key="NSKeyEquivalent">Gw</string>
<int key="NSPeriodicDelay">200</int>
<int key="NSPeriodicInterval">25</int>
</object>
<bool key="NSAllowsLogicalLayoutDirection">NO</bool>
</object>
<object class="NSTextField" id="141023835">
<reference key="NSNextResponder" ref="1006"/>
<int key="NSvFlags">266</int>
<string key="NSFrame">{{17, 86}, {271, 17}}</string>
<reference key="NSSuperview" ref="1006"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="702493616"/>
<bool key="NSEnabled">YES</bool>
<object class="NSTextFieldCell" key="NSCell" id="229940026">
<int key="NSCellFlags">67108864</int>
<int key="NSCellFlags2">71303168</int>
<string key="NSContents">هذا التحديث مقفول بكلمة سر.</string>
<object class="NSFont" key="NSSupport">
<string key="NSName">LucidaGrande-Bold</string>
<double key="NSSize">13</double>
<int key="NSfFlags">16</int>
</object>
<reference key="NSControlView" ref="141023835"/>
<reference key="NSBackgroundColor" ref="768468736"/>
<reference key="NSTextColor" ref="294895527"/>
</object>
<bool key="NSAllowsLogicalLayoutDirection">NO</bool>
</object>
<object class="NSImageView" id="470601067">
<reference key="NSNextResponder" ref="1006"/>
<int key="NSvFlags">268</int>
<object class="NSMutableSet" key="NSDragTypes">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="set.sortedObjects">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>Apple PDF pasteboard type</string>
<string>Apple PICT pasteboard type</string>
<string>Apple PNG pasteboard type</string>
<string>NSFilenamesPboardType</string>
<string>NeXT Encapsulated PostScript v1.2 pasteboard type</string>
<string>NeXT TIFF v4.0 pasteboard type</string>
</object>
</object>
<string key="NSFrame">{{310, 39}, {64, 64}}</string>
<reference key="NSSuperview" ref="1006"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView"/>
<bool key="NSEnabled">YES</bool>
<object class="NSImageCell" key="NSCell" id="415127758">
<int key="NSCellFlags">134217728</int>
<int key="NSCellFlags2">33554432</int>
<int key="NSAlign">0</int>
<int key="NSScale">0</int>
<int key="NSStyle">0</int>
<bool key="NSAnimates">NO</bool>
</object>
<bool key="NSAllowsLogicalLayoutDirection">NO</bool>
<bool key="NSEditable">YES</bool>
</object>
</object>
<string key="NSFrameSize">{394, 118}</string>
<reference key="NSSuperview"/>
<reference key="NSWindow"/>
<reference key="NSNextKeyView" ref="141023835"/>
</object>
<string key="NSScreenRect">{{0, 0}, {1280, 778}}</string>
<string key="NSMaxSize">{10000000000000, 10000000000000}</string>
<bool key="NSWindowIsRestorable">YES</bool>
</object>
</object>
<object class="IBObjectContainer" key="IBDocument.Objects">
<object class="NSMutableArray" key="connectionRecords">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">mPasswordField</string>
<reference key="source" ref="1001"/>
<reference key="destination" ref="702493616"/>
</object>
<int key="connectionID">19</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">window</string>
<reference key="source" ref="1001"/>
<reference key="destination" ref="1005"/>
</object>
<int key="connectionID">20</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">cancel:</string>
<reference key="source" ref="1001"/>
<reference key="destination" ref="253260072"/>
</object>
<int key="connectionID">21</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">accept:</string>
<reference key="source" ref="1001"/>
<reference key="destination" ref="17192395"/>
</object>
<int key="connectionID">22</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">mTextDescription</string>
<reference key="source" ref="1001"/>
<reference key="destination" ref="141023835"/>
</object>
<int key="connectionID">25</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">mIconView</string>
<reference key="source" ref="1001"/>
<reference key="destination" ref="470601067"/>
</object>
<int key="connectionID">26</int>
</object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBObjectRecord">
<int key="objectID">0</int>
<object class="NSArray" key="object" id="0">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<reference key="children" ref="1000"/>
<nil key="parent"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">-2</int>
<reference key="object" ref="1001"/>
<reference key="parent" ref="0"/>
<string key="objectName">File's Owner</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-1</int>
<reference key="object" ref="1003"/>
<reference key="parent" ref="0"/>
<string key="objectName">First Responder</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-3</int>
<reference key="object" ref="1004"/>
<reference key="parent" ref="0"/>
<string key="objectName">Application</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">1</int>
<reference key="object" ref="1005"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="1006"/>
</object>
<reference key="parent" ref="0"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">2</int>
<reference key="object" ref="1006"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="470601067"/>
<reference ref="141023835"/>
<reference ref="904376142"/>
<reference ref="702493616"/>
<reference ref="17192395"/>
<reference ref="253260072"/>
</object>
<reference key="parent" ref="1005"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">3</int>
<reference key="object" ref="702493616"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="952445980"/>
</object>
<reference key="parent" ref="1006"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">4</int>
<reference key="object" ref="952445980"/>
<reference key="parent" ref="702493616"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">5</int>
<reference key="object" ref="904376142"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="561848322"/>
</object>
<reference key="parent" ref="1006"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">6</int>
<reference key="object" ref="561848322"/>
<reference key="parent" ref="904376142"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">7</int>
<reference key="object" ref="17192395"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="611796391"/>
</object>
<reference key="parent" ref="1006"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">8</int>
<reference key="object" ref="611796391"/>
<reference key="parent" ref="17192395"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">9</int>
<reference key="object" ref="253260072"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="600635121"/>
</object>
<reference key="parent" ref="1006"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">10</int>
<reference key="object" ref="600635121"/>
<reference key="parent" ref="253260072"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">15</int>
<reference key="object" ref="141023835"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="229940026"/>
</object>
<reference key="parent" ref="1006"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">16</int>
<reference key="object" ref="229940026"/>
<reference key="parent" ref="141023835"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">17</int>
<reference key="object" ref="470601067"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="415127758"/>
</object>
<reference key="parent" ref="1006"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">18</int>
<reference key="object" ref="415127758"/>
<reference key="parent" ref="470601067"/>
</object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>-1.IBPluginDependency</string>
<string>-2.IBPluginDependency</string>
<string>-3.IBPluginDependency</string>
<string>1.IBPluginDependency</string>
<string>1.IBWindowTemplateEditedContentRect</string>
<string>1.NSWindowTemplate.visibleAtLaunch</string>
<string>10.IBPluginDependency</string>
<string>15.IBPluginDependency</string>
<string>16.IBPluginDependency</string>
<string>17.IBPluginDependency</string>
<string>18.IBPluginDependency</string>
<string>2.IBPluginDependency</string>
<string>3.IBPluginDependency</string>
<string>4.IBPluginDependency</string>
<string>5.IBPluginDependency</string>
<string>6.IBPluginDependency</string>
<string>7.IBPluginDependency</string>
<string>8.IBPluginDependency</string>
<string>9.IBPluginDependency</string>
</object>
<object class="NSArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>{{316, 826}, {362, 138}}</string>
<boolean value="NO"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
</object>
</object>
<object class="NSMutableDictionary" key="unlocalizedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference key="dict.sortedKeys" ref="0"/>
<reference key="dict.values" ref="0"/>
</object>
<nil key="activeLocalization"/>
<object class="NSMutableDictionary" key="localizations">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference key="dict.sortedKeys" ref="0"/>
<reference key="dict.values" ref="0"/>
</object>
<nil key="sourceID"/>
<int key="maxID">26</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBPartialClassDescription">
<string key="className">SUPasswordPrompt</string>
<string key="superclassName">SUWindowController</string>
<object class="NSMutableDictionary" key="actions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>accept:</string>
<string>cancel:</string>
</object>
<object class="NSArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>id</string>
<string>id</string>
</object>
</object>
<object class="NSMutableDictionary" key="actionInfosByName">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>accept:</string>
<string>cancel:</string>
</object>
<object class="NSArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBActionInfo">
<string key="name">accept:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo">
<string key="name">cancel:</string>
<string key="candidateClassName">id</string>
</object>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>mIconView</string>
<string>mPasswordField</string>
<string>mTextDescription</string>
</object>
<object class="NSArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>NSImageView</string>
<string>NSSecureTextField</string>
<string>NSTextField</string>
</object>
</object>
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>mIconView</string>
<string>mPasswordField</string>
<string>mTextDescription</string>
</object>
<object class="NSArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBToOneOutletInfo">
<string key="name">mIconView</string>
<string key="candidateClassName">NSImageView</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">mPasswordField</string>
<string key="candidateClassName">NSSecureTextField</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">mTextDescription</string>
<string key="candidateClassName">NSTextField</string>
</object>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/SUPasswordPrompt.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">SUWindowController</string>
<string key="superclassName">NSWindowController</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">./Classes/SUWindowController.h</string>
</object>
</object>
</object>
</object>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
<integer value="1050" key="NS.object.0"/>
</object>
<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
<integer value="3000" key="NS.object.0"/>
</object>
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
<int key="IBDocument.defaultPropertyAccessControl">3</int>
</data>
</archive>

Some files were not shown because too many files have changed in this diff Show More