Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 8784e62760
Fetching contributors…

Cannot retrieve contributors at this time

1668 lines (1306 sloc) 55.643 kb
//
// MGTwitterEngine.m
// MGTwitterEngine
//
// Created by Matt Gemmell on 10/02/2008.
// Copyright 2008 Instinctive Code.
//
#import "MGTwitterEngine.h"
#import "MGTwitterHTTPURLConnection.h"
#import "NSData+Base64.h"
#define USE_LIBXML 0
#if YAJL_AVAILABLE
#define API_FORMAT @"json"
#import "MGTwitterStatusesYAJLParser.h"
#import "MGTwitterMessagesYAJLParser.h"
#import "MGTwitterUsersYAJLParser.h"
#import "MGTwitterMiscYAJLParser.h"
#import "MGTwitterSearchYAJLParser.h"
#else
#define API_FORMAT @"xml"
#if USE_LIBXML
#import "MGTwitterStatusesLibXMLParser.h"
#import "MGTwitterMessagesLibXMLParser.h"
#import "MGTwitterUsersLibXMLParser.h"
#import "MGTwitterMiscLibXMLParser.h"
#else
#import "MGTwitterStatusesParser.h"
#import "MGTwitterUsersParser.h"
#import "MGTwitterMessagesParser.h"
#import "MGTwitterMiscParser.h"
#import "MGTwitterSocialGraphParser.h"
#endif
#endif
#define TWITTER_DOMAIN @"api.twitter.com/1"
#if YAJL_AVAILABLE
#define TWITTER_SEARCH_DOMAIN @"search.twitter.com"
#endif
#define HTTP_POST_METHOD @"POST"
#define MAX_MESSAGE_LENGTH 140 // Twitter recommends tweets of max 140 chars
#define MAX_NAME_LENGTH 20
#define MAX_EMAIL_LENGTH 40
#define MAX_URL_LENGTH 100
#define MAX_LOCATION_LENGTH 30
#define MAX_DESCRIPTION_LENGTH 160
#define DEFAULT_CLIENT_NAME @"MGTwitterEngine"
#define DEFAULT_CLIENT_VERSION @"1.0"
#define DEFAULT_CLIENT_URL @"http://mattgemmell.com/source"
#define DEFAULT_CLIENT_TOKEN @"mgtwitterengine"
#define URL_REQUEST_TIMEOUT 25.0 // Twitter usually fails quickly if it's going to fail at all.
@interface MGTwitterEngine (PrivateMethods)
// Utility methods
- (NSDateFormatter *)_HTTPDateFormatter;
- (NSString *)_queryStringWithBase:(NSString *)base parameters:(NSDictionary *)params prefixed:(BOOL)prefixed;
- (NSDate *)_HTTPToDate:(NSString *)httpDate;
- (NSString *)_dateToHTTP:(NSDate *)date;
- (NSString *)_encodeString:(NSString *)string;
// Connection/Request methods
- (NSString *)_sendRequestWithMethod:(NSString *)method
path:(NSString *)path
queryParameters:(NSDictionary *)params
body:(NSString *)body
requestType:(MGTwitterRequestType)requestType
responseType:(MGTwitterResponseType)responseType;
// Parsing methods
- (void)_parseDataForConnection:(MGTwitterHTTPURLConnection *)connection;
// Delegate methods
- (BOOL) _isValidDelegateForSelector:(SEL)selector;
@end
@implementation MGTwitterEngine
#pragma mark Constructors
+ (MGTwitterEngine *)twitterEngineWithDelegate:(NSObject *)theDelegate
{
return [[[MGTwitterEngine alloc] initWithDelegate:theDelegate] autorelease];
}
- (MGTwitterEngine *)initWithDelegate:(NSObject *)newDelegate
{
if (self = [super init]) {
_delegate = newDelegate; // deliberately weak reference
_connections = [[NSMutableDictionary alloc] initWithCapacity:0];
_clientName = [DEFAULT_CLIENT_NAME retain];
_clientVersion = [DEFAULT_CLIENT_VERSION retain];
_clientURL = [DEFAULT_CLIENT_URL retain];
_clientSourceToken = [DEFAULT_CLIENT_TOKEN retain];
_APIDomain = [TWITTER_DOMAIN retain];
#if YAJL_AVAILABLE
_searchDomain = [TWITTER_SEARCH_DOMAIN retain];
#endif
_secureConnection = YES;
_clearsCookies = NO;
#if YAJL_AVAILABLE
_deliveryOptions = MGTwitterEngineDeliveryAllResultsOption;
#endif
}
return self;
}
- (void)dealloc
{
_delegate = nil;
[[_connections allValues] makeObjectsPerformSelector:@selector(cancel)];
[_connections release];
[_username release];
[_password release];
[_clientName release];
[_clientVersion release];
[_clientURL release];
[_clientSourceToken release];
[_APIDomain release];
#if YAJL_AVAILABLE
[_searchDomain release];
#endif
[super dealloc];
}
#pragma mark Configuration and Accessors
+ (NSString *)version
{
// 1.0.0 = 22 Feb 2008
// 1.0.1 = 26 Feb 2008
// 1.0.2 = 04 Mar 2008
// 1.0.3 = 04 Mar 2008
// 1.0.4 = 11 Apr 2008
// 1.0.5 = 06 Jun 2008
// 1.0.6 = 05 Aug 2008
// 1.0.7 = 28 Sep 2008
// 1.0.8 = 01 Oct 2008
return @"1.0.8";
}
- (NSString *)username
{
return [[_username retain] autorelease];
}
- (NSString *)password
{
return [[_password retain] autorelease];
}
- (void)setUsername:(NSString *)newUsername password:(NSString *)newPassword
{
// Set new credentials.
[_username release];
_username = [newUsername retain];
[_password release];
_password = [newPassword retain];
if ([self clearsCookies]) {
// Remove all cookies for twitter, to ensure next connection uses new credentials.
NSString *urlString = [NSString stringWithFormat:@"%@://%@",
(_secureConnection) ? @"https" : @"http",
_APIDomain];
NSURL *url = [NSURL URLWithString:urlString];
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSEnumerator *enumerator = [[cookieStorage cookiesForURL:url] objectEnumerator];
NSHTTPCookie *cookie = nil;
while (cookie = [enumerator nextObject]) {
[cookieStorage deleteCookie:cookie];
}
}
}
- (NSString *)clientName
{
return [[_clientName retain] autorelease];
}
- (NSString *)clientVersion
{
return [[_clientVersion retain] autorelease];
}
- (NSString *)clientURL
{
return [[_clientURL retain] autorelease];
}
- (NSString *)clientSourceToken
{
return [[_clientSourceToken retain] autorelease];
}
- (void)setClientName:(NSString *)name version:(NSString *)version URL:(NSString *)url token:(NSString *)token;
{
[_clientName release];
_clientName = [name retain];
[_clientVersion release];
_clientVersion = [version retain];
[_clientURL release];
_clientURL = [url retain];
[_clientSourceToken release];
_clientSourceToken = [token retain];
}
- (NSString *)APIDomain
{
return [[_APIDomain retain] autorelease];
}
- (void)setAPIDomain:(NSString *)domain
{
[_APIDomain release];
if (!domain || [domain length] == 0) {
_APIDomain = [TWITTER_DOMAIN retain];
} else {
_APIDomain = [domain retain];
}
}
#if YAJL_AVAILABLE
- (NSString *)searchDomain
{
return [[_searchDomain retain] autorelease];
}
- (void)setSearchDomain:(NSString *)domain
{
[_searchDomain release];
if (!domain || [domain length] == 0) {
_searchDomain = [TWITTER_SEARCH_DOMAIN retain];
} else {
_searchDomain = [domain retain];
}
}
#endif
- (BOOL)usesSecureConnection
{
return _secureConnection;
}
- (void)setUsesSecureConnection:(BOOL)flag
{
_secureConnection = flag;
}
- (BOOL)clearsCookies
{
return _clearsCookies;
}
- (void)setClearsCookies:(BOOL)flag
{
_clearsCookies = flag;
}
#if YAJL_AVAILABLE
- (MGTwitterEngineDeliveryOptions)deliveryOptions
{
return _deliveryOptions;
}
- (void)setDeliveryOptions:(MGTwitterEngineDeliveryOptions)deliveryOptions
{
_deliveryOptions = deliveryOptions;
}
#endif
#pragma mark Connection methods
- (int)numberOfConnections
{
return [_connections count];
}
- (NSArray *)connectionIdentifiers
{
return [_connections allKeys];
}
- (void)closeConnection:(NSString *)connectionIdentifier
{
MGTwitterHTTPURLConnection *connection = [_connections objectForKey:connectionIdentifier];
if (connection) {
[connection cancel];
[_connections removeObjectForKey:connectionIdentifier];
if ([self _isValidDelegateForSelector:@selector(connectionFinished:)])
[_delegate connectionFinished:connectionIdentifier];
}
}
- (void)closeAllConnections
{
[[_connections allValues] makeObjectsPerformSelector:@selector(cancel)];
[_connections removeAllObjects];
}
#pragma mark Utility methods
- (NSDateFormatter *)_HTTPDateFormatter
{
// Returns a formatter for dates in HTTP format (i.e. RFC 822, updated by RFC 1123).
// e.g. "Sun, 06 Nov 1994 08:49:37 GMT"
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
//[dateFormatter setDateFormat:@"%a, %d %b %Y %H:%M:%S GMT"]; // won't work with -init, which uses new (unicode) format behaviour.
[dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
[dateFormatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss GMT"];
return dateFormatter;
}
- (NSString *)_queryStringWithBase:(NSString *)base parameters:(NSDictionary *)params prefixed:(BOOL)prefixed
{
// Append base if specified.
NSMutableString *str = [NSMutableString stringWithCapacity:0];
if (base) {
[str appendString:base];
}
// Append each name-value pair.
if (params) {
int i;
NSArray *names = [params allKeys];
for (i = 0; i < [names count]; i++) {
if (i == 0 && prefixed) {
[str appendString:@"?"];
} else if (i > 0) {
[str appendString:@"&"];
}
NSString *name = [names objectAtIndex:i];
[str appendString:[NSString stringWithFormat:@"%@=%@",
name, [self _encodeString:[params objectForKey:name]]]];
}
}
return str;
}
- (NSDate *)_HTTPToDate:(NSString *)httpDate
{
NSDateFormatter *dateFormatter = [self _HTTPDateFormatter];
return [dateFormatter dateFromString:httpDate];
}
- (NSString *)_dateToHTTP:(NSDate *)date
{
NSDateFormatter *dateFormatter = [self _HTTPDateFormatter];
return [dateFormatter stringFromDate:date];
}
- (NSString *)_encodeString:(NSString *)string
{
NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)string,
NULL,
(CFStringRef)@";/?:@&=$+{}<>,",
kCFStringEncodingUTF8);
return [result autorelease];
}
- (NSString *)getImageAtURL:(NSString *)urlString
{
// This is a method implemented for the convenience of the client,
// allowing asynchronous downloading of users' Twitter profile images.
NSString *encodedUrlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:encodedUrlString];
if (!url) {
return nil;
}
// Construct an NSMutableURLRequest for the URL and set appropriate request method.
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:URL_REQUEST_TIMEOUT];
// Create a connection using this request, with the default timeout and caching policy,
// and appropriate Twitter request and response types for parsing and error reporting.
MGTwitterHTTPURLConnection *connection;
connection = [[MGTwitterHTTPURLConnection alloc] initWithRequest:theRequest
delegate:self
requestType:MGTwitterImageRequest
responseType:MGTwitterImage];
if (!connection) {
return nil;
} else {
[_connections setObject:connection forKey:[connection identifier]];
[connection release];
}
return [connection identifier];
}
#pragma mark Request sending methods
#define SET_AUTHORIZATION_IN_HEADER 1
- (NSString *)_sendRequestWithMethod:(NSString *)method
path:(NSString *)path
queryParameters:(NSDictionary *)params
body:(NSString *)body
requestType:(MGTwitterRequestType)requestType
responseType:(MGTwitterResponseType)responseType
{
// Construct appropriate URL string.
NSString *fullPath = path;
if (params) {
fullPath = [self _queryStringWithBase:fullPath parameters:params prefixed:YES];
}
#if YAJL_AVAILABLE
NSString *domain = nil;
NSString *connectionType = nil;
if (requestType == MGTwitterSearchRequest || requestType == MGTwitterSearchCurrentTrendsRequest)
{
domain = _searchDomain;
connectionType = @"http";
}
else
{
domain = _APIDomain;
if (_secureConnection)
{
connectionType = @"https";
}
else
{
connectionType = @"http";
}
}
#else
NSString *domain = _APIDomain;
NSString *connectionType = nil;
if (_secureConnection)
{
connectionType = @"https";
}
else
{
connectionType = @"http";
}
#endif
#if SET_AUTHORIZATION_IN_HEADER
NSString *urlString = [NSString stringWithFormat:@"%@://%@/%@",
connectionType,
domain, fullPath];
#else
NSString *urlString = [NSString stringWithFormat:@"%@://%@:%@@%@/%@",
connectionType,
[self _encodeString:_username], [self _encodeString:_password],
domain, fullPath];
#endif
NSURL *finalURL = [NSURL URLWithString:urlString];
if (!finalURL) {
return nil;
}
#if DEBUG
if (YES) {
NSLog(@"MGTwitterEngine: finalURL = %@", finalURL);
}
#endif
// Construct an NSMutableURLRequest for the URL and set appropriate request method.
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:finalURL
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:URL_REQUEST_TIMEOUT];
if (method) {
[theRequest setHTTPMethod:method];
}
[theRequest setHTTPShouldHandleCookies:NO];
// Set headers for client information, for tracking purposes at Twitter.
[theRequest setValue:_clientName forHTTPHeaderField:@"X-Twitter-Client"];
[theRequest setValue:_clientVersion forHTTPHeaderField:@"X-Twitter-Client-Version"];
[theRequest setValue:_clientURL forHTTPHeaderField:@"X-Twitter-Client-URL"];
#if SET_AUTHORIZATION_IN_HEADER
if ([self username] && [self password]) {
// Set header for HTTP Basic authentication explicitly, to avoid problems with proxies and other intermediaries
NSString *authStr = [NSString stringWithFormat:@"%@:%@", [self username], [self password]];
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64EncodingWithLineLength:80]];
[theRequest setValue:authValue forHTTPHeaderField:@"Authorization"];
}
#endif
// Set the request body if this is a POST request.
BOOL isPOST = (method && [method isEqualToString:HTTP_POST_METHOD]);
if (isPOST) {
// Set request body, if specified (hopefully so), with 'source' parameter if appropriate.
NSString *finalBody = @"";
if (body) {
finalBody = [finalBody stringByAppendingString:body];
}
if (_clientSourceToken) {
finalBody = [finalBody stringByAppendingString:[NSString stringWithFormat:@"%@source=%@",
(body) ? @"&" : @"?" ,
_clientSourceToken]];
}
if (finalBody) {
[theRequest setHTTPBody:[finalBody dataUsingEncoding:NSUTF8StringEncoding]];
#if DEBUG
if (YES) {
NSLog(@"MGTwitterEngine: finalBody = %@", finalBody);
}
#endif
}
}
// Create a connection using this request, with the default timeout and caching policy,
// and appropriate Twitter request and response types for parsing and error reporting.
MGTwitterHTTPURLConnection *connection;
connection = [[MGTwitterHTTPURLConnection alloc] initWithRequest:theRequest
delegate:self
requestType:requestType
responseType:responseType];
if (!connection) {
return nil;
} else {
[_connections setObject:connection forKey:[connection identifier]];
[connection release];
}
return [connection identifier];
}
#pragma mark Parsing methods
#if YAJL_AVAILABLE
- (void)_parseDataForConnection:(MGTwitterHTTPURLConnection *)connection
{
NSString *identifier = [[[connection identifier] copy] autorelease];
NSData *jsonData = [[[connection data] copy] autorelease];
MGTwitterRequestType requestType = [connection requestType];
MGTwitterResponseType responseType = [connection responseType];
NSURL *URL = [connection URL];
#if DEBUG
if (NO) {
NSLog(@"MGTwitterEngine: jsonData = %@ from %@", [[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] autorelease], URL);
}
#endif
switch (responseType) {
case MGTwitterStatuses:
case MGTwitterStatus:
[MGTwitterStatusesYAJLParser parserWithJSON:jsonData delegate:self
connectionIdentifier:identifier requestType:requestType
responseType:responseType URL:URL deliveryOptions:_deliveryOptions];
break;
case MGTwitterUsers:
case MGTwitterUser:
[MGTwitterUsersYAJLParser parserWithJSON:jsonData delegate:self
connectionIdentifier:identifier requestType:requestType
responseType:responseType URL:URL deliveryOptions:_deliveryOptions];
break;
case MGTwitterDirectMessages:
case MGTwitterDirectMessage:
[MGTwitterMessagesYAJLParser parserWithJSON:jsonData delegate:self
connectionIdentifier:identifier requestType:requestType
responseType:responseType URL:URL deliveryOptions:_deliveryOptions];
break;
case MGTwitterMiscellaneous:
[MGTwitterMiscYAJLParser parserWithJSON:jsonData delegate:self
connectionIdentifier:identifier requestType:requestType
responseType:responseType URL:URL deliveryOptions:_deliveryOptions];
break;
case MGTwitterSearchResults:
[MGTwitterSearchYAJLParser parserWithJSON:jsonData delegate:self
connectionIdentifier:identifier requestType:requestType
responseType:responseType URL:URL deliveryOptions:_deliveryOptions];
break;
default:
break;
}
}
#else
- (void)_parseDataForConnection:(MGTwitterHTTPURLConnection *)connection
{
NSString *identifier = [[[connection identifier] copy] autorelease];
NSData *xmlData = [[[connection data] copy] autorelease];
MGTwitterRequestType requestType = [connection requestType];
MGTwitterResponseType responseType = [connection responseType];
#if USE_LIBXML
NSURL *URL = [connection URL];
switch (responseType) {
case MGTwitterStatuses:
case MGTwitterStatus:
[MGTwitterStatusesLibXMLParser parserWithXML:xmlData delegate:self
connectionIdentifier:identifier requestType:requestType
responseType:responseType URL:URL];
break;
case MGTwitterUsers:
case MGTwitterUser:
[MGTwitterUsersLibXMLParser parserWithXML:xmlData delegate:self
connectionIdentifier:identifier requestType:requestType
responseType:responseType URL:URL];
break;
case MGTwitterDirectMessages:
case MGTwitterDirectMessage:
[MGTwitterMessagesLibXMLParser parserWithXML:xmlData delegate:self
connectionIdentifier:identifier requestType:requestType
responseType:responseType URL:URL];
break;
case MGTwitterMiscellaneous:
[MGTwitterMiscLibXMLParser parserWithXML:xmlData delegate:self
connectionIdentifier:identifier requestType:requestType
responseType:responseType URL:URL];
break;
default:
break;
}
#else
// Determine which type of parser to use.
switch (responseType) {
case MGTwitterStatuses:
case MGTwitterStatus:
[MGTwitterStatusesParser parserWithXML:xmlData delegate:self
connectionIdentifier:identifier requestType:requestType
responseType:responseType];
break;
case MGTwitterUsers:
case MGTwitterUser:
[MGTwitterUsersParser parserWithXML:xmlData delegate:self
connectionIdentifier:identifier requestType:requestType
responseType:responseType];
break;
case MGTwitterDirectMessages:
case MGTwitterDirectMessage:
[MGTwitterMessagesParser parserWithXML:xmlData delegate:self
connectionIdentifier:identifier requestType:requestType
responseType:responseType];
break;
case MGTwitterMiscellaneous:
[MGTwitterMiscParser parserWithXML:xmlData delegate:self
connectionIdentifier:identifier requestType:requestType
responseType:responseType];
break;
case MGTwitterSocialGraph:
[MGTwitterSocialGraphParser parserWithXML:xmlData delegate:self
connectionIdentifier:identifier requestType:requestType
responseType:responseType];
default:
break;
}
#endif
}
#endif
#pragma mark Delegate methods
- (BOOL) _isValidDelegateForSelector:(SEL)selector
{
return ((_delegate != nil) && [_delegate respondsToSelector:selector]);
}
#pragma mark MGTwitterParserDelegate methods
- (void)parsingSucceededForRequest:(NSString *)identifier
ofResponseType:(MGTwitterResponseType)responseType
withParsedObjects:(NSArray *)parsedObjects
{
// Forward appropriate message to _delegate, depending on responseType.
switch (responseType) {
case MGTwitterStatuses:
case MGTwitterStatus:
if ([self _isValidDelegateForSelector:@selector(statusesReceived:forRequest:)])
[_delegate statusesReceived:parsedObjects forRequest:identifier];
break;
case MGTwitterUsers:
case MGTwitterUser:
if ([self _isValidDelegateForSelector:@selector(userInfoReceived:forRequest:)])
[_delegate userInfoReceived:parsedObjects forRequest:identifier];
break;
case MGTwitterDirectMessages:
case MGTwitterDirectMessage:
if ([self _isValidDelegateForSelector:@selector(directMessagesReceived:forRequest:)])
[_delegate directMessagesReceived:parsedObjects forRequest:identifier];
break;
case MGTwitterMiscellaneous:
if ([self _isValidDelegateForSelector:@selector(miscInfoReceived:forRequest:)])
[_delegate miscInfoReceived:parsedObjects forRequest:identifier];
break;
#if YAJL_AVAILABLE
case MGTwitterSearchResults:
if ([self _isValidDelegateForSelector:@selector(searchResultsReceived:forRequest:)])
[_delegate searchResultsReceived:parsedObjects forRequest:identifier];
break;
#endif
case MGTwitterSocialGraph:
if ([self _isValidDelegateForSelector:@selector(socialGraphInfoReceived:forRequest:)])
[_delegate socialGraphInfoReceived: parsedObjects forRequest:identifier];
break;
default:
break;
}
}
- (void)parsingFailedForRequest:(NSString *)requestIdentifier
ofResponseType:(MGTwitterResponseType)responseType
withError:(NSError *)error
{
if ([self _isValidDelegateForSelector:@selector(requestFailed:withError:)])
[_delegate requestFailed:requestIdentifier withError:error];
}
#if YAJL_AVAILABLE
- (void)parsedObject:(NSDictionary *)dictionary forRequest:(NSString *)requestIdentifier
ofResponseType:(MGTwitterResponseType)responseType
{
if ([self _isValidDelegateForSelector:@selector(receivedObject:forRequest:)])
[_delegate receivedObject:dictionary forRequest:requestIdentifier];
}
#endif
#pragma mark NSURLConnection delegate methods
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if (_username && _password && [challenge previousFailureCount] == 0 && ![challenge proposedCredential]) {
NSURLCredential *credential = [NSURLCredential credentialWithUser:_username password:_password
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
} else {
[[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
}
}
- (void)connection:(MGTwitterHTTPURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when the server has determined that it has enough information to create the NSURLResponse.
// it can be called multiple times, for example in the case of a redirect, so each time we reset the data.
[connection resetDataLength];
// Get response code.
NSHTTPURLResponse *resp = (NSHTTPURLResponse *)response;
int statusCode = [resp statusCode];
if (statusCode >= 400) {
// Assume failure, and report to delegate.
NSError *error = [NSError errorWithDomain:@"HTTP" code:statusCode userInfo:nil];
if ([self _isValidDelegateForSelector:@selector(requestFailed:withError:)])
[_delegate requestFailed:[connection identifier] withError:error];
// Destroy the connection.
[connection cancel];
NSString *connectionIdentifier = [connection identifier];
[_connections removeObjectForKey:connectionIdentifier];
if ([self _isValidDelegateForSelector:@selector(connectionFinished:)])
[_delegate connectionFinished:connectionIdentifier];
} else if (statusCode == 304 || [connection responseType] == MGTwitterGeneric) {
// Not modified, or generic success.
if ([self _isValidDelegateForSelector:@selector(requestSucceeded:)])
[_delegate requestSucceeded:[connection identifier]];
if (statusCode == 304) {
[self parsingSucceededForRequest:[connection identifier]
ofResponseType:[connection responseType]
withParsedObjects:[NSArray array]];
}
// Destroy the connection.
[connection cancel];
NSString *connectionIdentifier = [connection identifier];
[_connections removeObjectForKey:connectionIdentifier];
if ([self _isValidDelegateForSelector:@selector(connectionFinished:)])
[_delegate connectionFinished:connectionIdentifier];
}
#if DEBUG
if (NO) {
// Display headers for debugging.
NSHTTPURLResponse *resp = (NSHTTPURLResponse *)response;
NSLog(@"MGTwitterEngine: (%d) [%@]:\r%@",
[resp statusCode],
[NSHTTPURLResponse localizedStringForStatusCode:[resp statusCode]],
[resp allHeaderFields]);
}
#endif
}
- (void)connection:(MGTwitterHTTPURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to the receivedData.
[connection appendData:data];
}
- (void)connection:(MGTwitterHTTPURLConnection *)connection didFailWithError:(NSError *)error
{
// Inform delegate.
if ([self _isValidDelegateForSelector:@selector(requestFailed:withError:)])
[_delegate requestFailed:[connection identifier] withError:error];
// Release the connection.
NSString *connectionIdentifier = [connection identifier];
[_connections removeObjectForKey:connectionIdentifier];
if ([self _isValidDelegateForSelector:@selector(connectionFinished:)])
[_delegate connectionFinished:connectionIdentifier];
}
- (void)connectionDidFinishLoading:(MGTwitterHTTPURLConnection *)connection
{
// Inform delegate.
if ([self _isValidDelegateForSelector:@selector(requestSucceeded:)])
[_delegate requestSucceeded:[connection identifier]];
NSData *receivedData = [connection data];
if (receivedData) {
#if DEBUG
if (NO) {
// Dump data as string for debugging.
NSString *dataString = [NSString stringWithUTF8String:[receivedData bytes]];
NSLog(@"MGTwitterEngine: Succeeded! Received %d bytes of data:\r\r%@", [receivedData length], dataString);
}
if (NO) {
// Dump XML to file for debugging.
NSString *dataString = [NSString stringWithUTF8String:[receivedData bytes]];
[dataString writeToFile:[[NSString stringWithFormat:@"~/Desktop/twitter_messages.%@", API_FORMAT] stringByExpandingTildeInPath]
atomically:NO encoding:NSUnicodeStringEncoding error:NULL];
}
#endif
if ([connection responseType] == MGTwitterImage) {
// Create image from data.
#if TARGET_OS_IPHONE
UIImage *image = [[[UIImage alloc] initWithData:[connection data]] autorelease];
#else
NSImage *image = [[[NSImage alloc] initWithData:[connection data]] autorelease];
#endif
// Inform delegate.
if ([self _isValidDelegateForSelector:@selector(imageReceived:forRequest:)])
[_delegate imageReceived:image forRequest:[connection identifier]];
} else {
// Parse data from the connection (either XML or JSON.)
[self _parseDataForConnection:connection];
}
}
// Release the connection.
NSString *connectionIdentifier = [connection identifier];
[_connections removeObjectForKey:connectionIdentifier];
if ([self _isValidDelegateForSelector:@selector(connectionFinished:)])
[_delegate connectionFinished:connectionIdentifier];
}
#pragma mark -
#pragma mark REST API methods
#pragma mark -
#pragma mark Status methods
- (NSString *)getPublicTimeline
{
NSString *path = [NSString stringWithFormat:@"statuses/public_timeline.%@", API_FORMAT];
return [self _sendRequestWithMethod:nil path:path queryParameters:nil body:nil
requestType:MGTwitterPublicTimelineRequest
responseType:MGTwitterStatuses];
}
#pragma mark -
- (NSString *)getFollowedTimelineSinceID:(unsigned long)sinceID startingAtPage:(int)page count:(int)count
{
return [self getFollowedTimelineSinceID:sinceID withMaximumID:0 startingAtPage:page count:count];
}
- (NSString *)getFollowedTimelineSinceID:(unsigned long)sinceID withMaximumID:(unsigned long)maxID startingAtPage:(int)page count:(int)count
{
NSString *path = [NSString stringWithFormat:@"statuses/friends_timeline.%@", API_FORMAT];
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
if (sinceID > 0) {
[params setObject:[NSString stringWithFormat:@"%u", sinceID] forKey:@"since_id"];
}
if (maxID > 0) {
[params setObject:[NSString stringWithFormat:@"%u", maxID] forKey:@"max_id"];
}
if (page > 0) {
[params setObject:[NSString stringWithFormat:@"%d", page] forKey:@"page"];
}
if (count > 0) {
[params setObject:[NSString stringWithFormat:@"%d", count] forKey:@"count"];
}
return [self _sendRequestWithMethod:nil path:path queryParameters:params body:nil
requestType:MGTwitterFollowedTimelineRequest
responseType:MGTwitterStatuses];
}
#pragma mark -
- (NSString *)getUserTimelineFor:(NSString *)username sinceID:(unsigned long)sinceID startingAtPage:(int)page count:(int)count
{
return [self getUserTimelineFor:username sinceID:sinceID withMaximumID:0 startingAtPage:0 count:count];
}
- (NSString *)getUserTimelineFor:(NSString *)username sinceID:(unsigned long)sinceID withMaximumID:(unsigned long)maxID startingAtPage:(int)page count:(int)count
{
NSString *path = [NSString stringWithFormat:@"statuses/user_timeline.%@", API_FORMAT];
MGTwitterRequestType requestType = MGTwitterUserTimelineRequest;
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
if (sinceID > 0) {
[params setObject:[NSString stringWithFormat:@"%u", sinceID] forKey:@"since_id"];
}
if (maxID > 0) {
[params setObject:[NSString stringWithFormat:@"%u", maxID] forKey:@"max_id"];
}
if (page > 0) {
[params setObject:[NSString stringWithFormat:@"%d", page] forKey:@"page"];
}
if (count > 0) {
[params setObject:[NSString stringWithFormat:@"%d", count] forKey:@"count"];
}
if (username) {
path = [NSString stringWithFormat:@"statuses/user_timeline/%@.%@", username, API_FORMAT];
requestType = MGTwitterUserTimelineForUserRequest;
}
return [self _sendRequestWithMethod:nil path:path queryParameters:params body:nil
requestType:requestType
responseType:MGTwitterStatuses];
}
#pragma mark -
- (NSString *)getUpdate:(unsigned long)updateID
{
NSString *path = [NSString stringWithFormat:@"statuses/show/%u.%@", updateID, API_FORMAT];
return [self _sendRequestWithMethod:nil path:path queryParameters:nil body:nil
requestType:MGTwitterUpdateGetRequest
responseType:MGTwitterStatus];
}
- (NSString *)sendUpdate:(NSString *)status
{
return [self sendUpdate:status inReplyTo:0];
}
- (NSString *)sendUpdate:(NSString *)status inReplyTo:(unsigned long)updateID
{
if (!status) {
return nil;
}
NSString *path = [NSString stringWithFormat:@"statuses/update.%@", API_FORMAT];
NSString *trimmedText = status;
if ([trimmedText length] > MAX_MESSAGE_LENGTH) {
trimmedText = [trimmedText substringToIndex:MAX_MESSAGE_LENGTH];
}
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
[params setObject:trimmedText forKey:@"status"];
if (updateID > 0) {
[params setObject:[NSString stringWithFormat:@"%u", updateID] forKey:@"in_reply_to_status_id"];
}
NSString *body = [self _queryStringWithBase:nil parameters:params prefixed:NO];
return [self _sendRequestWithMethod:HTTP_POST_METHOD path:path
queryParameters:params body:body
requestType:MGTwitterUpdateSendRequest
responseType:MGTwitterStatus];
}
#pragma mark -
- (NSString *)getRepliesStartingAtPage:(int)page
{
return [self getRepliesSinceID:0 startingAtPage:page count:0]; // zero means default
}
- (NSString *)getRepliesSinceID:(unsigned long)sinceID startingAtPage:(int)page count:(int)count
{
return [self getRepliesSinceID:sinceID withMaximumID:0 startingAtPage:page count:count];
}
- (NSString *)getRepliesSinceID:(unsigned long)sinceID withMaximumID:(unsigned long)maxID startingAtPage:(int)page count:(int)count
{
// NOTE: identi.ca can't handle mentions URL yet...
// NSString *path = [NSString stringWithFormat:@"statuses/mentions.%@", API_FORMAT];
NSString *path = [NSString stringWithFormat:@"statuses/replies.%@", API_FORMAT];
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
if (sinceID > 0) {
[params setObject:[NSString stringWithFormat:@"%u", sinceID] forKey:@"since_id"];
}
if (maxID > 0) {
[params setObject:[NSString stringWithFormat:@"%u", maxID] forKey:@"max_id"];
}
if (page > 0) {
[params setObject:[NSString stringWithFormat:@"%d", page] forKey:@"page"];
}
if (count > 0) {
[params setObject:[NSString stringWithFormat:@"%d", count] forKey:@"count"];
}
return [self _sendRequestWithMethod:nil path:path queryParameters:params body:nil
requestType:MGTwitterRepliesRequest
responseType:MGTwitterStatuses];
}
#pragma mark -
- (NSString *)deleteUpdate:(unsigned long)updateID
{
NSString *path = [NSString stringWithFormat:@"statuses/destroy/%u.%@", updateID, API_FORMAT];
return [self _sendRequestWithMethod:HTTP_POST_METHOD path:path queryParameters:nil body:nil
requestType:MGTwitterUpdateDeleteRequest
responseType:MGTwitterStatus];
}
#pragma mark -
- (NSString *)getFeaturedUsers
{
NSString *path = [NSString stringWithFormat:@"statuses/featured.%@", API_FORMAT];
return [self _sendRequestWithMethod:nil path:path queryParameters:nil body:nil
requestType:MGTwitterFeaturedUsersRequest
responseType:MGTwitterUsers];
}
#pragma mark User methods
- (NSString *)getFriendIDsFor:(NSString *)username startingFromCursor:(int)cursor
{
NSLog(@"getFriendIDsFor:%@ atCursor:%d", username, cursor);
NSString *path = [NSString stringWithFormat:@"friends/ids.%@", API_FORMAT];
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
if (username != nil) {
[params setObject:username forKey:@"screen_name"];
}
if (cursor >= -1) {
[params setObject:[NSString stringWithFormat:@"%ld", cursor] forKey:@"cursor"];
}
return [self _sendRequestWithMethod:nil path:path queryParameters:params body:nil
requestType:MGTwitterFriendIDsRequest
responseType:MGTwitterSocialGraph];
}
- (NSString *)getFollowerIDsFor:(NSString *)username startingFromCursor:(int)cursor
{
NSString *path = [NSString stringWithFormat:@"followers/ids.%@", API_FORMAT];
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
if (username != nil) {
[params setObject:username forKey:@"screen_name"];
}
if (cursor >= -1) {
[params setObject:[NSString stringWithFormat:@"%ld", cursor] forKey:@"cursor"];
}
return [self _sendRequestWithMethod:nil path:path queryParameters:params body:nil
requestType:MGTwitterFollowerIDsRequest
responseType:MGTwitterSocialGraph];
}
- (NSString *)getRecentlyUpdatedFriendsFor:(NSString *)username startingAtPage:(int)page
{
NSString *path = [NSString stringWithFormat:@"statuses/friends.%@", API_FORMAT];
MGTwitterRequestType requestType = MGTwitterFriendUpdatesRequest;
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
if (username) {
path = [NSString stringWithFormat:@"statuses/friends/%@.%@", username, API_FORMAT];
requestType = MGTwitterFriendUpdatesForUserRequest;
}
if (page > 0) {
[params setObject:[NSString stringWithFormat:@"%d", page] forKey:@"page"];
}
return [self _sendRequestWithMethod:nil path:path queryParameters:params body:nil
requestType:requestType
responseType:MGTwitterUsers];
}
#pragma mark -
- (NSString *)getFollowersIncludingCurrentStatus:(BOOL)flag
{
NSString *path = [NSString stringWithFormat:@"statuses/followers.%@", API_FORMAT];
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
if (!flag) {
[params setObject:@"true" forKey:@"lite"]; // slightly bizarre, but correct.
}
return [self _sendRequestWithMethod:nil path:path queryParameters:params body:nil
requestType:MGTwitterFollowerUpdatesRequest
responseType:MGTwitterUsers];
}
#pragma mark -
- (NSString *)getUserInformationFor:(NSString *)usernameOrID
{
if (!usernameOrID) {
return nil;
}
NSString *path = [NSString stringWithFormat:@"users/show/%@.%@", usernameOrID, API_FORMAT];
return [self _sendRequestWithMethod:nil path:path queryParameters:nil body:nil
requestType:MGTwitterUserInformationRequest
responseType:MGTwitterUser];
}
- (NSString *)getUserInformationForEmail:(NSString *)email
{
NSString *path = [NSString stringWithFormat:@"users/show.%@", API_FORMAT];
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
if (email) {
[params setObject:email forKey:@"email"];
} else {
return nil;
}
return [self _sendRequestWithMethod:nil path:path queryParameters:params body:nil
requestType:MGTwitterUserInformationRequest
responseType:MGTwitterUser];
}
#pragma mark Direct Message methods
- (NSString *)getDirectMessagesSinceID:(unsigned long)sinceID startingAtPage:(int)page
{
return [self getDirectMessagesSinceID:sinceID withMaximumID:0 startingAtPage:page count:0];
}
- (NSString *)getDirectMessagesSinceID:(unsigned long)sinceID withMaximumID:(unsigned long)maxID startingAtPage:(int)page count:(int)count
{
NSString *path = [NSString stringWithFormat:@"direct_messages.%@", API_FORMAT];
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
if (sinceID > 0) {
[params setObject:[NSString stringWithFormat:@"%u", sinceID] forKey:@"since_id"];
}
if (maxID > 0) {
[params setObject:[NSString stringWithFormat:@"%u", maxID] forKey:@"max_id"];
}
if (page > 0) {
[params setObject:[NSString stringWithFormat:@"%d", page] forKey:@"page"];
}
if (count > 0) {
[params setObject:[NSString stringWithFormat:@"%d", count] forKey:@"count"];
}
return [self _sendRequestWithMethod:nil path:path queryParameters:params body:nil
requestType:MGTwitterDirectMessagesRequest
responseType:MGTwitterDirectMessages];
}
#pragma mark -
- (NSString *)getSentDirectMessagesSinceID:(unsigned long)sinceID startingAtPage:(int)page
{
return [self getSentDirectMessagesSinceID:sinceID withMaximumID:0 startingAtPage:page count:0];
}
- (NSString *)getSentDirectMessagesSinceID:(unsigned long)sinceID withMaximumID:(unsigned long)maxID startingAtPage:(int)page count:(int)count
{
NSString *path = [NSString stringWithFormat:@"direct_messages/sent.%@", API_FORMAT];
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
if (sinceID > 0) {
[params setObject:[NSString stringWithFormat:@"%u", sinceID] forKey:@"since_id"];
}
if (maxID > 0) {
[params setObject:[NSString stringWithFormat:@"%u", maxID] forKey:@"max_id"];
}
if (page > 0) {
[params setObject:[NSString stringWithFormat:@"%d", page] forKey:@"page"];
}
if (count > 0) {
[params setObject:[NSString stringWithFormat:@"%d", count] forKey:@"count"];
}
return [self _sendRequestWithMethod:nil path:path queryParameters:params body:nil
requestType:MGTwitterDirectMessagesSentRequest
responseType:MGTwitterDirectMessages];
}
#pragma mark -
- (NSString *)sendDirectMessage:(NSString *)message to:(NSString *)username
{
if (!message || !username) {
return nil;
}
NSString *path = [NSString stringWithFormat:@"direct_messages/new.%@", API_FORMAT];
NSString *trimmedText = message;
if ([trimmedText length] > MAX_MESSAGE_LENGTH) {
trimmedText = [trimmedText substringToIndex:MAX_MESSAGE_LENGTH];
}
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
[params setObject:trimmedText forKey:@"text"];
[params setObject:username forKey:@"user"];
NSString *body = [self _queryStringWithBase:nil parameters:params prefixed:NO];
return [self _sendRequestWithMethod:HTTP_POST_METHOD path:path
queryParameters:params body:body
requestType:MGTwitterDirectMessageSendRequest
responseType:MGTwitterDirectMessage];
}
- (NSString *)deleteDirectMessage:(unsigned long)updateID
{
NSString *path = [NSString stringWithFormat:@"direct_messages/destroy/%u.%@", updateID, API_FORMAT];
return [self _sendRequestWithMethod:HTTP_POST_METHOD path:path queryParameters:nil body:nil
requestType:MGTwitterDirectMessageDeleteRequest
responseType:MGTwitterDirectMessage];
}
#pragma mark Friendship methods
- (NSString *)enableUpdatesFor:(NSString *)username
{
// i.e. follow
if (!username) {
return nil;
}
NSString *path = [NSString stringWithFormat:@"friendships/create/%@.%@", username, API_FORMAT];
return [self _sendRequestWithMethod:HTTP_POST_METHOD path:path queryParameters:nil body:nil
requestType:MGTwitterUpdatesEnableRequest
responseType:MGTwitterUser];
}
- (NSString *)disableUpdatesFor:(NSString *)username
{
// i.e. no longer follow
if (!username) {
return nil;
}
NSString *path = [NSString stringWithFormat:@"friendships/destroy/%@.%@", username, API_FORMAT];
return [self _sendRequestWithMethod:HTTP_POST_METHOD path:path queryParameters:nil body:nil
requestType:MGTwitterUpdatesDisableRequest
responseType:MGTwitterUser];
}
- (NSString *)isUser:(NSString *)username1 receivingUpdatesFor:(NSString *)username2
{
if (!username1 || !username2) {
return nil;
}
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
[params setObject:username1 forKey:@"user_a"];
[params setObject:username2 forKey:@"user_b"];
NSString *path = [NSString stringWithFormat:@"friendships/exists.%@", API_FORMAT];
return [self _sendRequestWithMethod:nil path:path queryParameters:params body:nil
requestType:MGTwitterUpdatesCheckRequest
responseType:MGTwitterMiscellaneous];
}
#pragma mark Account methods
- (NSString *)checkUserCredentials
{
NSString *path = [NSString stringWithFormat:@"account/verify_credentials.%@", API_FORMAT];
return [self _sendRequestWithMethod:nil path:path queryParameters:nil body:nil
requestType:MGTwitterAccountRequest
responseType:MGTwitterUser];
}
- (NSString *)endUserSession
{
NSString *path = @"account/end_session"; // deliberately no format specified
return [self _sendRequestWithMethod:nil path:path queryParameters:nil body:nil
requestType:MGTwitterAccountRequest
responseType:MGTwitterGeneric];
}
#pragma mark -
// TODO: this API is deprecated, change to account/update_profile
- (NSString *)setLocation:(NSString *)location
{
if (!location) {
return nil;
}
NSString *path = [NSString stringWithFormat:@"account/update_location.%@", API_FORMAT];
NSString *trimmedLocation = location;
if ([trimmedLocation length] > MAX_LOCATION_LENGTH) {
trimmedLocation = [trimmedLocation substringToIndex:MAX_LOCATION_LENGTH];
}
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
[params setObject:trimmedLocation forKey:@"location"];
NSString *body = [self _queryStringWithBase:nil parameters:params prefixed:NO];
return [self _sendRequestWithMethod:HTTP_POST_METHOD path:path
queryParameters:params body:body
requestType:MGTwitterAccountLocationRequest
responseType:MGTwitterUser];
}
#pragma mark -
- (NSString *)setNotificationsDeliveryMethod:(NSString *)method
{
NSString *deliveryMethod = method;
if (!method || [method length] == 0) {
deliveryMethod = @"none";
}
NSString *path = [NSString stringWithFormat:@"account/update_delivery_device.%@", API_FORMAT];
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
if (deliveryMethod) {
[params setObject:deliveryMethod forKey:@"device"];
}
return [self _sendRequestWithMethod:HTTP_POST_METHOD path:path queryParameters:params body:nil
requestType:MGTwitterAccountDeliveryRequest
responseType:MGTwitterUser];
}
#pragma mark -
- (NSString *)getRateLimitStatus
{
NSString *path = [NSString stringWithFormat:@"account/rate_limit_status.%@", API_FORMAT];
return [self _sendRequestWithMethod:nil path:path queryParameters:nil body:nil
requestType:MGTwitterAccountStatusRequest
responseType:MGTwitterMiscellaneous];
}
#pragma mark Favorite methods
- (NSString *)getFavoriteUpdatesFor:(NSString *)username startingAtPage:(int)page
{
NSString *path = [NSString stringWithFormat:@"favorites.%@", API_FORMAT];
MGTwitterRequestType requestType = MGTwitterFavoritesRequest;
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
if (page > 0) {
[params setObject:[NSString stringWithFormat:@"%d", page] forKey:@"page"];
}
if (username) {
path = [NSString stringWithFormat:@"favorites/%@.%@", username, API_FORMAT];
requestType = MGTwitterFavoritesForUserRequest;
}
return [self _sendRequestWithMethod:nil path:path queryParameters:params body:nil
requestType:requestType
responseType:MGTwitterStatuses];
}
#pragma mark -
- (NSString *)markUpdate:(unsigned long)updateID asFavorite:(BOOL)flag
{
NSString *path = nil;
MGTwitterRequestType requestType;
if (flag)
{
path = [NSString stringWithFormat:@"favorites/create/%u.%@", updateID, API_FORMAT];
requestType = MGTwitterFavoritesEnableRequest;
}
else {
path = [NSString stringWithFormat:@"favorites/destroy/%u.%@", updateID, API_FORMAT];
requestType = MGTwitterFavoritesDisableRequest;
}
return [self _sendRequestWithMethod:HTTP_POST_METHOD path:path queryParameters:nil body:nil
requestType:requestType
responseType:MGTwitterStatus];
}
#pragma mark Notification methods
- (NSString *)enableNotificationsFor:(NSString *)username
{
if (!username) {
return nil;
}
NSString *path = [NSString stringWithFormat:@"notifications/follow/%@.%@", username, API_FORMAT];
return [self _sendRequestWithMethod:HTTP_POST_METHOD path:path queryParameters:nil body:nil
requestType:MGTwitterNotificationsEnableRequest
responseType:MGTwitterUser];
}
- (NSString *)disableNotificationsFor:(NSString *)username
{
if (!username) {
return nil;
}
NSString *path = [NSString stringWithFormat:@"notifications/leave/%@.%@", username, API_FORMAT];
return [self _sendRequestWithMethod:HTTP_POST_METHOD path:path queryParameters:nil body:nil
requestType:MGTwitterNotificationsDisableRequest
responseType:MGTwitterUser];
}
#pragma mark Block methods
- (NSString *)block:(NSString *)username
{
if (!username) {
return nil;
}
NSString *path = [NSString stringWithFormat:@"blocks/create/%@.%@", username, API_FORMAT];
return [self _sendRequestWithMethod:HTTP_POST_METHOD path:path queryParameters:nil body:nil
requestType:MGTwitterBlockEnableRequest
responseType:MGTwitterUser];
}
- (NSString *)unblock:(NSString *)username
{
if (!username) {
return nil;
}
NSString *path = [NSString stringWithFormat:@"blocks/destroy/%@.%@", username, API_FORMAT];
return [self _sendRequestWithMethod:HTTP_POST_METHOD path:path queryParameters:nil body:nil
requestType:MGTwitterBlockDisableRequest
responseType:MGTwitterUser];
}
#pragma mark Help methods
- (NSString *)testService
{
NSString *path = [NSString stringWithFormat:@"help/test.%@", API_FORMAT];
return [self _sendRequestWithMethod:nil path:path queryParameters:nil body:nil
requestType:MGTwitterAccountRequest
responseType:MGTwitterMiscellaneous];
}
- (NSString *)getDowntimeSchedule
{
NSString *path = [NSString stringWithFormat:@"help/downtime_schedule.%@", API_FORMAT];
return [self _sendRequestWithMethod:nil path:path queryParameters:nil body:nil
requestType:MGTwitterAccountRequest
responseType:MGTwitterMiscellaneous];
}
#if YAJL_AVAILABLE
#pragma mark -
#pragma mark Search API methods
#pragma mark -
#pragma mark Search
- (NSString *)getSearchResultsForQuery:(NSString *)query
{
return [self getSearchResultsForQuery:query sinceID:0 startingAtPage:0 count:0]; // zero means default
}
- (NSString *)getSearchResultsForQuery:(NSString *)query sinceID:(unsigned long)sinceID startingAtPage:(int)page count:(int)count
{
return [self getSearchResultsForQuery:query sinceID:sinceID startingAtPage:0 count:0 geocode:nil]; // zero means default
}
- (NSString *)getSearchResultsForQuery:(NSString *)query sinceID:(unsigned long)sinceID startingAtPage:(int)page count:(int)count geocode:(NSString *)geocode
{
NSString *path = [NSString stringWithFormat:@"search.%@", API_FORMAT];
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:0];
if (query) {
[params setObject:query forKey:@"q"];
}
if (sinceID > 0) {
[params setObject:[NSString stringWithFormat:@"%u", sinceID] forKey:@"since_id"];
}
if (page > 0) {
[params setObject:[NSString stringWithFormat:@"%d", page] forKey:@"page"];
}
if (count > 0) {
[params setObject:[NSString stringWithFormat:@"%d", count] forKey:@"rpp"];
}
if (geocode) {
[params setObject:geocode forKey:@"geocode"];
}
/*
NOTE: These parameters are also available but not implemented yet:
lang: restricts tweets to the given language, given by an ISO 639-1 code.
Ex: http://search.twitter.com/search.atom?lang=en&q=devo
geocode: returns tweets by users located within a given radius of the given latitude/longitude, where the user's
location is taken from their Twitter profile. The parameter value is specified by "latitide,longitude,radius",
where radius units must be specified as either "mi" (miles) or "km" (kilometers).
Note that you cannot use the near operator via the API to geocode arbitrary locations; however you can use this
geocode parameter to search near geocodes directly.
Ex: http://search.twitter.com/search.atom?geocode=40.757929%2C-73.985506%2C25km
*/
return [self _sendRequestWithMethod:nil path:path queryParameters:params body:nil
requestType:MGTwitterSearchRequest
responseType:MGTwitterSearchResults];
}
- (NSString *)getCurrentTrends
{
NSString *path = [NSString stringWithFormat:@"trends/current.%@", API_FORMAT];
return [self _sendRequestWithMethod:nil path:path queryParameters:nil body:nil
requestType:MGTwitterSearchCurrentTrendsRequest
responseType:MGTwitterSearchResults];
}
#endif
@end
Jump to Line
Something went wrong with that request. Please try again.