Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 250 lines (218 sloc) 8.042 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
5aa1e18 Improved headers from Charles D. H. Williams.
andym authored
9 #import "Sparkle.h"
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
10 #import "SUAppcast.h"
11
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
12 @interface SUAppcast (Private)
13 - (void)reportError:(NSError *)error;
a148504 @andymatuschak Fixes 252986
andymatuschak authored
14 - (NSXMLNode *)bestNodeInNodes:(NSArray *)nodes;
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
15 @end
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
16
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
17 @implementation SUAppcast
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
18
19 - (void)dealloc
20 {
21 [items release];
46312a2 @andymatuschak Fixes 258060
andymatuschak authored
22 [userAgentString release];
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
23 [super dealloc];
24 }
25
26 - (NSArray *)items
27 {
28 return items;
29 }
30
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
31 - (void)fetchAppcastFromURL:(NSURL *)url
32 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
33 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0];
34 if (userAgentString)
35 [request setValue:userAgentString forHTTPHeaderField:@"User-Agent"];
36
9d260f9 @andymatuschak Bug #275309: Crash in NSURLConnection
andymatuschak authored
37 NSURLDownload *download = [[[NSURLDownload alloc] initWithRequest:request delegate:self] autorelease];
38 CFRetain(download);
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
39 }
40
9d260f9 @andymatuschak Bug #275309: Crash in NSURLConnection
andymatuschak authored
41 - (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
42 {
9d260f9 @andymatuschak Bug #275309: Crash in NSURLConnection
andymatuschak authored
43 NSString *destinationFilename = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];
44 [download setDestination:destinationFilename allowOverwrite:NO];
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
45 }
46
9d260f9 @andymatuschak Bug #275309: Crash in NSURLConnection
andymatuschak authored
47 - (void)download:(NSURLDownload *)download didCreateDestination:(NSString *)path
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
48 {
9d260f9 @andymatuschak Bug #275309: Crash in NSURLConnection
andymatuschak authored
49 [downloadFilename release];
50 downloadFilename = [path copy];
51 }
52
53 - (void)downloadDidFinish:(NSURLDownload *)download
54 {
55 CFRelease(download);
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
56
57 NSError *error = nil;
9d260f9 @andymatuschak Bug #275309: Crash in NSURLConnection
andymatuschak authored
58 NSXMLDocument *document = [[NSXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:downloadFilename] options:0 error:&error];
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
59 BOOL failed = NO;
60 NSArray *xmlItems = nil;
61 NSMutableArray *appcastItems = [NSMutableArray array];
4fad530 Change availability checks so that they build on 10.4
Stuart Morgan authored
62 #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
7316a00 @andymatuschak Removed SL-deprecated NSFileManager methods. Left the old ones around…
andymatuschak authored
63 [[NSFileManager defaultManager] removeFileAtPath:downloadFilename handler:nil];
54299d7 added #ifdef's for Tiger support
August Joki authored
64 #else
f2a7b4b Fixed deprecated APIs to use replacements.
August Joki authored
65 [[NSFileManager defaultManager] removeItemAtPath:downloadFilename error:NULL];
54299d7 added #ifdef's for Tiger support
August Joki authored
66 #endif
9d260f9 @andymatuschak Bug #275309: Crash in NSURLConnection
andymatuschak authored
67 [downloadFilename release];
68 downloadFilename = nil;
69
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
70 if (nil == document)
74337fb @andymatuschak Fixed 243883:
andymatuschak authored
71 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
72 failed = YES;
73 }
74 else
75 {
76 xmlItems = [document nodesForXPath:@"/rss/channel/item" error:&error];
77 if (nil == xmlItems)
74337fb @andymatuschak Fixed 243883:
andymatuschak authored
78 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
79 failed = YES;
74337fb @andymatuschak Fixed 243883:
andymatuschak authored
80 }
81 }
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
82
83 if (failed == NO)
74337fb @andymatuschak Fixed 243883:
andymatuschak authored
84 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
85
86 NSEnumerator *nodeEnum = [xmlItems objectEnumerator];
87 NSXMLNode *node;
a148504 @andymatuschak Fixes 252986
andymatuschak authored
88 NSMutableDictionary *nodesDict = [NSMutableDictionary dictionary];
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
89 NSMutableDictionary *dict = [NSMutableDictionary dictionary];
90
91 while (failed == NO && (node = [nodeEnum nextObject]))
92 {
a148504 @andymatuschak Fixes 252986
andymatuschak authored
93 // First, we'll "index" all the first-level children of this appcast item so we can pick them out by language later.
94 if ([[node children] count])
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
95 {
a148504 @andymatuschak Fixes 252986
andymatuschak authored
96 node = [node childAtIndex:0];
97 while (nil != node)
98 {
99 NSString *name = [node name];
0343569 @andymatuschak Fixes 256106
andymatuschak authored
100 if (name)
a148504 @andymatuschak Fixes 252986
andymatuschak authored
101 {
0343569 @andymatuschak Fixes 256106
andymatuschak authored
102 NSMutableArray *nodes = [nodesDict objectForKey:name];
103 if (nodes == nil)
104 {
105 nodes = [NSMutableArray array];
106 [nodesDict setObject:nodes forKey:name];
107 }
108 [nodes addObject:node];
a148504 @andymatuschak Fixes 252986
andymatuschak authored
109 }
110 node = [node nextSibling];
111 }
112 }
113
114 NSEnumerator *nameEnum = [nodesDict keyEnumerator];
115 NSString *name;
116 while ((name = [nameEnum nextObject]))
117 {
118 node = [self bestNodeInNodes:[nodesDict objectForKey:name]];
119 if ([name isEqualToString:@"enclosure"])
120 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
121 // enclosure is flattened as a separate dictionary for some reason
122 NSEnumerator *attributeEnum = [[(NSXMLElement *)node attributes] objectEnumerator];
123 NSXMLNode *attribute;
124 NSMutableDictionary *encDict = [NSMutableDictionary dictionary];
125
126 while ((attribute = [attributeEnum nextObject]))
127 [encDict setObject:[attribute stringValue] forKey:[attribute name]];
128 [dict setObject:encDict forKey:@"enclosure"];
129
130 }
131 else if ([name isEqualToString:@"pubDate"])
132 {
133 // pubDate is expected to be an NSDate by SUAppcastItem, but the RSS class was returning an NSString
134 NSDate *date = [NSDate dateWithNaturalLanguageString:[node stringValue]];
135 if (date)
136 [dict setObject:date forKey:name];
137 }
bc7aff3 @andymatuschak If Sparkle can't parse one item, it no longer fails the entire appcast.
andymatuschak authored
138 else if (name != nil)
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
139 {
140 // add all other values as strings
141 [dict setObject:[[node stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] forKey:name];
142 }
a148504 @andymatuschak Fixes 252986
andymatuschak authored
143 }
144
7bfbe83 @nevyn When failing to parse a feed item, tell the developer *what* the erro…
nevyn authored
145 NSString *errString;
146 SUAppcastItem *anItem = [[SUAppcastItem alloc] initWithDictionary:dict failureReason:&errString];
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
147 if (anItem)
148 {
149 [appcastItems addObject:anItem];
150 [anItem release];
151 }
152 else
153 {
7bfbe83 @nevyn When failing to parse a feed item, tell the developer *what* the erro…
nevyn authored
154 NSLog(@"Sparkle Updater: Failed to parse appcast item: %@.\nAppcast dictionary was: %@", errString, dict);
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
155 }
a148504 @andymatuschak Fixes 252986
andymatuschak authored
156 [nodesDict removeAllObjects];
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
157 [dict removeAllObjects];
158 }
159 }
160
161 [document release];
162
163 if ([appcastItems count])
164 {
165 NSSortDescriptor *sort = [[[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO] autorelease];
166 [appcastItems sortUsingDescriptors:[NSArray arrayWithObject:sort]];
167 items = [appcastItems copy];
168 }
169
170 if (failed)
171 {
172 [self reportError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUAppcastParseError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:SULocalizedString(@"An error occurred while parsing the update feed.", nil), NSLocalizedDescriptionKey, nil]]];
173 }
174 else if ([delegate respondsToSelector:@selector(appcastDidFinishLoading:)])
175 {
176 [delegate appcastDidFinishLoading:self];
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
177 }
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
178 }
179
9d260f9 @andymatuschak Bug #275309: Crash in NSURLConnection
andymatuschak authored
180 - (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
181 {
9d260f9 @andymatuschak Bug #275309: Crash in NSURLConnection
andymatuschak authored
182 CFRelease(download);
bd80144 @andymatuschak Fixing #456514: Appcast download crashes on 10.5 if download fails
andymatuschak authored
183 if (downloadFilename)
184 {
4fad530 Change availability checks so that they build on 10.4
Stuart Morgan authored
185 #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
186 [[NSFileManager defaultManager] removeFileAtPath:downloadFilename handler:nil];
54299d7 added #ifdef's for Tiger support
August Joki authored
187 #else
bd80144 @andymatuschak Fixing #456514: Appcast download crashes on 10.5 if download fails
andymatuschak authored
188 [[NSFileManager defaultManager] removeItemAtPath:downloadFilename error:NULL];
54299d7 added #ifdef's for Tiger support
August Joki authored
189 #endif
bd80144 @andymatuschak Fixing #456514: Appcast download crashes on 10.5 if download fails
andymatuschak authored
190 }
9d260f9 @andymatuschak Bug #275309: Crash in NSURLConnection
andymatuschak authored
191 [downloadFilename release];
192 downloadFilename = nil;
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
193
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
194 [self reportError:error];
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
195 }
196
9d260f9 @andymatuschak Bug #275309: Crash in NSURLConnection
andymatuschak authored
197 - (NSURLRequest *)download:(NSURLDownload *)download willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
198 {
199 return request;
bc3be9a Touched practically every line of code in a super-monster-awesome ref…
andym authored
200 }
201
202 - (void)reportError:(NSError *)error
203 {
204 if ([delegate respondsToSelector:@selector(appcast:failedToLoadWithError:)])
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
205 {
bc3be9a Touched practically every line of code in a super-monster-awesome ref…
andym authored
206 [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
207 }
208 }
209
a148504 @andymatuschak Fixes 252986
andymatuschak authored
210 - (NSXMLNode *)bestNodeInNodes:(NSArray *)nodes
211 {
212 // We use this method to pick out the localized version of a node when one's available.
213 if ([nodes count] == 1)
214 return [nodes objectAtIndex:0];
215 else if ([nodes count] == 0)
216 return nil;
217
218 NSEnumerator *nodeEnum = [nodes objectEnumerator];
219 NSXMLElement *node;
220 NSMutableArray *languages = [NSMutableArray array];
221 NSString *lang;
222 NSInteger i;
223 while ((node = [nodeEnum nextObject]))
224 {
225 lang = [[node attributeForName:@"xml:lang"] stringValue];
0343569 @andymatuschak Fixes 256106
andymatuschak authored
226 [languages addObject:(lang ?: @"")];
a148504 @andymatuschak Fixes 252986
andymatuschak authored
227 }
228 lang = [[NSBundle preferredLocalizationsFromArray:languages] objectAtIndex:0];
0343569 @andymatuschak Fixes 256106
andymatuschak authored
229 i = [languages indexOfObject:([languages containsObject:lang] ? lang : @"")];
a148504 @andymatuschak Fixes 252986
andymatuschak authored
230 if (i == NSNotFound)
231 i = 0;
232 return [nodes objectAtIndex:i];
233 }
234
bc3be9a Touched practically every line of code in a super-monster-awesome ref…
andym authored
235 - (void)setUserAgentString:(NSString *)uas
236 {
a5dcf94 @andymatuschak Fixed all setters to eliminate the possibility of accidentally releas…
andymatuschak authored
237 if (uas != userAgentString)
238 {
239 [userAgentString release];
240 userAgentString = [uas copy];
241 }
bc3be9a Touched practically every line of code in a super-monster-awesome ref…
andym authored
242 }
243
244 - (void)setDelegate:del
245 {
246 delegate = del;
247 }
248
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
249 @end
Something went wrong with that request. Please try again.