Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 181 lines (151 sloc) 5.217 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;
14 @end
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
15
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
16 @implementation SUAppcast
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
17
18 - (void)dealloc
19 {
20 [items release];
21 [super dealloc];
22 }
23
24 - (NSArray *)items
25 {
26 return items;
27 }
28
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
29 - (void)fetchAppcastFromURL:(NSURL *)url
30 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
31 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0];
32 if (userAgentString)
33 [request setValue:userAgentString forHTTPHeaderField:@"User-Agent"];
34
35 incrementalData = [[NSMutableData alloc] init];
36 NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
37 CFRetain(connection);
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
38 }
39
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
40 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
41 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
42 [incrementalData appendData:data];
43 }
44
45 - (void)connectionDidFinishLoading:(NSURLConnection *)connection
46 {
47 CFRelease(connection);
48
49 NSError *error = nil;
50 NSXMLDocument *document = [[NSXMLDocument alloc] initWithData:incrementalData options:0 error:&error];
51 BOOL failed = NO;
52 NSArray *xmlItems = nil;
53 NSMutableArray *appcastItems = [NSMutableArray array];
54
55 if (nil == document)
74337fb @andymatuschak Fixed 243883:
andymatuschak authored
56 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
57 failed = YES;
58 }
59 else
60 {
61 xmlItems = [document nodesForXPath:@"/rss/channel/item" error:&error];
62 if (nil == xmlItems)
74337fb @andymatuschak Fixed 243883:
andymatuschak authored
63 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
64 failed = YES;
74337fb @andymatuschak Fixed 243883:
andymatuschak authored
65 }
66 }
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
67
68 if (failed == NO)
74337fb @andymatuschak Fixed 243883:
andymatuschak authored
69 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
70
71 NSEnumerator *nodeEnum = [xmlItems objectEnumerator];
72 NSXMLNode *node;
73 NSMutableDictionary *dict = [NSMutableDictionary dictionary];
74
75 while (failed == NO && (node = [nodeEnum nextObject]))
76 {
77 // walk the children in reverse
78 node = [[node children] lastObject];
79 while (nil != node)
80 {
81
82 NSString *name = [node name];
83
84 if ([name isEqualToString:@"enclosure"]) {
85 // enclosure is flattened as a separate dictionary for some reason
86 NSEnumerator *attributeEnum = [[(NSXMLElement *)node attributes] objectEnumerator];
87 NSXMLNode *attribute;
88 NSMutableDictionary *encDict = [NSMutableDictionary dictionary];
89
90 while ((attribute = [attributeEnum nextObject]))
91 {
92 [encDict setObject:[attribute stringValue] forKey:[attribute name]];
93 }
94 [dict setObject:encDict forKey:@"enclosure"];
95
96 }
97 else if ([name isEqualToString:@"pubDate"])
98 {
99 // pubDate is expected to be an NSDate by SUAppcastItem, but the RSS class was returning an NSString
100 NSDate *date = [NSDate dateWithNaturalLanguageString:[node stringValue]];
101 if (date)
102 [dict setObject:date forKey:name];
103 }
bc7aff3 @andymatuschak If Sparkle can't parse one item, it no longer fails the entire appcast.
andymatuschak authored
104 else if (name != nil)
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
105 {
106 // add all other values as strings
107 [dict setObject:[[node stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] forKey:name];
108 }
109
110 // previous sibling; returns nil when exhausted
111 node = [node previousSibling];
112 }
113 SUAppcastItem *anItem = [[SUAppcastItem alloc] initWithDictionary:dict];
114 if (anItem)
115 {
116 [appcastItems addObject:anItem];
117 [anItem release];
118 }
119 else
120 {
bc7aff3 @andymatuschak If Sparkle can't parse one item, it no longer fails the entire appcast.
andymatuschak authored
121 NSLog(@"Sparkle Updater: Failed to parse appcast item with appcast dictionary %@!", dict);
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
122 }
123 [dict removeAllObjects];
124 }
125 }
126
127 [document release];
128
129 if ([appcastItems count])
130 {
131 NSSortDescriptor *sort = [[[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO] autorelease];
132 [appcastItems sortUsingDescriptors:[NSArray arrayWithObject:sort]];
133 items = [appcastItems copy];
134 }
135
136 if (failed)
137 {
138 [self reportError:[NSError errorWithDomain:SUSparkleErrorDomain code:SUAppcastParseError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:SULocalizedString(@"An error occurred while parsing the update feed.", nil), NSLocalizedDescriptionKey, nil]]];
139 }
140 else if ([delegate respondsToSelector:@selector(appcastDidFinishLoading:)])
141 {
142 [delegate appcastDidFinishLoading:self];
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
143 }
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
144 }
145
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
146 - (void)connection:(NSURLConnection*)connection didFailWithError:(NSError *)error
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
147 {
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
148 CFRelease(connection);
149
d06b2f5 @andymatuschak Fixes bug #228449: now the appcast doesn't run the RSS feed fetching …
andymatuschak authored
150 [self reportError:error];
82c2448 @andymatuschak Fixes 244419
andymatuschak authored
151 }
152
153 - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
154 {
155 return request;
bc3be9a Touched practically every line of code in a super-monster-awesome ref…
andym authored
156 }
157
158 - (void)reportError:(NSError *)error
159 {
160 if ([delegate respondsToSelector:@selector(appcast:failedToLoadWithError:)])
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
161 {
bc3be9a Touched practically every line of code in a super-monster-awesome ref…
andym authored
162 [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
163 }
164 }
165
bc3be9a Touched practically every line of code in a super-monster-awesome ref…
andym authored
166 - (void)setUserAgentString:(NSString *)uas
167 {
a5dcf94 @andymatuschak Fixed all setters to eliminate the possibility of accidentally releas…
andymatuschak authored
168 if (uas != userAgentString)
169 {
170 [userAgentString release];
171 userAgentString = [uas copy];
172 }
bc3be9a Touched practically every line of code in a super-monster-awesome ref…
andym authored
173 }
174
175 - (void)setDelegate:del
176 {
177 delegate = del;
178 }
179
9fa3da5 Holy restructuring, batman! Watch out for falling folders.
andym authored
180 @end
Something went wrong with that request. Please try again.