├── Classes ├── AppDelegate.h ├── AppDelegate.m ├── DetailViewController.h ├── DetailViewController.m ├── MGTwitterEngine │ ├── MGTwitterEngine.h │ ├── MGTwitterEngine.m │ ├── MGTwitterEngineDelegate.h │ ├── MGTwitterEngineGlobalHeader.h │ ├── MGTwitterHTTPURLConnection.h │ ├── MGTwitterHTTPURLConnection.m │ ├── MGTwitterLibXMLParser.h │ ├── MGTwitterLibXMLParser.m │ ├── MGTwitterMessagesLibXMLParser.h │ ├── MGTwitterMessagesLibXMLParser.m │ ├── MGTwitterMessagesParser.h │ ├── MGTwitterMessagesParser.m │ ├── MGTwitterMiscLibXMLParser.h │ ├── MGTwitterMiscLibXMLParser.m │ ├── MGTwitterMiscParser.h │ ├── MGTwitterMiscParser.m │ ├── MGTwitterParserDelegate.h │ ├── MGTwitterRequestTypes.h │ ├── MGTwitterSocialGraphLibXMLParser.h │ ├── MGTwitterSocialGraphLibXMLParser.m │ ├── MGTwitterSocialGraphParser.h │ ├── MGTwitterSocialGraphParser.m │ ├── MGTwitterStatusesLibXMLParser.h │ ├── MGTwitterStatusesLibXMLParser.m │ ├── MGTwitterStatusesParser.h │ ├── MGTwitterStatusesParser.m │ ├── MGTwitterUserListsParser.h │ ├── MGTwitterUserListsParser.m │ ├── MGTwitterUsersLibXMLParser.h │ ├── MGTwitterUsersLibXMLParser.m │ ├── MGTwitterUsersParser.h │ ├── MGTwitterUsersParser.m │ ├── MGTwitterXMLParser.h │ ├── MGTwitterXMLParser.m │ ├── NSData+Base64.h │ ├── NSData+Base64.m │ ├── NSString+UUID.h │ └── NSString+UUID.m ├── TwitterFeed │ ├── Tweet.h │ ├── Tweet.m │ ├── TwitterFeed.h │ ├── TwitterFeed.m │ ├── TwitterFeedCell.h │ └── TwitterFeedCell.m └── oauthconsumer │ ├── Categories │ ├── NSMutableURLRequest+Parameters.h │ ├── NSMutableURLRequest+Parameters.m │ ├── NSString+URLEncoding.h │ ├── NSString+URLEncoding.m │ ├── NSURL+Base.h │ └── NSURL+Base.m │ ├── Crypto │ ├── Base64Transcoder.c │ ├── Base64Transcoder.h │ ├── hmac.c │ ├── hmac.h │ ├── sha1.c │ └── sha1.h │ ├── OACall.h │ ├── OACall.m │ ├── OAConsumer.h │ ├── OAConsumer.m │ ├── OADataFetcher.h │ ├── OADataFetcher.m │ ├── OAHMAC_SHA1SignatureProvider.h │ ├── OAHMAC_SHA1SignatureProvider.m │ ├── OAMutableURLRequest.h │ ├── OAMutableURLRequest.m │ ├── OAPlaintextSignatureProvider.h │ ├── OAPlaintextSignatureProvider.m │ ├── OAProblem.h │ ├── OAProblem.m │ ├── OARequestParameter.h │ ├── OARequestParameter.m │ ├── OAServiceTicket.h │ ├── OAServiceTicket.m │ ├── OASignatureProviding.h │ ├── OAToken.h │ ├── OAToken.m │ ├── OATokenManager.h │ ├── OATokenManager.m │ └── OAuthConsumer.h ├── MainWindow.xib ├── README.txt ├── TwitterFeed-Info.plist ├── TwitterFeed.xcodeproj ├── maxbaeumle.mode1v3 ├── maxbaeumle.pbxuser └── project.pbxproj ├── TwitterFeed_Prefix.pch └── main.m /Classes/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Created by http://github.com/iosdeveloper 4 | // 5 | 6 | #import 7 | 8 | @interface AppDelegate : NSObject { 9 | UIWindow *window; 10 | } 11 | 12 | @property (nonatomic, retain) IBOutlet UIWindow *window; 13 | 14 | @end -------------------------------------------------------------------------------- /Classes/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Created by http://github.com/iosdeveloper 4 | // 5 | 6 | #import "AppDelegate.h" 7 | #import "TwitterFeed.h" 8 | 9 | @implementation AppDelegate 10 | 11 | @synthesize window; 12 | 13 | #pragma mark - 14 | #pragma mark Application lifecycle 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 17 | [[self window] setRootViewController: 18 | [[[UINavigationController alloc] initWithRootViewController: 19 | [[[TwitterFeed alloc] initWithUsername:@"twitter"] autorelease]] autorelease]]; 20 | [[self window] makeKeyAndVisible]; 21 | 22 | return YES; 23 | } 24 | 25 | #pragma mark - 26 | #pragma mark Memory management 27 | 28 | - (void)dealloc { 29 | [window release]; 30 | [super dealloc]; 31 | } 32 | 33 | @end -------------------------------------------------------------------------------- /Classes/DetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DetailViewController.h 3 | // Created by http://github.com/iosdeveloper 4 | // 5 | 6 | #import 7 | 8 | @interface DetailViewController : UIViewController { 9 | NSString *text; 10 | } 11 | 12 | @property (retain) NSString *text; 13 | 14 | @end -------------------------------------------------------------------------------- /Classes/DetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DetailViewController.m 3 | // Created by http://github.com/iosdeveloper 4 | // 5 | 6 | #import "DetailViewController.h" 7 | 8 | @implementation DetailViewController 9 | 10 | @synthesize text; 11 | 12 | - (void)viewDidLoad { 13 | [super viewDidLoad]; 14 | 15 | UITextView *textView = [[UITextView alloc] initWithFrame:[[self view] frame]]; 16 | [textView setText:text]; 17 | [textView setEditable:NO]; 18 | [textView setDataDetectorTypes:UIDataDetectorTypeAll]; 19 | 20 | [[self view] addSubview:textView]; 21 | 22 | [textView release]; 23 | } 24 | 25 | - (void)dealloc { 26 | [text release]; 27 | [super dealloc]; 28 | } 29 | 30 | @end -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterEngine.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterEngine.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 10/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | #import "MGTwitterEngineDelegate.h" 12 | #import "MGTwitterParserDelegate.h" 13 | 14 | #import "OAToken.h" 15 | 16 | 17 | @interface MGTwitterEngine : NSObject 18 | { 19 | __weak NSObject *_delegate; 20 | NSMutableDictionary *_connections; // MGTwitterHTTPURLConnection objects 21 | NSString *_clientName; 22 | NSString *_clientVersion; 23 | NSString *_clientURL; 24 | NSString *_clientSourceToken; 25 | NSString *_APIDomain; 26 | #if YAJL_AVAILABLE || TOUCHJSON_AVAILABLE 27 | NSString *_searchDomain; 28 | #endif 29 | BOOL _secureConnection; 30 | BOOL _clearsCookies; 31 | #if YAJL_AVAILABLE || TOUCHJSON_AVAILABLE 32 | MGTwitterEngineDeliveryOptions _deliveryOptions; 33 | #endif 34 | 35 | // OAuth 36 | NSString *_consumerKey; 37 | NSString *_consumerSecret; 38 | OAToken *_accessToken; 39 | 40 | // basic auth - deprecated 41 | NSString *_username; 42 | NSString *_password; 43 | } 44 | 45 | #pragma mark Class management 46 | 47 | // Constructors 48 | + (MGTwitterEngine *)twitterEngineWithDelegate:(NSObject *)delegate; 49 | - (MGTwitterEngine *)initWithDelegate:(NSObject *)delegate; 50 | 51 | // Configuration and Accessors 52 | + (NSString *)version; // returns the version of MGTwitterEngine 53 | - (NSString *)clientName; // see README.txt for info on clientName/Version/URL/SourceToken 54 | - (NSString *)clientVersion; 55 | - (NSString *)clientURL; 56 | - (NSString *)clientSourceToken; 57 | - (void)setClientName:(NSString *)name version:(NSString *)version URL:(NSString *)url token:(NSString *)token; 58 | - (NSString *)APIDomain; 59 | - (void)setAPIDomain:(NSString *)domain; 60 | #if YAJL_AVAILABLE || TOUCHJSON_AVAILABLE 61 | - (NSString *)searchDomain; 62 | - (void)setSearchDomain:(NSString *)domain; 63 | #endif 64 | - (BOOL)usesSecureConnection; // YES = uses HTTPS, default is YES 65 | - (void)setUsesSecureConnection:(BOOL)flag; 66 | - (BOOL)clearsCookies; // YES = deletes twitter.com cookies when setting username/password, default is NO (see README.txt) 67 | - (void)setClearsCookies:(BOOL)flag; 68 | #if YAJL_AVAILABLE || TOUCHJSON_AVAILABLE 69 | - (MGTwitterEngineDeliveryOptions)deliveryOptions; 70 | - (void)setDeliveryOptions:(MGTwitterEngineDeliveryOptions)deliveryOptions; 71 | #endif 72 | 73 | // Connection methods 74 | - (NSUInteger)numberOfConnections; 75 | - (NSArray *)connectionIdentifiers; 76 | - (void)closeConnection:(NSString *)identifier; 77 | - (void)closeAllConnections; 78 | 79 | // Utility methods 80 | /// Note: the -getImageAtURL: method works for any image URL, not just Twitter images. 81 | // It does not require authentication, and is provided here for convenience. 82 | // As with the Twitter API methods below, it returns a unique connection identifier. 83 | // Retrieved images are sent to the delegate via the -imageReceived:forRequest: method. 84 | - (NSString *)getImageAtURL:(NSString *)urlString; 85 | 86 | #pragma mark REST API methods 87 | 88 | // ====================================================================================================== 89 | // Twitter REST API methods 90 | // See documentation at: http://apiwiki.twitter.com/Twitter-API-Documentation 91 | // All methods below return a unique connection identifier. 92 | // ====================================================================================================== 93 | 94 | // Status methods 95 | 96 | - (NSString *)getPublicTimeline; // statuses/public_timeline 97 | 98 | - (NSString *)getHomeTimelineSinceID:(MGTwitterEngineID)sinceID startingAtPage:(int)pageNum count:(int)count; // statuses/home_timeline 99 | - (NSString *)getHomeTimelineSinceID:(MGTwitterEngineID)sinceID withMaximumID:(MGTwitterEngineID)maxID startingAtPage:(int)pageNum count:(int)count; // statuses/home_timeline 100 | 101 | - (NSString *)getFollowedTimelineSinceID:(MGTwitterEngineID)sinceID startingAtPage:(int)pageNum count:(int)count; // statuses/friends_timeline 102 | - (NSString *)getFollowedTimelineSinceID:(MGTwitterEngineID)sinceID withMaximumID:(MGTwitterEngineID)maxID startingAtPage:(int)pageNum count:(int)count; // statuses/friends_timeline 103 | 104 | - (NSString *)getUserTimelineFor:(NSString *)username sinceID:(MGTwitterEngineID)sinceID startingAtPage:(int)pageNum count:(int)count; // statuses/user_timeline & statuses/user_timeline/user 105 | - (NSString *)getUserTimelineFor:(NSString *)username sinceID:(MGTwitterEngineID)sinceID withMaximumID:(MGTwitterEngineID)maxID startingAtPage:(int)pageNum count:(int)count; // statuses/user_timeline & statuses/user_timeline/user 106 | 107 | - (NSString *)getUpdate:(MGTwitterEngineID)updateID; // statuses/show 108 | - (NSString *)sendUpdate:(NSString *)status; // statuses/update 109 | 110 | - (NSString *)sendUpdate:(NSString *)status withLatitude:(MGTwitterEngineLocationDegrees)latitude longitude:(MGTwitterEngineLocationDegrees)longitude; // statuses/update 111 | - (NSString *)sendUpdate:(NSString *)status inReplyTo:(MGTwitterEngineID)updateID; // statuses/update 112 | - (NSString *)sendUpdate:(NSString *)status inReplyTo:(MGTwitterEngineID)updateID withLatitude:(MGTwitterEngineLocationDegrees)latitude longitude:(MGTwitterEngineLocationDegrees)longitude; // statuses/update 113 | - (NSString *)sendRetweet:(MGTwitterEngineID)tweetID; // statuses/retweet 114 | 115 | - (NSString *)getRepliesStartingAtPage:(int)pageNum; // statuses/mentions 116 | - (NSString *)getRepliesSinceID:(MGTwitterEngineID)sinceID startingAtPage:(int)pageNum count:(int)count; // statuses/mentions 117 | - (NSString *)getRepliesSinceID:(MGTwitterEngineID)sinceID withMaximumID:(MGTwitterEngineID)maxID startingAtPage:(int)pageNum count:(int)count; // statuses/mentions 118 | 119 | - (NSString *)deleteUpdate:(MGTwitterEngineID)updateID; // statuses/destroy 120 | 121 | - (NSString *)getFeaturedUsers; // statuses/features (undocumented, returns invalid JSON data) 122 | 123 | 124 | // User methods 125 | 126 | - (NSString *)getRecentlyUpdatedFriendsFor:(NSString *)username startingAtPage:(int)pageNum; // statuses/friends & statuses/friends/user 127 | 128 | - (NSString *)getFollowersIncludingCurrentStatus:(BOOL)flag; // statuses/followers 129 | 130 | - (NSString *)getUserInformationFor:(NSString *)usernameOrID; // users/show 131 | - (NSString *)getBulkUserInformationFor:(NSString *)userIDs; 132 | 133 | - (NSString *)getUserInformationForEmail:(NSString *)email; // users/show 134 | 135 | // List Methods 136 | 137 | // List the lists of the specified user. Private lists will be included if the 138 | // authenticated users is the same as the user who's lists are being returned. 139 | - (NSString *)getListsForUser:(NSString *)username; 140 | 141 | // Creates a new list for the authenticated user. Accounts are limited to 20 lists. 142 | // Options include: 143 | // mode - Whether your list is public or private. Values can be public or private. 144 | // If no mode is specified the list will be public. 145 | // description - The description to give the list. 146 | - (NSString *)createListForUser:(NSString *)username withName:(NSString *)listName withOptions:(NSDictionary *)options; 147 | 148 | // update an existing list 149 | - (NSString *)updateListForUser:(NSString *)username withID:(MGTwitterEngineID)listID withOptions:(NSDictionary *)options; 150 | 151 | // Show the specified list. Private lists will only be shown if the authenticated user owns the specified list. 152 | - (NSString *)getListForUser:(NSString *)username withID:(MGTwitterEngineID)listID; 153 | 154 | // Direct Message methods 155 | 156 | - (NSString *)getDirectMessagesSinceID:(MGTwitterEngineID)sinceID startingAtPage:(int)pageNum; // direct_messages 157 | - (NSString *)getDirectMessagesSinceID:(MGTwitterEngineID)sinceID withMaximumID:(MGTwitterEngineID)maxID startingAtPage:(int)pageNum count:(int)count; // direct_messages 158 | 159 | - (NSString *)getSentDirectMessagesSinceID:(MGTwitterEngineID)sinceID startingAtPage:(int)pageNum; // direct_messages/sent 160 | - (NSString *)getSentDirectMessagesSinceID:(MGTwitterEngineID)sinceID withMaximumID:(MGTwitterEngineID)maxID startingAtPage:(int)pageNum count:(int)count; // direct_messages/sent 161 | 162 | - (NSString *)sendDirectMessage:(NSString *)message to:(NSString *)username; // direct_messages/new 163 | - (NSString *)deleteDirectMessage:(MGTwitterEngineID)updateID;// direct_messages/destroy 164 | 165 | 166 | // Friendship methods 167 | 168 | - (NSString *)enableUpdatesFor:(NSString *)username; // friendships/create (follow username) 169 | - (NSString *)disableUpdatesFor:(NSString *)username; // friendships/destroy (unfollow username) 170 | - (NSString *)isUser:(NSString *)username1 receivingUpdatesFor:(NSString *)username2; // friendships/exists (test if username1 follows username2) 171 | 172 | 173 | // Account methods 174 | 175 | - (NSString *)checkUserCredentials; // account/verify_credentials 176 | - (NSString *)endUserSession; // account/end_session 177 | 178 | - (NSString *)setLocation:(NSString *)location; // account/update_location (deprecated, use account/update_profile instead) 179 | 180 | - (NSString *)setNotificationsDeliveryMethod:(NSString *)method; // account/update_delivery_device 181 | 182 | // TODO: Add: account/update_profile_colors 183 | - (NSString *)setProfileImageWithImageAtPath:(NSString *)pathToFile; 184 | - (NSString *)setProfileBackgroundImageWithImageAtPath:(NSString *)pathToFile andTitle:(NSString *)title; 185 | 186 | - (NSString *)getRateLimitStatus; // account/rate_limit_status 187 | 188 | // TODO: Add: account/update_profile 189 | 190 | // - (NSString *)getUserUpdatesArchiveStartingAtPage:(int)pageNum; // account/archive (removed, use /statuses/user_timeline instead) 191 | 192 | 193 | // Favorite methods 194 | 195 | - (NSString *)getFavoriteUpdatesFor:(NSString *)username startingAtPage:(int)pageNum; // favorites 196 | 197 | - (NSString *)markUpdate:(MGTwitterEngineID)updateID asFavorite:(BOOL)flag; // favorites/create, favorites/destroy 198 | 199 | 200 | // Notification methods 201 | 202 | - (NSString *)enableNotificationsFor:(NSString *)username; // notifications/follow 203 | - (NSString *)disableNotificationsFor:(NSString *)username; // notifications/leave 204 | 205 | 206 | // Block methods 207 | 208 | - (NSString *)block:(NSString *)username; // blocks/create 209 | - (NSString *)unblock:(NSString *)username; // blocks/destroy 210 | 211 | 212 | // Help methods 213 | 214 | - (NSString *)testService; // help/test 215 | 216 | - (NSString *)getDowntimeSchedule; // help/downtime_schedule (undocumented) 217 | 218 | 219 | // Social Graph methods 220 | - (NSString *)getFriendIDsFor:(NSString *)username startingFromCursor:(MGTwitterEngineCursorID)cursor; // friends/ids 221 | - (NSString *)getFollowerIDsFor:(NSString *)username startingFromCursor:(MGTwitterEngineCursorID)cursor; // followers/ids 222 | 223 | 224 | #pragma mark Search API methods 225 | 226 | // ====================================================================================================== 227 | // Twitter Search API methods 228 | // See documentation at: http://apiwiki.twitter.com/Twitter-API-Documentation 229 | // All methods below return a unique connection identifier. 230 | // ====================================================================================================== 231 | 232 | #if YAJL_AVAILABLE || TOUCHJSON_AVAILABLE 233 | 234 | // Search method 235 | 236 | - (NSString *)getSearchResultsForQuery:(NSString *)query; 237 | - (NSString *)getSearchResultsForQuery:(NSString *)query sinceID:(MGTwitterEngineID)sinceID startingAtPage:(int)pageNum count:(int)count; // search 238 | - (NSString *)getSearchResultsForQuery:(NSString *)query sinceID:(MGTwitterEngineID)sinceID startingAtPage:(int)pageNum count:(int)count geocode:(NSString *)geocode; 239 | 240 | // Trends method 241 | 242 | - (NSString *)getCurrentTrends; // current trends 243 | 244 | #endif 245 | 246 | @end 247 | 248 | @interface MGTwitterEngine (BasicAuth) 249 | 250 | - (NSString *)username; 251 | - (void)setUsername:(NSString *) newUsername; 252 | 253 | - (NSString *)password DEPRECATED_ATTRIBUTE; 254 | - (void)setUsername:(NSString *)username password:(NSString *)password DEPRECATED_ATTRIBUTE; 255 | 256 | @end 257 | 258 | @interface MGTwitterEngine (OAuth) 259 | 260 | - (void)setConsumerKey:(NSString *)key secret:(NSString *)secret; 261 | - (NSString *)consumerKey; 262 | - (NSString *)consumerSecret; 263 | 264 | - (void)setAccessToken: (OAToken *)token; 265 | - (OAToken *)accessToken; 266 | 267 | // XAuth login - NOTE: You MUST email Twitter with your application's OAuth key/secret to 268 | // get OAuth access. This will not work if you don't do this. 269 | - (NSString *)getXAuthAccessTokenForUsername:(NSString *)username 270 | password:(NSString *)password; 271 | 272 | @end 273 | 274 | 275 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterEngineDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterEngineDelegate.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 16/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | @class OAToken; 11 | 12 | typedef enum _MGTwitterEngineDeliveryOptions { 13 | // all results will be delivered as an array via statusesReceived: and similar delegate methods 14 | MGTwitterEngineDeliveryAllResultsOption = 1 << 0, 15 | 16 | // individual results will be delivered as a dictionary via the receivedObject: delegate method 17 | MGTwitterEngineDeliveryIndividualResultsOption = 1 << 1, 18 | 19 | // these options can be combined with the | operator 20 | } MGTwitterEngineDeliveryOptions; 21 | 22 | 23 | 24 | @protocol MGTwitterEngineDelegate 25 | 26 | // These delegate methods are called after a connection has been established 27 | - (void)requestSucceeded:(NSString *)connectionIdentifier; 28 | - (void)requestFailed:(NSString *)connectionIdentifier withError:(NSError *)error; 29 | 30 | @optional 31 | 32 | #if YAJL_AVAILABLE || TOUCHJSON_AVAILABLE 33 | // This delegate method is called each time a new result is parsed from the connection and 34 | // the deliveryOption is configured for MGTwitterEngineDeliveryIndividualResults. 35 | - (void)receivedObject:(NSDictionary *)dictionary forRequest:(NSString *)connectionIdentifier; 36 | #endif 37 | 38 | // These delegate methods are called after all results are parsed from the connection. If 39 | // the deliveryOption is configured for MGTwitterEngineDeliveryAllResults (the default), a 40 | // collection of all results is also returned. 41 | - (void)statusesReceived:(NSArray *)statuses forRequest:(NSString *)connectionIdentifier; 42 | - (void)directMessagesReceived:(NSArray *)messages forRequest:(NSString *)connectionIdentifier; 43 | - (void)userInfoReceived:(NSArray *)userInfo forRequest:(NSString *)connectionIdentifier; 44 | - (void)userListsReceived:(NSArray *)userInfo forRequest:(NSString *)connectionIdentifier; 45 | - (void)miscInfoReceived:(NSArray *)miscInfo forRequest:(NSString *)connectionIdentifier; 46 | #if YAJL_AVAILABLE || TOUCHJSON_AVAILABLE 47 | - (void)searchResultsReceived:(NSArray *)searchResults forRequest:(NSString *)connectionIdentifier; 48 | #endif 49 | - (void)socialGraphInfoReceived:(NSArray *)socialGraphInfo forRequest:(NSString *)connectionIdentifier; 50 | - (void)accessTokenReceived:(OAToken *)token forRequest:(NSString *)connectionIdentifier; 51 | 52 | #if TARGET_OS_IPHONE 53 | - (void)imageReceived:(UIImage *)image forRequest:(NSString *)connectionIdentifier; 54 | #else 55 | - (void)imageReceived:(NSImage *)image forRequest:(NSString *)connectionIdentifier; 56 | #endif 57 | 58 | // This delegate method is called whenever a connection has finished. 59 | - (void)connectionStarted:(NSString *)connectionIdentifier; 60 | - (void)connectionFinished:(NSString *)connectionIdentifier; 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterEngineGlobalHeader.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterEngineGlobalHeader.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 09/08/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | /* 10 | This file conditionally includes the correct headers for either Mac OS X or iPhone deployment. 11 | */ 12 | 13 | #if TARGET_OS_IPHONE 14 | #import 15 | #import 16 | #else 17 | #import 18 | #endif 19 | 20 | /* 21 | Set YAJL_AVAILABLE to 1 if the YAJL JSON parser is available and you'd like MGTwitterEngine to use it. 22 | 23 | More information about this parser here: 24 | 25 | http://lloydforge.org/projects/yajl/ 26 | 27 | There are some speed advantages to using JSON instead of XML. Also, the Twitter Search API 28 | uses JSON, so adding this library to your project makes additional methods available to your 29 | application. 30 | 31 | Be aware, however, that the data types in the dictionaries returned by JSON may be different 32 | than the ones returned by XML. There is more type information in a JSON stream, so you may find 33 | that you get an NSNumber value instead of an NSString value for some keys in the dictionary. 34 | Make sure to test the new result sets in your application after switching from XML to JSON. 35 | 36 | Likewise, some keys may differ between the XML and JSON parsers. An example is the hourly limit 37 | returned by the getRateLimitStatus: method. For JSON, the key is "hourly_limit", for XML it is 38 | "hourly-limit". 39 | 40 | The event driven nature of the YAJL parser also allows delivery options to be specified. By 41 | default, all results are returned as an array of dictionaries. In some environments, such as the 42 | iPhone, the memory overhead of putting all the data into the array can be avoided by choosing 43 | the individual results option. This allows your application to process and store results without 44 | instantatiating a large collection and then enumerating over the items. 45 | 46 | If you want to use YAJL, change the following definition and make sure that the 47 | MGTwitterEngine*YAJLParser.m files are added to the Compile Sources phase of the MGTwitterEngine 48 | target. 49 | */ 50 | 51 | #define YAJL_AVAILABLE 0 52 | #define TOUCHJSON_AVAILABLE 0 53 | 54 | #ifndef __MGTWITTERENGINEID__ 55 | #define __MGTWITTERENGINEID__ 56 | typedef unsigned long long MGTwitterEngineID; 57 | typedef long long MGTwitterEngineCursorID; 58 | #endif 59 | 60 | #ifndef __MGTWITTERENGINELOCATIONDEGREES__ 61 | #define __MGTWITTERENGINELOCATIONDEGREES__ 62 | typedef double MGTwitterEngineLocationDegrees; 63 | #endif 64 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterHTTPURLConnection.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterHTTPURLConnection.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 16/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | #import "MGTwitterRequestTypes.h" 12 | 13 | 14 | @interface MGTwitterHTTPURLConnection : NSURLConnection 15 | { 16 | NSMutableData *_data; // accumulated data received on this connection 17 | MGTwitterRequestType _requestType; // general type of this request, mostly for error handling 18 | MGTwitterResponseType _responseType; // type of response data expected (if successful) 19 | NSString *_identifier; 20 | NSURL *_URL; // the URL used for the connection (needed as a base URL when parsing with libxml) 21 | NSHTTPURLResponse * _response; // the response. 22 | } 23 | 24 | // Initializer 25 | - (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate 26 | requestType:(MGTwitterRequestType)requestType responseType:(MGTwitterResponseType)responseType; 27 | 28 | // Data helper methods 29 | - (void)resetDataLength; 30 | - (void)appendData:(NSData *)data; 31 | 32 | // Accessors 33 | - (NSString *)identifier; 34 | - (NSData *)data; 35 | - (NSURL *)URL; 36 | - (MGTwitterRequestType)requestType; 37 | - (MGTwitterResponseType)responseType; 38 | - (NSString *)description; 39 | 40 | @property (nonatomic, retain) NSHTTPURLResponse *response; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterHTTPURLConnection.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterHTTPURLConnection.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 16/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterHTTPURLConnection.h" 10 | #import "NSString+UUID.h" 11 | 12 | 13 | 14 | @interface NSURLRequest (OAuthExtensions) 15 | -(void)prepare; 16 | @end 17 | 18 | @implementation NSURLRequest (OAuthExtensions) 19 | 20 | -(void)prepare{ 21 | // do nothing 22 | } 23 | 24 | @end 25 | 26 | 27 | 28 | @implementation MGTwitterHTTPURLConnection 29 | 30 | 31 | @synthesize response = _response; 32 | 33 | #pragma mark Initializer 34 | 35 | 36 | - (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate 37 | requestType:(MGTwitterRequestType)requestType responseType:(MGTwitterResponseType)responseType 38 | { 39 | // OAuth requests need to have -prepare called on them first. handle that case before the NSURLConnection sends it 40 | [request prepare]; 41 | 42 | if ((self = [super initWithRequest:request delegate:delegate])) { 43 | _data = [[NSMutableData alloc] initWithCapacity:0]; 44 | _identifier = [[NSString stringWithNewUUID] retain]; 45 | _requestType = requestType; 46 | _responseType = responseType; 47 | _URL = [[request URL] retain]; 48 | } 49 | 50 | return self; 51 | } 52 | 53 | 54 | - (void)dealloc 55 | { 56 | [_response release]; 57 | [_data release]; 58 | [_identifier release]; 59 | [_URL release]; 60 | [super dealloc]; 61 | } 62 | 63 | 64 | #pragma mark Data helper methods 65 | 66 | 67 | - (void)resetDataLength 68 | { 69 | [_data setLength:0]; 70 | } 71 | 72 | 73 | - (void)appendData:(NSData *)data 74 | { 75 | [_data appendData:data]; 76 | } 77 | 78 | 79 | #pragma mark Accessors 80 | 81 | 82 | - (NSString *)identifier 83 | { 84 | return [[_identifier retain] autorelease]; 85 | } 86 | 87 | 88 | - (NSData *)data 89 | { 90 | return [[_data retain] autorelease]; 91 | } 92 | 93 | 94 | - (NSURL *)URL 95 | { 96 | return [[_URL retain] autorelease]; 97 | } 98 | 99 | 100 | - (MGTwitterRequestType)requestType 101 | { 102 | return _requestType; 103 | } 104 | 105 | 106 | - (MGTwitterResponseType)responseType 107 | { 108 | return _responseType; 109 | } 110 | 111 | 112 | - (NSString *)description 113 | { 114 | NSString *description = [super description]; 115 | 116 | return [description stringByAppendingFormat:@" (requestType = %d, identifier = %@)", _requestType, _identifier]; 117 | } 118 | 119 | @end 120 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterLibXMLParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterLibXMLParser.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 18/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | #include 11 | 12 | #import "MGTwitterParserDelegate.h" 13 | 14 | @interface MGTwitterLibXMLParser : NSObject { 15 | __weak NSObject *delegate; // weak ref 16 | NSString *identifier; 17 | MGTwitterRequestType requestType; 18 | MGTwitterResponseType responseType; 19 | NSURL *URL; 20 | NSData *xml; 21 | NSMutableArray *parsedObjects; 22 | 23 | xmlTextReaderPtr _reader; 24 | } 25 | 26 | + (id)parserWithXML:(NSData *)theXML delegate:(NSObject *)theDelegate 27 | connectionIdentifier:(NSString *)identifier requestType:(MGTwitterRequestType)reqType 28 | responseType:(MGTwitterResponseType)respType URL:(NSURL *)URL; 29 | - (id)initWithXML:(NSData *)theXML delegate:(NSObject *)theDelegate 30 | connectionIdentifier:(NSString *)identifier requestType:(MGTwitterRequestType)reqType 31 | responseType:(MGTwitterResponseType)respType URL:(NSURL *)URL; 32 | 33 | - (void)parse; 34 | 35 | // subclass utilities 36 | - (xmlChar *)_nodeValue; 37 | - (NSString *)_nodeValueAsString; 38 | - (NSDate *)_nodeValueAsDate; 39 | - (NSNumber *)_nodeValueAsInt; 40 | - (NSNumber *)_nodeValueAsBool; 41 | - (NSDictionary *)_statusDictionaryForNodeWithName:(const xmlChar *)parentNodeName; 42 | - (NSDictionary *)_userDictionaryForNodeWithName:(const xmlChar *)parentNodeName; 43 | - (NSDictionary *)_hashDictionaryForNodeWithName:(const xmlChar *)parentNodeName; 44 | 45 | // delegate callbacks 46 | - (void)_parsingDidEnd; 47 | - (void)_parsingErrorOccurred:(NSError *)parseError; 48 | 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterLibXMLParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterLibXMLParser.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 18/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | // Major portions derived from BSTweetParser by Brent Simmons 9 | // 10 | 11 | #import "MGTwitterLibXMLParser.h" 12 | 13 | 14 | @implementation MGTwitterLibXMLParser 15 | 16 | 17 | #pragma mark Creation and Destruction 18 | 19 | 20 | + (id)parserWithXML:(NSData *)theXML delegate:(NSObject *)theDelegate 21 | connectionIdentifier:(NSString *)identifier requestType:(MGTwitterRequestType)reqType 22 | responseType:(MGTwitterResponseType)respType URL:(NSURL *)URL 23 | { 24 | id parser = [[self alloc] initWithXML:theXML 25 | delegate:theDelegate 26 | connectionIdentifier:identifier 27 | requestType:reqType 28 | responseType:respType 29 | URL:URL]; 30 | 31 | return [parser autorelease]; 32 | } 33 | 34 | 35 | - (id)initWithXML:(NSData *)theXML delegate:(NSObject *)theDelegate 36 | connectionIdentifier:(NSString *)theIdentifier requestType:(MGTwitterRequestType)reqType 37 | responseType:(MGTwitterResponseType)respType URL:(NSURL *)theURL 38 | { 39 | if ((self = [super init])) 40 | { 41 | xml = [theXML retain]; 42 | identifier = [theIdentifier retain]; 43 | requestType = reqType; 44 | responseType = respType; 45 | URL = [theURL retain]; 46 | delegate = theDelegate; 47 | parsedObjects = [[NSMutableArray alloc] initWithCapacity:0]; 48 | 49 | // setup the xml reader 50 | _reader = xmlReaderForMemory([xml bytes], (int)[xml length], [[URL absoluteString] UTF8String], nil, XML_PARSE_NOBLANKS | XML_PARSE_NOCDATA | XML_PARSE_NOERROR | XML_PARSE_NOWARNING); 51 | if (! _reader) 52 | { 53 | return nil; 54 | } 55 | 56 | // run the parser and create parsedObjects 57 | [self parse]; 58 | 59 | // free the xml reader used for parsing 60 | xmlFree(_reader); 61 | 62 | // notify the delegate that parsing completed 63 | [self _parsingDidEnd]; 64 | } 65 | 66 | return self; 67 | } 68 | 69 | 70 | - (void)dealloc 71 | { 72 | [parsedObjects release]; 73 | [xml release]; 74 | [identifier release]; 75 | [URL release]; 76 | 77 | delegate = nil; 78 | [super dealloc]; 79 | } 80 | 81 | - (void)parse 82 | { 83 | // empty implementation -- override in subclasses 84 | } 85 | 86 | #pragma mark Subclass utilities 87 | 88 | // get the value from the current node 89 | - (xmlChar *)_nodeValue 90 | { 91 | if (xmlTextReaderIsEmptyElement(_reader)) 92 | { 93 | return nil; 94 | } 95 | 96 | xmlChar *result = nil; 97 | int nodeType = xmlTextReaderNodeType(_reader); 98 | while (nodeType != XML_READER_TYPE_END_ELEMENT) 99 | { 100 | if (nodeType == XML_READER_TYPE_TEXT) 101 | { 102 | result = xmlTextReaderValue(_reader); 103 | } 104 | 105 | // advance reader 106 | int readerResult = xmlTextReaderRead(_reader); 107 | if (readerResult != 1) 108 | { 109 | break; 110 | } 111 | nodeType = xmlTextReaderNodeType(_reader); 112 | } 113 | 114 | //NSLog(@"node: %25s = %s", xmlTextReaderConstName(_reader), result); 115 | 116 | return result; 117 | } 118 | 119 | - (NSString *)_nodeValueAsString 120 | { 121 | xmlChar *nodeValue = [self _nodeValue]; 122 | if (! nodeValue) 123 | { 124 | return nil; 125 | } 126 | 127 | NSMutableString *value = [NSMutableString stringWithUTF8String:(const char *)nodeValue]; 128 | xmlFree(nodeValue); 129 | 130 | // convert HTML entities back into UTF-8 131 | [value replaceOccurrencesOfString:@">" withString:@">" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [value length])]; 132 | [value replaceOccurrencesOfString:@"<" withString:@"<" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [value length])]; 133 | 134 | NSString *result = [NSString stringWithString:value]; 135 | return result; 136 | } 137 | 138 | - (NSDate *)_nodeValueAsDate 139 | { 140 | xmlChar *nodeValue = [self _nodeValue]; 141 | if (! nodeValue) 142 | { 143 | return nil; 144 | } 145 | 146 | struct tm theTime; 147 | strptime((char *)nodeValue, "%a %b %d %H:%M:%S +0000 %Y", &theTime); 148 | xmlFree(nodeValue); 149 | time_t epochTime = timegm(&theTime); 150 | return [NSDate dateWithTimeIntervalSince1970:epochTime]; 151 | } 152 | 153 | - (NSNumber *)_nodeValueAsInt 154 | { 155 | xmlChar *nodeValue = [self _nodeValue]; 156 | if (! nodeValue) 157 | { 158 | return nil; 159 | } 160 | 161 | NSString *intString = [NSString stringWithUTF8String:(const char *)nodeValue]; 162 | xmlFree(nodeValue); 163 | return [NSNumber numberWithLongLong:[intString longLongValue]]; 164 | } 165 | 166 | - (NSNumber *)_nodeValueAsBool 167 | { 168 | xmlChar *nodeValue = [self _nodeValue]; 169 | if (! nodeValue) 170 | { 171 | return nil; 172 | } 173 | 174 | NSString *boolString = [NSString stringWithUTF8String:(const char *)nodeValue]; 175 | xmlFree(nodeValue); 176 | return [NSNumber numberWithBool:[boolString isEqualToString:@"true"]]; 177 | } 178 | 179 | - (NSDictionary *)_statusDictionaryForNodeWithName:(const xmlChar *)parentNodeName 180 | { 181 | if (xmlTextReaderIsEmptyElement(_reader)) 182 | return nil; 183 | NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; 184 | 185 | int readerResult = xmlTextReaderRead(_reader); 186 | if (readerResult != 1) 187 | return nil; 188 | int nodeType = xmlTextReaderNodeType(_reader); 189 | const xmlChar *name = xmlTextReaderConstName(_reader); 190 | while (! (nodeType == XML_READER_TYPE_END_ELEMENT && xmlStrEqual(parentNodeName, name))) 191 | { 192 | if (nodeType == XML_READER_TYPE_ELEMENT) 193 | { 194 | if (xmlStrEqual(name, BAD_CAST "user")) 195 | { 196 | // "user" is the name of a sub-dictionary in each item 197 | [dictionary setObject:[self _userDictionaryForNodeWithName:name] forKey:@"user"]; 198 | } 199 | else if (xmlStrEqual(name, BAD_CAST "id") || xmlStrEqual(name, BAD_CAST "in_reply_to_user_id") || xmlStrEqual(name, BAD_CAST "in_reply_to_status_id")) 200 | { 201 | // process element as an integer 202 | NSNumber *number = [self _nodeValueAsInt]; 203 | if (number) 204 | { 205 | [dictionary setObject:number forKey:[NSString stringWithUTF8String:(const char *)name]]; 206 | } 207 | } 208 | else if (xmlStrEqual(name, BAD_CAST "created_at")) 209 | { 210 | // process element as a date 211 | NSDate *date = [self _nodeValueAsDate]; 212 | if (date) 213 | { 214 | [dictionary setObject:date forKey:[NSString stringWithUTF8String:(const char *)name]]; 215 | } 216 | } 217 | else if (xmlStrEqual(name, BAD_CAST "truncated") || xmlStrEqual(name, BAD_CAST "favorited")) 218 | { 219 | // process element as a boolean 220 | NSNumber *number = [self _nodeValueAsBool]; 221 | if (number) 222 | { 223 | [dictionary setObject:number forKey:[NSString stringWithUTF8String:(const char *)name]]; 224 | } 225 | } 226 | else if (xmlStrEqual(name, BAD_CAST "retweeted_status")) 227 | { 228 | [dictionary setObject:[self _statusDictionaryForNodeWithName:name] forKey:[NSString stringWithUTF8String:(const char *)name]]; 229 | } 230 | else 231 | { 232 | // process element as a string 233 | NSString *string = [self _nodeValueAsString]; 234 | if (string) 235 | { 236 | [dictionary setObject:string forKey:[NSString stringWithUTF8String:(const char *)name]]; 237 | } 238 | } 239 | } 240 | 241 | // advance reader 242 | readerResult = xmlTextReaderRead(_reader); 243 | if (readerResult != 1) 244 | break; 245 | nodeType = xmlTextReaderNodeType(_reader); 246 | name = xmlTextReaderConstName(_reader); 247 | } 248 | 249 | // save the request type in the tweet 250 | [dictionary setObject:[NSNumber numberWithInt:requestType] forKey:TWITTER_SOURCE_REQUEST_TYPE]; 251 | 252 | return dictionary; 253 | } 254 | 255 | - (NSDictionary *)_userDictionaryForNodeWithName:(const xmlChar *)parentNodeName 256 | { 257 | if (xmlTextReaderIsEmptyElement(_reader)) 258 | return nil; 259 | NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; 260 | 261 | int readerResult = xmlTextReaderRead(_reader); 262 | if (readerResult != 1) 263 | return nil; 264 | int nodeType = xmlTextReaderNodeType(_reader); 265 | const xmlChar *name = xmlTextReaderConstName(_reader); 266 | while (! (nodeType == XML_READER_TYPE_END_ELEMENT && xmlStrEqual(parentNodeName, name))) 267 | { 268 | if (nodeType == XML_READER_TYPE_ELEMENT) 269 | { 270 | if (xmlStrEqual(name, BAD_CAST "id") || xmlStrEqual(name, BAD_CAST "followers_count") 271 | || xmlStrEqual(name, BAD_CAST "friends_count") || xmlStrEqual(name, BAD_CAST "favourites_count") 272 | || xmlStrEqual(name, BAD_CAST "statuses_count")) 273 | { 274 | // process element as an integer 275 | NSNumber *number = [self _nodeValueAsInt]; 276 | if (number) 277 | { 278 | [dictionary setObject:number forKey:[NSString stringWithUTF8String:(const char *)name]]; 279 | } 280 | } 281 | else if (xmlStrEqual(name, BAD_CAST "protected")) 282 | { 283 | // process element as a boolean 284 | NSNumber *number = [self _nodeValueAsBool]; 285 | if (number) 286 | { 287 | [dictionary setObject:number forKey:[NSString stringWithUTF8String:(const char *)name]]; 288 | } 289 | } 290 | else 291 | { 292 | // process element as a string 293 | NSString *s = [self _nodeValueAsString]; 294 | if (s) 295 | { 296 | [dictionary setObject:s forKey:[NSString stringWithUTF8String:(const char *)name]]; 297 | } 298 | } 299 | } 300 | 301 | // advance reader 302 | readerResult = xmlTextReaderRead(_reader); 303 | if (readerResult != 1) 304 | break; 305 | nodeType = xmlTextReaderNodeType(_reader); 306 | name = xmlTextReaderConstName(_reader); 307 | } 308 | 309 | return dictionary; 310 | } 311 | 312 | - (NSDictionary *)_hashDictionaryForNodeWithName:(const xmlChar *)parentNodeName 313 | { 314 | if (xmlTextReaderIsEmptyElement(_reader)) 315 | return nil; 316 | NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; 317 | 318 | int readerResult = xmlTextReaderRead(_reader); 319 | if (readerResult != 1) 320 | return nil; 321 | int nodeType = xmlTextReaderNodeType(_reader); 322 | const xmlChar *name = xmlTextReaderConstName(_reader); 323 | while (! (nodeType == XML_READER_TYPE_END_ELEMENT && xmlStrEqual(parentNodeName, name))) 324 | { 325 | if (nodeType == XML_READER_TYPE_ELEMENT) 326 | { 327 | if (xmlStrEqual(name, BAD_CAST "hourly-limit") || xmlStrEqual(name, BAD_CAST "remaining-hits") 328 | || xmlStrEqual(name, BAD_CAST "reset-time-in-seconds")) 329 | { 330 | // process element as an integer 331 | NSNumber *number = [self _nodeValueAsInt]; 332 | if (number) 333 | { 334 | [dictionary setObject:number forKey:[NSString stringWithUTF8String:(const char *)name]]; 335 | } 336 | } 337 | else 338 | { 339 | // process element as a string 340 | NSString *s = [self _nodeValueAsString]; 341 | if (s) 342 | { 343 | [dictionary setObject:s forKey:[NSString stringWithUTF8String:(const char *)name]]; 344 | } 345 | } 346 | } 347 | 348 | // advance reader 349 | readerResult = xmlTextReaderRead(_reader); 350 | if (readerResult != 1) 351 | break; 352 | nodeType = xmlTextReaderNodeType(_reader); 353 | name = xmlTextReaderConstName(_reader); 354 | } 355 | 356 | return dictionary; 357 | } 358 | 359 | 360 | #pragma mark Delegate callbacks 361 | 362 | - (void)_parsingDidEnd 363 | { 364 | //NSLog(@"Parsing complete: %@", parsedObjects); 365 | [delegate parsingSucceededForRequest:identifier ofResponseType:responseType withParsedObjects:parsedObjects]; 366 | } 367 | 368 | - (void)_parsingErrorOccurred:(NSError *)parseError 369 | { 370 | //NSLog(@"Parsing error occurred: %@", parseError); 371 | [delegate parsingFailedForRequest:identifier ofResponseType:responseType withError:parseError]; 372 | } 373 | 374 | @end 375 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterMessagesLibXMLParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterMessagesLibXMLParser.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 11/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | #import "MGTwitterLibXMLParser.h" 12 | 13 | @interface MGTwitterMessagesLibXMLParser : MGTwitterLibXMLParser { 14 | 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterMessagesLibXMLParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterMessagesLibXMLParser.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 11/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterMessagesLibXMLParser.h" 10 | 11 | 12 | @implementation MGTwitterMessagesLibXMLParser 13 | 14 | - (NSDictionary *)_directMessageDictionaryForNodeWithName:(const xmlChar *)parentNodeName { 15 | if (xmlTextReaderIsEmptyElement(_reader)) 16 | return nil; 17 | NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; 18 | 19 | int readerResult = xmlTextReaderRead(_reader); 20 | if (readerResult != 1) 21 | return nil; 22 | int nodeType = xmlTextReaderNodeType(_reader); 23 | const xmlChar *name = xmlTextReaderConstName(_reader); 24 | while (! (nodeType == XML_READER_TYPE_END_ELEMENT && xmlStrEqual(parentNodeName, name))) 25 | { 26 | if (nodeType == XML_READER_TYPE_ELEMENT) 27 | { 28 | if (xmlStrEqual(name, BAD_CAST "sender") || xmlStrEqual(name, BAD_CAST "recipient")) 29 | { 30 | // "user" is the name of a sub-dictionary in each item 31 | [dictionary setObject:[self _userDictionaryForNodeWithName:name] forKey:[NSString stringWithUTF8String:(const char *)name]]; 32 | } 33 | else if (xmlStrEqual(name, BAD_CAST "id") || xmlStrEqual(name, BAD_CAST "sender_id") || xmlStrEqual(name, BAD_CAST "recipient_id")) 34 | { 35 | // process element as an integer 36 | NSNumber *number = [self _nodeValueAsInt]; 37 | if (number) 38 | { 39 | [dictionary setObject:number forKey:[NSString stringWithUTF8String:(const char *)name]]; 40 | } 41 | } 42 | else if (xmlStrEqual(name, BAD_CAST "created_at")) 43 | { 44 | // process element as a date 45 | NSDate *date = [self _nodeValueAsDate]; 46 | if (date) 47 | { 48 | [dictionary setObject:date forKey:[NSString stringWithUTF8String:(const char *)name]]; 49 | } 50 | } 51 | else if (xmlStrEqual(name, BAD_CAST "protected")) 52 | { 53 | // process element as a boolean 54 | NSNumber *number = [self _nodeValueAsBool]; 55 | if (number) 56 | { 57 | [dictionary setObject:number forKey:[NSString stringWithUTF8String:(const char *)name]]; 58 | } 59 | } 60 | else 61 | { 62 | // process element as a string 63 | NSString *string = [self _nodeValueAsString]; 64 | if (string) 65 | { 66 | [dictionary setObject:string forKey:[NSString stringWithUTF8String:(const char *)name]]; 67 | } 68 | } 69 | } 70 | 71 | // advance reader 72 | readerResult = xmlTextReaderRead(_reader); 73 | if (readerResult != 1) 74 | break; 75 | nodeType = xmlTextReaderNodeType(_reader); 76 | name = xmlTextReaderConstName(_reader); 77 | } 78 | 79 | // save the request type in the tweet 80 | [dictionary setObject:[NSNumber numberWithInt:requestType] forKey:TWITTER_SOURCE_REQUEST_TYPE]; 81 | 82 | return dictionary; 83 | } 84 | 85 | 86 | - (void)parse 87 | { 88 | int readerResult = xmlTextReaderRead(_reader); 89 | if (readerResult != 1) 90 | return; 91 | int nodeType = xmlTextReaderNodeType(_reader); 92 | const xmlChar *name = xmlTextReaderConstName(_reader); 93 | while (! (nodeType == XML_READER_TYPE_END_ELEMENT && xmlStrEqual(BAD_CAST "direct-messages", name))) 94 | { 95 | if (nodeType == XML_READER_TYPE_ELEMENT) 96 | { 97 | if (xmlStrEqual(name, BAD_CAST "direct_message")) 98 | { 99 | [parsedObjects addObject:[self _directMessageDictionaryForNodeWithName:BAD_CAST "direct_message"]]; 100 | } 101 | } 102 | 103 | // advance reader 104 | readerResult = xmlTextReaderRead(_reader); 105 | if (readerResult != 1) 106 | { 107 | break; 108 | } 109 | nodeType = xmlTextReaderNodeType(_reader); 110 | name = xmlTextReaderConstName(_reader); 111 | } 112 | } 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterMessagesParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterMessagesParser.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 19/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | #import "MGTwitterStatusesParser.h" 12 | 13 | @interface MGTwitterMessagesParser : MGTwitterStatusesParser { 14 | 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterMessagesParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterMessagesParser.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 19/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterMessagesParser.h" 10 | 11 | 12 | @implementation MGTwitterMessagesParser 13 | 14 | 15 | #pragma mark NSXMLParser delegate methods 16 | 17 | 18 | - (void)parser:(NSXMLParser *)theParser didStartElement:(NSString *)elementName 19 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName 20 | attributes:(NSDictionary *)attributeDict 21 | { 22 | //NSLog(@"Started element: %@ (%@)", elementName, attributeDict); 23 | [self setLastOpenedElement:elementName]; 24 | 25 | if ([elementName isEqualToString:@"direct_message"]) { 26 | // Make new entry in parsedObjects. 27 | NSMutableDictionary *newNode = [NSMutableDictionary dictionaryWithCapacity:0]; 28 | [parsedObjects addObject:newNode]; 29 | currentNode = newNode; 30 | } else if ([elementName isEqualToString:@"sender"] || [elementName isEqualToString:@"recipient"]) { 31 | // Add an appropriate dictionary to current node. 32 | NSMutableDictionary *newNode = [NSMutableDictionary dictionaryWithCapacity:0]; 33 | [currentNode setObject:newNode forKey:elementName]; 34 | currentNode = newNode; 35 | } else if (currentNode) { 36 | // Create relevant name-value pair. 37 | [currentNode setObject:[NSMutableString string] forKey:elementName]; 38 | } 39 | } 40 | 41 | 42 | - (void)parser:(NSXMLParser *)theParser didEndElement:(NSString *)elementName 43 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 44 | { 45 | [super parser:theParser didEndElement:elementName namespaceURI:namespaceURI qualifiedName:qName]; 46 | 47 | if ([elementName isEqualToString:@"sender"] || [elementName isEqualToString:@"recipient"]) { 48 | currentNode = [parsedObjects lastObject]; 49 | } else if ([elementName isEqualToString:@"direct_message"]) { 50 | [self addSource]; 51 | currentNode = nil; 52 | } 53 | } 54 | 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterMiscLibXMLParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterMiscLibXMLParser.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 11/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | #import "MGTwitterLibXMLParser.h" 12 | 13 | @interface MGTwitterMiscLibXMLParser : MGTwitterLibXMLParser { 14 | 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterMiscLibXMLParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterMiscLibXMLParser.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 11/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterMiscLibXMLParser.h" 10 | 11 | 12 | @implementation MGTwitterMiscLibXMLParser 13 | 14 | - (void)parse 15 | { 16 | int readerResult = xmlTextReaderRead(_reader); 17 | if (readerResult != 1) 18 | return; 19 | 20 | int nodeType = xmlTextReaderNodeType(_reader); 21 | const xmlChar *name = xmlTextReaderConstName(_reader); 22 | while (! (nodeType == XML_READER_TYPE_END_ELEMENT)) 23 | { 24 | if (nodeType == XML_READER_TYPE_ELEMENT) 25 | { 26 | if (xmlStrEqual(name, BAD_CAST "hash")) 27 | { 28 | [parsedObjects addObject:[self _hashDictionaryForNodeWithName:name]]; 29 | } 30 | else 31 | { 32 | // process element as a string -- API calls like friendships/exists.xml just return false or true 33 | NSString *string = [self _nodeValueAsString]; 34 | if (string) 35 | { 36 | NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; 37 | [dictionary setObject:string forKey:[NSString stringWithUTF8String:(const char *)name]]; 38 | [parsedObjects addObject:dictionary]; 39 | } 40 | } 41 | } 42 | 43 | // advance reader 44 | readerResult = xmlTextReaderRead(_reader); 45 | if (readerResult != 1) 46 | { 47 | break; 48 | } 49 | nodeType = xmlTextReaderNodeType(_reader); 50 | name = xmlTextReaderConstName(_reader); 51 | } 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterMiscParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterMiscParser.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 06/06/2008. 6 | // Copyright 2008 Instinctive Code. All rights reserved. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | #import "MGTwitterStatusesParser.h" 12 | 13 | @interface MGTwitterMiscParser : MGTwitterStatusesParser { 14 | 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterMiscParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterMiscParser.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 06/06/2008. 6 | // Copyright 2008 Instinctive Code. All rights reserved. 7 | // 8 | 9 | #import "MGTwitterMiscParser.h" 10 | 11 | 12 | @implementation MGTwitterMiscParser 13 | 14 | 15 | #pragma mark NSXMLParser delegate methods 16 | 17 | 18 | - (void)parser:(NSXMLParser *)theParser didStartElement:(NSString *)elementName 19 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName 20 | attributes:(NSDictionary *)attributeDict 21 | { 22 | //NSLog(@"Started element: %@ (%@)", elementName, attributeDict); 23 | [self setLastOpenedElement:elementName]; 24 | 25 | if (!currentNode) { 26 | NSMutableDictionary *newNode = [NSMutableDictionary dictionaryWithCapacity:0]; 27 | [parsedObjects addObject:newNode]; 28 | currentNode = newNode; 29 | } 30 | 31 | // Create relevant name-value pair. 32 | [currentNode setObject:[NSMutableString string] forKey:elementName]; 33 | } 34 | 35 | 36 | - (void)parser:(NSXMLParser *)theParser didEndElement:(NSString *)elementName 37 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 38 | { 39 | [super parser:theParser didEndElement:elementName namespaceURI:namespaceURI qualifiedName:qName]; 40 | 41 | if ([elementName isEqualToString:@"remaining_hits"]) { 42 | NSNumber *hits = [NSNumber numberWithInt:[[currentNode objectForKey:elementName] intValue]]; 43 | [currentNode setObject:hits forKey:elementName]; 44 | } 45 | } 46 | 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterParserDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterParserDelegate.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 18/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | #import "MGTwitterRequestTypes.h" 12 | 13 | @protocol MGTwitterParserDelegate 14 | 15 | - (void)parsingSucceededForRequest:(NSString *)identifier 16 | ofResponseType:(MGTwitterResponseType)responseType 17 | withParsedObjects:(NSArray *)parsedObjects; 18 | 19 | - (void)parsingFailedForRequest:(NSString *)requestIdentifier 20 | ofResponseType:(MGTwitterResponseType)responseType 21 | withError:(NSError *)error; 22 | 23 | #if YAJL_AVAILABLE || TOUCHJSON_AVAILABLE 24 | - (void)parsedObject:(NSDictionary *)parsedObject forRequest:(NSString *)identifier 25 | ofResponseType:(MGTwitterResponseType)responseType; 26 | #endif 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterRequestTypes.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterEngineDelegate.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 17/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | typedef enum _MGTwitterRequestType { 12 | MGTwitterPublicTimelineRequest = 0, // latest statuses from the public timeline 13 | MGTwitterHomeTimelineRequest, // latest statuses from the home timeline 14 | MGTwitterFollowedTimelineRequest, // latest statuses from the people that the current users follows 15 | MGTwitterUserTimelineRequest, // statuses archive for the current user 16 | MGTwitterUserTimelineForUserRequest, // statuses archive for the specified user 17 | MGTwitterUpdateGetRequest, // get a status update for the specified id 18 | MGTwitterUpdateSendRequest, // send a new update for the current user 19 | MGTwitterUpdateDeleteRequest, // delete an update for the current user using the specified id 20 | MGTwitterRepliesRequest, // latest reply status for the current user 21 | MGTwitterRetweetSendRequest, // send a new retweet for the current user 22 | MGTwitterFeaturedUsersRequest, // latest status from featured users 23 | MGTwitterFriendUpdatesRequest, // last status for the people that the current user follows 24 | MGTwitterFriendUpdatesForUserRequest, // last status for the people that the specified user follows 25 | MGTwitterFollowerUpdatesRequest, // last status for the people that follow the current user 26 | MGTwitterUserInformationRequest, // user information using the specified id or email 27 | MGTwitterBulkUserInformationRequest, // user information using the specified id or email 28 | MGTwitterDirectMessagesRequest, // latest direct messages to the current user 29 | MGTwitterDirectMessagesSentRequest, // latest direct messages from the current user 30 | MGTwitterDirectMessageSendRequest, // send a new direct message from the current user 31 | MGTwitterDirectMessageDeleteRequest, // delete a direct message to/from the current user 32 | MGTwitterUpdatesEnableRequest, // enable status updates for specified user (e.g. follow) 33 | MGTwitterUpdatesDisableRequest, // disable status updates for specified user (e.g. unfollow) 34 | MGTwitterUpdatesCheckRequest, // check if the specified user is following another user 35 | MGTwitterAccountRequest, // changing account information for the current user 36 | MGTwitterAccountLocationRequest, // change location in account information for the current user 37 | MGTwitterAccountDeliveryRequest, // change notification delivery in account information for the current user 38 | MGTwitterAccountStatusRequest, // get rate limiting status for the current user 39 | MGTwitterFavoritesRequest, // latest favorites for the current user 40 | MGTwitterFavoritesForUserRequest, // latest favorites for the specified user 41 | MGTwitterFavoritesEnableRequest, // create a favorite for the current user using the specified id 42 | MGTwitterFavoritesDisableRequest, // remove a favorite for the current user using the specified id 43 | MGTwitterNotificationsEnableRequest, // enable notifications for the specified user 44 | MGTwitterNotificationsDisableRequest, // disable notifications for the specified user 45 | MGTwitterBlockEnableRequest, // enable block for the specified user 46 | MGTwitterBlockDisableRequest, // disable block for the specified user 47 | MGTwitterImageRequest, // requesting an image 48 | MGTwitterFriendIDsRequest, // request the numeric IDs for every user the specified user is following 49 | MGTwitterFollowerIDsRequest, // request the numeric IDs of the followers of the specified user 50 | MGTwitterUserListsRequest, 51 | MGTwitterUserListCreate, 52 | #if YAJL_AVAILABLE || TOUCHJSON_AVAILABLE 53 | MGTwitterSearchRequest, // performing a search 54 | MGTwitterSearchCurrentTrendsRequest, // getting the current trends 55 | #endif 56 | MGTwitterOAuthTokenRequest, 57 | } MGTwitterRequestType; 58 | 59 | typedef enum _MGTwitterResponseType { 60 | MGTwitterStatuses = 0, // one or more statuses 61 | MGTwitterStatus = 1, // exactly one status 62 | MGTwitterUsers = 2, // one or more user's information 63 | MGTwitterUser = 3, // info for exactly one user 64 | MGTwitterDirectMessages = 4, // one or more direct messages 65 | MGTwitterDirectMessage = 5, // exactly one direct message 66 | MGTwitterGeneric = 6, // a generic response not requiring parsing 67 | MGTwitterMiscellaneous = 8, // a miscellaneous response of key-value pairs 68 | MGTwitterImage = 7, // an image 69 | #if YAJL_AVAILABLE || TOUCHJSON_AVAILABLE 70 | MGTwitterSearchResults = 9, // search results 71 | #endif 72 | MGTwitterSocialGraph = 10, 73 | MGTwitterOAuthToken = 11, 74 | MGTwitterUserLists = 12, 75 | } MGTwitterResponseType; 76 | 77 | // This key is added to each tweet or direct message returned, 78 | // with an NSNumber value containing an MGTwitterRequestType. 79 | // This is designed to help client applications aggregate updates. 80 | #define TWITTER_SOURCE_REQUEST_TYPE @"source_api_request_type" 81 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterSocialGraphLibXMLParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterSocialGraphLibXMLParser.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Robert McGovern on 2010/03/20. 6 | // Copyright 2010 Tarasis. All rights reserved. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | #import "MGTwitterLibXMLParser.h" 12 | 13 | @interface MGTwitterSocialGraphLibXMLParser : MGTwitterLibXMLParser { 14 | NSMutableArray * twitterIDs; 15 | } 16 | 17 | - (NSDictionary *)_socialGraphDictionaryForNodeWithName:(const xmlChar *)parentNodeName; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterSocialGraphLibXMLParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterSocialGraphLibXMLParser.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Robert McGovern on 2010/03/20. 6 | // Copyright 2010 Tarasis. All rights reserved. 7 | // 8 | 9 | #import "MGTwitterSocialGraphLibXMLParser.h" 10 | 11 | 12 | @implementation MGTwitterSocialGraphLibXMLParser 13 | - (void)parse 14 | { 15 | int readerResult = xmlTextReaderRead(_reader); 16 | if (readerResult != 1) 17 | return; 18 | 19 | int nodeType = xmlTextReaderNodeType(_reader); 20 | const xmlChar *name = xmlTextReaderConstName(_reader); 21 | 22 | NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; 23 | 24 | while (! (nodeType == XML_READER_TYPE_END_ELEMENT)) 25 | { 26 | //NSLog(@"name is: %@", [NSString stringWithUTF8String:(const char *)name]); 27 | if (nodeType == XML_READER_TYPE_ELEMENT) 28 | { 29 | if (xmlStrEqual(name, BAD_CAST "ids")) 30 | { 31 | [dictionary addEntriesFromDictionary:[self _socialGraphDictionaryForNodeWithName:name]]; 32 | } 33 | else if (xmlStrEqual(BAD_CAST "previous_cursor", name) || xmlStrEqual(BAD_CAST "next_cursor", name)) 34 | { 35 | // process element as a string -- API calls like friendships/exists.xml just return false or true 36 | NSString *string = [self _nodeValueAsString]; 37 | if (string) 38 | { 39 | [dictionary setObject:string forKey:[NSString stringWithUTF8String:(const char *)name]]; 40 | } 41 | } 42 | 43 | } 44 | 45 | // advance reader 46 | readerResult = xmlTextReaderRead(_reader); 47 | if (readerResult != 1) 48 | { 49 | break; 50 | } 51 | nodeType = xmlTextReaderNodeType(_reader); 52 | name = xmlTextReaderConstName(_reader); 53 | } 54 | 55 | [dictionary setObject:[NSNumber numberWithInt:requestType] forKey:TWITTER_SOURCE_REQUEST_TYPE]; 56 | [parsedObjects addObject:dictionary]; 57 | } 58 | 59 | - (NSDictionary *)_socialGraphDictionaryForNodeWithName:(const xmlChar *)parentNodeName 60 | { 61 | if (xmlTextReaderIsEmptyElement(_reader)) 62 | return nil; 63 | NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; 64 | twitterIDs = [NSMutableArray arrayWithCapacity:0]; 65 | 66 | int readerResult = xmlTextReaderRead(_reader); 67 | if (readerResult != 1) 68 | return nil; 69 | int nodeType = xmlTextReaderNodeType(_reader); 70 | const xmlChar *name = xmlTextReaderConstName(_reader); 71 | while (! (nodeType == XML_READER_TYPE_END_ELEMENT && xmlStrEqual(parentNodeName, name))) 72 | { 73 | if (nodeType == XML_READER_TYPE_ELEMENT) 74 | { 75 | //NSLog(@" name is: %@", [NSString stringWithUTF8String:(const char *)name]); 76 | // process element as an integer 77 | NSNumber *number = [self _nodeValueAsInt]; 78 | if (number) 79 | { 80 | //[dictionary setObject:number forKey:[NSString stringWithUTF8String:(const char *)name]]; 81 | [twitterIDs addObject:number]; 82 | } 83 | } 84 | 85 | // advance reader 86 | readerResult = xmlTextReaderRead(_reader); 87 | if (readerResult != 1) 88 | break; 89 | nodeType = xmlTextReaderNodeType(_reader); 90 | name = xmlTextReaderConstName(_reader); 91 | } 92 | 93 | [dictionary setObject:twitterIDs forKey:[NSString stringWithUTF8String:(const char *)name]]; 94 | 95 | return dictionary; 96 | } 97 | 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterSocialGraphParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterSocialGraphParser.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Robert McGovern on 2010/03/19. 6 | // Copyright 2010 Tarasis. All rights reserved. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | #import "MGTwitterStatusesParser.h" 12 | 13 | @interface MGTwitterSocialGraphParser : MGTwitterStatusesParser { 14 | NSMutableArray * twitterIDs; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterSocialGraphParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterSocialGraphParser.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Robert McGovern on 2010/03/19. 6 | // Copyright 2010 Tarasis. All rights reserved. 7 | // 8 | 9 | #import "MGTwitterSocialGraphParser.h" 10 | #import "MGTwitterMiscParser.h" 11 | 12 | 13 | @implementation MGTwitterSocialGraphParser 14 | 15 | 16 | #pragma mark NSXMLParser delegate methods 17 | 18 | 19 | - (void)parser:(NSXMLParser *)theParser didStartElement:(NSString *)elementName 20 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName 21 | attributes:(NSDictionary *)attributeDict 22 | { 23 | //NSLog(@"SG: Started element: %@ (%@)", elementName, attributeDict); 24 | [self setLastOpenedElement:elementName]; 25 | 26 | if ([elementName isEqualToString:@"ids"]) { 27 | twitterIDs = [NSMutableArray arrayWithCapacity:0]; 28 | NSMutableDictionary *newNode = [NSMutableDictionary dictionaryWithCapacity:0]; 29 | [parsedObjects addObject:newNode]; 30 | currentNode = newNode; 31 | } else if (currentNode && ![elementName isEqualToString:@"id"]) { 32 | // Create relevant name-value pair. 33 | [currentNode setObject:[NSMutableString string] forKey:elementName]; 34 | } 35 | } 36 | 37 | - (void)parser:(NSXMLParser *)theParser foundCharacters:(NSString *)characters 38 | { 39 | //NSLog(@"SG: Found characters: %@", characters); 40 | // Add the Twitter ID to the array 41 | if ([lastOpenedElement isEqualToString:@"id"]) { 42 | [twitterIDs addObject:characters]; 43 | // Append found characters to value of lastOpenedElement in currentNode. 44 | } else if (lastOpenedElement && currentNode) { 45 | [[currentNode objectForKey:lastOpenedElement] appendString:characters]; 46 | } 47 | } 48 | 49 | - (void)parser:(NSXMLParser *)theParser didEndElement:(NSString *)elementName 50 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 51 | { 52 | //NSLog(@"SG: didEndElement: %@", elementName); 53 | 54 | [super parser:theParser didEndElement:elementName namespaceURI:namespaceURI qualifiedName:qName]; 55 | 56 | // At the end of parsing, add the source type 57 | if ([elementName isEqualToString:@"id_list"]) { 58 | [self addSource]; 59 | currentNode = nil; 60 | } else if ([elementName isEqualToString:@"ids"]) { 61 | [currentNode setObject:twitterIDs forKey:elementName]; 62 | currentNode = [parsedObjects lastObject]; 63 | } 64 | } 65 | 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterStatusesLibXMLParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterStatusesLibXMLParser.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 11/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | #import "MGTwitterLibXMLParser.h" 12 | 13 | @interface MGTwitterStatusesLibXMLParser : MGTwitterLibXMLParser { 14 | 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterStatusesLibXMLParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterStatusesLibXMLParser.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 11/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterStatusesLibXMLParser.h" 10 | 11 | 12 | @implementation MGTwitterStatusesLibXMLParser 13 | 14 | 15 | - (void)parse 16 | { 17 | int readerResult = xmlTextReaderRead(_reader); 18 | if (readerResult != 1) 19 | return; 20 | int nodeType = xmlTextReaderNodeType(_reader); 21 | const xmlChar *name = xmlTextReaderConstName(_reader); 22 | while (! (nodeType == XML_READER_TYPE_END_ELEMENT && xmlStrEqual(BAD_CAST "statuses", name))) 23 | { 24 | if (nodeType == XML_READER_TYPE_ELEMENT) 25 | { 26 | if (xmlStrEqual(name, BAD_CAST "status")) 27 | { 28 | [parsedObjects addObject:[self _statusDictionaryForNodeWithName:name]]; 29 | } 30 | } 31 | 32 | // advance reader 33 | readerResult = xmlTextReaderRead(_reader); 34 | if (readerResult != 1) 35 | { 36 | break; 37 | } 38 | nodeType = xmlTextReaderNodeType(_reader); 39 | name = xmlTextReaderConstName(_reader); 40 | } 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterStatusesParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterStatusesParser.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 11/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | #import "MGTwitterXMLParser.h" 12 | 13 | @interface MGTwitterStatusesParser : MGTwitterXMLParser { 14 | 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterStatusesParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterStatusesParser.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 11/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterStatusesParser.h" 10 | 11 | 12 | @implementation MGTwitterStatusesParser 13 | 14 | 15 | #pragma mark NSXMLParser delegate methods 16 | 17 | 18 | - (void)parser:(NSXMLParser *)theParser didStartElement:(NSString *)elementName 19 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName 20 | attributes:(NSDictionary *)attributeDict 21 | { 22 | //NSLog(@"Started element: %@ (%@)", elementName, attributeDict); 23 | [self setLastOpenedElement:elementName]; 24 | 25 | if ([elementName isEqualToString:@"status"]) { 26 | // Make new entry in parsedObjects. 27 | NSMutableDictionary *newNode = [NSMutableDictionary dictionaryWithCapacity:0]; 28 | [parsedObjects addObject:newNode]; 29 | currentNode = newNode; 30 | } else if ([elementName isEqualToString:@"user"]) { 31 | // Add a 'user' dictionary to current node. 32 | NSMutableDictionary *newNode = [NSMutableDictionary dictionaryWithCapacity:0]; 33 | [currentNode setObject:newNode forKey:elementName]; 34 | currentNode = newNode; 35 | } else if ([elementName isEqualToString:@"place"]) { 36 | // Add a 'place' dictionary to current node. 37 | NSMutableDictionary *newNode = [NSMutableDictionary dictionaryWithCapacity:0]; 38 | [currentNode setObject:newNode forKey:elementName]; 39 | currentNode = newNode; 40 | } else if ([elementName isEqualToString:@"retweeted_status"]) { 41 | // Add a 'retweet_status' dictionary to current node. 42 | NSMutableDictionary *newNode = [NSMutableDictionary dictionaryWithCapacity:0]; 43 | [currentNode setObject:newNode forKey:elementName]; 44 | currentNode = newNode; 45 | } else if (currentNode) { 46 | // Create relevant name-value pair. 47 | [currentNode setObject:[NSMutableString string] forKey:elementName]; 48 | } 49 | } 50 | 51 | 52 | - (void)parser:(NSXMLParser *)theParser foundCharacters:(NSString *)characters 53 | { 54 | //NSLog(@"Found characters: %@", characters); 55 | // Append found characters to value of lastOpenedElement in currentNode. 56 | if (lastOpenedElement && currentNode) { 57 | [[currentNode objectForKey:lastOpenedElement] appendString:characters]; 58 | } 59 | } 60 | 61 | 62 | - (void)parser:(NSXMLParser *)theParser didEndElement:(NSString *)elementName 63 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 64 | { 65 | [super parser:theParser didEndElement:elementName namespaceURI:namespaceURI qualifiedName:qName]; 66 | 67 | if ([elementName isEqualToString:@"user"]) { 68 | currentNode = [parsedObjects lastObject]; 69 | } else if ([elementName isEqualToString:@"place"]) { 70 | currentNode = [parsedObjects lastObject]; 71 | } else if ([elementName isEqualToString:@"retweeted_status"]) { 72 | currentNode = [parsedObjects lastObject]; 73 | } else if ([elementName isEqualToString:@"status"]) { 74 | [self addSource]; 75 | currentNode = nil; 76 | } 77 | } 78 | 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterUserListsParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterUserListsParser.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Clinton Shryock on 6/10/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | #import "MGTwitterStatusesParser.h" 12 | 13 | @interface MGTwitterUserListsParser : MGTwitterStatusesParser { 14 | 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterUserListsParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterUserListsParser.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Clinton Shryock on 6/10/10. 6 | // Copyright 2010 scary-robot. All rights reserved. 7 | // 8 | 9 | #import "MGTwitterUserListsParser.h" 10 | 11 | 12 | @implementation MGTwitterUserListsParser 13 | 14 | #pragma mark NSXMLParser delegate methods 15 | 16 | 17 | - (void)parser:(NSXMLParser *)theParser didStartElement:(NSString *)elementName 18 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName 19 | attributes:(NSDictionary *)attributeDict 20 | { 21 | //NSLog(@"Started element: %@ (%@)", elementName, attributeDict); 22 | [self setLastOpenedElement:elementName]; 23 | 24 | if ([elementName isEqualToString:@"list"]) { 25 | // Make new entry in parsedObjects. 26 | NSMutableDictionary *newNode = [NSMutableDictionary dictionaryWithCapacity:0]; 27 | [parsedObjects addObject:newNode]; 28 | currentNode = newNode; 29 | } else if ([elementName isEqualToString:@"user"]) { 30 | // Add a 'user' dictionary to current node. 31 | NSMutableDictionary *newNode = [NSMutableDictionary dictionaryWithCapacity:0]; 32 | [currentNode setObject:newNode forKey:elementName]; 33 | currentNode = newNode; 34 | } else if (currentNode) { 35 | // Create relevant name-value pair. 36 | [currentNode setObject:[NSMutableString string] forKey:elementName]; 37 | } 38 | } 39 | 40 | - (void)parser:(NSXMLParser *)theParser didEndElement:(NSString *)elementName 41 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 42 | { 43 | [super parser:theParser didEndElement:elementName namespaceURI:namespaceURI qualifiedName:qName]; 44 | 45 | if ([elementName isEqualToString:@"list"]) { 46 | currentNode = [parsedObjects lastObject]; 47 | } else if ([elementName isEqualToString:@"user"]) { 48 | [self addSource]; 49 | currentNode = nil; 50 | } 51 | } 52 | 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterUsersLibXMLParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterUsersLibXMLParser.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 11/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | #import "MGTwitterLibXMLParser.h" 12 | 13 | @interface MGTwitterUsersLibXMLParser : MGTwitterLibXMLParser { 14 | 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterUsersLibXMLParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterUsersLibXMLParser.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 11/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterUsersLibXMLParser.h" 10 | 11 | 12 | @implementation MGTwitterUsersLibXMLParser 13 | 14 | - (void)parse 15 | { 16 | int readerResult = xmlTextReaderRead(_reader); 17 | if (readerResult != 1) 18 | return; 19 | int nodeType = xmlTextReaderNodeType(_reader); 20 | const xmlChar *name = xmlTextReaderConstName(_reader); 21 | while (! (nodeType == XML_READER_TYPE_END_ELEMENT && xmlStrEqual(BAD_CAST "users", name))) 22 | { 23 | if (nodeType == XML_READER_TYPE_ELEMENT) 24 | { 25 | if (xmlStrEqual(name, BAD_CAST "user")) 26 | { 27 | [parsedObjects addObject:[self _userDictionaryForNodeWithName:name]]; 28 | } 29 | } 30 | 31 | // advance reader 32 | readerResult = xmlTextReaderRead(_reader); 33 | if (readerResult != 1) 34 | { 35 | break; 36 | } 37 | nodeType = xmlTextReaderNodeType(_reader); 38 | name = xmlTextReaderConstName(_reader); 39 | } 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterUsersParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterUsersParser.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 19/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | #import "MGTwitterStatusesParser.h" 12 | 13 | @interface MGTwitterUsersParser : MGTwitterStatusesParser { 14 | 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterUsersParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterUsersParser.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 19/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterUsersParser.h" 10 | 11 | 12 | @implementation MGTwitterUsersParser 13 | 14 | 15 | #pragma mark NSXMLParser delegate methods 16 | 17 | 18 | - (void)parser:(NSXMLParser *)theParser didStartElement:(NSString *)elementName 19 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName 20 | attributes:(NSDictionary *)attributeDict 21 | { 22 | //NSLog(@"Started element: %@ (%@)", elementName, attributeDict); 23 | [self setLastOpenedElement:elementName]; 24 | 25 | if ([elementName isEqualToString:@"user"]) { 26 | // Make new entry in parsedObjects. 27 | NSMutableDictionary *newNode = [NSMutableDictionary dictionaryWithCapacity:0]; 28 | [parsedObjects addObject:newNode]; 29 | currentNode = newNode; 30 | } else if ([elementName isEqualToString:@"status"]) { 31 | // Add an appropriate dictionary to current node. 32 | NSMutableDictionary *newNode = [NSMutableDictionary dictionaryWithCapacity:0]; 33 | [currentNode setObject:newNode forKey:elementName]; 34 | currentNode = newNode; 35 | } else if (currentNode) { 36 | // Create relevant name-value pair. 37 | [currentNode setObject:[NSMutableString string] forKey:elementName]; 38 | } 39 | } 40 | 41 | 42 | - (void)parser:(NSXMLParser *)theParser didEndElement:(NSString *)elementName 43 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 44 | { 45 | [super parser:theParser didEndElement:elementName namespaceURI:namespaceURI qualifiedName:qName]; 46 | 47 | if ([elementName isEqualToString:@"status"]) { 48 | currentNode = [parsedObjects lastObject]; 49 | } else if ([elementName isEqualToString:@"user"]) { 50 | [self addSource]; 51 | currentNode = nil; 52 | } 53 | } 54 | 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterXMLParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterXMLParser.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 18/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | #import "MGTwitterParserDelegate.h" 11 | 12 | @interface MGTwitterXMLParser : NSObject { 13 | __weak NSObject *delegate; // weak ref 14 | NSString *identifier; 15 | MGTwitterRequestType requestType; 16 | MGTwitterResponseType responseType; 17 | NSData *xml; 18 | NSMutableArray *parsedObjects; 19 | NSXMLParser *parser; 20 | __weak NSMutableDictionary *currentNode; 21 | NSString *lastOpenedElement; 22 | } 23 | 24 | + (id)parserWithXML:(NSData *)theXML delegate:(NSObject *)theDelegate 25 | connectionIdentifier:(NSString *)identifier requestType:(MGTwitterRequestType)reqType 26 | responseType:(MGTwitterResponseType)respType; 27 | - (id)initWithXML:(NSData *)theXML delegate:(NSObject *)theDelegate 28 | connectionIdentifier:(NSString *)identifier requestType:(MGTwitterRequestType)reqType 29 | responseType:(MGTwitterResponseType)respType; 30 | 31 | - (NSString *)lastOpenedElement; 32 | - (void)setLastOpenedElement:(NSString *)value; 33 | 34 | - (void)addSource; 35 | 36 | - (void)parser:(NSXMLParser *)theParser didEndElement:(NSString *)elementName 37 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName; 38 | 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/MGTwitterXMLParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // MGTwitterXMLParser.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 18/02/2008. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterXMLParser.h" 10 | 11 | 12 | @implementation MGTwitterXMLParser 13 | 14 | 15 | #pragma mark Creation and Destruction 16 | 17 | 18 | + (id)parserWithXML:(NSData *)theXML delegate:(NSObject *)theDelegate 19 | connectionIdentifier:(NSString *)identifier requestType:(MGTwitterRequestType)reqType 20 | responseType:(MGTwitterResponseType)respType 21 | { 22 | id parser = [[self alloc] initWithXML:theXML 23 | delegate:theDelegate 24 | connectionIdentifier:identifier 25 | requestType:reqType 26 | responseType:respType]; 27 | return [parser autorelease]; 28 | } 29 | 30 | 31 | - (id)initWithXML:(NSData *)theXML delegate:(NSObject *)theDelegate 32 | connectionIdentifier:(NSString *)theIdentifier requestType:(MGTwitterRequestType)reqType 33 | responseType:(MGTwitterResponseType)respType 34 | { 35 | if ((self = [super init])) { 36 | xml = [theXML retain]; 37 | identifier = [theIdentifier retain]; 38 | requestType = reqType; 39 | responseType = respType; 40 | delegate = theDelegate; 41 | parsedObjects = [[NSMutableArray alloc] initWithCapacity:0]; 42 | 43 | // Set up the parser object. 44 | parser = [[NSXMLParser alloc] initWithData:xml]; 45 | [parser setDelegate:self]; 46 | [parser setShouldReportNamespacePrefixes:NO]; 47 | [parser setShouldProcessNamespaces:NO]; 48 | [parser setShouldResolveExternalEntities:NO]; 49 | 50 | // Begin parsing. 51 | [parser parse]; 52 | } 53 | 54 | return self; 55 | } 56 | 57 | 58 | - (void)dealloc 59 | { 60 | [parser release]; 61 | [parsedObjects release]; 62 | [xml release]; 63 | [identifier release]; 64 | delegate = nil; 65 | [super dealloc]; 66 | } 67 | 68 | 69 | #pragma mark NSXMLParser delegate methods 70 | 71 | 72 | - (void)parserDidStartDocument:(NSXMLParser *)theParser 73 | { 74 | //NSLog(@"Parsing begun"); 75 | } 76 | 77 | 78 | - (void)parserDidEndDocument:(NSXMLParser *)theParser 79 | { 80 | //NSLog(@"Parsing complete: %@", parsedObjects); 81 | [delegate parsingSucceededForRequest:identifier ofResponseType:responseType 82 | withParsedObjects:parsedObjects]; 83 | } 84 | 85 | 86 | - (void)parser:(NSXMLParser *)theParser didStartElement:(NSString *)elementName 87 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName 88 | attributes:(NSDictionary *)attributeDict 89 | { 90 | //NSLog(@"Started element: %@ (%@)", elementName, attributeDict); 91 | } 92 | 93 | 94 | - (void)parser:(NSXMLParser *)theParser foundCharacters:(NSString *)characters 95 | { 96 | //NSLog(@"Found characters: %@", characters); 97 | } 98 | 99 | 100 | - (void)parser:(NSXMLParser *)theParser didEndElement:(NSString *)elementName 101 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 102 | { 103 | //NSLog(@"Ended element: %@", elementName); 104 | [self setLastOpenedElement:nil]; 105 | 106 | if ([elementName isEqualToString:@"protected"] 107 | || [elementName isEqualToString:@"truncated"] 108 | || [elementName isEqualToString:@"following"]) { 109 | // Change "true"/"false" into an NSNumber with a BOOL value. 110 | NSNumber *boolNumber = [NSNumber numberWithBool:[[currentNode objectForKey:elementName] isEqualToString:@"true"]]; 111 | [currentNode setObject:boolNumber forKey:elementName]; 112 | } else if ([elementName isEqualToString:@"created_at"]) { 113 | // Change date-string into an NSDate. 114 | // NSLog(@"%@", [currentNode objectForKey:elementName]); 115 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 116 | [dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]]; 117 | dateFormatter.dateFormat = @"EEE MMM dd HH:mm:ss +0000 yyyy"; 118 | NSDate *creationDate = [dateFormatter dateFromString:[currentNode objectForKey:elementName]]; 119 | [dateFormatter release]; 120 | if (creationDate) { 121 | [currentNode setObject:creationDate forKey:elementName]; 122 | } 123 | } 124 | } 125 | 126 | 127 | - (void)parser:(NSXMLParser *)theParser foundAttributeDeclarationWithName:(NSString *)attributeName 128 | forElement:(NSString *)elementName type:(NSString *)type defaultValue:(NSString *)defaultValue 129 | { 130 | //NSLog(@"Found attribute: %@ (%@) [%@] {%@}", attributeName, elementName, type, defaultValue); 131 | } 132 | 133 | 134 | - (void)parser:(NSXMLParser *)theParser foundIgnorableWhitespace:(NSString *)whitespaceString 135 | { 136 | //NSLog(@"Found ignorable whitespace: %@", whitespaceString); 137 | } 138 | 139 | 140 | - (void)parser:(NSXMLParser *)theParser parseErrorOccurred:(NSError *)parseError 141 | { 142 | //NSLog(@"Parsing error occurred: %@", parseError); 143 | [delegate parsingFailedForRequest:identifier ofResponseType:responseType 144 | withError:parseError]; 145 | } 146 | 147 | 148 | #pragma mark Accessors 149 | 150 | 151 | - (NSString *)lastOpenedElement { 152 | return [[lastOpenedElement retain] autorelease]; 153 | } 154 | 155 | 156 | - (void)setLastOpenedElement:(NSString *)value { 157 | if (lastOpenedElement != value) { 158 | [lastOpenedElement release]; 159 | lastOpenedElement = [value copy]; 160 | } 161 | } 162 | 163 | 164 | #pragma mark Utility methods 165 | 166 | 167 | - (void)addSource 168 | { 169 | if (![currentNode objectForKey:TWITTER_SOURCE_REQUEST_TYPE]) { 170 | [currentNode setObject:[NSNumber numberWithInt:requestType] 171 | forKey:TWITTER_SOURCE_REQUEST_TYPE]; 172 | } 173 | } 174 | 175 | 176 | @end 177 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/NSData+Base64.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Base64.m 3 | // 4 | // Derived from http://colloquy.info/project/browser/trunk/NSDataAdditions.h?rev=1576 5 | // Created by khammond on Mon Oct 29 2001. 6 | // Formatted by Timothy Hatcher on Sun Jul 4 2004. 7 | // Copyright (c) 2001 Kyle Hammond. All rights reserved. 8 | // Original development by Dave Winer. 9 | // 10 | 11 | #import "MGTwitterEngineGlobalHeader.h" 12 | 13 | @interface NSData (Base64) 14 | 15 | /*! @function +dataWithBase64EncodedString: 16 | @discussion This method returns an autoreleased NSData object. The NSData object is initialized with the 17 | contents of the Base 64 encoded string. This is a convenience method. 18 | @param inBase64String An NSString object that contains only Base 64 encoded data. 19 | @result The NSData object. */ 20 | + (NSData *) dataWithBase64EncodedString:(NSString *) string; 21 | 22 | /*! @function -initWithBase64EncodedString: 23 | @discussion The NSData object is initialized with the contents of the Base 64 encoded string. 24 | This method returns self as a convenience. 25 | @param inBase64String An NSString object that contains only Base 64 encoded data. 26 | @result This method returns self. */ 27 | - (id) initWithBase64EncodedString:(NSString *) string; 28 | 29 | /*! @function -base64EncodingWithLineLength: 30 | @discussion This method returns a Base 64 encoded string representation of the data object. 31 | @param inLineLength A value of zero means no line breaks. This is crunched to a multiple of 4 (the next 32 | one greater than inLineLength). 33 | @result The base 64 encoded data. */ 34 | - (NSString *) base64EncodingWithLineLength:(unsigned int) lineLength; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/NSData+Base64.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+Base64.m 3 | // 4 | // Derived from http://colloquy.info/project/browser/trunk/NSDataAdditions.h?rev=1576 5 | // Created by khammond on Mon Oct 29 2001. 6 | // Formatted by Timothy Hatcher on Sun Jul 4 2004. 7 | // Copyright (c) 2001 Kyle Hammond. All rights reserved. 8 | // Original development by Dave Winer. 9 | // 10 | 11 | #import "NSData+Base64.h" 12 | 13 | #import 14 | 15 | static char encodingTable[64] = { 16 | 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 17 | 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 18 | 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 19 | 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' }; 20 | 21 | @implementation NSData (Base64) 22 | 23 | + (NSData *) dataWithBase64EncodedString:(NSString *) string { 24 | NSData *result = [[NSData alloc] initWithBase64EncodedString:string]; 25 | return [result autorelease]; 26 | } 27 | 28 | - (id) initWithBase64EncodedString:(NSString *) string { 29 | NSMutableData *mutableData = nil; 30 | 31 | if( string ) { 32 | unsigned long ixtext = 0; 33 | unsigned long lentext = 0; 34 | unsigned char ch = 0; 35 | unsigned char inbuf[3], outbuf[4]; 36 | short i = 0, ixinbuf = 0; 37 | BOOL flignore = NO; 38 | BOOL flendtext = NO; 39 | NSData *base64Data = nil; 40 | const unsigned char *base64Bytes = nil; 41 | 42 | // Convert the string to ASCII data. 43 | base64Data = [string dataUsingEncoding:NSASCIIStringEncoding]; 44 | base64Bytes = [base64Data bytes]; 45 | mutableData = [NSMutableData dataWithCapacity:[base64Data length]]; 46 | lentext = [base64Data length]; 47 | 48 | while( YES ) { 49 | if( ixtext >= lentext ) break; 50 | ch = base64Bytes[ixtext++]; 51 | flignore = NO; 52 | 53 | if( ( ch >= 'A' ) && ( ch <= 'Z' ) ) ch = ch - 'A'; 54 | else if( ( ch >= 'a' ) && ( ch <= 'z' ) ) ch = ch - 'a' + 26; 55 | else if( ( ch >= '0' ) && ( ch <= '9' ) ) ch = ch - '0' + 52; 56 | else if( ch == '+' ) ch = 62; 57 | else if( ch == '=' ) flendtext = YES; 58 | else if( ch == '/' ) ch = 63; 59 | else flignore = YES; 60 | 61 | if( ! flignore ) { 62 | short ctcharsinbuf = 3; 63 | BOOL flbreak = NO; 64 | 65 | if( flendtext ) { 66 | if( ! ixinbuf ) break; 67 | if( ( ixinbuf == 1 ) || ( ixinbuf == 2 ) ) ctcharsinbuf = 1; 68 | else ctcharsinbuf = 2; 69 | ixinbuf = 3; 70 | flbreak = YES; 71 | } 72 | 73 | inbuf [ixinbuf++] = ch; 74 | 75 | if( ixinbuf == 4 ) { 76 | ixinbuf = 0; 77 | outbuf [0] = ( inbuf[0] << 2 ) | ( ( inbuf[1] & 0x30) >> 4 ); 78 | outbuf [1] = ( ( inbuf[1] & 0x0F ) << 4 ) | ( ( inbuf[2] & 0x3C ) >> 2 ); 79 | outbuf [2] = ( ( inbuf[2] & 0x03 ) << 6 ) | ( inbuf[3] & 0x3F ); 80 | 81 | for( i = 0; i < ctcharsinbuf; i++ ) 82 | [mutableData appendBytes:&outbuf[i] length:1]; 83 | } 84 | 85 | if( flbreak ) break; 86 | } 87 | } 88 | } 89 | 90 | self = [self initWithData:mutableData]; 91 | return self; 92 | } 93 | 94 | - (NSString *) base64EncodingWithLineLength:(unsigned int) lineLength { 95 | const unsigned char *bytes = [self bytes]; 96 | NSMutableString *result = [NSMutableString stringWithCapacity:[self length]]; 97 | unsigned long ixtext = 0; 98 | unsigned long lentext = [self length]; 99 | long ctremaining = 0; 100 | unsigned char inbuf[3], outbuf[4]; 101 | short i = 0; 102 | unsigned int charsonline = 0; 103 | short ctcopy = 0; 104 | unsigned long ix = 0; 105 | 106 | while( YES ) { 107 | ctremaining = lentext - ixtext; 108 | if( ctremaining <= 0 ) break; 109 | 110 | for( i = 0; i < 3; i++ ) { 111 | ix = ixtext + i; 112 | if( ix < lentext ) inbuf[i] = bytes[ix]; 113 | else inbuf [i] = 0; 114 | } 115 | 116 | outbuf [0] = (inbuf [0] & 0xFC) >> 2; 117 | outbuf [1] = ((inbuf [0] & 0x03) << 4) | ((inbuf [1] & 0xF0) >> 4); 118 | outbuf [2] = ((inbuf [1] & 0x0F) << 2) | ((inbuf [2] & 0xC0) >> 6); 119 | outbuf [3] = inbuf [2] & 0x3F; 120 | ctcopy = 4; 121 | 122 | switch( ctremaining ) { 123 | case 1: 124 | ctcopy = 2; 125 | break; 126 | case 2: 127 | ctcopy = 3; 128 | break; 129 | } 130 | 131 | for( i = 0; i < ctcopy; i++ ) 132 | [result appendFormat:@"%c", encodingTable[outbuf[i]]]; 133 | 134 | for( i = ctcopy; i < 4; i++ ) 135 | [result appendFormat:@"%c",'=']; 136 | 137 | ixtext += 3; 138 | charsonline += 4; 139 | 140 | if( lineLength > 0 ) { 141 | if (charsonline >= lineLength) { 142 | charsonline = 0; 143 | [result appendString:@"\n"]; 144 | } 145 | } 146 | } 147 | 148 | return result; 149 | } 150 | 151 | @end 152 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/NSString+UUID.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+UUID.h 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 16/09/2007. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "MGTwitterEngineGlobalHeader.h" 10 | 11 | @interface NSString (UUID) 12 | 13 | + (NSString*)stringWithNewUUID; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Classes/MGTwitterEngine/NSString+UUID.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+UUID.m 3 | // MGTwitterEngine 4 | // 5 | // Created by Matt Gemmell on 16/09/2007. 6 | // Copyright 2008 Instinctive Code. 7 | // 8 | 9 | #import "NSString+UUID.h" 10 | 11 | 12 | @implementation NSString (UUID) 13 | 14 | 15 | + (NSString*)stringWithNewUUID 16 | { 17 | // Create a new UUID 18 | CFUUIDRef uuidObj = CFUUIDCreate(nil); 19 | 20 | // Get the string representation of the UUID 21 | NSString *newUUID = (NSString*)CFUUIDCreateString(nil, uuidObj); 22 | CFRelease(uuidObj); 23 | return [newUUID autorelease]; 24 | } 25 | 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Classes/TwitterFeed/Tweet.h: -------------------------------------------------------------------------------- 1 | // 2 | // Tweet.h 3 | // Created by http://github.com/iosdeveloper 4 | // 5 | 6 | @interface Tweet : NSObject { 7 | NSString *text; 8 | NSString *screenName; 9 | NSString *profileImageIdentifier; 10 | UIImage *profileImage; 11 | } 12 | 13 | @property (retain) NSString *text; 14 | @property (retain) NSString *screenName; 15 | @property (retain) NSString *profileImageIdentifier; 16 | @property (retain) UIImage *profileImage; 17 | 18 | @end -------------------------------------------------------------------------------- /Classes/TwitterFeed/Tweet.m: -------------------------------------------------------------------------------- 1 | // 2 | // Tweet.m 3 | // Created by http://github.com/iosdeveloper 4 | // 5 | 6 | #import "Tweet.h" 7 | 8 | @implementation Tweet 9 | 10 | @synthesize text, screenName, profileImageIdentifier, profileImage; 11 | 12 | - (void)dealloc { 13 | [text release]; 14 | [screenName release]; 15 | [profileImageIdentifier release]; 16 | [profileImage release]; 17 | 18 | [super dealloc]; 19 | } 20 | 21 | @end -------------------------------------------------------------------------------- /Classes/TwitterFeed/TwitterFeed.h: -------------------------------------------------------------------------------- 1 | // 2 | // TwitterFeed.h 3 | // Created by http://github.com/iosdeveloper 4 | // 5 | 6 | #import 7 | #import "MGTwitterEngine.h" 8 | 9 | @interface TwitterFeed : UITableViewController { 10 | NSMutableArray *tweets; 11 | MGTwitterEngine *twitterEngine; 12 | } 13 | 14 | @property (retain) NSMutableArray *tweets; 15 | 16 | - (id)initWithUsername:(NSString *)username; 17 | 18 | @end -------------------------------------------------------------------------------- /Classes/TwitterFeed/TwitterFeed.m: -------------------------------------------------------------------------------- 1 | // 2 | // TwitterFeed.m 3 | // Created by http://github.com/iosdeveloper 4 | // 5 | 6 | #import "TwitterFeed.h" 7 | #import "DetailViewController.h" 8 | #import "Tweet.h" 9 | #import "TwitterFeedCell.h" 10 | 11 | @implementation TwitterFeed 12 | 13 | @synthesize tweets; 14 | 15 | #pragma mark - 16 | #pragma mark Initialization 17 | 18 | - (id)initWithUsername:(NSString *)username { 19 | self = [super init]; 20 | if (self) { 21 | [self setTweets:[[NSMutableArray alloc] init]]; 22 | 23 | twitterEngine = [[MGTwitterEngine alloc] initWithDelegate:self]; 24 | 25 | NSLog(@"MGTwitterEngine version %@", [MGTwitterEngine version]); 26 | 27 | [twitterEngine setUsesSecureConnection:NO]; 28 | [twitterEngine setUsername:username]; 29 | 30 | [twitterEngine getUserTimelineFor:[twitterEngine username] sinceID:0 startingAtPage:0 count:NSIntegerMax]; 31 | } 32 | return self; 33 | } 34 | 35 | #pragma mark - 36 | #pragma mark Table view data source 37 | 38 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 39 | return 1; 40 | } 41 | 42 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 43 | return [[self tweets] count]; 44 | } 45 | 46 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 47 | static NSString *CellIdentifier = @"Cell"; 48 | 49 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 50 | if (cell == nil) { 51 | cell = [[[TwitterFeedCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease]; 52 | } 53 | 54 | Tweet *tweet = [[self tweets] objectAtIndex:[indexPath row]]; 55 | 56 | [[cell textLabel] setText:[tweet screenName]]; 57 | [[cell detailTextLabel] setText:[tweet text]]; 58 | [[cell imageView] setImage:[tweet profileImage]]; 59 | 60 | return cell; 61 | } 62 | 63 | #pragma mark - 64 | #pragma mark Table view delegate 65 | 66 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 67 | Tweet *tweet = [[self tweets] objectAtIndex:[indexPath row]]; 68 | 69 | float height = [[tweet text] sizeWithFont:[UIFont systemFontOfSize:14.0] constrainedToSize:CGSizeMake(300.0 - 58.0, CGFLOAT_MAX) lineBreakMode:UILineBreakModeWordWrap].height; 70 | 71 | if (height == 18.0) { 72 | height += 5.0; 73 | } 74 | 75 | return 5.0 + 22.0 + height + 5.0; 76 | } 77 | 78 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 79 | DetailViewController *detailViewController = [[DetailViewController alloc] init]; 80 | 81 | Tweet *tweet = [[self tweets] objectAtIndex:[indexPath row]]; 82 | 83 | [detailViewController setText:[tweet text]]; 84 | 85 | [[self navigationController] pushViewController:detailViewController animated:YES]; 86 | 87 | [detailViewController release]; 88 | } 89 | 90 | #pragma mark - 91 | #pragma mark MGTwitterEngineDelegate 92 | 93 | - (void)requestSucceeded:(NSString *)connectionIdentifier { 94 | NSLog(@"Request succeeded for connectionIdentifier = %@", connectionIdentifier); 95 | } 96 | 97 | - (void)requestFailed:(NSString *)connectionIdentifier withError:(NSError *)error { 98 | NSLog(@"Request failed for connectionIdentifier = %@, error = %@ (%@)", 99 | connectionIdentifier, 100 | [error localizedDescription], 101 | [error userInfo]); 102 | } 103 | 104 | - (void)statusesReceived:(NSArray *)statuses forRequest:(NSString *)connectionIdentifier { 105 | for (NSDictionary *dict in statuses) { 106 | NSString *text = [dict objectForKey:@"text"]; 107 | NSString *screenName = [[dict objectForKey:@"user"] objectForKey:@"screen_name"]; 108 | NSString *profileImageIdentifier = [twitterEngine getImageAtURL:[[dict objectForKey:@"user"] objectForKey:@"profile_image_url"]]; 109 | 110 | Tweet *tweet = [[Tweet alloc] init]; 111 | [tweet setText:text]; 112 | [tweet setScreenName:screenName]; 113 | [tweet setProfileImageIdentifier:profileImageIdentifier]; 114 | 115 | [[self tweets] addObject:tweet]; 116 | 117 | [tweet release]; 118 | } 119 | 120 | [[self tableView] performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO]; 121 | } 122 | 123 | - (void)imageReceived:(UIImage *)image forRequest:(NSString *)connectionIdentifier { 124 | for (int i = 0; i < [[self tweets] count]; i ++) { 125 | Tweet *tweet = [[self tweets] objectAtIndex:i]; 126 | 127 | if ([connectionIdentifier isEqualToString:[tweet profileImageIdentifier]]) { 128 | [tweet setProfileImage:image]; 129 | 130 | [[self tweets] replaceObjectAtIndex:i withObject:tweet]; 131 | 132 | [[self tableView] performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO]; 133 | } 134 | } 135 | } 136 | 137 | #pragma mark - 138 | #pragma mark Memory management 139 | 140 | - (void)dealloc { 141 | [twitterEngine release]; 142 | [tweets release]; 143 | 144 | [super dealloc]; 145 | } 146 | 147 | @end -------------------------------------------------------------------------------- /Classes/TwitterFeed/TwitterFeedCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // TwitterFeedCell.h 3 | // Created by http://github.com/iosdeveloper 4 | // 5 | 6 | #import 7 | 8 | @interface TwitterFeedCell : UITableViewCell { 9 | 10 | } 11 | 12 | @end -------------------------------------------------------------------------------- /Classes/TwitterFeed/TwitterFeedCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // TwitterFeedCell.m 3 | // Created by http://github.com/iosdeveloper 4 | // 5 | 6 | #import "TwitterFeedCell.h" 7 | #import 8 | 9 | @implementation TwitterFeedCell 10 | 11 | - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 12 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 13 | if (self) { 14 | [[self detailTextLabel] setLineBreakMode:UILineBreakModeWordWrap]; 15 | [[self detailTextLabel] setNumberOfLines:NSIntegerMax]; 16 | 17 | [[[self imageView] layer] setMasksToBounds:YES]; 18 | [[[self imageView] layer] setCornerRadius:5.0]; 19 | 20 | //[self setSelectionStyle:UITableViewCellSelectionStyleNone]; 21 | } 22 | return self; 23 | } 24 | 25 | - (void)layoutSubviews { 26 | [super layoutSubviews]; 27 | 28 | CGRect rect = [[self imageView] frame]; 29 | rect.origin.x = 5.0; 30 | rect.origin.y = 5.0; 31 | [[self imageView] setFrame:rect]; 32 | 33 | rect = [[self textLabel] frame]; 34 | rect.origin.x = 68.0; 35 | rect.origin.y = 5.0; 36 | [[self textLabel] setFrame:rect]; 37 | 38 | rect = [[self detailTextLabel] frame]; 39 | rect.origin.x = 68.0; 40 | rect.origin.y = 27.0; 41 | [[self detailTextLabel] setFrame:rect]; 42 | } 43 | 44 | @end -------------------------------------------------------------------------------- /Classes/oauthconsumer/Categories/NSMutableURLRequest+Parameters.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableURLRequest+Parameters.h 3 | // 4 | // Created by Jon Crosby on 10/19/07. 5 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #import 26 | #import "OARequestParameter.h" 27 | #import "NSURL+Base.h" 28 | 29 | 30 | @interface NSMutableURLRequest (OAParameterAdditions) 31 | 32 | @property(nonatomic, retain) NSArray *parameters; 33 | 34 | - (void)setHTTPBodyWithString:(NSString *)body; 35 | - (void)attachFileWithName:(NSString *)name filename:(NSString*)filename contentType:(NSString *)contentType data:(NSData*)data; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/Categories/NSMutableURLRequest+Parameters.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableURLRequest+Parameters.m 3 | // 4 | // Created by Jon Crosby on 10/19/07. 5 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | 26 | #import "NSMutableURLRequest+Parameters.h" 27 | 28 | static NSString *Boundary = @"-----------------------------------0xCoCoaouTHeBouNDaRy"; 29 | 30 | @implementation NSMutableURLRequest (OAParameterAdditions) 31 | 32 | - (BOOL)isMultipart { 33 | return [[self valueForHTTPHeaderField:@"Content-Type"] hasPrefix:@"multipart/form-data"]; 34 | } 35 | 36 | - (NSArray *)parameters { 37 | NSString *encodedParameters = nil; 38 | 39 | if (![self isMultipart]) { 40 | if ([[self HTTPMethod] isEqualToString:@"GET"] || [[self HTTPMethod] isEqualToString:@"DELETE"]) { 41 | encodedParameters = [[self URL] query]; 42 | } else { 43 | encodedParameters = [[[NSString alloc] initWithData:[self HTTPBody] encoding:NSASCIIStringEncoding] autorelease]; 44 | } 45 | } 46 | 47 | if (encodedParameters == nil || [encodedParameters isEqualToString:@""]) { 48 | return nil; 49 | } 50 | // NSLog(@"raw parameters %@", encodedParameters); 51 | NSArray *encodedParameterPairs = [encodedParameters componentsSeparatedByString:@"&"]; 52 | NSMutableArray *requestParameters = [NSMutableArray arrayWithCapacity:[encodedParameterPairs count]]; 53 | 54 | for (NSString *encodedPair in encodedParameterPairs) { 55 | NSArray *encodedPairElements = [encodedPair componentsSeparatedByString:@"="]; 56 | OARequestParameter *parameter = [[OARequestParameter alloc] initWithName:[[encodedPairElements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] 57 | value:[[encodedPairElements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; 58 | [requestParameters addObject:parameter]; 59 | [parameter release], parameter = nil; 60 | } 61 | 62 | return requestParameters; 63 | } 64 | 65 | - (void)setParameters:(NSArray *)parameters 66 | { 67 | NSMutableArray *pairs = [[[NSMutableArray alloc] initWithCapacity:[parameters count]] autorelease]; 68 | for (OARequestParameter *requestParameter in parameters) { 69 | [pairs addObject:[requestParameter URLEncodedNameValuePair]]; 70 | } 71 | 72 | NSString *encodedParameterPairs = [pairs componentsJoinedByString:@"&"]; 73 | 74 | if ([[self HTTPMethod] isEqualToString:@"GET"] || [[self HTTPMethod] isEqualToString:@"DELETE"]) { 75 | [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", [[self URL] URLStringWithoutQuery], encodedParameterPairs]]]; 76 | } else { 77 | // POST, PUT 78 | [self setHTTPBodyWithString:encodedParameterPairs]; 79 | [self setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; 80 | } 81 | } 82 | 83 | - (void)setHTTPBodyWithString:(NSString *)body { 84 | NSData *bodyData = [body dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; 85 | [self setValue:[NSString stringWithFormat:@"%d", [bodyData length]] forHTTPHeaderField:@"Content-Length"]; 86 | [self setHTTPBody:bodyData]; 87 | } 88 | 89 | - (void)attachFileWithName:(NSString *)name filename:(NSString*)filename contentType:(NSString *)contentType data:(NSData*)data { 90 | 91 | NSArray *parameters = [self parameters]; 92 | [self setValue:[@"multipart/form-data; boundary=" stringByAppendingString:Boundary] forHTTPHeaderField:@"Content-type"]; 93 | 94 | NSMutableData *bodyData = [NSMutableData new]; 95 | for (OARequestParameter *parameter in parameters) { 96 | NSString *param = [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n", 97 | Boundary, [parameter URLEncodedName], [parameter value]]; 98 | 99 | [bodyData appendData:[param dataUsingEncoding:NSUTF8StringEncoding]]; 100 | } 101 | 102 | NSString *filePrefix = [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\nContent-Type: %@\r\n\r\n", 103 | Boundary, name, filename, contentType]; 104 | [bodyData appendData:[filePrefix dataUsingEncoding:NSUTF8StringEncoding]]; 105 | [bodyData appendData:data]; 106 | 107 | [bodyData appendData:[[[@"--" stringByAppendingString:Boundary] stringByAppendingString:@"--"] dataUsingEncoding:NSUTF8StringEncoding]]; 108 | [self setValue:[NSString stringWithFormat:@"%d", [bodyData length]] forHTTPHeaderField:@"Content-Length"]; 109 | [self setHTTPBody:bodyData]; 110 | [bodyData release]; 111 | } 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/Categories/NSString+URLEncoding.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+URLEncoding.h 3 | // 4 | // Created by Jon Crosby on 10/19/07. 5 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | 26 | #import 27 | 28 | 29 | @interface NSString (OAURLEncodingAdditions) 30 | 31 | - (NSString *)encodedURLString; 32 | - (NSString *)encodedURLParameterString; 33 | - (NSString *)decodedURLString; 34 | - (NSString *)removeQuotes; 35 | @end 36 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/Categories/NSString+URLEncoding.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+URLEncoding.m 3 | // 4 | // Created by Jon Crosby on 10/19/07. 5 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | 26 | #import "NSString+URLEncoding.h" 27 | 28 | 29 | @implementation NSString (OAURLEncodingAdditions) 30 | 31 | - (NSString *)encodedURLString { 32 | NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, 33 | (CFStringRef)self, 34 | NULL, // characters to leave unescaped (NULL = all escaped sequences are replaced) 35 | CFSTR("?=&+"), // legal URL characters to be escaped (NULL = all legal characters are replaced) 36 | kCFStringEncodingUTF8); // encoding 37 | return [result autorelease]; 38 | } 39 | 40 | - (NSString *)encodedURLParameterString { 41 | NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, 42 | (CFStringRef)self, 43 | NULL, 44 | CFSTR(":/=,!$&'()*+;[]@#?"), 45 | kCFStringEncodingUTF8); 46 | return [result autorelease]; 47 | } 48 | 49 | - (NSString *)decodedURLString { 50 | NSString *result = (NSString*)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, 51 | (CFStringRef)self, 52 | CFSTR(""), 53 | kCFStringEncodingUTF8); 54 | 55 | return [result autorelease]; 56 | 57 | } 58 | 59 | -(NSString *)removeQuotes 60 | { 61 | NSUInteger length = [self length]; 62 | NSString *ret = self; 63 | if ([self characterAtIndex:0] == '"') { 64 | ret = [ret substringFromIndex:1]; 65 | } 66 | if ([self characterAtIndex:length - 1] == '"') { 67 | ret = [ret substringToIndex:length - 2]; 68 | } 69 | 70 | return ret; 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/Categories/NSURL+Base.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSURL+Base.h 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import 28 | 29 | 30 | @interface NSURL (OABaseAdditions) 31 | 32 | - (NSString *)URLStringWithoutQuery; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/Categories/NSURL+Base.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSURL+Base.m 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import "NSURL+Base.h" 28 | 29 | 30 | @implementation NSURL (OABaseAdditions) 31 | 32 | - (NSString *)URLStringWithoutQuery { 33 | NSArray *parts = [[self absoluteString] componentsSeparatedByString:@"?"]; 34 | return [parts objectAtIndex:0]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/Crypto/Base64Transcoder.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Base64Transcoder.c 3 | * Base64Test 4 | * 5 | * Created by Jonathan Wight on Tue Mar 18 2003. 6 | * Copyright (c) 2003 Toxic Software. All rights reserved. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | * 26 | */ 27 | 28 | #include "Base64Transcoder.h" 29 | 30 | #include 31 | #include 32 | 33 | const u_int8_t kBase64EncodeTable[64] = { 34 | /* 0 */ 'A', /* 1 */ 'B', /* 2 */ 'C', /* 3 */ 'D', 35 | /* 4 */ 'E', /* 5 */ 'F', /* 6 */ 'G', /* 7 */ 'H', 36 | /* 8 */ 'I', /* 9 */ 'J', /* 10 */ 'K', /* 11 */ 'L', 37 | /* 12 */ 'M', /* 13 */ 'N', /* 14 */ 'O', /* 15 */ 'P', 38 | /* 16 */ 'Q', /* 17 */ 'R', /* 18 */ 'S', /* 19 */ 'T', 39 | /* 20 */ 'U', /* 21 */ 'V', /* 22 */ 'W', /* 23 */ 'X', 40 | /* 24 */ 'Y', /* 25 */ 'Z', /* 26 */ 'a', /* 27 */ 'b', 41 | /* 28 */ 'c', /* 29 */ 'd', /* 30 */ 'e', /* 31 */ 'f', 42 | /* 32 */ 'g', /* 33 */ 'h', /* 34 */ 'i', /* 35 */ 'j', 43 | /* 36 */ 'k', /* 37 */ 'l', /* 38 */ 'm', /* 39 */ 'n', 44 | /* 40 */ 'o', /* 41 */ 'p', /* 42 */ 'q', /* 43 */ 'r', 45 | /* 44 */ 's', /* 45 */ 't', /* 46 */ 'u', /* 47 */ 'v', 46 | /* 48 */ 'w', /* 49 */ 'x', /* 50 */ 'y', /* 51 */ 'z', 47 | /* 52 */ '0', /* 53 */ '1', /* 54 */ '2', /* 55 */ '3', 48 | /* 56 */ '4', /* 57 */ '5', /* 58 */ '6', /* 59 */ '7', 49 | /* 60 */ '8', /* 61 */ '9', /* 62 */ '+', /* 63 */ '/' 50 | }; 51 | 52 | /* 53 | -1 = Base64 end of data marker. 54 | -2 = White space (tabs, cr, lf, space) 55 | -3 = Noise (all non whitespace, non-base64 characters) 56 | -4 = Dangerous noise 57 | -5 = Illegal noise (null byte) 58 | */ 59 | 60 | const int8_t kBase64DecodeTable[128] = { 61 | /* 0x00 */ -5, /* 0x01 */ -3, /* 0x02 */ -3, /* 0x03 */ -3, 62 | /* 0x04 */ -3, /* 0x05 */ -3, /* 0x06 */ -3, /* 0x07 */ -3, 63 | /* 0x08 */ -3, /* 0x09 */ -2, /* 0x0a */ -2, /* 0x0b */ -2, 64 | /* 0x0c */ -2, /* 0x0d */ -2, /* 0x0e */ -3, /* 0x0f */ -3, 65 | /* 0x10 */ -3, /* 0x11 */ -3, /* 0x12 */ -3, /* 0x13 */ -3, 66 | /* 0x14 */ -3, /* 0x15 */ -3, /* 0x16 */ -3, /* 0x17 */ -3, 67 | /* 0x18 */ -3, /* 0x19 */ -3, /* 0x1a */ -3, /* 0x1b */ -3, 68 | /* 0x1c */ -3, /* 0x1d */ -3, /* 0x1e */ -3, /* 0x1f */ -3, 69 | /* ' ' */ -2, /* '!' */ -3, /* '"' */ -3, /* '#' */ -3, 70 | /* '$' */ -3, /* '%' */ -3, /* '&' */ -3, /* ''' */ -3, 71 | /* '(' */ -3, /* ')' */ -3, /* '*' */ -3, /* '+' */ 62, 72 | /* ',' */ -3, /* '-' */ -3, /* '.' */ -3, /* '/' */ 63, 73 | /* '0' */ 52, /* '1' */ 53, /* '2' */ 54, /* '3' */ 55, 74 | /* '4' */ 56, /* '5' */ 57, /* '6' */ 58, /* '7' */ 59, 75 | /* '8' */ 60, /* '9' */ 61, /* ':' */ -3, /* ';' */ -3, 76 | /* '<' */ -3, /* '=' */ -1, /* '>' */ -3, /* '?' */ -3, 77 | /* '@' */ -3, /* 'A' */ 0, /* 'B' */ 1, /* 'C' */ 2, 78 | /* 'D' */ 3, /* 'E' */ 4, /* 'F' */ 5, /* 'G' */ 6, 79 | /* 'H' */ 7, /* 'I' */ 8, /* 'J' */ 9, /* 'K' */ 10, 80 | /* 'L' */ 11, /* 'M' */ 12, /* 'N' */ 13, /* 'O' */ 14, 81 | /* 'P' */ 15, /* 'Q' */ 16, /* 'R' */ 17, /* 'S' */ 18, 82 | /* 'T' */ 19, /* 'U' */ 20, /* 'V' */ 21, /* 'W' */ 22, 83 | /* 'X' */ 23, /* 'Y' */ 24, /* 'Z' */ 25, /* '[' */ -3, 84 | /* '\' */ -3, /* ']' */ -3, /* '^' */ -3, /* '_' */ -3, 85 | /* '`' */ -3, /* 'a' */ 26, /* 'b' */ 27, /* 'c' */ 28, 86 | /* 'd' */ 29, /* 'e' */ 30, /* 'f' */ 31, /* 'g' */ 32, 87 | /* 'h' */ 33, /* 'i' */ 34, /* 'j' */ 35, /* 'k' */ 36, 88 | /* 'l' */ 37, /* 'm' */ 38, /* 'n' */ 39, /* 'o' */ 40, 89 | /* 'p' */ 41, /* 'q' */ 42, /* 'r' */ 43, /* 's' */ 44, 90 | /* 't' */ 45, /* 'u' */ 46, /* 'v' */ 47, /* 'w' */ 48, 91 | /* 'x' */ 49, /* 'y' */ 50, /* 'z' */ 51, /* '{' */ -3, 92 | /* '|' */ -3, /* '}' */ -3, /* '~' */ -3, /* 0x7f */ -3 93 | }; 94 | 95 | const u_int8_t kBits_00000011 = 0x03; 96 | const u_int8_t kBits_00001111 = 0x0F; 97 | const u_int8_t kBits_00110000 = 0x30; 98 | const u_int8_t kBits_00111100 = 0x3C; 99 | const u_int8_t kBits_00111111 = 0x3F; 100 | const u_int8_t kBits_11000000 = 0xC0; 101 | const u_int8_t kBits_11110000 = 0xF0; 102 | const u_int8_t kBits_11111100 = 0xFC; 103 | 104 | size_t EstimateBas64EncodedDataSize(size_t inDataSize) 105 | { 106 | size_t theEncodedDataSize = (int)ceil(inDataSize / 3.0) * 4; 107 | theEncodedDataSize = theEncodedDataSize / 72 * 74 + theEncodedDataSize % 72; 108 | return(theEncodedDataSize); 109 | } 110 | 111 | size_t EstimateBas64DecodedDataSize(size_t inDataSize) 112 | { 113 | size_t theDecodedDataSize = (int)ceil(inDataSize / 4.0) * 3; 114 | //theDecodedDataSize = theDecodedDataSize / 72 * 74 + theDecodedDataSize % 72; 115 | return(theDecodedDataSize); 116 | } 117 | 118 | bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize) 119 | { 120 | size_t theEncodedDataSize = EstimateBas64EncodedDataSize(inInputDataSize); 121 | if (*ioOutputDataSize < theEncodedDataSize) 122 | return(false); 123 | *ioOutputDataSize = theEncodedDataSize; 124 | const u_int8_t *theInPtr = (const u_int8_t *)inInputData; 125 | u_int32_t theInIndex = 0, theOutIndex = 0; 126 | for (; theInIndex < (inInputDataSize / 3) * 3; theInIndex += 3) 127 | { 128 | outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; 129 | outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4]; 130 | outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (theInPtr[theInIndex + 2] & kBits_11000000) >> 6]; 131 | outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 2] & kBits_00111111) >> 0]; 132 | if (theOutIndex % 74 == 72) 133 | { 134 | outOutputData[theOutIndex++] = '\r'; 135 | outOutputData[theOutIndex++] = '\n'; 136 | } 137 | } 138 | const size_t theRemainingBytes = inInputDataSize - theInIndex; 139 | if (theRemainingBytes == 1) 140 | { 141 | outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; 142 | outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (0 & kBits_11110000) >> 4]; 143 | outOutputData[theOutIndex++] = '='; 144 | outOutputData[theOutIndex++] = '='; 145 | if (theOutIndex % 74 == 72) 146 | { 147 | outOutputData[theOutIndex++] = '\r'; 148 | outOutputData[theOutIndex++] = '\n'; 149 | } 150 | } 151 | else if (theRemainingBytes == 2) 152 | { 153 | outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; 154 | outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4]; 155 | outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (0 & kBits_11000000) >> 6]; 156 | outOutputData[theOutIndex++] = '='; 157 | if (theOutIndex % 74 == 72) 158 | { 159 | outOutputData[theOutIndex++] = '\r'; 160 | outOutputData[theOutIndex++] = '\n'; 161 | } 162 | } 163 | (void)theOutIndex; // tell the static analyser we don't care that the last postincrement is never read 164 | return(true); 165 | 166 | // MODS THS - silence analyzer warnings about stored values never being read 167 | #pragma unused(theOutIndex) 168 | } 169 | 170 | bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize) 171 | { 172 | memset(ioOutputData, '.', *ioOutputDataSize); 173 | 174 | size_t theDecodedDataSize = EstimateBas64DecodedDataSize(inInputDataSize); 175 | if (*ioOutputDataSize < theDecodedDataSize) 176 | return(false); 177 | *ioOutputDataSize = 0; 178 | const u_int8_t *theInPtr = (const u_int8_t *)inInputData; 179 | u_int8_t *theOutPtr = (u_int8_t *)ioOutputData; 180 | size_t theInIndex = 0, theOutIndex = 0; 181 | u_int8_t theOutputOctet = 0; 182 | size_t theSequence = 0; 183 | for (; theInIndex < inInputDataSize; ) 184 | { 185 | int8_t theSextet = 0; 186 | 187 | int8_t theCurrentInputOctet = theInPtr[theInIndex]; 188 | theSextet = kBase64DecodeTable[theCurrentInputOctet]; 189 | if (theSextet == -1) 190 | break; 191 | while (theSextet == -2) 192 | { 193 | theCurrentInputOctet = theInPtr[++theInIndex]; 194 | theSextet = kBase64DecodeTable[theCurrentInputOctet]; 195 | } 196 | while (theSextet == -3) 197 | { 198 | theCurrentInputOctet = theInPtr[++theInIndex]; 199 | theSextet = kBase64DecodeTable[theCurrentInputOctet]; 200 | } 201 | if (theSequence == 0) 202 | { 203 | theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 2 & kBits_11111100; 204 | } 205 | else if (theSequence == 1) 206 | { 207 | theOutputOctet |= (theSextet >- 0 ? theSextet : 0) >> 4 & kBits_00000011; 208 | theOutPtr[theOutIndex++] = theOutputOctet; 209 | } 210 | else if (theSequence == 2) 211 | { 212 | theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 4 & kBits_11110000; 213 | } 214 | else if (theSequence == 3) 215 | { 216 | theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 2 & kBits_00001111; 217 | theOutPtr[theOutIndex++] = theOutputOctet; 218 | } 219 | else if (theSequence == 4) 220 | { 221 | theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 6 & kBits_11000000; 222 | } 223 | else if (theSequence == 5) 224 | { 225 | theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 0 & kBits_00111111; 226 | theOutPtr[theOutIndex++] = theOutputOctet; 227 | } 228 | theSequence = (theSequence + 1) % 6; 229 | if (theSequence != 2 && theSequence != 4) 230 | theInIndex++; 231 | } 232 | *ioOutputDataSize = theOutIndex; 233 | return(true); 234 | } 235 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/Crypto/Base64Transcoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Base64Transcoder.h 3 | * Base64Test 4 | * 5 | * Created by Jonathan Wight on Tue Mar 18 2003. 6 | * Copyright (c) 2003 Toxic Software. All rights reserved. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | * 26 | */ 27 | 28 | #include 29 | #include 30 | 31 | extern size_t EstimateBas64EncodedDataSize(size_t inDataSize); 32 | extern size_t EstimateBas64DecodedDataSize(size_t inDataSize); 33 | 34 | extern bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize); 35 | extern bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize); 36 | 37 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/Crypto/hmac.c: -------------------------------------------------------------------------------- 1 | // 2 | // hmac.c 3 | // OAuthConsumer 4 | // 5 | // Created by Jonathan Wight on 4/8/8. 6 | // Copyright 2008 Jonathan Wight. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | /* 27 | * Implementation of HMAC-SHA1. Adapted from example at http://tools.ietf.org/html/rfc2104 28 | 29 | */ 30 | 31 | #include "sha1.h" 32 | #include "hmac.h" 33 | 34 | #include 35 | #include 36 | 37 | void hmac_sha1(const unsigned char *inText, int inTextLength, unsigned char* inKey, const unsigned int inKeyLengthConst, unsigned char *outDigest) 38 | { 39 | const int B = 64; 40 | const size_t L = 20; 41 | 42 | SHA1_CTX theSHA1Context; 43 | unsigned char k_ipad[B + 1]; /* inner padding - key XORd with ipad */ 44 | unsigned char k_opad[B + 1]; /* outer padding - key XORd with opad */ 45 | 46 | /* if key is longer than 64 bytes reset it to key=SHA1 (key) */ 47 | unsigned int inKeyLength = inKeyLengthConst; 48 | if (inKeyLength > B) 49 | { 50 | SHA1Init(&theSHA1Context); 51 | SHA1Update(&theSHA1Context, inKey, inKeyLength); 52 | SHA1Final(inKey, &theSHA1Context); 53 | inKeyLength = L; 54 | } 55 | 56 | /* start out by storing key in pads */ 57 | memset(k_ipad, 0, sizeof k_ipad); 58 | memset(k_opad, 0, sizeof k_opad); 59 | memcpy(k_ipad, inKey, inKeyLength); 60 | memcpy(k_opad, inKey, inKeyLength); 61 | 62 | /* XOR key with ipad and opad values */ 63 | int i; 64 | for (i = 0; i < B; i++) 65 | { 66 | k_ipad[i] ^= 0x36; 67 | k_opad[i] ^= 0x5c; 68 | } 69 | 70 | /* 71 | * perform inner SHA1 72 | */ 73 | SHA1Init(&theSHA1Context); /* init context for 1st pass */ 74 | SHA1Update(&theSHA1Context, k_ipad, B); /* start with inner pad */ 75 | SHA1Update(&theSHA1Context, (unsigned char *)inText, inTextLength); /* then text of datagram */ 76 | SHA1Final((unsigned char *)outDigest, &theSHA1Context); /* finish up 1st pass */ 77 | 78 | /* 79 | * perform outer SHA1 80 | */ 81 | SHA1Init(&theSHA1Context); /* init context for 2nd 82 | * pass */ 83 | SHA1Update(&theSHA1Context, k_opad, B); /* start with outer pad */ 84 | SHA1Update(&theSHA1Context, outDigest, L); /* then results of 1st 85 | * hash */ 86 | SHA1Final(outDigest, &theSHA1Context); /* finish up 2nd pass */ 87 | 88 | } 89 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/Crypto/hmac.h: -------------------------------------------------------------------------------- 1 | // 2 | // hmac.h 3 | // OAuthConsumer 4 | // 5 | // Created by Jonathan Wight on 4/8/8. 6 | // Copyright 2008 Jonathan Wight. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #ifndef HMAC_H 27 | #define HMAC_H 1 28 | 29 | extern void hmac_sha1(const unsigned char *inText, int inTextLength, unsigned char* inKey, const unsigned int inKeyLength, unsigned char *outDigest); 30 | 31 | #endif /* HMAC_H */ 32 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/Crypto/sha1.c: -------------------------------------------------------------------------------- 1 | /* 2 | SHA-1 in C 3 | By Steve Reid 4 | 100% Public Domain 5 | 6 | Test Vectors (from FIPS PUB 180-1) 7 | "abc" 8 | A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D 9 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 10 | 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 11 | A million repetitions of "a" 12 | 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F 13 | */ 14 | 15 | /* #define LITTLE_ENDIAN * This should be #define'd if true. */ 16 | #if __LITTLE_ENDIAN__ 17 | #define LITTLE_ENDIAN 18 | #endif 19 | /* #define SHA1HANDSOFF * Copies data before messing with it. */ 20 | 21 | #include 22 | #include 23 | 24 | #include "sha1.h" 25 | 26 | void SHA1Transform(unsigned long state[5], unsigned char buffer[64]); 27 | 28 | #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 29 | 30 | /* blk0() and blk() perform the initial expand. */ 31 | /* I got the idea of expanding during the round function from SSLeay */ 32 | #ifdef LITTLE_ENDIAN 33 | #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ 34 | |(rol(block->l[i],8)&0x00FF00FF)) 35 | #else 36 | #define blk0(i) block->l[i] 37 | #endif 38 | #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ 39 | ^block->l[(i+2)&15]^block->l[i&15],1)) 40 | 41 | /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ 42 | #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); 43 | #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); 44 | #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); 45 | #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); 46 | #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); 47 | 48 | 49 | /* Hash a single 512-bit block. This is the core of the algorithm. */ 50 | 51 | void SHA1Transform(unsigned long state[5], unsigned char buffer[64]) 52 | { 53 | unsigned long a, b, c, d, e; 54 | typedef union { 55 | unsigned char c[64]; 56 | unsigned long l[16]; 57 | } CHAR64LONG16; 58 | CHAR64LONG16* block; 59 | #ifdef SHA1HANDSOFF 60 | static unsigned char workspace[64]; 61 | block = (CHAR64LONG16*)workspace; 62 | memcpy(block, buffer, 64); 63 | #else 64 | block = (CHAR64LONG16*)buffer; 65 | #endif 66 | /* Copy context->state[] to working vars */ 67 | a = state[0]; 68 | b = state[1]; 69 | c = state[2]; 70 | d = state[3]; 71 | e = state[4]; 72 | /* 4 rounds of 20 operations each. Loop unrolled. */ 73 | R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); 74 | R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); 75 | R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); 76 | R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); 77 | R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); 78 | R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); 79 | R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); 80 | R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); 81 | R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); 82 | R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); 83 | R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); 84 | R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); 85 | R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); 86 | R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); 87 | R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); 88 | R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); 89 | R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); 90 | R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); 91 | R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); 92 | R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); 93 | /* Add the working vars back into context.state[] */ 94 | state[0] += a; 95 | state[1] += b; 96 | state[2] += c; 97 | state[3] += d; 98 | state[4] += e; 99 | /* Wipe variables */ 100 | a = b = c = d = e = 0; 101 | 102 | (void)a; (void)b; (void)c; (void)d; (void)e; 103 | } 104 | 105 | 106 | /* SHA1Init - Initialize new context */ 107 | 108 | void SHA1Init(SHA1_CTX* context) 109 | { 110 | /* SHA1 initialization constants */ 111 | context->state[0] = 0x67452301; 112 | context->state[1] = 0xEFCDAB89; 113 | context->state[2] = 0x98BADCFE; 114 | context->state[3] = 0x10325476; 115 | context->state[4] = 0xC3D2E1F0; 116 | context->count[0] = context->count[1] = 0; 117 | } 118 | 119 | 120 | /* Run your data through this. */ 121 | 122 | void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len) 123 | { 124 | unsigned int i, j; 125 | 126 | j = (context->count[0] >> 3) & 63; 127 | if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; 128 | context->count[1] += (len >> 29); 129 | if ((j + len) > 63) { 130 | memcpy(&context->buffer[j], data, (i = 64-j)); 131 | SHA1Transform(context->state, context->buffer); 132 | for ( ; i + 63 < len; i += 64) { 133 | SHA1Transform(context->state, &data[i]); 134 | } 135 | j = 0; 136 | } 137 | else i = 0; 138 | memcpy(&context->buffer[j], &data[i], len - i); 139 | } 140 | 141 | 142 | /* Add padding and return the message digest. */ 143 | 144 | void SHA1Final(unsigned char digest[20], SHA1_CTX* context) 145 | { 146 | unsigned long i, j; 147 | unsigned char finalcount[8]; 148 | 149 | for (i = 0; i < 8; i++) { 150 | finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] 151 | >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ 152 | } 153 | SHA1Update(context, (unsigned char *)"\200", 1); 154 | while ((context->count[0] & 504) != 448) { 155 | SHA1Update(context, (unsigned char *)"\0", 1); 156 | } 157 | SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ 158 | for (i = 0; i < 20; i++) { 159 | digest[i] = (unsigned char) 160 | ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); 161 | } 162 | /* Wipe variables */ 163 | i = j = 0; 164 | 165 | (void)i; (void)j; 166 | 167 | memset(context->buffer, 0, 64); 168 | memset(context->state, 0, 20); 169 | memset(context->count, 0, 8); 170 | memset(&finalcount, 0, 8); 171 | #ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ 172 | SHA1Transform(context->state, context->buffer); 173 | #endif 174 | } 175 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/Crypto/sha1.h: -------------------------------------------------------------------------------- 1 | 2 | // From http://www.mirrors.wiretapped.net/security/cryptography/hashes/sha1/sha1.c 3 | 4 | typedef struct { 5 | unsigned long state[5]; 6 | unsigned long count[2]; 7 | unsigned char buffer[64]; 8 | } SHA1_CTX; 9 | 10 | extern void SHA1Init(SHA1_CTX* context); 11 | extern void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len); 12 | extern void SHA1Final(unsigned char digest[20], SHA1_CTX* context); 13 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OACall.h: -------------------------------------------------------------------------------- 1 | // 2 | // OACall.h 3 | // OAuthConsumer 4 | // 5 | // Created by Alberto García Hierro on 04/09/08. 6 | // Copyright 2008 Alberto García Hierro. All rights reserved. 7 | // bynotes.com 8 | 9 | #import 10 | 11 | @class OAProblem; 12 | @class OACall; 13 | 14 | @protocol OACallDelegate 15 | 16 | - (void)call:(OACall *)call failedWithError:(NSError *)error; 17 | - (void)call:(OACall *)call failedWithProblem:(OAProblem *)problem; 18 | 19 | @end 20 | 21 | @class OAConsumer; 22 | @class OAToken; 23 | @class OADataFetcher; 24 | @class OAMutableURLRequest; 25 | @class OAServiceTicket; 26 | 27 | @interface OACall : NSObject { 28 | NSURL *url; 29 | NSString *method; 30 | NSArray *parameters; 31 | NSDictionary *files; 32 | NSObject *delegate; 33 | SEL finishedSelector; 34 | OADataFetcher *fetcher; 35 | OAMutableURLRequest *request; 36 | OAServiceTicket *ticket; 37 | } 38 | 39 | @property(readonly) NSURL *url; 40 | @property(readonly) NSString *method; 41 | @property(readonly) NSArray *parameters; 42 | @property(readonly) NSDictionary *files; 43 | @property(nonatomic, retain) OAServiceTicket *ticket; 44 | 45 | - (id)init; 46 | - (id)initWithURL:(NSURL *)aURL; 47 | - (id)initWithURL:(NSURL *)aURL method:(NSString *)aMethod; 48 | - (id)initWithURL:(NSURL *)aURL parameters:(NSArray *)theParameters; 49 | - (id)initWithURL:(NSURL *)aURL method:(NSString *)aMethod parameters:(NSArray *)theParameters; 50 | - (id)initWithURL:(NSURL *)aURL parameters:(NSArray *)theParameters files:(NSDictionary*)theFiles; 51 | 52 | - (id)initWithURL:(NSURL *)aURL 53 | method:(NSString *)aMethod 54 | parameters:(NSArray *)theParameters 55 | files:(NSDictionary*)theFiles; 56 | 57 | - (void)perform:(OAConsumer *)consumer 58 | token:(OAToken *)token 59 | realm:(NSString *)realm 60 | delegate:(NSObject *)aDelegate 61 | didFinish:(SEL)finished; 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OACall.m: -------------------------------------------------------------------------------- 1 | // 2 | // OACall.m 3 | // OAuthConsumer 4 | // 5 | // Created by Alberto García Hierro on 04/09/08. 6 | // Copyright 2008 Alberto García Hierro. All rights reserved. 7 | // bynotes.com 8 | 9 | #import "OAConsumer.h" 10 | #import "OAToken.h" 11 | #import "OAProblem.h" 12 | #import "OADataFetcher.h" 13 | #import "OAServiceTicket.h" 14 | #import "OAMutableURLRequest.h" 15 | #import "OACall.h" 16 | 17 | #import "NSMutableURLRequest+Parameters.h" 18 | 19 | @interface OACall (Private) 20 | 21 | - (void)callFinished:(OAServiceTicket *)ticket withData:(NSData *)data; 22 | - (void)callFailed:(OAServiceTicket *)ticket withError:(NSError *)error; 23 | 24 | @end 25 | 26 | @implementation OACall 27 | 28 | @synthesize url, method, parameters, files, ticket; 29 | 30 | - (id)init { 31 | return [self initWithURL:nil 32 | method:nil 33 | parameters:nil 34 | files:nil]; 35 | } 36 | 37 | - (id)initWithURL:(NSURL *)aURL { 38 | return [self initWithURL:aURL 39 | method:nil 40 | parameters:nil 41 | files:nil]; 42 | } 43 | 44 | - (id)initWithURL:(NSURL *)aURL method:(NSString *)aMethod { 45 | return [self initWithURL:aURL 46 | method:aMethod 47 | parameters:nil 48 | files:nil]; 49 | } 50 | 51 | - (id)initWithURL:(NSURL *)aURL parameters:(NSArray *)theParameters { 52 | return [self initWithURL:aURL 53 | method:nil 54 | parameters:theParameters]; 55 | } 56 | 57 | - (id)initWithURL:(NSURL *)aURL method:(NSString *)aMethod parameters:(NSArray *)theParameters { 58 | return [self initWithURL:aURL 59 | method:aMethod 60 | parameters:theParameters 61 | files:nil]; 62 | } 63 | 64 | - (id)initWithURL:(NSURL *)aURL parameters:(NSArray *)theParameters files:(NSDictionary*)theFiles { 65 | return [self initWithURL:aURL 66 | method:@"POST" 67 | parameters:theParameters 68 | files:theFiles]; 69 | } 70 | 71 | - (id)initWithURL:(NSURL *)aURL 72 | method:(NSString *)aMethod 73 | parameters:(NSArray *)theParameters 74 | files:(NSDictionary*)theFiles { 75 | url = [aURL retain]; 76 | method = [aMethod retain]; 77 | parameters = [theParameters retain]; 78 | files = [theFiles retain]; 79 | fetcher = nil; 80 | request = nil; 81 | 82 | return self; 83 | } 84 | 85 | - (void)dealloc { 86 | [url release]; 87 | [method release]; 88 | [parameters release]; 89 | [files release]; 90 | [fetcher release]; 91 | [request release]; 92 | [ticket release]; 93 | [super dealloc]; 94 | } 95 | 96 | - (void)callFailed:(OAServiceTicket *)aTicket withError:(NSError *)error { 97 | NSLog(@"error body: %@", aTicket.body); 98 | self.ticket = aTicket; 99 | [aTicket release]; 100 | OAProblem *problem = [OAProblem problemWithResponseBody:ticket.body]; 101 | if (problem) { 102 | [delegate call:self failedWithProblem:problem]; 103 | } else { 104 | [delegate call:self failedWithError:error]; 105 | } 106 | } 107 | 108 | - (void)callFinished:(OAServiceTicket *)aTicket withData:(NSData *)data { 109 | self.ticket = aTicket; 110 | [aTicket release]; 111 | if (ticket.didSucceed) { 112 | // NSLog(@"Call body: %@", ticket.body); 113 | [delegate performSelector:finishedSelector withObject:self withObject:ticket.body]; 114 | } else { 115 | // NSLog(@"Failed call body: %@", ticket.body); 116 | [self callFailed:[ticket retain] withError:nil]; 117 | } 118 | } 119 | 120 | - (void)perform:(OAConsumer *)consumer 121 | token:(OAToken *)token 122 | realm:(NSString *)realm 123 | delegate:(NSObject *)aDelegate 124 | didFinish:(SEL)finished 125 | 126 | { 127 | delegate = aDelegate; 128 | finishedSelector = finished; 129 | 130 | request = [[OAMutableURLRequest alloc] initWithURL:url 131 | consumer:consumer 132 | token:token 133 | realm:realm 134 | signatureProvider:nil]; 135 | if(method) { 136 | [request setHTTPMethod:method]; 137 | } 138 | 139 | if (self.parameters) { 140 | [request setParameters:self.parameters]; 141 | } 142 | 143 | // if (self.files) { 144 | // for (NSString *key in self.files) { 145 | // [request attachFileWithName:@"file" filename:NSLocalizedString(@"Photo.jpg", @"") data:[self.files objectForKey:key]]; 146 | // } 147 | // } 148 | 149 | fetcher = [[OADataFetcher alloc] init]; 150 | [fetcher fetchDataWithRequest:request 151 | delegate:self 152 | didFinishSelector:@selector(callFinished:withData:) 153 | didFailSelector:@selector(callFailed:withError:)]; 154 | } 155 | 156 | /*- (BOOL)isEqual:(id)object { 157 | if ([object isKindOfClass:[self class]]) { 158 | return [self isEqualToCall:(OACall *)object]; 159 | } 160 | return NO; 161 | } 162 | 163 | - (BOOL)isEqualToCall:(OACall *)aCall { 164 | return (delegate == aCall->delegate 165 | && finishedSelector == aCall->finishedSelector 166 | && [url isEqualTo:aCall.url] 167 | && [method isEqualToString:aCall.method] 168 | && [parameters isEqualToArray:aCall.parameters] 169 | && [files isEqualToDictionary:aCall.files]); 170 | }*/ 171 | 172 | @end 173 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAConsumer.h: -------------------------------------------------------------------------------- 1 | // 2 | // OAConsumer.h 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import 28 | 29 | 30 | @interface OAConsumer : NSObject { 31 | @protected 32 | NSString *key; 33 | NSString *secret; 34 | } 35 | @property(copy, readwrite) NSString *key; 36 | @property(copy, readwrite) NSString *secret; 37 | 38 | - (id)initWithKey:(const NSString *)aKey secret:(const NSString *)aSecret; 39 | 40 | - (BOOL)isEqualToConsumer:(OAConsumer *)aConsumer; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAConsumer.m: -------------------------------------------------------------------------------- 1 | // 2 | // OAConsumer.m 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "OAConsumer.h" 27 | 28 | 29 | @implementation OAConsumer 30 | @synthesize key, secret; 31 | 32 | #pragma mark init 33 | 34 | - (id)initWithKey:(const NSString *)aKey secret:(const NSString *)aSecret { 35 | [super init]; 36 | self.key = [aKey retain]; 37 | self.secret = [aSecret retain]; 38 | return self; 39 | } 40 | 41 | - (BOOL)isEqual:(id)object { 42 | if ([object isKindOfClass:[self class]]) { 43 | return [self isEqualToConsumer:(OAConsumer*)object]; 44 | } 45 | return NO; 46 | } 47 | 48 | - (BOOL)isEqualToConsumer:(OAConsumer *)aConsumer { 49 | return ([self.key isEqualToString:aConsumer.key] && 50 | [self.secret isEqualToString:aConsumer.secret]); 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OADataFetcher.h: -------------------------------------------------------------------------------- 1 | // 2 | // OADataFetcher.h 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 11/5/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | #import "OAMutableURLRequest.h" 28 | #import "OAServiceTicket.h" 29 | 30 | 31 | @interface OADataFetcher : NSObject { 32 | @private 33 | OAMutableURLRequest *request; 34 | NSURLResponse *response; 35 | NSURLConnection *connection; 36 | NSMutableData *responseData; 37 | id delegate; 38 | SEL didFinishSelector; 39 | SEL didFailSelector; 40 | } 41 | 42 | @property (nonatomic, assign) id delegate; 43 | 44 | - (void)fetchDataWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OADataFetcher.m: -------------------------------------------------------------------------------- 1 | // 2 | // OADataFetcher.m 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 11/5/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import "OADataFetcher.h" 28 | 29 | 30 | @implementation OADataFetcher 31 | 32 | 33 | @synthesize delegate; 34 | 35 | - (id)init { 36 | [super init]; 37 | responseData = [[NSMutableData alloc] init]; 38 | return self; 39 | } 40 | 41 | - (void)dealloc { 42 | [connection release]; 43 | [response release]; 44 | [responseData release]; 45 | [request release]; 46 | [super dealloc]; 47 | } 48 | 49 | /* Protocol for async URL loading */ 50 | - (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)aResponse { 51 | [response release]; 52 | response = [aResponse retain]; 53 | [responseData setLength:0]; 54 | } 55 | 56 | - (void)connection:(NSURLConnection *)aConnection didFailWithError:(NSError *)error { 57 | OAServiceTicket *ticket = [[OAServiceTicket alloc] initWithRequest:request 58 | response:response 59 | data:responseData 60 | didSucceed:NO]; 61 | [ticket autorelease]; 62 | [delegate performSelector:didFailSelector withObject:ticket withObject:error]; 63 | [ticket release], ticket = nil; 64 | } 65 | 66 | - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 67 | [responseData appendData:data]; 68 | } 69 | 70 | - (void)connectionDidFinishLoading:(NSURLConnection *)connection { 71 | OAServiceTicket *ticket = [[OAServiceTicket alloc] initWithRequest:request 72 | response:response 73 | data:responseData 74 | didSucceed:[(NSHTTPURLResponse *)response statusCode] < 400]; 75 | [ticket autorelease]; 76 | [delegate performSelector:didFinishSelector withObject:ticket withObject:responseData]; 77 | [ticket release], ticket = nil; 78 | } 79 | 80 | - (void)fetchDataWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector { 81 | request = [aRequest retain]; 82 | delegate = aDelegate; 83 | didFinishSelector = finishSelector; 84 | didFailSelector = failSelector; 85 | 86 | [request prepare]; 87 | 88 | connection = [[NSURLConnection alloc] initWithRequest:aRequest delegate:self]; 89 | } 90 | 91 | @end 92 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAHMAC_SHA1SignatureProvider.h: -------------------------------------------------------------------------------- 1 | // 2 | // OAHMAC_SHA1SignatureProvider.h 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import 28 | #import "OASignatureProviding.h" 29 | 30 | 31 | @interface OAHMAC_SHA1SignatureProvider : NSObject 32 | @end 33 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAHMAC_SHA1SignatureProvider.m: -------------------------------------------------------------------------------- 1 | // 2 | // OAHMAC_SHA1SignatureProvider.m 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import "OAHMAC_SHA1SignatureProvider.h" 28 | 29 | // #include "hmac.h" 30 | #include "Base64Transcoder.h" 31 | 32 | #import 33 | #import 34 | 35 | @implementation OAHMAC_SHA1SignatureProvider 36 | 37 | - (NSString *)name { 38 | return @"HMAC-SHA1"; 39 | } 40 | 41 | - (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret { 42 | NSData *secretData = [secret dataUsingEncoding:NSUTF8StringEncoding]; 43 | NSData *clearTextData = [text dataUsingEncoding:NSUTF8StringEncoding]; 44 | unsigned char result[CC_SHA1_DIGEST_LENGTH]; 45 | 46 | // hmac_sha1((unsigned char *)[clearTextData bytes], [clearTextData length], (unsigned char *)[secretData bytes], [secretData length], result); 47 | 48 | CCHmac(kCCHmacAlgSHA1, (const void *)[secretData bytes], [secretData length], (const void *)[clearTextData bytes], [clearTextData length], result); 49 | 50 | //Base64 Encoding 51 | 52 | char base64Result[32]; 53 | size_t theResultLength = 32; 54 | Base64EncodeData(result, 20, base64Result, &theResultLength); 55 | NSData *theData = [NSData dataWithBytes:base64Result length:theResultLength]; 56 | 57 | NSString *base64EncodedResult = [[[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding] autorelease]; 58 | 59 | return base64EncodedResult; 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAMutableURLRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // OAMutableURLRequest.h 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import 28 | #import "OAConsumer.h" 29 | #import "OAToken.h" 30 | #import "OAHMAC_SHA1SignatureProvider.h" 31 | #import "OASignatureProviding.h" 32 | #import "NSMutableURLRequest+Parameters.h" 33 | #import "NSURL+Base.h" 34 | 35 | 36 | @interface OAMutableURLRequest : NSMutableURLRequest { 37 | @protected 38 | OAConsumer *consumer; 39 | OAToken *token; 40 | NSString *realm; 41 | NSString *signature; 42 | id signatureProvider; 43 | NSString *nonce; 44 | NSString *timestamp; 45 | } 46 | @property(readonly) NSString *signature; 47 | @property(readonly) NSString *nonce; 48 | 49 | - (id)initWithURL:(NSURL *)aUrl 50 | consumer:(OAConsumer *)aConsumer 51 | token:(OAToken *)aToken 52 | realm:(NSString *)aRealm 53 | signatureProvider:(id)aProvider; 54 | 55 | - (id)initWithURL:(NSURL *)aUrl 56 | consumer:(OAConsumer *)aConsumer 57 | token:(OAToken *)aToken 58 | realm:(NSString *)aRealm 59 | signatureProvider:(id)aProvider 60 | nonce:(NSString *)aNonce 61 | timestamp:(NSString *)aTimestamp; 62 | 63 | - (void)prepare; 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAMutableURLRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // OAMutableURLRequest.m 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import "OAMutableURLRequest.h" 28 | 29 | 30 | @interface OAMutableURLRequest (Private) 31 | - (void)_generateTimestamp; 32 | - (void)_generateNonce; 33 | - (NSString *)_signatureBaseString; 34 | @end 35 | 36 | @implementation OAMutableURLRequest 37 | @synthesize signature, nonce; 38 | 39 | #pragma mark init 40 | 41 | - (id)initWithURL:(NSURL *)aUrl 42 | consumer:(OAConsumer *)aConsumer 43 | token:(OAToken *)aToken 44 | realm:(NSString *)aRealm 45 | signatureProvider:(id)aProvider { 46 | [super initWithURL:aUrl 47 | cachePolicy:NSURLRequestReloadIgnoringCacheData 48 | timeoutInterval:10.0]; 49 | 50 | consumer = aConsumer; 51 | 52 | // empty token for Unauthorized Request Token transaction 53 | if (aToken == nil) { 54 | token = [[OAToken alloc] init]; 55 | } else { 56 | token = [aToken retain]; 57 | } 58 | 59 | if (aRealm == nil) { 60 | realm = @""; 61 | } else { 62 | realm = [aRealm copy]; 63 | } 64 | 65 | // default to HMAC-SHA1 66 | if (aProvider == nil) { 67 | signatureProvider = [[OAHMAC_SHA1SignatureProvider alloc] init]; 68 | } else { 69 | signatureProvider = [aProvider retain]; 70 | } 71 | 72 | [self _generateTimestamp]; 73 | [self _generateNonce]; 74 | 75 | return self; 76 | } 77 | 78 | // Setting a timestamp and nonce to known 79 | // values can be helpful for testing 80 | - (id)initWithURL:(NSURL *)aUrl 81 | consumer:(OAConsumer *)aConsumer 82 | token:(OAToken *)aToken 83 | realm:(NSString *)aRealm 84 | signatureProvider:(id)aProvider 85 | nonce:(NSString *)aNonce 86 | timestamp:(NSString *)aTimestamp { 87 | [self initWithURL:aUrl 88 | consumer:aConsumer 89 | token:aToken 90 | realm:aRealm 91 | signatureProvider:aProvider]; 92 | 93 | nonce = [aNonce copy]; 94 | timestamp = [aTimestamp copy]; 95 | 96 | return self; 97 | } 98 | 99 | - (void)prepare { 100 | // sign 101 | // NSLog(@"Base string is: %@", [self _signatureBaseString]); 102 | signature = [signatureProvider signClearText:[self _signatureBaseString] 103 | withSecret:[NSString stringWithFormat:@"%@&%@", 104 | consumer.secret, 105 | token.secret ? token.secret : @""]]; 106 | 107 | // set OAuth headers 108 | NSMutableArray *chunks = [[NSMutableArray alloc] init]; 109 | [chunks addObject:[NSString stringWithFormat:@"realm=\"%@\"", [realm encodedURLParameterString]]]; 110 | [chunks addObject:[NSString stringWithFormat:@"oauth_consumer_key=\"%@\"", [consumer.key encodedURLParameterString]]]; 111 | 112 | NSDictionary *tokenParameters = [token parameters]; 113 | for (NSString *k in tokenParameters) { 114 | [chunks addObject:[NSString stringWithFormat:@"%@=\"%@\"", k, [[tokenParameters objectForKey:k] encodedURLParameterString]]]; 115 | } 116 | 117 | [chunks addObject:[NSString stringWithFormat:@"oauth_signature_method=\"%@\"", [[signatureProvider name] encodedURLParameterString]]]; 118 | [chunks addObject:[NSString stringWithFormat:@"oauth_signature=\"%@\"", [signature encodedURLParameterString]]]; 119 | [chunks addObject:[NSString stringWithFormat:@"oauth_timestamp=\"%@\"", timestamp]]; 120 | [chunks addObject:[NSString stringWithFormat:@"oauth_nonce=\"%@\"", nonce]]; 121 | [chunks addObject:@"oauth_version=\"1.0\""]; 122 | 123 | NSString *oauthHeader = [NSString stringWithFormat:@"OAuth %@", [chunks componentsJoinedByString:@", "]]; 124 | [chunks release]; 125 | 126 | [self setValue:oauthHeader forHTTPHeaderField:@"Authorization"]; 127 | } 128 | 129 | - (void)_generateTimestamp { 130 | [timestamp release]; 131 | timestamp = [[NSString alloc]initWithFormat:@"%d", time(NULL)]; 132 | } 133 | 134 | - (void)_generateNonce { 135 | CFUUIDRef theUUID = CFUUIDCreate(NULL); 136 | CFStringRef string = CFUUIDCreateString(NULL, theUUID); 137 | 138 | CFRelease(theUUID); 139 | if (nonce) { 140 | CFRelease(nonce); 141 | } 142 | 143 | nonce = (NSString *)string; 144 | } 145 | 146 | - (NSString *)_signatureBaseString { 147 | // OAuth Spec, Section 9.1.1 "Normalize Request Parameters" 148 | // build a sorted array of both request parameters and OAuth header parameters 149 | NSDictionary *tokenParameters = [token parameters]; 150 | // 6 being the number of OAuth params in the Signature Base String 151 | NSMutableArray *parameterPairs = [[NSMutableArray alloc] initWithCapacity:(5 + [[self parameters] count] + [tokenParameters count])]; 152 | 153 | [parameterPairs addObject:[[[[OARequestParameter alloc] initWithName:@"oauth_consumer_key" value:consumer.key] autorelease] URLEncodedNameValuePair]]; 154 | [parameterPairs addObject:[[[[OARequestParameter alloc] initWithName:@"oauth_signature_method" value:[signatureProvider name]] autorelease] URLEncodedNameValuePair]]; 155 | [parameterPairs addObject:[[[[OARequestParameter alloc] initWithName:@"oauth_timestamp" value:timestamp] autorelease] URLEncodedNameValuePair]]; 156 | [parameterPairs addObject:[[[[OARequestParameter alloc] initWithName:@"oauth_nonce" value:nonce] autorelease] URLEncodedNameValuePair]]; 157 | [parameterPairs addObject:[[[[OARequestParameter alloc] initWithName:@"oauth_version" value:@"1.0"] autorelease] URLEncodedNameValuePair]]; 158 | 159 | 160 | for(NSString *k in tokenParameters) { 161 | [parameterPairs addObject:[[OARequestParameter requestParameter:k value:[tokenParameters objectForKey:k]] URLEncodedNameValuePair]]; 162 | } 163 | 164 | if (![[self valueForHTTPHeaderField:@"Content-Type"] hasPrefix:@"multipart/form-data"]) { 165 | for (OARequestParameter *param in [self parameters]) { 166 | [parameterPairs addObject:[param URLEncodedNameValuePair]]; 167 | } 168 | } 169 | 170 | [parameterPairs sortUsingSelector:@selector(compare:)]; 171 | NSString *normalizedRequestParameters = [parameterPairs componentsJoinedByString:@"&"]; 172 | [parameterPairs release]; 173 | 174 | // NSLog(@"Normalized: %@", normalizedRequestParameters); 175 | // OAuth Spec, Section 9.1.2 "Concatenate Request Elements" 176 | return [NSString stringWithFormat:@"%@&%@&%@", 177 | [self HTTPMethod], 178 | [[[self URL] URLStringWithoutQuery] encodedURLParameterString], 179 | [normalizedRequestParameters encodedURLString]]; 180 | } 181 | 182 | - (void) dealloc 183 | { 184 | [token release]; 185 | [(NSObject*)signatureProvider release]; 186 | [timestamp release]; 187 | CFRelease(nonce); 188 | [super dealloc]; 189 | } 190 | 191 | @end 192 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAPlaintextSignatureProvider.h: -------------------------------------------------------------------------------- 1 | // 2 | // OAPlaintextSignatureProvider.h 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import 28 | #import "OASignatureProviding.h" 29 | 30 | @interface OAPlaintextSignatureProvider : NSObject 31 | @end 32 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAPlaintextSignatureProvider.m: -------------------------------------------------------------------------------- 1 | // 2 | // OAPlaintextSignatureProvider.m 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import "OAPlaintextSignatureProvider.h" 28 | 29 | 30 | @implementation OAPlaintextSignatureProvider 31 | 32 | - (NSString *)name { 33 | return @"PLAINTEXT"; 34 | } 35 | 36 | - (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret { 37 | return secret; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAProblem.h: -------------------------------------------------------------------------------- 1 | // 2 | // OAProblem.h 3 | // OAuthConsumer 4 | // 5 | // Created by Alberto García Hierro on 03/09/08. 6 | // Copyright 2008 Alberto García Hierro. All rights reserved. 7 | // bynotes.com 8 | 9 | #import 10 | 11 | enum { 12 | kOAProblemSignatureMethodRejected = 0, 13 | kOAProblemParameterAbsent, 14 | kOAProblemVersionRejected, 15 | kOAProblemConsumerKeyUnknown, 16 | kOAProblemTokenRejected, 17 | kOAProblemSignatureInvalid, 18 | kOAProblemNonceUsed, 19 | kOAProblemTimestampRefused, 20 | kOAProblemTokenExpired, 21 | kOAProblemTokenNotRenewable 22 | }; 23 | 24 | @interface OAProblem : NSObject { 25 | const NSString *problem; 26 | } 27 | 28 | @property (readonly) const NSString *problem; 29 | 30 | - (id)initWithProblem:(const NSString *)aProblem; 31 | - (id)initWithResponseBody:(const NSString *)response; 32 | 33 | - (BOOL)isEqualToProblem:(OAProblem *)aProblem; 34 | - (BOOL)isEqualToString:(const NSString *)aProblem; 35 | - (BOOL)isEqualTo:(id)aProblem; 36 | - (int)code; 37 | 38 | + (OAProblem *)problemWithResponseBody:(const NSString *)response; 39 | 40 | + (const NSArray *)validProblems; 41 | 42 | + (OAProblem *)SignatureMethodRejected; 43 | + (OAProblem *)ParameterAbsent; 44 | + (OAProblem *)VersionRejected; 45 | + (OAProblem *)ConsumerKeyUnknown; 46 | + (OAProblem *)TokenRejected; 47 | + (OAProblem *)SignatureInvalid; 48 | + (OAProblem *)NonceUsed; 49 | + (OAProblem *)TimestampRefused; 50 | + (OAProblem *)TokenExpired; 51 | + (OAProblem *)TokenNotRenewable; 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAProblem.m: -------------------------------------------------------------------------------- 1 | // 2 | // OAProblem.m 3 | // OAuthConsumer 4 | // 5 | // Created by Alberto García Hierro on 03/09/08. 6 | // Copyright 2008 Alberto García Hierro. All rights reserved. 7 | // bynotes.com 8 | 9 | #import "OAProblem.h" 10 | 11 | const NSString *signature_method_rejected = @"signature_method_rejected"; 12 | const NSString *parameter_absent = @"parameter_absent"; 13 | const NSString *version_rejected = @"version_rejected"; 14 | const NSString *consumer_key_unknown = @"consumer_key_unknown"; 15 | const NSString *token_rejected = @"token_rejected"; 16 | const NSString *signature_invalid = @"signature_invalid"; 17 | const NSString *nonce_used = @"nonce_used"; 18 | const NSString *timestamp_refused = @"timestamp_refused"; 19 | const NSString *token_expired = @"token_expired"; 20 | const NSString *token_not_renewable = @"token_not_renewable"; 21 | 22 | @implementation OAProblem 23 | 24 | @synthesize problem; 25 | 26 | - (id)initWithPointer:(const NSString *) aPointer 27 | { 28 | [super init]; 29 | problem = aPointer; 30 | return self; 31 | } 32 | 33 | - (id)initWithProblem:(const NSString *) aProblem 34 | { 35 | NSUInteger idx = [[OAProblem validProblems] indexOfObject:aProblem]; 36 | if (idx == NSNotFound) { 37 | return nil; 38 | } 39 | 40 | return [self initWithPointer: [[OAProblem validProblems] objectAtIndex:idx]]; 41 | } 42 | 43 | - (id)initWithResponseBody:(const NSString *) response 44 | { 45 | NSArray *fields = [response componentsSeparatedByString:@"&"]; 46 | for (NSString *field in fields) { 47 | if ([field hasPrefix:@"oauth_problem="]) { 48 | NSString *value = [[field componentsSeparatedByString:@"="] objectAtIndex:1]; 49 | return [self initWithProblem:value]; 50 | } 51 | } 52 | 53 | return nil; 54 | } 55 | 56 | + (OAProblem *)problemWithResponseBody:(const NSString *) response 57 | { 58 | return [[[OAProblem alloc] initWithResponseBody:response] autorelease]; 59 | } 60 | 61 | + (const NSArray *)validProblems 62 | { 63 | static NSArray *array; 64 | if (!array) { 65 | array = [[NSArray alloc] initWithObjects:signature_method_rejected, 66 | parameter_absent, 67 | version_rejected, 68 | consumer_key_unknown, 69 | token_rejected, 70 | signature_invalid, 71 | nonce_used, 72 | timestamp_refused, 73 | token_expired, 74 | token_not_renewable, 75 | nil]; 76 | } 77 | 78 | return array; 79 | } 80 | 81 | - (BOOL)isEqualToProblem:(OAProblem *) aProblem 82 | { 83 | return [problem isEqualToString:(NSString *)aProblem->problem]; 84 | } 85 | 86 | - (BOOL)isEqualToString:(const NSString *) aProblem 87 | { 88 | return [problem isEqualToString:(NSString *)aProblem]; 89 | } 90 | 91 | - (BOOL)isEqualTo:(id) aProblem 92 | { 93 | if ([aProblem isKindOfClass:[NSString class]]) { 94 | return [self isEqualToString:aProblem]; 95 | } 96 | 97 | if ([aProblem isKindOfClass:[OAProblem class]]) { 98 | return [self isEqualToProblem:aProblem]; 99 | } 100 | 101 | return NO; 102 | } 103 | 104 | - (int)code { 105 | return [[[self class] validProblems] indexOfObject:problem]; 106 | } 107 | 108 | - (NSString *)description 109 | { 110 | return [NSString stringWithFormat:@"OAuth Problem: %@", (NSString *)problem]; 111 | } 112 | 113 | #pragma mark class_methods 114 | 115 | + (OAProblem *)SignatureMethodRejected 116 | { 117 | return [[[OAProblem alloc] initWithPointer:signature_method_rejected] autorelease]; 118 | } 119 | 120 | + (OAProblem *)ParameterAbsent 121 | { 122 | return [[[OAProblem alloc] initWithPointer:parameter_absent] autorelease]; 123 | } 124 | 125 | + (OAProblem *)VersionRejected 126 | { 127 | return [[[OAProblem alloc] initWithPointer:version_rejected] autorelease]; 128 | } 129 | 130 | + (OAProblem *)ConsumerKeyUnknown 131 | { 132 | return [[[OAProblem alloc] initWithPointer:consumer_key_unknown] autorelease]; 133 | } 134 | 135 | + (OAProblem *)TokenRejected 136 | { 137 | return [[[OAProblem alloc] initWithPointer:token_rejected] autorelease]; 138 | } 139 | 140 | + (OAProblem *)SignatureInvalid 141 | { 142 | return [[[OAProblem alloc] initWithPointer:signature_invalid] autorelease]; 143 | } 144 | 145 | + (OAProblem *)NonceUsed 146 | { 147 | return [[[OAProblem alloc] initWithPointer:nonce_used] autorelease]; 148 | } 149 | 150 | + (OAProblem *)TimestampRefused 151 | { 152 | return [[[OAProblem alloc] initWithPointer:timestamp_refused] autorelease]; 153 | } 154 | 155 | + (OAProblem *)TokenExpired 156 | { 157 | return [[[OAProblem alloc] initWithPointer:token_expired] autorelease]; 158 | } 159 | 160 | + (OAProblem *)TokenNotRenewable 161 | { 162 | return [[[OAProblem alloc] initWithPointer:token_not_renewable] autorelease]; 163 | } 164 | 165 | @end 166 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OARequestParameter.h: -------------------------------------------------------------------------------- 1 | // 2 | // OARequestParameter.h 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import 28 | #import "NSString+URLEncoding.h" 29 | 30 | 31 | @interface OARequestParameter : NSObject { 32 | @protected 33 | NSString *name; 34 | NSString *value; 35 | } 36 | @property(copy, readwrite) NSString *name; 37 | @property(copy, readwrite) NSString *value; 38 | 39 | - (id)initWithName:(NSString *)aName value:(NSString *)aValue; 40 | - (NSString *)URLEncodedName; 41 | - (NSString *)URLEncodedValue; 42 | - (NSString *)URLEncodedNameValuePair; 43 | 44 | - (BOOL)isEqualToRequestParameter:(OARequestParameter *)parameter; 45 | 46 | + (id)requestParameter:(NSString *)aName value:(NSString *)aValue; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OARequestParameter.m: -------------------------------------------------------------------------------- 1 | // 2 | // OARequestParameter.m 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import "OARequestParameter.h" 28 | 29 | 30 | @implementation OARequestParameter 31 | @synthesize name, value; 32 | 33 | - (id)initWithName:(NSString *)aName value:(NSString *)aValue { 34 | [super init]; 35 | self.name = aName; 36 | self.value = aValue; 37 | return self; 38 | } 39 | 40 | - (NSString *)URLEncodedName { 41 | return self.name; 42 | // return [self.name encodedURLParameterString]; 43 | } 44 | 45 | - (NSString *)URLEncodedValue { 46 | return [self.value encodedURLParameterString]; 47 | } 48 | 49 | - (NSString *)URLEncodedNameValuePair { 50 | return [NSString stringWithFormat:@"%@=%@", [self URLEncodedName], [self URLEncodedValue]]; 51 | } 52 | 53 | - (BOOL)isEqual:(id)object { 54 | if ([object isKindOfClass:[self class]]) { 55 | return [self isEqualToRequestParameter:(OARequestParameter *)object]; 56 | } 57 | 58 | return NO; 59 | } 60 | 61 | - (BOOL)isEqualToRequestParameter:(OARequestParameter *)parameter { 62 | return ([self.name isEqualToString:parameter.name] && 63 | [self.value isEqualToString:parameter.value]); 64 | } 65 | 66 | 67 | + (id)requestParameter:(NSString *)aName value:(NSString *)aValue 68 | { 69 | return [[[self alloc] initWithName:aName value:aValue] autorelease]; 70 | } 71 | 72 | - (void)dealloc{ 73 | [name release]; 74 | [value release]; 75 | [super dealloc]; 76 | } 77 | @end 78 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAServiceTicket.h: -------------------------------------------------------------------------------- 1 | // 2 | // OAServiceTicket.h 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 11/5/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import 28 | #import "OAMutableURLRequest.h" 29 | 30 | 31 | @interface OAServiceTicket : NSObject { 32 | @private 33 | OAMutableURLRequest *request; 34 | NSURLResponse *response; 35 | NSData *data; 36 | BOOL didSucceed; 37 | } 38 | @property(readonly) OAMutableURLRequest *request; 39 | @property(readonly) NSURLResponse *response; 40 | @property(readonly) NSData *data; 41 | @property(readonly) BOOL didSucceed; 42 | @property(readonly) NSString *body; 43 | 44 | - (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSURLResponse *)aResponse data:(NSData *)aData didSucceed:(BOOL)success; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAServiceTicket.m: -------------------------------------------------------------------------------- 1 | // 2 | // OAServiceTicket.m 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 11/5/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import "OAServiceTicket.h" 28 | 29 | 30 | @implementation OAServiceTicket 31 | @synthesize request, response, data, didSucceed; 32 | 33 | - (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSURLResponse *)aResponse data:(NSData *)aData didSucceed:(BOOL)success { 34 | [super init]; 35 | request = aRequest; 36 | response = aResponse; 37 | data = aData; 38 | didSucceed = success; 39 | return self; 40 | } 41 | 42 | - (NSString *)body 43 | { 44 | if (!data) { 45 | return nil; 46 | } 47 | 48 | return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; 49 | } 50 | 51 | - (NSString *)description { 52 | return [NSString stringWithFormat:@"", [self body]]; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OASignatureProviding.h: -------------------------------------------------------------------------------- 1 | // 2 | // OASignatureProviding.h 3 | // 4 | // Created by Jon Crosby on 10/19/07. 5 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | 26 | #import 27 | 28 | 29 | @protocol OASignatureProviding 30 | 31 | - (NSString *)name; 32 | - (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAToken.h: -------------------------------------------------------------------------------- 1 | // 2 | // OAToken.h 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | @interface OAToken : NSObject { 29 | @protected 30 | NSString *key; 31 | NSString *secret; 32 | NSString *verifier; 33 | NSString *session; 34 | NSNumber *duration; 35 | NSMutableDictionary *attributes; 36 | NSDate *created; 37 | BOOL renewable; 38 | BOOL forRenewal; 39 | } 40 | @property(retain, readwrite) NSString *key; 41 | @property(retain, readwrite) NSString *secret; 42 | @property(retain, readwrite) NSString *verifier; 43 | @property(retain, readwrite) NSString *session; 44 | @property(retain, readwrite) NSNumber *duration; 45 | @property(retain, readwrite) NSDictionary *attributes; 46 | @property(readwrite, getter=isForRenewal) BOOL forRenewal; 47 | 48 | - (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret; 49 | - (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret verifier:(NSString *)aVerifier session:(NSString *)aSession 50 | duration:(NSNumber *)aDuration attributes:(NSDictionary *)theAttributes created:(NSDate *)creation 51 | renewable:(BOOL)renew; 52 | - (id)initWithHTTPResponseBody:(NSString *)body; 53 | 54 | - (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix; 55 | - (int)storeInUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix; 56 | 57 | - (BOOL)isValid; 58 | 59 | - (void)setAttribute:(NSString *)aKey value:(NSString *)aValue; 60 | - (NSString *)attribute:(NSString *)aKey; 61 | - (void)setAttributesWithString:(NSString *)aAttributes; 62 | - (NSString *)attributeString; 63 | 64 | - (BOOL)hasExpired; 65 | - (BOOL)isRenewable; 66 | - (void)setDurationWithString:(NSString *)aDuration; 67 | - (BOOL)hasAttributes; 68 | - (NSDictionary *)parameters; 69 | 70 | - (BOOL)isEqualToToken:(OAToken *)aToken; 71 | 72 | + (void)removeFromUserDefaultsWithServiceProviderName:(const NSString *)provider prefix:(const NSString *)prefix; 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAToken.m: -------------------------------------------------------------------------------- 1 | // 2 | // OAToken.m 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import "NSString+URLEncoding.h" 28 | #import "OAToken.h" 29 | 30 | @interface OAToken (Private) 31 | 32 | + (NSString *)settingsKey:(const NSString *)name provider:(const NSString *)provider prefix:(const NSString *)prefix; 33 | + (id)loadSetting:(const NSString *)name provider:(const NSString *)provider prefix:(const NSString *)prefix; 34 | + (void)saveSetting:(NSString *)name object:(id)object provider:(const NSString *)provider prefix:(const NSString *)prefix; 35 | + (NSNumber *)durationWithString:(NSString *)aDuration; 36 | + (NSMutableDictionary *)attributesWithString:(NSString *)theAttributes; 37 | 38 | @end 39 | 40 | @implementation OAToken 41 | 42 | @synthesize key, secret, session, duration, forRenewal, verifier; 43 | 44 | #pragma mark init 45 | 46 | - (id)init { 47 | return [self initWithKey:nil secret:nil]; 48 | } 49 | 50 | - (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret { 51 | return [self initWithKey:aKey secret:aSecret verifier:nil session:nil duration:nil 52 | attributes:nil created:nil renewable:NO]; 53 | } 54 | 55 | - (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret verifier:(NSString *)aVerifier session:(NSString *)aSession 56 | duration:(NSNumber *)aDuration attributes:(NSDictionary *)theAttributes created:(NSDate *)creation 57 | renewable:(BOOL)renew { 58 | [super init]; 59 | self.key = aKey; 60 | self.secret = aSecret; 61 | self.verifier = aVerifier; 62 | self.session = aSession; 63 | self.duration = aDuration; 64 | self.attributes = theAttributes; 65 | created = [creation retain]; 66 | renewable = renew; 67 | forRenewal = NO; 68 | 69 | return self; 70 | } 71 | 72 | - (id)initWithHTTPResponseBody:(const NSString *)body { 73 | NSString *aKey = nil; 74 | NSString *aSecret = nil; 75 | NSString *aVerifier = nil; 76 | NSString *aSession = nil; 77 | NSNumber *aDuration = nil; 78 | NSDate *creationDate = nil; 79 | NSDictionary *attrs = nil; 80 | BOOL renew = NO; 81 | NSArray *pairs = [body componentsSeparatedByString:@"&"]; 82 | 83 | for (NSString *pair in pairs) { 84 | NSArray *elements = [pair componentsSeparatedByString:@"="]; 85 | if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token"]) { 86 | aKey = [elements objectAtIndex:1]; 87 | } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token_secret"]) { 88 | aSecret = [elements objectAtIndex:1]; 89 | } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_verifier"]) { 90 | aVerifier = [elements objectAtIndex:1]; 91 | } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_session_handle"]) { 92 | aSession = [elements objectAtIndex:1]; 93 | } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token_duration"]) { 94 | aDuration = [[self class] durationWithString:[elements objectAtIndex:1]]; 95 | creationDate = [NSDate date]; 96 | } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token_attributes"]) { 97 | attrs = [[self class] attributesWithString:[[elements objectAtIndex:1] decodedURLString]]; 98 | } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token_renewable"]) { 99 | NSString *lowerCase = [[elements objectAtIndex:1] lowercaseString]; 100 | if ([lowerCase isEqualToString:@"true"] || [lowerCase isEqualToString:@"t"]) { 101 | renew = YES; 102 | } 103 | } 104 | } 105 | 106 | return [self initWithKey:aKey secret:aSecret verifier:aVerifier session:aSession duration:aDuration 107 | attributes:attrs created:creationDate renewable:renew]; 108 | } 109 | 110 | - (id)initWithUserDefaultsUsingServiceProviderName:(const NSString *)provider prefix:(const NSString *)prefix { 111 | [super init]; 112 | self.key = [OAToken loadSetting:@"key" provider:provider prefix:prefix]; 113 | self.secret = [OAToken loadSetting:@"secret" provider:provider prefix:prefix]; 114 | self.verifier = [OAToken loadSetting:@"verifier" provider:provider prefix:prefix]; 115 | self.session = [OAToken loadSetting:@"session" provider:provider prefix:prefix]; 116 | self.duration = [OAToken loadSetting:@"duration" provider:provider prefix:prefix]; 117 | self.attributes = [OAToken loadSetting:@"attributes" provider:provider prefix:prefix]; 118 | created = [OAToken loadSetting:@"created" provider:provider prefix:prefix]; 119 | renewable = [[OAToken loadSetting:@"renewable" provider:provider prefix:prefix] boolValue]; 120 | 121 | if (![self isValid]) { 122 | [self autorelease]; 123 | return nil; 124 | } 125 | 126 | return self; 127 | } 128 | 129 | #pragma mark dealloc 130 | 131 | - (void)dealloc { 132 | self.key = nil; 133 | self.secret = nil; 134 | self.verifier = nil; 135 | self.duration = nil; 136 | self.attributes = nil; 137 | [super dealloc]; 138 | } 139 | 140 | #pragma mark settings 141 | 142 | - (BOOL)isValid { 143 | return (key != nil && ![key isEqualToString:@""] && secret != nil && ![secret isEqualToString:@""]); 144 | } 145 | 146 | - (int)storeInUserDefaultsWithServiceProviderName:(const NSString *)provider prefix:(const NSString *)prefix { 147 | [OAToken saveSetting:@"key" object:key provider:provider prefix:prefix]; 148 | [OAToken saveSetting:@"secret" object:secret provider:provider prefix:prefix]; 149 | [OAToken saveSetting:@"verifier" object:verifier provider:provider prefix:prefix]; 150 | [OAToken saveSetting:@"created" object:created provider:provider prefix:prefix]; 151 | [OAToken saveSetting:@"duration" object:duration provider:provider prefix:prefix]; 152 | [OAToken saveSetting:@"session" object:session provider:provider prefix:prefix]; 153 | [OAToken saveSetting:@"attributes" object:attributes provider:provider prefix:prefix]; 154 | [OAToken saveSetting:@"renewable" object:renewable ? @"t" : @"f" provider:provider prefix:prefix]; 155 | 156 | [[NSUserDefaults standardUserDefaults] synchronize]; 157 | return(0); 158 | } 159 | 160 | #pragma mark duration 161 | 162 | - (void)setDurationWithString:(NSString *)aDuration { 163 | self.duration = [[self class] durationWithString:aDuration]; 164 | } 165 | 166 | - (BOOL)hasExpired 167 | { 168 | return created && [created timeIntervalSinceNow] > [duration intValue]; 169 | } 170 | 171 | - (BOOL)isRenewable 172 | { 173 | return session && renewable && created && [created timeIntervalSinceNow] < (2 * [duration intValue]); 174 | } 175 | 176 | 177 | #pragma mark attributes 178 | 179 | - (void)setAttribute:(const NSString *)aKey value:(const NSString *)aAttribute { 180 | if (!attributes) { 181 | attributes = [[NSMutableDictionary alloc] init]; 182 | } 183 | [attributes setObject: aAttribute forKey: aKey]; 184 | } 185 | 186 | - (NSDictionary *)attributes { 187 | return [[attributes copy] autorelease]; 188 | } 189 | 190 | - (void)setAttributes:(NSDictionary *)theAttributes { 191 | [attributes release]; 192 | 193 | if (theAttributes) { 194 | attributes = [[NSMutableDictionary alloc] initWithDictionary:theAttributes]; 195 | }else { 196 | attributes = nil; 197 | } 198 | } 199 | 200 | - (BOOL)hasAttributes { 201 | return (attributes && [attributes count] > 0); 202 | } 203 | 204 | - (NSString *)attributeString { 205 | if (![self hasAttributes]) { 206 | return @""; 207 | } 208 | 209 | NSMutableArray *chunks = [[NSMutableArray alloc] init]; 210 | for(NSString *aKey in self->attributes) { 211 | [chunks addObject:[NSString stringWithFormat:@"%@:%@", aKey, [attributes objectForKey:aKey]]]; 212 | } 213 | NSString *attrs = [chunks componentsJoinedByString:@";"]; 214 | [chunks release]; 215 | return attrs; 216 | } 217 | 218 | - (NSString *)attribute:(NSString *)aKey 219 | { 220 | return [attributes objectForKey:aKey]; 221 | } 222 | 223 | - (void)setAttributesWithString:(NSString *)theAttributes 224 | { 225 | self.attributes = [[self class] attributesWithString:theAttributes]; 226 | } 227 | 228 | - (NSDictionary *)parameters 229 | { 230 | NSMutableDictionary *params = [[[NSMutableDictionary alloc] init] autorelease]; 231 | 232 | if (key) { 233 | [params setObject:key forKey:@"oauth_token"]; 234 | if ([self isForRenewal]) { 235 | [params setObject:session forKey:@"oauth_session_handle"]; 236 | } 237 | } else { 238 | if (duration) { 239 | [params setObject:[duration stringValue] forKey: @"oauth_token_duration"]; 240 | } 241 | if ([attributes count]) { 242 | [params setObject:[self attributeString] forKey:@"oauth_token_attributes"]; 243 | } 244 | } 245 | return params; 246 | } 247 | 248 | #pragma mark comparisions 249 | 250 | - (BOOL)isEqual:(id)object { 251 | if([object isKindOfClass:[self class]]) { 252 | return [self isEqualToToken:(OAToken *)object]; 253 | } 254 | return NO; 255 | } 256 | 257 | - (BOOL)isEqualToToken:(OAToken *)aToken { 258 | /* Since ScalableOAuth determines that the token may be 259 | renewed using the same key and secret, we must also 260 | check the creation date */ 261 | if ([self.key isEqualToString:aToken.key] && 262 | [self.secret isEqualToString:aToken.secret]) { 263 | /* May be nil */ 264 | if (created == aToken->created || [created isEqualToDate:aToken->created]) { 265 | return YES; 266 | } 267 | } 268 | 269 | return NO; 270 | } 271 | 272 | #pragma mark class_functions 273 | 274 | + (NSString *)settingsKey:(NSString *)name provider:(NSString *)provider prefix:(NSString *)prefix { 275 | return [NSString stringWithFormat:@"OAUTH_%@_%@_%@", provider, prefix, [name uppercaseString]]; 276 | } 277 | 278 | + (id)loadSetting:(NSString *)name provider:(NSString *)provider prefix:(NSString *)prefix { 279 | return [[NSUserDefaults standardUserDefaults] objectForKey:[self settingsKey:name 280 | provider:provider 281 | prefix:prefix]]; 282 | } 283 | 284 | + (void)saveSetting:(NSString *)name object:(id)object provider:(NSString *)provider prefix:(NSString *)prefix { 285 | [[NSUserDefaults standardUserDefaults] setObject:object forKey:[self settingsKey:name 286 | provider:provider 287 | prefix:prefix]]; 288 | } 289 | 290 | + (void)removeFromUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix { 291 | NSArray *keys = [NSArray arrayWithObjects:@"key", @"secret", @"created", @"duration", @"session", @"attributes", @"renewable", nil]; 292 | for(NSString *name in keys) { 293 | [[NSUserDefaults standardUserDefaults] removeObjectForKey:[OAToken settingsKey:name provider:provider prefix:prefix]]; 294 | } 295 | } 296 | 297 | + (NSNumber *)durationWithString:(NSString *)aDuration { 298 | NSUInteger length = [aDuration length]; 299 | unichar c = toupper([aDuration characterAtIndex:length - 1]); 300 | int mult; 301 | if (c >= '0' && c <= '9') { 302 | return [NSNumber numberWithInt:[aDuration intValue]]; 303 | } 304 | if (c == 'S') { 305 | mult = 1; 306 | } else if (c == 'H') { 307 | mult = 60 * 60; 308 | } else if (c == 'D') { 309 | mult = 60 * 60 * 24; 310 | } else if (c == 'W') { 311 | mult = 60 * 60 * 24 * 7; 312 | } else if (c == 'M') { 313 | mult = 60 * 60 * 24 * 30; 314 | } else if (c == 'Y') { 315 | mult = 60 * 60 * 365; 316 | } else { 317 | mult = 1; 318 | } 319 | 320 | return [NSNumber numberWithInt: mult * [[aDuration substringToIndex:length - 1] intValue]]; 321 | } 322 | 323 | + (NSDictionary *)attributesWithString:(NSString *)theAttributes { 324 | NSArray *attrs = [theAttributes componentsSeparatedByString:@";"]; 325 | NSMutableDictionary *dct = [[NSMutableDictionary alloc] init]; 326 | for (NSString *pair in attrs) { 327 | NSArray *elements = [pair componentsSeparatedByString:@":"]; 328 | [dct setObject:[elements objectAtIndex:1] forKey:[elements objectAtIndex:0]]; 329 | } 330 | return [dct autorelease]; 331 | } 332 | 333 | #pragma mark description 334 | 335 | - (NSString *)description { 336 | return [NSString stringWithFormat:@"Key \"%@\" Secret:\"%@\"", key, secret]; 337 | } 338 | 339 | @end 340 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OATokenManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // OATokenManager.h 3 | // OAuthConsumer 4 | // 5 | // Created by Alberto García Hierro on 01/09/08. 6 | // Copyright 2008 Alberto García Hierro. All rights reserved. 7 | // bynotes.com 8 | 9 | #import 10 | 11 | #import "OACall.h" 12 | 13 | @class OATokenManager; 14 | 15 | @protocol OATokenManagerDelegate 16 | 17 | - (BOOL)tokenManager:(OATokenManager *)manager failedCall:(OACall *)call withError:(NSError *)error; 18 | - (BOOL)tokenManager:(OATokenManager *)manager failedCall:(OACall *)call withProblem:(OAProblem *)problem; 19 | 20 | @optional 21 | 22 | - (BOOL)tokenManagerNeedsToken:(OATokenManager *)manager; 23 | 24 | @end 25 | 26 | @class OAConsumer; 27 | @class OAToken; 28 | 29 | @interface OATokenManager : NSObject { 30 | OAConsumer *consumer; 31 | OAToken *acToken; 32 | OAToken *reqToken; 33 | OAToken *initialToken; 34 | NSString *authorizedTokenKey; 35 | NSString *oauthBase; 36 | NSString *realm; 37 | NSString *callback; 38 | NSObject *delegate; 39 | NSMutableArray *calls; 40 | NSMutableArray *selectors; 41 | NSMutableDictionary *delegates; 42 | BOOL isDispatching; 43 | } 44 | 45 | 46 | - (id)init; 47 | 48 | - (id)initWithConsumer:(OAConsumer *)aConsumer token:(OAToken *)aToken oauthBase:(const NSString *)base 49 | realm:(const NSString *)aRealm callback:(const NSString *)aCallback 50 | delegate:(NSObject *)aDelegate; 51 | 52 | - (void)authorizedToken:(const NSString *)key; 53 | 54 | - (void)fetchData:(NSString *)aURL finished:(SEL)didFinish; 55 | 56 | - (void)fetchData:(NSString *)aURL method:(NSString *)aMethod parameters:(NSArray *)theParameters 57 | finished:(SEL)didFinish; 58 | 59 | - (void)fetchData:(NSString *)aURL method:(NSString *)aMethod parameters:(NSArray *)theParameters 60 | files:(NSDictionary *)theFiles finished:(SEL)didFinish; 61 | 62 | - (void)fetchData:(NSString *)aURL method:(NSString *)aMethod parameters:(NSArray *)theParameters 63 | files:(NSDictionary *)theFiles finished:(SEL)didFinish delegate:(NSObject*)aDelegate; 64 | 65 | - (void)call:(OACall *)call failedWithError:(NSError *)error; 66 | - (void)call:(OACall *)call failedWithProblem:(OAProblem *)problem; 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /Classes/oauthconsumer/OAuthConsumer.h: -------------------------------------------------------------------------------- 1 | // 2 | // OAuthConsumer.h 3 | // OAuthConsumer 4 | // 5 | // Created by Jon Crosby on 10/19/07. 6 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | #import "OAProblem.h" 28 | #import "OAToken.h" 29 | #import "OAConsumer.h" 30 | #import "OAMutableURLRequest.h" 31 | #import "NSString+URLEncoding.h" 32 | #import "NSMutableURLRequest+Parameters.h" 33 | #import "NSURL+Base.h" 34 | #import "OASignatureProviding.h" 35 | #import "OAHMAC_SHA1SignatureProvider.h" 36 | #import "OAPlaintextSignatureProvider.h" 37 | #import "OARequestParameter.h" 38 | #import "OAServiceTicket.h" 39 | #import "OADataFetcher.h" 40 | #import "OATokenManager.h" -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | TwitterFeed 2 | Created by http://github.com/iosdeveloper 3 | 4 | How to use TwitterFeed 5 | ====================== 6 | 7 | 1. Add existing frameworks to your own project: 8 | - libxml2.dylib 9 | - oauthconsumer requires it and MGTwitterEngine recommends it for XML parsing on the iPhone. 10 | - Add $SDKROOT/usr/include/libxml2 as a Header Search Path in project info for all targets. 11 | - Add USE_LIBXML=1 as a Preprocessor Macro in project info for all targets. 12 | - QuartzCore.framework 13 | - We use it for rounded corners around profile images. 14 | 15 | 2. Copy the source files into your own project. 16 | - You need everything from the Classes/TwitterFeed folder. 17 | - You need DetailViewController.h and DetailViewController.m. 18 | - If you don't want a detail view controller, uncomment 19 | [self setSelectionStyle:UITableViewCellSelectionStyleNone]; 20 | in TwitterFeedCell.m and remove the method 21 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; 22 | in TwitterFeed.m. 23 | - TwitterFeed is powered by MGTwitterEngine so you need everything from the Classes/MGTwitterEngine folder. 24 | - You also need everything from the Classes/oauthconsumer folder. oauthconsumer is only required by MGTwitterEngine but not needed for what we do. Altough, it could be useful for further use. 25 | 26 | 3. Make sure you #import TwitterFeed.h in every class you're going to use TwitterFeed from. 27 | 28 | 4. Example usage: 29 | [self.navigationController pushViewController: 30 | [[[TwitterFeed alloc] initWithUsername:@"twitter"] autorelease] animated:YES]; 31 | 32 | TwitterFeed license 33 | =================== 34 | 35 | Open source. Use at your own risk. 36 | 37 | MGTwitterEngine is available from: http://github.com/mattgemmell/MGTwitterEngine 38 | 39 | oauthconsumer is available from: http://github.com/ctshryock/oauthconsumer 40 | 41 | Includes MGTwitterEngine code by http://mattgemmell.com -------------------------------------------------------------------------------- /TwitterFeed-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | de.max-baeumle.twitterfeed 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | NSMainNibFile 28 | MainWindow 29 | 30 | 31 | -------------------------------------------------------------------------------- /TwitterFeed.xcodeproj/maxbaeumle.pbxuser: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | 1D3623240D0F684500981E51 /* AppDelegate.h */ = { 4 | uiCtxt = { 5 | sepNavIntBoundsRect = "{{0, 0}, {519, 245}}"; 6 | sepNavSelRange = "{0, 0}"; 7 | sepNavVisRange = "{0, 243}"; 8 | }; 9 | }; 10 | 1D3623250D0F684500981E51 /* AppDelegate.m */ = { 11 | uiCtxt = { 12 | sepNavIntBoundsRect = "{{0, 0}, {782, 364}}"; 13 | sepNavSelRange = "{0, 0}"; 14 | sepNavVisRange = "{0, 517}"; 15 | }; 16 | }; 17 | 1D6058900D05DD3D006BFB54 /* TwitterFeed */ = { 18 | activeExec = 0; 19 | executables = ( 20 | 36DF62A7138ABF4E00E28B14 /* TwitterFeed */, 21 | ); 22 | }; 23 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 24 | activeBuildConfigurationName = Debug; 25 | activeExecutable = 36DF62A7138ABF4E00E28B14 /* TwitterFeed */; 26 | activeTarget = 1D6058900D05DD3D006BFB54 /* TwitterFeed */; 27 | addToTargets = ( 28 | 1D6058900D05DD3D006BFB54 /* TwitterFeed */, 29 | ); 30 | breakpoints = ( 31 | ); 32 | codeSenseManager = 36DF62AC138ABF6C00E28B14 /* Code sense */; 33 | executables = ( 34 | 36DF62A7138ABF4E00E28B14 /* TwitterFeed */, 35 | ); 36 | perUserDictionary = { 37 | PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { 38 | PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; 39 | PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; 40 | PBXFileTableDataSourceColumnWidthsKey = ( 41 | 20, 42 | 341, 43 | 20, 44 | 48, 45 | 43, 46 | 43, 47 | 20, 48 | ); 49 | PBXFileTableDataSourceColumnsKey = ( 50 | PBXFileDataSource_FiletypeID, 51 | PBXFileDataSource_Filename_ColumnID, 52 | PBXFileDataSource_Built_ColumnID, 53 | PBXFileDataSource_ObjectSize_ColumnID, 54 | PBXFileDataSource_Errors_ColumnID, 55 | PBXFileDataSource_Warnings_ColumnID, 56 | PBXFileDataSource_Target_ColumnID, 57 | ); 58 | }; 59 | PBXPerProjectTemplateStateSaveDate = 327867596; 60 | PBXWorkspaceStateSaveDate = 327867596; 61 | }; 62 | sourceControlManager = 36DF62AB138ABF6C00E28B14 /* Source Control */; 63 | userBuildSettings = { 64 | }; 65 | }; 66 | 29B97316FDCFA39411CA2CEA /* main.m */ = { 67 | uiCtxt = { 68 | sepNavIntBoundsRect = "{{0, 0}, {519, 245}}"; 69 | sepNavSelRange = "{0, 0}"; 70 | sepNavVisRange = "{0, 293}"; 71 | }; 72 | }; 73 | 32CA4F630368D1EE00C91783 /* TwitterFeed_Prefix.pch */ = { 74 | uiCtxt = { 75 | sepNavIntBoundsRect = "{{0, 0}, {670, 245}}"; 76 | sepNavSelRange = "{0, 0}"; 77 | sepNavVisRange = "{0, 191}"; 78 | }; 79 | }; 80 | 36DF62A7138ABF4E00E28B14 /* TwitterFeed */ = { 81 | isa = PBXExecutable; 82 | activeArgIndices = ( 83 | ); 84 | argumentStrings = ( 85 | ); 86 | autoAttachOnCrash = 1; 87 | breakpointsEnabled = 0; 88 | configStateDict = { 89 | }; 90 | customDataFormattersEnabled = 1; 91 | dataTipCustomDataFormattersEnabled = 1; 92 | dataTipShowTypeColumn = 1; 93 | dataTipSortType = 0; 94 | debuggerPlugin = GDBDebugging; 95 | disassemblyDisplayState = 0; 96 | dylibVariantSuffix = ""; 97 | enableDebugStr = 1; 98 | environmentEntries = ( 99 | ); 100 | executableSystemSymbolLevel = 0; 101 | executableUserSymbolLevel = 0; 102 | libgmallocEnabled = 0; 103 | name = TwitterFeed; 104 | showTypeColumn = 0; 105 | sourceDirectories = ( 106 | ); 107 | }; 108 | 36DF62AB138ABF6C00E28B14 /* Source Control */ = { 109 | isa = PBXSourceControlManager; 110 | fallbackIsa = XCSourceControlManager; 111 | isSCMEnabled = 0; 112 | scmConfiguration = { 113 | repositoryNamesForRoots = { 114 | "" = ""; 115 | }; 116 | }; 117 | }; 118 | 36DF62AC138ABF6C00E28B14 /* Code sense */ = { 119 | isa = PBXCodeSenseManager; 120 | indexTemplatePath = ""; 121 | }; 122 | 36DF63A4138AC7EE00E28B14 /* TwitterFeed.h */ = { 123 | uiCtxt = { 124 | sepNavIntBoundsRect = "{{0, 0}, {530, 245}}"; 125 | sepNavSelRange = "{0, 0}"; 126 | sepNavVisRange = "{0, 354}"; 127 | }; 128 | }; 129 | 36DF63A5138AC7EE00E28B14 /* TwitterFeed.m */ = { 130 | uiCtxt = { 131 | sepNavIntBoundsRect = "{{0, 0}, {519, 1989}}"; 132 | sepNavSelRange = "{0, 0}"; 133 | sepNavVisRange = "{0, 340}"; 134 | }; 135 | }; 136 | 36DF63DB138ACD0700E28B14 /* Tweet.h */ = { 137 | uiCtxt = { 138 | sepNavIntBoundsRect = "{{0, 0}, {519, 245}}"; 139 | sepNavSelRange = "{0, 0}"; 140 | sepNavVisRange = "{0, 373}"; 141 | }; 142 | }; 143 | 36DF63DC138ACD0700E28B14 /* Tweet.m */ = { 144 | uiCtxt = { 145 | sepNavIntBoundsRect = "{{0, 0}, {519, 273}}"; 146 | sepNavSelRange = "{0, 0}"; 147 | sepNavVisRange = "{0, 316}"; 148 | }; 149 | }; 150 | 36DF63DE138ACDC400E28B14 /* TwitterFeedCell.h */ = { 151 | uiCtxt = { 152 | sepNavIntBoundsRect = "{{0, 0}, {519, 245}}"; 153 | sepNavSelRange = "{0, 0}"; 154 | sepNavVisRange = "{0, 155}"; 155 | }; 156 | }; 157 | 36DF63DF138ACDC400E28B14 /* TwitterFeedCell.m */ = { 158 | uiCtxt = { 159 | sepNavIntBoundsRect = "{{0, 0}, {663, 520}}"; 160 | sepNavSelRange = "{0, 0}"; 161 | sepNavVisRange = "{0, 587}"; 162 | }; 163 | }; 164 | 36DF63F7138AD47100E28B14 /* DetailViewController.h */ = { 165 | uiCtxt = { 166 | sepNavIntBoundsRect = "{{0, 0}, {519, 245}}"; 167 | sepNavSelRange = "{0, 0}"; 168 | sepNavVisRange = "{0, 218}"; 169 | }; 170 | }; 171 | 36DF63F8138AD47100E28B14 /* DetailViewController.m */ = { 172 | uiCtxt = { 173 | sepNavIntBoundsRect = "{{0, 0}, {586, 338}}"; 174 | sepNavSelRange = "{0, 0}"; 175 | sepNavVisRange = "{0, 412}"; 176 | }; 177 | }; 178 | } 179 | -------------------------------------------------------------------------------- /TwitterFeed_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'TwitterFeed' target in the 'TwitterFeed' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Created by http://github.com/iosdeveloper 4 | // 5 | 6 | #import 7 | 8 | int main(int argc, char *argv[]) { 9 | 10 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 11 | int retVal = UIApplicationMain(argc, argv, nil, nil); 12 | [pool release]; 13 | return retVal; 14 | } 15 | --------------------------------------------------------------------------------