Skip to content
Newer
Older
100644 294 lines (257 sloc) 8.81 KB
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
1 //
2 // SUAppcast.m
3 // Sparkle
4 //
5 // Created by Andy Matuschak on 3/12/06.
6 // Copyright 2006 Andy Matuschak. All rights reserved.
7 //
8
43a0a7d @uliwitness Merge of changes from SVN repository:
uliwitness authored
9 #import "SUUpdater.h"
10
11 #import "SUAppcast.h"
12 #import "SUAppcastItem.h"
13 #import "SUVersionComparisonProtocol.h"
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
14 #import "SUAppcast.h"
43a0a7d @uliwitness Merge of changes from SVN repository:
uliwitness authored
15 #import "SUConstants.h"
16 #import "SULog.h"
17
6e648f1 Add support for parsing an extended <sparkle:deltas> element in the a…
Mark Rowe authored
18 @interface NSXMLElement (SUAppcastExtensions)
19 - (NSDictionary *)attributesAsDictionary;
20 @end
21
22 @implementation NSXMLElement (SUAppcastExtensions)
23 - (NSDictionary *)attributesAsDictionary
24 {
25 NSEnumerator *attributeEnum = [[self attributes] objectEnumerator];
26 NSXMLNode *attribute;
27 NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
28
29 while ((attribute = [attributeEnum nextObject]))
30 [dictionary setObject:[attribute stringValue] forKey:[attribute name]];
31 return dictionary;
32 }
33 @end
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
34
73e96cd @andymatuschak Updating project for 4.2.1; changing SDK to 10.7
andymatuschak authored
35 @interface SUAppcast () <NSURLDownloadDelegate>
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
36 - (void)reportError:(NSError *)error;
a148504 @andymatuschak Fixes 252986
andymatuschak authored
37 - (NSXMLNode *)bestNodeInNodes:(NSArray *)nodes;
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
38 @end
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
39
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
40 @implementation SUAppcast
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
41
42 - (void)dealloc
43 {
44 [items release];
43a0a7d @uliwitness Merge of changes from SVN repository:
uliwitness authored
45 items = nil;
46312a2 @andymatuschak Fixes 258060
andymatuschak authored
46 [userAgentString release];
43a0a7d @uliwitness Merge of changes from SVN repository:
uliwitness authored
47 userAgentString = nil;
48 [downloadFilename release];
49 downloadFilename = nil;
2e3ed79 @andymatuschak Fixing #502212: clang static analyzer identifies 2 leaks in Sparkle code
andymatuschak authored
50 [download release];
9937e5a @uliwitness Merge andymatuschak/Sparkle.
uliwitness authored
51 download = nil;
43a0a7d @uliwitness Merge of changes from SVN repository:
uliwitness authored
52
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
53 [super dealloc];
54 }
55
56 - (NSArray *)items
57 {
58 return items;
59 }
60
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
61 - (void)fetchAppcastFromURL:(NSURL *)url
62 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
63 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0];
64 if (userAgentString)
65 [request setValue:userAgentString forHTTPHeaderField:@"User-Agent"];
66
2e3ed79 @andymatuschak Fixing #502212: clang static analyzer identifies 2 leaks in Sparkle code
andymatuschak authored
67 download = [[NSURLDownload alloc] initWithRequest:request delegate:self];
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
68 }
69
2e3ed79 @andymatuschak Fixing #502212: clang static analyzer identifies 2 leaks in Sparkle code
andymatuschak authored
70 - (void)download:(NSURLDownload *)aDownload decideDestinationWithSuggestedFilename:(NSString *)filename
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
71 {
d7774c0 performed a code review, specifically:
Sean McBride authored
72 NSString* destinationFilename = NSTemporaryDirectory();
73 if (destinationFilename)
74 {
75 destinationFilename = [destinationFilename stringByAppendingPathComponent:filename];
76 [download setDestination:destinationFilename allowOverwrite:NO];
77 }
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
78 }
79
2e3ed79 @andymatuschak Fixing #502212: clang static analyzer identifies 2 leaks in Sparkle code
andymatuschak authored
80 - (void)download:(NSURLDownload *)aDownload didCreateDestination:(NSString *)path
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
81 {
9d260f9 @andymatuschak Bug #275309: Crash in NSURLConnection
andymatuschak authored
82 [downloadFilename release];
83 downloadFilename = [path copy];
84 }
85
2e3ed79 @andymatuschak Fixing #502212: clang static analyzer identifies 2 leaks in Sparkle code
andymatuschak authored
86 - (void)downloadDidFinish:(NSURLDownload *)aDownload
87 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
88 NSError *error = nil;
c34e9b3 @andymatuschak Added an extra null check to SUAppcast downloadDidFinish because NSXM…
andymatuschak authored
89
a6fcfa6 @andymatuschak Fixing ridiculous error in the last commit caused by non-initializati…
andymatuschak authored
90 NSXMLDocument *document = nil;
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
91 BOOL failed = NO;
92 NSArray *xmlItems = nil;
93 NSMutableArray *appcastItems = [NSMutableArray array];
c34e9b3 @andymatuschak Added an extra null check to SUAppcast downloadDidFinish because NSXM…
andymatuschak authored
94
95 if (downloadFilename)
96 {
97 document = [[[NSXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:downloadFilename] options:0 error:&error] autorelease];
43a0a7d @uliwitness Merge of changes from SVN repository:
uliwitness authored
98
4fad530 Change availability checks so that they build on 10.4
Stuart Morgan authored
99 #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
c34e9b3 @andymatuschak Added an extra null check to SUAppcast downloadDidFinish because NSXM…
andymatuschak authored
100 [[NSFileManager defaultManager] removeFileAtPath:downloadFilename handler:nil];
54299d7 added #ifdef's for Tiger support
August Joki authored
101 #else
c34e9b3 @andymatuschak Added an extra null check to SUAppcast downloadDidFinish because NSXM…
andymatuschak authored
102 [[NSFileManager defaultManager] removeItemAtPath:downloadFilename error:nil];
54299d7 added #ifdef's for Tiger support
August Joki authored
103 #endif
c34e9b3 @andymatuschak Added an extra null check to SUAppcast downloadDidFinish because NSXM…
andymatuschak authored
104 [downloadFilename release];
105 downloadFilename = nil;
106 }
107 else
108 {
109 failed = YES;
110 }
9d260f9 @andymatuschak Bug #275309: Crash in NSURLConnection
andymatuschak authored
111
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
112 if (nil == document)
74337fb @andymatuschak Fixed 243883:
andymatuschak authored
113 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
114 failed = YES;
115 }
116 else
117 {
118 xmlItems = [document nodesForXPath:@"/rss/channel/item" error:&error];
119 if (nil == xmlItems)
74337fb @andymatuschak Fixed 243883:
andymatuschak authored
120 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
121 failed = YES;
74337fb @andymatuschak Fixed 243883:
andymatuschak authored
122 }
123 }
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
124
125 if (failed == NO)
74337fb @andymatuschak Fixed 243883:
andymatuschak authored
126 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
127
128 NSEnumerator *nodeEnum = [xmlItems objectEnumerator];
129 NSXMLNode *node;
a148504 @andymatuschak Fixes 252986
andymatuschak authored
130 NSMutableDictionary *nodesDict = [NSMutableDictionary dictionary];
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
131 NSMutableDictionary *dict = [NSMutableDictionary dictionary];
132
133 while (failed == NO && (node = [nodeEnum nextObject]))
134 {
a148504 @andymatuschak Fixes 252986
andymatuschak authored
135 // First, we'll "index" all the first-level children of this appcast item so we can pick them out by language later.
136 if ([[node children] count])
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
137 {
a148504 @andymatuschak Fixes 252986
andymatuschak authored
138 node = [node childAtIndex:0];
139 while (nil != node)
140 {
141 NSString *name = [node name];
0343569 @andymatuschak Fixes 256106
andymatuschak authored
142 if (name)
a148504 @andymatuschak Fixes 252986
andymatuschak authored
143 {
0343569 @andymatuschak Fixes 256106
andymatuschak authored
144 NSMutableArray *nodes = [nodesDict objectForKey:name];
145 if (nodes == nil)
146 {
147 nodes = [NSMutableArray array];
148 [nodesDict setObject:nodes forKey:name];
149 }
150 [nodes addObject:node];
a148504 @andymatuschak Fixes 252986
andymatuschak authored
151 }
152 node = [node nextSibling];
153 }
154 }
155
156 NSEnumerator *nameEnum = [nodesDict keyEnumerator];
157 NSString *name;
158 while ((name = [nameEnum nextObject]))
159 {
160 node = [self bestNodeInNodes:[nodesDict objectForKey:name]];
161 if ([name isEqualToString:@"enclosure"])
162 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
163 // enclosure is flattened as a separate dictionary for some reason
6e648f1 Add support for parsing an extended <sparkle:deltas> element in the a…
Mark Rowe authored
164 NSDictionary *encDict = [(NSXMLElement *)node attributesAsDictionary];
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
165 [dict setObject:encDict forKey:@"enclosure"];
166
167 }
168 else if ([name isEqualToString:@"pubDate"])
169 {
170 // pubDate is expected to be an NSDate by SUAppcastItem, but the RSS class was returning an NSString
171 NSDate *date = [NSDate dateWithNaturalLanguageString:[node stringValue]];
172 if (date)
173 [dict setObject:date forKey:name];
174 }
6e648f1 Add support for parsing an extended <sparkle:deltas> element in the a…
Mark Rowe authored
175 else if ([name isEqualToString:@"sparkle:deltas"])
176 {
177 NSMutableArray *deltas = [NSMutableArray array];
178 NSEnumerator *childEnum = [[node children] objectEnumerator];
179 NSXMLNode *child;
180 while ((child = [childEnum nextObject])) {
181 if ([[child name] isEqualToString:@"enclosure"])
182 [deltas addObject:[(NSXMLElement *)child attributesAsDictionary]];
183 }
184 [dict setObject:deltas forKey:@"deltas"];
185 }
186 else if (name != nil)
187 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
188 // add all other values as strings
189 [dict setObject:[[node stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] forKey:name];
190 }
a148504 @andymatuschak Fixes 252986
andymatuschak authored
191 }
192
7bfbe83 @nevyn When failing to parse a feed item, tell the developer *what* the erro…
nevyn authored
193 NSString *errString;
b21b308 all but a few places use the typical [[[foo alloc] init] autorelease]…
Sean McBride authored
194 SUAppcastItem *anItem = [[[SUAppcastItem alloc] initWithDictionary:dict failureReason:&errString] autorelease];
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
195 if (anItem)
196 {
197 [appcastItems addObject:anItem];
198 }
199 else
200 {
4f8d745 @uliwitness Changed a few NSLogs() to SULogs().
uliwitness authored
201 SULog(@"Sparkle Updater: Failed to parse appcast item: %@.\nAppcast dictionary was: %@", errString, dict);
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
202 }
a148504 @andymatuschak Fixes 252986
andymatuschak authored
203 [nodesDict removeAllObjects];
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
204 [dict removeAllObjects];
205 }
206 }
207
208 if ([appcastItems count])
209 {
210 NSSortDescriptor *sort = [[[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO] autorelease];
211 [appcastItems sortUsingDescriptors:[NSArray arrayWithObject:sort]];
212 items = [appcastItems copy];
213 }
214
215 if (failed)
216 {
217 [self reportError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUAppcastParseError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:SULocalizedString(@"An error occurred while parsing the update feed.", nil), NSLocalizedDescriptionKey, nil]]];
218 }
219 else if ([delegate respondsToSelector:@selector(appcastDidFinishLoading:)])
220 {
221 [delegate appcastDidFinishLoading:self];
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
222 }
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
223 }
224
a5245ac @andymatuschak Fixed a few local-vs-ivar variable ambiguities.
andymatuschak authored
225 - (void)download:(NSURLDownload *)aDownload didFailWithError:(NSError *)error
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
226 {
bd80144 @andymatuschak Fixing #456514: Appcast download crashes on 10.5 if download fails
andymatuschak authored
227 if (downloadFilename)
228 {
4fad530 Change availability checks so that they build on 10.4
Stuart Morgan authored
229 #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
bd80144 @andymatuschak Fixing #456514: Appcast download crashes on 10.5 if download fails
andymatuschak authored
230 [[NSFileManager defaultManager] removeFileAtPath:downloadFilename handler:nil];
54299d7 added #ifdef's for Tiger support
August Joki authored
231 #else
d7774c0 performed a code review, specifically:
Sean McBride authored
232 [[NSFileManager defaultManager] removeItemAtPath:downloadFilename error:nil];
54299d7 added #ifdef's for Tiger support
August Joki authored
233 #endif
bd80144 @andymatuschak Fixing #456514: Appcast download crashes on 10.5 if download fails
andymatuschak authored
234 }
9d260f9 @andymatuschak Bug #275309: Crash in NSURLConnection
andymatuschak authored
235 [downloadFilename release];
236 downloadFilename = nil;
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
237
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
238 [self reportError:error];
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
239 }
240
a5245ac @andymatuschak Fixed a few local-vs-ivar variable ambiguities.
andymatuschak authored
241 - (NSURLRequest *)download:(NSURLDownload *)aDownload willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
242 {
243 return request;
bc3be9a Touched practically every line of code in a super-monster-awesome ref…
andym authored
244 }
245
246 - (void)reportError:(NSError *)error
247 {
248 if ([delegate respondsToSelector:@selector(appcast:failedToLoadWithError:)])
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
249 {
bc3be9a Touched practically every line of code in a super-monster-awesome ref…
andym authored
250 [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]]];
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
251 }
252 }
253
a148504 @andymatuschak Fixes 252986
andymatuschak authored
254 - (NSXMLNode *)bestNodeInNodes:(NSArray *)nodes
255 {
256 // We use this method to pick out the localized version of a node when one's available.
257 if ([nodes count] == 1)
258 return [nodes objectAtIndex:0];
259 else if ([nodes count] == 0)
260 return nil;
261
262 NSEnumerator *nodeEnum = [nodes objectEnumerator];
263 NSXMLElement *node;
264 NSMutableArray *languages = [NSMutableArray array];
265 NSString *lang;
d7774c0 performed a code review, specifically:
Sean McBride authored
266 NSUInteger i;
a148504 @andymatuschak Fixes 252986
andymatuschak authored
267 while ((node = [nodeEnum nextObject]))
268 {
269 lang = [[node attributeForName:@"xml:lang"] stringValue];
a032358 @andymatuschak Removing GNU-style ?: operators. Thanks for the report, Uli.
andymatuschak authored
270 [languages addObject:(lang ? lang : @"")];
a148504 @andymatuschak Fixes 252986
andymatuschak authored
271 }
272 lang = [[NSBundle preferredLocalizationsFromArray:languages] objectAtIndex:0];
0343569 @andymatuschak Fixes 256106
andymatuschak authored
273 i = [languages indexOfObject:([languages containsObject:lang] ? lang : @"")];
a148504 @andymatuschak Fixes 252986
andymatuschak authored
274 if (i == NSNotFound)
275 i = 0;
276 return [nodes objectAtIndex:i];
277 }
278
bc3be9a Touched practically every line of code in a super-monster-awesome ref…
andym authored
279 - (void)setUserAgentString:(NSString *)uas
280 {
a5dcf94 @andymatuschak Fixed all setters to eliminate the possibility of accidentally releas…
andymatuschak authored
281 if (uas != userAgentString)
282 {
283 [userAgentString release];
284 userAgentString = [uas copy];
285 }
bc3be9a Touched practically every line of code in a super-monster-awesome ref…
andym authored
286 }
287
288 - (void)setDelegate:del
289 {
290 delegate = del;
291 }
292
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
293 @end
Something went wrong with that request. Please try again.