Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 294 lines (257 sloc) 9.021 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 appc...
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 in ...
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 in ...
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 in ...
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 in ...
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 in ...
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 NSXMLDo...
andymatuschak authored
89
a6fcfa6 @andymatuschak Fixing ridiculous error in the last commit caused by non-initialization ...
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 NSXMLDo...
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 NSXMLDo...
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 NSXMLDo...
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 NSXMLDo...
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 appc...
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 appc...
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 error i...
nevyn authored
193 NSString *errString;
b21b308 all but a few places use the typical [[[foo alloc] init] autorelease] pa...
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 in ...
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 in ...
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 in ...
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 refact...
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 refact...
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 refact...
andym authored
279 - (void)setUserAgentString:(NSString *)uas
280 {
a5dcf94 @andymatuschak Fixed all setters to eliminate the possibility of accidentally releasing...
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 refact...
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.