Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial import

  • Loading branch information...
commit 40d6df4f26d0672352421aee0e284f1b88577ae5 0 parents
Stefan Arentz authored
0  README
No changes.
BIN  src/.DS_Store
Binary file not shown
14 src/AtomContent.h
@@ -0,0 +1,14 @@
+// AtomContent.h
+
+#import <Foundation/Foundation.h>
+#import <CoreData/CoreData.h>
+
+@interface AtomContent : NSObject {
+ NSString* text_;
+ NSString* type_;
+}
+
+@property (nonatomic,retain) NSString* text;
+@property (nonatomic,retain) NSString* type;
+
+@end
17 src/AtomContent.m
@@ -0,0 +1,17 @@
+// AtomContent.m
+
+#import "AtomContent.h"
+
+@implementation AtomContent
+
+@synthesize text = text_;
+@synthesize type = type_;
+
+- (void) dealloc
+{
+ [text_ release];
+ [type_ release];
+ [super dealloc];
+}
+
+@end
20 src/AtomEngine.h
@@ -0,0 +1,20 @@
+// AtomEngine.h
+
+@class AtomSubscription;
+
+@interface AtomEngine : NSObject {
+ @private
+ NSMutableArray* subscriptions_;
+ NSOperationQueue* operationQueue_;
+}
+
++ (id) sharedEngine;
+
+- (NSArray*) subscriptions;
+- (AtomSubscription*) subscriptionWithURL: (NSURL*) url;
+- (void) addSubscription: (AtomSubscription*) subscription;
+
+- (void) refreshAllSubscriptions;
+- (void) refreshSubscription: (AtomSubscription*) subscription;
+
+@end
86 src/AtomEngine.m
@@ -0,0 +1,86 @@
+// AtomEngine.m
+
+#import "AtomRefreshSubscriptionOperation.h"
+#import "AtomSubscription.h"
+#import "AtomEngine.h"
+
+@implementation AtomEngine
+
++ (id) sharedEngine
+{
+ static AtomEngine* atomEngineSingleton = nil;
+
+ @synchronized (self) {
+ if (atomEngineSingleton == nil) {
+ atomEngineSingleton = [self new];
+ }
+ }
+
+ return atomEngineSingleton;
+}
+
+#pragma mark -
+
+- (id) init
+{
+ if ((self = [super init]) != nil) {
+ subscriptions_ = [NSMutableArray new];
+ operationQueue_ = [NSOperationQueue new];
+ [operationQueue_ setMaxConcurrentOperationCount: 2];
+ }
+
+ return self;
+}
+
+- (void) dealloc
+{
+ [subscriptions_ release];
+ [operationQueue_ release];
+ [super dealloc];
+}
+
+#pragma mark -
+
+- (NSArray*) subscriptions
+{
+ return [subscriptions_ copy];
+}
+
+- (AtomSubscription*) subscriptionWithURL: (NSURL*) url
+{
+ for (AtomSubscription* subscription in subscriptions_) {
+ if ([subscription.url isEqual: url]) {
+ return subscription;
+ }
+ }
+ return nil;
+}
+
+- (void) addSubscription: (AtomSubscription*) subscription
+{
+ if ([self subscriptionWithURL: subscription.url]) {
+ return;
+ }
+
+ [subscriptions_ addObject: subscription];
+}
+
+#pragma mark -
+
+- (void) refreshAllSubscriptions
+{
+ for (AtomSubscription* subscription in subscriptions_) {
+ [self refreshSubscription: subscription];
+ }
+}
+
+- (void) refreshSubscription: (AtomSubscription*) subscription
+{
+ AtomRefreshSubscriptionOperation* operation = [[AtomRefreshSubscriptionOperation alloc] initWithSubscription: subscription];
+ if (operation != nil) {
+ [operationQueue_ addOperation: operation];
+ [operation release];
+ }
+}
+
+@end
28 src/AtomEntry.h
@@ -0,0 +1,28 @@
+// AtomEntry.h
+
+#import <Foundation/Foundation.h>
+#import <CoreData/CoreData.h>
+
+@class AtomContent;
+
+@interface AtomEntry : NSObject {
+ @private
+ NSString* title_;
+ NSString* summary_;
+ NSString* identifier_;
+ NSDate* published_;
+ NSDate* updated_;
+ AtomContent* content_;
+}
+
+@property (nonatomic,retain) NSString* title;
+@property (nonatomic,retain) NSString* summary;
+@property (nonatomic,retain) NSString* identifier;
+@property (nonatomic,retain) NSDate* published;
+@property (nonatomic,retain) NSDate* updated;
+@property (nonatomic,retain) AtomContent* content;
+
+- (void) setPublishedFromString: (NSString*) string;
+- (void) setUpdatedFromString: (NSString*) string;
+
+@end
40 src/AtomEntry.m
@@ -0,0 +1,40 @@
+// AtomEntry.m
+
+#import "AtomEntry.h"
+#import "AtomContent.h"
+
+@implementation AtomEntry
+
+@synthesize title = title_;
+@synthesize summary = summary_;
+@synthesize identifier = identifier_;
+@synthesize published = published_;
+@synthesize updated = updated_;
+@synthesize content = content_;
+
+- (void) dealloc
+{
+ [title_ release];
+ [summary_ release];
+ [identifier_ release];
+ [published_ release];
+ [updated_ release];
+ [content_ release];
+ [super dealloc];
+}
+
+- (void) setPublishedFromString: (NSString*) string
+{
+ NSDateFormatter* dateFormatter = [[NSDateFormatter new] autorelease];
+ [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"];
+ self.published = [dateFormatter dateFromString: string];
+}
+
+- (void) setUpdatedFromString: (NSString*) string
+{
+ NSDateFormatter* dateFormatter = [[NSDateFormatter new] autorelease];
+ [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"];
+ self.updated = [dateFormatter dateFromString: string];
+}
+
+@end
27 src/AtomFeed.h
@@ -0,0 +1,27 @@
+// AtomFeed.h
+
+#import <Foundation/Foundation.h>
+#import <CoreData/CoreData.h>
+
+@class AtomEntry;
+
+@interface AtomFeed : NSObject {
+ @private
+ NSString* identifier_;
+ NSString* title_;
+ NSString* subtitle_;
+ NSDate* updated_;
+ NSMutableArray* entries_;
+}
+
+@property (nonatomic,retain) NSString* identifier;
+@property (nonatomic,retain) NSString* title;
+@property (nonatomic,retain) NSString* subtitle;
+@property (nonatomic,retain) NSDate* updated;
+@property (nonatomic,readonly) NSMutableArray* entries;
+
+- (void) setUpdatedFromString: (NSString*) string;
+
+- (AtomEntry*) entryWithIdentifier: (NSString*) identifier;
+
+@end
49 src/AtomFeed.m
@@ -0,0 +1,49 @@
+// AtomFeed.m
+
+#import "AtomEntry.h"
+#import "AtomFeed.h"
+
+@implementation AtomFeed
+
+@synthesize identifier = identifier_;
+@synthesize entries = entries_;
+@synthesize title = title_;
+@synthesize subtitle = subtitle_;
+@synthesize updated = updated_;
+
+- (id) init
+{
+ if ((self = [super init]) != nil) {
+ entries_ = [NSMutableArray new];
+ }
+ return self;
+}
+
+- (void) dealloc
+{
+ [identifier_ release];
+ [title_ release];
+ [subtitle_ release];
+ [entries_ release];
+ [updated_ release];
+ [super dealloc];
+}
+
+- (void) setUpdatedFromString: (NSString*) string
+{
+ NSDateFormatter* dateFormatter = [[NSDateFormatter new] autorelease];
+ [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"];
+ self.updated = [dateFormatter dateFromString: string];
+}
+
+- (AtomEntry*) entryWithIdentifier: (NSString*) identifier
+{
+ for (AtomEntry* entry in entries_) {
+ if ([entry.identifier isEqualToString: identifier]) {
+ return entry;
+ }
+ }
+ return nil;
+}
+
+@end
15 src/AtomFeedParser.h
@@ -0,0 +1,15 @@
+// AtomFeedParser.h
+
+#import <Foundation/Foundation.h>
+
+@class AtomFeed;
+
+@interface AtomFeedParser : NSObject {
+
+}
+
++ (AtomFeed*) parseAtomFeedFromData: (NSData*) data;
++ (AtomFeed*) parseAtomFeedFromURL: (NSURL*) url;
++ (AtomFeed*) parseAtomFeedFromFile: (NSString*) path;
+
+@end
97 src/AtomFeedParser.m
@@ -0,0 +1,97 @@
+// AtomFeedParser.m
+
+#import "XMLDigester.h"
+
+#import "AtomFeed.h"
+#import "AtomEntry.h"
+#import "AtomContent.h"
+
+#import "AtomFeedParser.h"
+
+@implementation AtomFeedParser
+
++ (AtomFeed*) parseAtomFeedFromData: (NSData*) data
+{
+ AtomFeed* atomFeed = nil;
+
+ if (data != nil)
+ {
+ XMLDigester* digester = [XMLDigester digesterWithData: data];
+ if (digester != nil)
+ {
+ [digester addRule:
+ [XMLDigesterObjectCreateRule objectCreateRuleWithClass: [AtomFeed class]]
+ forPattern: @"feed"];
+
+ [digester addRule: [XMLDigesterCallMethodWithElementBodyRule callMethodWithElementBodyRuleWithSelector: @selector(setTitle:)]
+ forPattern: @"feed/title"];
+
+ [digester addRule: [XMLDigesterCallMethodWithElementBodyRule callMethodWithElementBodyRuleWithSelector: @selector(setSubtitle:)]
+ forPattern: @"feed/subtitle"];
+
+ // TODO: This should use some converter instead of setFooFromString:
+
+ [digester addRule: [XMLDigesterCallMethodWithElementBodyRule callMethodWithElementBodyRuleWithSelector: @selector(setUpdatedFromString:)]
+ forPattern: @"feed/updated"];
+
+ [digester addRule: [XMLDigesterCallMethodWithElementBodyRule callMethodWithElementBodyRuleWithSelector: @selector(setIdentifier:)]
+ forPattern: @"feed/id"];
+
+ [digester addRule:
+ [XMLDigesterObjectCreateRule objectCreateRuleWithClass: [AtomEntry class]]
+ forPattern: @"feed/entry"];
+
+ [digester addRule: [XMLDigesterCallMethodWithElementBodyRule callMethodWithElementBodyRuleWithSelector: @selector(setTitle:)]
+ forPattern: @"feed/entry/title"];
+
+ [digester addRule: [XMLDigesterCallMethodWithElementBodyRule callMethodWithElementBodyRuleWithSelector: @selector(setIdentifier:)]
+ forPattern: @"feed/entry/id"];
+
+ [digester addRule: [XMLDigesterCallMethodWithElementBodyRule callMethodWithElementBodyRuleWithSelector: @selector(setSummary:)]
+ forPattern: @"feed/entry/summary"];
+
+ // TODO: This should use some converter instead of setFooFromString:
+
+ [digester addRule: [XMLDigesterCallMethodWithElementBodyRule callMethodWithElementBodyRuleWithSelector: @selector(setPublishedFromString:)]
+ forPattern: @"feed/entry/published"];
+
+ [digester addRule: [XMLDigesterCallMethodWithElementBodyRule callMethodWithElementBodyRuleWithSelector: @selector(setUpdatedFromString:)]
+ forPattern: @"feed/entry/updated"];
+
+ [digester addRule:
+ [XMLDigesterObjectCreateRule objectCreateRuleWithClass: [AtomContent class]]
+ forPattern: @"feed/entry/content"];
+
+ [digester addRule:
+ [XMLDigesterSetPropertiesRule setPropertiesRuleWithMappings: [NSDictionary dictionaryWithObject: @"type" forKey: @"type"]]
+ forPattern: @"feed/entry/content"];
+
+ [digester addRule: [XMLDigesterCallMethodWithElementBodyRule callMethodWithElementBodyRuleWithSelector: @selector(setText:)]
+ forPattern: @"feed/entry/content"];
+
+ [digester addRule:
+ [XMLDigesterSetNextRule setNextRuleWithSelector: @selector(setContent:)]
+ forPattern: @"feed/entry/content"];
+
+ [digester addRule:
+ [XMLDigesterAddObjectRule addObjectRuleWithProperty: @"entries"]
+ forPattern: @"feed/entry"];
+
+ atomFeed = (AtomFeed*) [digester digest];
+ }
+ }
+
+ return atomFeed;
+}
+
++ (AtomFeed*) parseAtomFeedFromURL: (NSURL*) url
+{
+ return [self parseAtomFeedFromData: [NSData dataWithContentsOfURL: url]];
+}
+
++ (AtomFeed*) parseAtomFeedFromFile: (NSString*) path
+{
+ return [self parseAtomFeedFromData: [NSData dataWithContentsOfFile: path]];
+}
+
+@end
18 src/AtomRefreshSubscriptionOperation.h
@@ -0,0 +1,18 @@
+// AtomRefreshOperation.h
+
+@class AtomSubscription;
+
+@interface AtomRefreshSubscriptionOperation : NSOperation {
+ @private
+ AtomSubscription* subscription_;
+ @private
+ NSURLConnection* connection_;
+ NSMutableData* data_;
+ NSInteger statusCode_;
+ BOOL executing_;
+ BOOL finished_;
+}
+
+- (id) initWithSubscription: (AtomSubscription*) subscription;
+
+@end
157 src/AtomRefreshSubscriptionOperation.m
@@ -0,0 +1,157 @@
+// AtomRefreshOperation.m
+
+#import "AtomFeedParser.h"
+#import "AtomFeed.h"
+#import "AtomEntry.h"
+#import "AtomSubscription.h"
+#import "AtomRefreshSubscriptionOperation.h"
+
+@implementation AtomRefreshSubscriptionOperation
+
+- (id) initWithSubscription: (AtomSubscription*) subscription
+{
+ if ((self = [super init]) != nil) {
+ subscription_ = [subscription retain];
+ data_ = [NSMutableData new];
+ }
+ return self;
+}
+
+- (void) dealloc
+{
+ [subscription_ release];
+ [super dealloc];
+}
+
+#pragma mark -
+
+- (void) start
+{
+ if (![self isCancelled])
+ {
+ connection_ = [[NSURLConnection connectionWithRequest:
+ [NSURLRequest requestWithURL: subscription_.url] delegate: self] retain];
+
+ if (connection_ != nil) {
+ [self willChangeValueForKey:@"isExecuting"];
+ executing_ = YES;
+ [self didChangeValueForKey:@"isExecuting"];
+ } else {
+ [self willChangeValueForKey:@"isExecuting"];
+ finished_ = YES;
+ [self didChangeValueForKey:@"isExecuting"];
+ }
+ }
+ else
+ {
+ // If it's already been cancelled, mark the operation as finished.
+ [self willChangeValueForKey:@"isFinished"];
+ {
+ finished_ = YES;
+ }
+ [self didChangeValueForKey:@"isFinished"];
+ }
+}
+
+- (BOOL) isConcurrent
+{
+ return YES;
+}
+
+- (BOOL) isExecuting
+{
+ return executing_;
+}
+
+- (BOOL) isFinished
+{
+ return finished_;
+}
+
+#pragma mark NSURLConnection Delegate Methods
+
+- (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) data
+{
+ [data_ appendData: data];
+}
+
+- (void)connection: (NSURLConnection*) connection didReceiveResponse: (NSHTTPURLResponse*) response
+{
+ statusCode_ = [response statusCode];
+}
+
+- (void) connection: (NSURLConnection*) connection didFailWithError: (NSError*) error
+{
+ [self willChangeValueForKey:@"isFinished"];
+ [self willChangeValueForKey:@"isExecuting"];
+ {
+ finished_ = YES;
+ executing_ = NO;
+ }
+ [self didChangeValueForKey:@"isExecuting"];
+ [self didChangeValueForKey:@"isFinished"];
+
+ //[delegate_ loadImageDataOperationDidFail: self];
+}
+
+- (void) connectionDidFinishLoading: (NSURLConnection*) connection
+{
+ [self willChangeValueForKey:@"isFinished"];
+ [self willChangeValueForKey:@"isExecuting"];
+ {
+ finished_ = YES;
+ executing_ = NO;
+ }
+ [self didChangeValueForKey:@"isExecuting"];
+ [self didChangeValueForKey:@"isFinished"];
+
+ if (statusCode_ == 200)
+ {
+ NSLog(@"----- %@", subscription_.name);
+
+ AtomFeed* feed = [AtomFeedParser parseAtomFeedFromData: data_];
+ if (feed != nil)
+ {
+ if (subscription_.feed == nil)
+ {
+ subscription_.feed = feed;
+ for (AtomEntry* entry in subscription_.feed.entries) {
+ NSLog(@" %@", entry.title);
+ }
+ }
+ else
+ {
+ // If the feed has been replaced then delete the feed we have and store the new one
+
+ if ([subscription_.feed.identifier isEqualToString: feed.identifier] == NO)
+ {
+ NSLog(@"Reloading complete feed");
+ subscription_.feed = feed;
+ }
+ else
+ {
+ for (AtomEntry* entry in feed.entries)
+ {
+ AtomEntry* existingEntry = [subscription_.feed entryWithIdentifier: entry.identifier];
+ if (existingEntry == nil) {
+ [feed.entries addObject: entry];
+ NSLog(@" %@ (NEW)", entry.title);
+ }
+ }
+ }
+ }
+
+ // If this subscription did not have a name then take the name from the feed
+
+ if (subscription_.name == nil && feed.title != nil) {
+ subscription_.name = feed.title;
+ }
+ }
+ }
+ else
+ {
+ //[delegate_ loadImageDataOperationDidFail: self];
+ }
+}
+
+@end
68 src/AtomSubscription.h
@@ -0,0 +1,68 @@
+// AtomSubscription.h
+
+#import <Foundation/Foundation.h>
+
+@class AtomFeed;
+
+@interface AtomSubscription : NSObject {
+ @private
+ NSURL* url_;
+ NSString* name_;
+ AtomFeed* feed_;
+}
+
+@property (nonatomic,retain) NSURL* url;
+@property (nonatomic,retain) NSString* name;
+@property (nonatomic,retain) AtomFeed* feed;
+
++ (id) subscriptionWithURL: (NSURL*) url name: (NSString*) name;
+- (id) initWithURL: (NSURL*) url name: (NSString*) name;
+
+@end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#if 0
+// Create a repository
+AtomRepository* repository = [[AtomRepository repositoryAtPath: ...] retain];
+
+// Create a new subscription
+
+AtomSubscription* subscription = [AtomSubscription subscriptionWithName: ... URL: ...];
+[repository addSubscription: subscription];
+
+// Get a unique identifier for the subscription that we can store in the prefs
+NSString* subscriptionIdentifier = subscription.identifier;
+
+// Reload the repository, only feeds that need a reload
+[repository reload];
+
+// List of feeds
+NSArray* feeds = [repository feeds];
+
+// Display each feed and it's unread count
+for (AtomFeed* feed in feeds) {
+ NSLog(@"Feed '%@' has %d unread items", feed.name, feed.unreadCount);
+}
+
+// List items in a feed
+for (AtomEntry* entry in feed.entries) {
+ NSLog(@" - %@", entry.title);
+}
+
+// Mark an entry read
+entry.read = YES;
+#endif
34 src/AtomSubscription.m
@@ -0,0 +1,34 @@
+// AtomSubscription.m
+
+#import "AtomFeed.h"
+#import "AtomSubscription.h"
+
+@implementation AtomSubscription
+
+@synthesize url = url_;
+@synthesize name = name_;
+@synthesize feed = feed_;
+
++ (id) subscriptionWithURL: (NSURL*) url name: (NSString*) name
+{
+ return [[[self alloc] initWithURL: url name: name] autorelease];
+}
+
+- (id) initWithURL: (NSURL*) url name: (NSString*) name
+{
+ if ((self = [super init]) != nil) {
+ url_ = [url retain];
+ name_ = [name retain];
+ }
+ return self;
+}
+
+- (void) dealloc
+{
+ [url_ release];
+ [name_ release];
+ [feed_ release];
+ [super dealloc];
+}
+
+@end
Please sign in to comment.
Something went wrong with that request. Please try again.