Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of https://code.google.com/p/xmppframework

  • Loading branch information...
commit 31817592f636f0a3c9597b56759e0209f7bdb09f 2 parents d62a19e + 5313480
@robbiehanson authored
Showing with 1,021 additions and 4,925 deletions.
  1. +1 −0  .gitignore
  2. +3 −0  .gitmodules
  3. +20 −3 Core/XMPPStream.h
  4. +245 −239 Core/XMPPStream.m
  5. +0 −37 Extensions/X-FACEBOOK-PLATFORM/XMPPStreamFacebook.h
  6. +0 −606 Extensions/X-FACEBOOK-PLATFORM/XMPPStreamFacebook.m
  7. +4 −1 Extensions/XEP-0054/CoreDataStorage/XMPPvCard.xcdatamodeld/.xccurrentversion
  8. +43 −0 Utilities/XMPPDigestAuthentication.h
  9. +182 −0 Utilities/XMPPDigestAuthentication.m
  10. +15 −0 Utilities/XMPPSASLAuthentication.h
  11. +32 −0 Utilities/XMPPXFacebookPlatformAuthentication.h
  12. +118 −0 Utilities/XMPPXFacebookPlatformAuthentication.m
  13. +1 −0  Vendor/facebook-ios-sdk
  14. +15 −1 Xcode/DesktopXMPP/XMPPStream.xcodeproj/project.pbxproj
  15. BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginNormal.png
  16. BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginNormal@2x.png
  17. BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginPressed.png
  18. BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginPressed@2x.png
  19. BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginWithFacebookNormal.png
  20. BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginWithFacebookNormal@2x.png
  21. BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginWithFacebookPressed.png
  22. BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginWithFacebookPressed@2x.png
  23. BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LogoutNormal.png
  24. BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LogoutNormal@2x.png
  25. BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LogoutPressed.png
  26. BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LogoutPressed@2x.png
  27. BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/runaround_image.jpg
  28. +0 −22 Xcode/Testing/FacebookTest/FBConnect/FBConnect.h
  29. BIN  Xcode/Testing/FacebookTest/FBConnect/FBDialog.bundle/images/close.png
  30. BIN  Xcode/Testing/FacebookTest/FBConnect/FBDialog.bundle/images/fbicon.png
  31. +0 −167 Xcode/Testing/FacebookTest/FBConnect/FBDialog.h
  32. +0 −656 Xcode/Testing/FacebookTest/FBConnect/FBDialog.m
  33. +0 −48 Xcode/Testing/FacebookTest/FBConnect/FBLoginDialog.h
  34. +0 −94 Xcode/Testing/FacebookTest/FBConnect/FBLoginDialog.m
  35. +0 −116 Xcode/Testing/FacebookTest/FBConnect/FBRequest.h
  36. +0 −363 Xcode/Testing/FacebookTest/FBConnect/FBRequest.m
  37. +0 −114 Xcode/Testing/FacebookTest/FBConnect/Facebook.h
  38. +0 −614 Xcode/Testing/FacebookTest/FBConnect/Facebook.m
  39. +0 −50 Xcode/Testing/FacebookTest/FBConnect/JSON/JSON.h
  40. +0 −68 Xcode/Testing/FacebookTest/FBConnect/JSON/NSObject+SBJSON.h
  41. +0 −53 Xcode/Testing/FacebookTest/FBConnect/JSON/NSObject+SBJSON.m
  42. +0 −58 Xcode/Testing/FacebookTest/FBConnect/JSON/NSString+SBJSON.h
  43. +0 −55 Xcode/Testing/FacebookTest/FBConnect/JSON/NSString+SBJSON.m
  44. +0 −75 Xcode/Testing/FacebookTest/FBConnect/JSON/SBJSON.h
  45. +0 −212 Xcode/Testing/FacebookTest/FBConnect/JSON/SBJSON.m
  46. +0 −86 Xcode/Testing/FacebookTest/FBConnect/JSON/SBJsonBase.h
  47. +0 −78 Xcode/Testing/FacebookTest/FBConnect/JSON/SBJsonBase.m
  48. +0 −87 Xcode/Testing/FacebookTest/FBConnect/JSON/SBJsonParser.h
  49. +0 −475 Xcode/Testing/FacebookTest/FBConnect/JSON/SBJsonParser.m
  50. +0 −129 Xcode/Testing/FacebookTest/FBConnect/JSON/SBJsonWriter.h
  51. +0 −237 Xcode/Testing/FacebookTest/FBConnect/JSON/SBJsonWriter.m
  52. +96 −107 Xcode/Testing/FacebookTest/FacebookTest.xcodeproj/project.pbxproj
  53. +5 −1 Xcode/Testing/FacebookTest/FacebookTest/FacebookTest-Info.plist
  54. +2 −2 Xcode/Testing/FacebookTest/FacebookTest/FacebookTestAppDelegate.h
  55. +59 −35 Xcode/Testing/FacebookTest/FacebookTest/FacebookTestAppDelegate.m
  56. +2 −0  Xcode/Testing/FacebookTest/FacebookTest/FacebookTestViewController.h
  57. +3 −0  Xcode/Testing/FacebookTest/FacebookTest/FacebookTestViewController.m
  58. +152 −30 Xcode/Testing/FacebookTest/FacebookTest/en.lproj/FacebookTestViewController.xib
  59. +5 −5 Xcode/iPhoneXMPP/Classes/iPhoneXMPPAppDelegate.m
  60. +1 −0  Xcode/iPhoneXMPP/Vendor/facebook-ios-sdk
  61. +17 −1 Xcode/iPhoneXMPP/iPhoneXMPP.xcodeproj/project.pbxproj
View
1  .gitignore
@@ -2,3 +2,4 @@
*.mode1v3
*.mode2v3
xcuserdata
+.DS_Store
View
3  .gitmodules
@@ -0,0 +1,3 @@
+[submodule "Vendor/facebook-ios-sdk"]
+ path = Vendor/facebook-ios-sdk
+ url = git://github.com/facebook/facebook-ios-sdk.git
View
23 Core/XMPPStream.h
@@ -62,6 +62,9 @@ typedef enum XMPPStreamErrorCode XMPPStreamErrorCode;
UInt16 hostPort;
NSString *tempPassword;
+ BOOL isAccessToken;
+
+ NSString *appId;
XMPPJID *myJID;
XMPPJID *remoteJID;
@@ -104,6 +107,12 @@ typedef enum XMPPStreamErrorCode XMPPStreamErrorCode;
- (id)initP2PFrom:(XMPPJID *)myJID;
/**
+ * Facebook Chat X-FACEBOOK-PLATFORM SASL authentication initialization.
+ * This is a convienence init method to help configure Facebook Chat.
+ **/
+- (id)initWithFacebookAppId:(NSString *)fbAppId;
+
+/**
* XMPPStream uses a multicast delegate.
* This allows one to add multiple delegates to a single XMPPStream instance,
* which makes it easier to separate various components and extensions.
@@ -120,6 +129,12 @@ typedef enum XMPPStreamErrorCode XMPPStreamErrorCode;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
+ * The appId can be passed to custom authentication classes.
+ * For example, the appId is used for Facebook Chat X-FACEBOOK-PLATFORM SASL authentication.
+**/
+@property (readwrite,copy) NSString *appId;
+
+/**
* The server's hostname that should be used to make the TCP connection.
* This may be a domain name (e.g. "deusty.com") or an IP address (e.g. "70.85.193.226").
*
@@ -405,12 +420,12 @@ typedef enum XMPPStreamErrorCode XMPPStreamErrorCode;
/**
* Authentication.
*
- * The authenticateWithPassword:error: method is asynchronous.
- * It will return immediately, and the delegate methods are used to determine success.
+ * The authenticateWithPassword:error: and authenticateWithFacebookAccessToken:error: methods are asynchronous.
+ * Each will return immediately, and the delegate methods are used to determine success.
* See the xmppStreamDidAuthenticate: and xmppStream:didNotAuthenticate: methods.
*
* If there is something immediately wrong, such as the stream is not connected,
- * this method will return NO and set the error.
+ * the method will return NO and set the error.
*
* The errPtr parameter is optional - you may pass nil.
*
@@ -425,8 +440,10 @@ typedef enum XMPPStreamErrorCode XMPPStreamErrorCode;
- (BOOL)supportsAnonymousAuthentication;
- (BOOL)supportsPlainAuthentication;
- (BOOL)supportsDigestMD5Authentication;
+- (BOOL)supportsXFacebookPlatformAuthentication;
- (BOOL)supportsDeprecatedPlainAuthentication;
- (BOOL)supportsDeprecatedDigestAuthentication;
+- (BOOL)authenticateWithFacebookAccessToken:(NSString *)accessToken error:(NSError **)errPtr;
- (BOOL)authenticateWithPassword:(NSString *)password error:(NSError **)errPtr;
- (BOOL)authenticateAnonymously:(NSError **)errPtr;
View
484 Core/XMPPStream.m
@@ -9,6 +9,8 @@
#import "XMPPLogging.h"
#import "NSData+XMPP.h"
#import "NSXMLElement+XMPP.h"
+#import "XMPPDigestAuthentication.h"
+#import "XMPPXFacebookPlatformAuthentication.h"
#import "XMPPSRVResolver.h"
#import "DDList.h"
@@ -43,6 +45,9 @@
NSString *const XMPPStreamErrorDomain = @"XMPPStreamErrorDomain";
NSString *const XMPPStreamDidChangeMyJIDNotification = @"XMPPStreamDidChangeMyJID";
+static NSString *const XMPPFacebookChatHostName = @"chat.facebook.com";
+
+
enum XMPPStreamFlags
{
kP2PInitiator = 1 << 0, // If set, we are the P2P initializer
@@ -64,35 +69,6 @@
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-@interface XMPPDigestAuthentication : NSObject
-{
- NSString *rspauth;
- NSString *realm;
- NSString *nonce;
- NSString *qop;
- NSString *username;
- NSString *password;
- NSString *cnonce;
- NSString *nc;
- NSString *digestURI;
-}
-
-- (id)initWithChallenge:(NSXMLElement *)challenge;
-
-- (NSString *)rspauth;
-
-- (NSString *)realm;
-- (void)setRealm:(NSString *)realm;
-
-- (void)setDigestURI:(NSString *)digestURI;
-
-- (void)setUsername:(NSString *)username password:(NSString *)password;
-
-- (NSString *)response;
-- (NSString *)base64EncodedFullResponse;
-
-@end
-
@interface XMPPStream (PrivateAPI)
- (void)cleanup;
@@ -197,6 +173,22 @@ - (id)initP2PFrom:(XMPPJID *)jid
return self;
}
+
+/**
+ * Facebook Chat X-FACEBOOK-PLATFORM SASL authentication initialization.
+ * This is a convienence init method to help configure Facebook Chat.
+**/
+- (id)initWithFacebookAppId:(NSString *)fbAppId
+{
+ if ((self = [self init]))
+ {
+ self.appId = fbAppId;
+ self.myJID = [XMPPJID jidWithString:XMPPFacebookChatHostName];
+ self.hostName = XMPPFacebookChatHostName;
+ }
+ return self;
+}
+
/**
* Standard deallocation method.
* Every object variable declared in the header file should be released here.
@@ -258,6 +250,47 @@ - (void)dealloc
#pragma mark Properties
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+- (NSString *)appId
+{
+ if (dispatch_get_current_queue() == xmppQueue)
+ {
+ return appId;
+ }
+ else
+ {
+ __block NSString *result;
+
+ dispatch_sync(xmppQueue, ^{
+ result = [appId retain];
+ });
+
+ return [result autorelease];
+ }
+}
+
+- (void)setAppId:(NSString *)newAppId
+{
+ if (dispatch_get_current_queue() == xmppQueue)
+ {
+ if (appId != newAppId)
+ {
+ [appId release];
+ appId = [newAppId copy];
+ }
+ }
+ else
+ {
+ NSString *newAppIdCopy = [newAppId copy];
+
+ dispatch_async(xmppQueue, ^{
+ [appId release];
+ appId = [newAppIdCopy retain];
+ });
+
+ [newAppIdCopy release];
+ }
+}
+
- (NSString *)hostName
{
if (dispatch_get_current_queue() == xmppQueue)
@@ -799,6 +832,14 @@ - (BOOL)connect:(NSError **)errPtr
// Notify delegates
[multicastDelegate xmppStreamWillConnect:self];
+
+ // Check for Facebook Chat and set hostName if not set.
+ // As of October 8, 2011, Facebook doesn't have their XMPP SRV records configured properly
+ // and we have to wait for the SRV timeout before trying the A record.
+ if ([hostName length] == 0 && [myJID.domain isEqualToString:XMPPFacebookChatHostName])
+ {
+ self.hostName = XMPPFacebookChatHostName;
+ }
if ([hostName length] == 0)
{
@@ -1238,6 +1279,20 @@ - (BOOL)supportsStartTLS
return result;
}
+- (void)sendSASLRequestForMechanism:(NSString *)mechanism
+{
+ NSString *auth = [NSString stringWithFormat:@"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='%@'/>", mechanism];
+
+ NSData *outgoingData = [auth dataUsingEncoding:NSUTF8StringEncoding];
+
+ XMPPLogSend(@"SEND: %@", auth);
+ numberOfBytesSent += [outgoingData length];
+
+ [asyncSocket writeData:outgoingData
+ withTimeout:TIMEOUT_XMPP_WRITE
+ tag:TAG_XMPP_WRITE_STREAM];
+}
+
- (void)sendStartTLSRequest
{
NSAssert(dispatch_get_current_queue() == xmppQueue, @"Invoked on incorrect queue");
@@ -1577,6 +1632,49 @@ - (BOOL)supportsDigestMD5Authentication
}
/**
+ * This method checks the stream features of the connected server to
+ * determine if X-FACEBOOK-PLATFORM authentication is supported.
+ * If we are not connected to a server, this method simply returns NO.
+ **/
+- (BOOL)supportsXFacebookPlatformAuthentication
+{
+ __block BOOL result = NO;
+
+ dispatch_block_t block = ^{
+
+ // The root element can be properly queried for authentication mechanisms anytime after the
+ // stream:features are received, and TLS has been setup (if required)
+ if (state >= STATE_XMPP_POST_NEGOTIATION)
+ {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSXMLElement *features = [rootElement elementForName:@"stream:features"];
+ NSXMLElement *mech = [features elementForName:@"mechanisms" xmlns:@"urn:ietf:params:xml:ns:xmpp-sasl"];
+
+ NSArray *mechanisms = [mech elementsForName:@"mechanism"];
+
+ for (NSXMLElement *mechanism in mechanisms)
+ {
+ if ([[mechanism stringValue] isEqualToString:@"X-FACEBOOK-PLATFORM"])
+ {
+ result = YES;
+ break;
+ }
+ }
+
+ [pool drain];
+ }
+ };
+
+ if (dispatch_get_current_queue() == xmppQueue)
+ block();
+ else
+ dispatch_sync(xmppQueue, block);
+
+ return result;
+}
+
+/**
* This method only applies to servers that don't support XMPP version 1.0, as defined in RFC 3920.
* With these servers, we attempt to discover supported authentication modes via the jabber:iq:auth namespace.
**/
@@ -1683,8 +1781,62 @@ - (BOOL)supportsDeprecatedDigestAuthentication
}
/**
+ * This method attempts to connect to the Facebook Chat servers
+ * using the Facebook OAuth token returned by the Facebook OAuth 2.0 authentication process.
+**/
+- (BOOL)authenticateWithFacebookAccessToken:(NSString *)accessToken error:(NSError **)errPtr
+{
+ XMPPLogTrace();
+
+ __block BOOL result = YES;
+ __block NSError *err = nil;
+
+ dispatch_block_t block = ^{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ if (![self supportsXFacebookPlatformAuthentication])
+ {
+ NSString *errMsg = @"The server does not support X-FACEBOOK-PLATFORM authentication.";
+ NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
+
+ err = [NSError errorWithDomain:XMPPStreamErrorDomain code:XMPPStreamUnsupportedAction userInfo:info];
+
+ [err retain];
+ [pool drain];
+
+ result = NO;
+ return_from_block;
+ }
+
+ // Save authentication information
+ isAccessToken = YES;
+ [tempPassword release];
+ tempPassword = [accessToken copy];
+
+ result = [self authenticateWithPassword:accessToken error:&err];
+
+ [err retain];
+ [pool drain];
+ };
+
+
+ if (dispatch_get_current_queue() == xmppQueue)
+ block();
+ else
+ dispatch_sync(xmppQueue, block);
+
+ if (errPtr)
+ *errPtr = [err autorelease];
+ else
+ [err release];
+
+ return result;
+}
+
+/**
* This method attempts to sign-in to the server using the configured myJID and given password.
- * If this method immediately fails
+ * This method also works with Facebook Chat and the Facebook user's password, but authenticating
+ * with authenticateWithFacebookAccessToken:error: is preferred by Facebook.
**/
- (BOOL)authenticateWithPassword:(NSString *)password error:(NSError **)errPtr
{
@@ -1724,20 +1876,20 @@ - (BOOL)authenticateWithPassword:(NSString *)password error:(NSError **)errPtr
return_from_block;
}
- if ([self supportsDigestMD5Authentication])
+ // Facebook authentication
+ if (isAccessToken)
+ {
+ [self sendSASLRequestForMechanism:@"X-FACEBOOK-PLATFORM"];
+
+ // Update state
+ state = STATE_XMPP_AUTH_1;
+ }
+ else if ([self supportsDigestMD5Authentication])
{
- NSString *auth = @"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/>";
-
- NSData *outgoingData = [auth dataUsingEncoding:NSUTF8StringEncoding];
-
- XMPPLogSend(@"SEND: %@", auth);
- numberOfBytesSent += [outgoingData length];
-
- [asyncSocket writeData:outgoingData
- withTimeout:TIMEOUT_XMPP_WRITE
- tag:TAG_XMPP_WRITE_STREAM];
+ [self sendSASLRequestForMechanism:@"DIGEST-MD5"];
// Save authentication information
+ isAccessToken = NO;
[tempPassword release];
tempPassword = [password copy];
@@ -1899,6 +2051,8 @@ - (BOOL)authenticateAnonymously:(NSError **)errPtr
withTimeout:TIMEOUT_XMPP_WRITE
tag:TAG_XMPP_WRITE_STREAM];
+ isAccessToken = NO;
+
// Update state
state = STATE_XMPP_AUTH_3;
@@ -2730,12 +2884,14 @@ - (void)handleRegistration:(NSXMLElement *)response
}
/**
- * After the authenticateUser:withPassword:resource method is invoked, a authentication message is sent to the server.
+ * After the authenticateWithPassword:error: or authenticateWithFacebookAccessToken:error: methods are invoked, an
+ * authentication message is sent to the server.
* If the server supports digest-md5 sasl authentication, it is used. Otherwise plain sasl authentication is used,
* assuming the server supports it.
*
- * Now if digest-md5 was used, we sent a challenge request, and we're waiting for a challenge response.
- * If plain sasl was used, we sent our authentication information, and we're waiting for a success response.
+ * Now if digest-md5 or X-FACEBOOK-PLATFORM was used, we sent a challenge request, and we're waiting for a
+ * challenge response. If plain sasl was used, we sent our authentication information, and we're waiting for a
+ * success response.
**/
- (void)handleAuth1:(NSXMLElement *)response
{
@@ -2743,7 +2899,7 @@ - (void)handleAuth1:(NSXMLElement *)response
XMPPLogTrace();
- if ([self supportsDigestMD5Authentication])
+ if ([self supportsDigestMD5Authentication] || isAccessToken)
{
// We're expecting a challenge response
// If we get anything else we can safely assume it's the equivalent of a failure response
@@ -2758,29 +2914,46 @@ - (void)handleAuth1:(NSXMLElement *)response
{
// Create authentication object from the given challenge
// We'll release this object at the end of this else block
- XMPPDigestAuthentication *auth = [[XMPPDigestAuthentication alloc] initWithChallenge:response];
-
- NSString *virtualHostName = [myJID domain];
- NSString *serverHostName = hostName;
-
- // Sometimes the realm isn't specified
- // In this case I believe the realm is implied as the virtual host name
- if (![auth realm])
- {
- if([virtualHostName length] > 0)
- [auth setRealm:virtualHostName];
- else
- [auth setRealm:serverHostName];
- }
-
- // Set digest-uri
- if([virtualHostName length] > 0)
- [auth setDigestURI:[NSString stringWithFormat:@"xmpp/%@", virtualHostName]];
- else
- [auth setDigestURI:[NSString stringWithFormat:@"xmpp/%@", serverHostName]];
-
- // Set username and password
- [auth setUsername:[myJID user] password:tempPassword];
+ id<XMPPSASLAuthentication> auth = nil;
+
+ if (isAccessToken)
+ {
+ auth = [[XMPPXFacebookPlatformAuthentication alloc] initWithChallenge:response
+ appId:self.appId
+ accessToken:tempPassword];
+
+ // Update state
+ state = STATE_XMPP_AUTH_3;
+ }
+ else
+ {
+ auth = [[XMPPDigestAuthentication alloc] initWithChallenge:response];
+
+ NSString *virtualHostName = [myJID domain];
+ NSString *serverHostName = hostName;
+
+ // Sometimes the realm isn't specified
+ // In this case I believe the realm is implied as the virtual host name
+ if (![(XMPPDigestAuthentication *)auth realm])
+ {
+ if([virtualHostName length] > 0)
+ [(XMPPDigestAuthentication *)auth setRealm:virtualHostName];
+ else
+ [(XMPPDigestAuthentication *)auth setRealm:serverHostName];
+ }
+
+ // Set digest-uri
+ if([virtualHostName length] > 0)
+ [(XMPPDigestAuthentication *)auth setDigestURI:[NSString stringWithFormat:@"xmpp/%@", virtualHostName]];
+ else
+ [(XMPPDigestAuthentication *)auth setDigestURI:[NSString stringWithFormat:@"xmpp/%@", serverHostName]];
+
+ // Set username and password
+ [(XMPPDigestAuthentication *)auth setUsername:[myJID user] password:tempPassword];
+
+ // Update state
+ state = STATE_XMPP_AUTH_2;
+ }
// Create and send challenge response element
NSXMLElement *cr = [NSXMLElement elementWithName:@"response" xmlns:@"urn:ietf:params:xml:ns:xmpp-sasl"];
@@ -2795,13 +2968,11 @@ - (void)handleAuth1:(NSXMLElement *)response
[asyncSocket writeData:outgoingData
withTimeout:TIMEOUT_XMPP_WRITE
tag:TAG_XMPP_WRITE_STREAM];
-
- // Release unneeded resources
+
+ // Release unneeded resources
[auth release];
+ isAccessToken = NO;
[tempPassword release]; tempPassword = nil;
-
- // Update state
- state = STATE_XMPP_AUTH_2;
}
}
else if ([self supportsPlainAuthentication])
@@ -3294,6 +3465,7 @@ - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
parser = nil;
// Clear any saved authentication information
+ isAccessToken = NO;
[tempPassword release]; tempPassword = nil;
// Clear stored elements
@@ -4182,169 +4354,3 @@ - (void)dealloc
}
@end
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark -
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-@implementation XMPPDigestAuthentication
-
-- (id)initWithChallenge:(NSXMLElement *)challenge
-{
- if((self = [super init]))
- {
- // Convert the base 64 encoded data into a string
- NSData *base64Data = [[challenge stringValue] dataUsingEncoding:NSASCIIStringEncoding];
- NSData *decodedData = [base64Data base64Decoded];
-
- NSString *authStr = [[[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding] autorelease];
-
- XMPPLogVerbose(@"%@: Decoded challenge: %@", THIS_FILE, authStr);
-
- // Extract all the key=value pairs, and put them in a dictionary for easy lookup
- NSMutableDictionary *auth = [NSMutableDictionary dictionaryWithCapacity:5];
-
- NSArray *components = [authStr componentsSeparatedByString:@","];
-
- int i;
- for(i = 0; i < [components count]; i++)
- {
- NSString *component = [components objectAtIndex:i];
-
- NSRange separator = [component rangeOfString:@"="];
- if(separator.location != NSNotFound)
- {
- NSMutableString *key = [[component substringToIndex:separator.location] mutableCopy];
- NSMutableString *value = [[component substringFromIndex:separator.location+1] mutableCopy];
-
- if(key) CFStringTrimWhitespace((CFMutableStringRef)key);
- if(value) CFStringTrimWhitespace((CFMutableStringRef)value);
-
- if([value hasPrefix:@"\""] && [value hasSuffix:@"\""] && [value length] > 2)
- {
- // Strip quotes from value
- [value deleteCharactersInRange:NSMakeRange(0, 1)];
- [value deleteCharactersInRange:NSMakeRange([value length]-1, 1)];
- }
-
- [auth setObject:value forKey:key];
-
- [value release];
- [key release];
- }
- }
-
- // Extract and retain the elements we need
- rspauth = [[auth objectForKey:@"rspauth"] copy];
- realm = [[auth objectForKey:@"realm"] copy];
- nonce = [[auth objectForKey:@"nonce"] copy];
- qop = [[auth objectForKey:@"qop"] copy];
-
- // Generate cnonce
- cnonce = [[XMPPStream generateUUID] retain];
- }
- return self;
-}
-
-- (void)dealloc
-{
- [rspauth release];
- [realm release];
- [nonce release];
- [qop release];
- [username release];
- [password release];
- [cnonce release];
- [nc release];
- [digestURI release];
- [super dealloc];
-}
-
-- (NSString *)rspauth
-{
- return [[rspauth copy] autorelease];
-}
-
-- (NSString *)realm
-{
- return [[realm copy] autorelease];
-}
-
-- (void)setRealm:(NSString *)newRealm
-{
- if(![realm isEqual:newRealm])
- {
- [realm release];
- realm = [newRealm copy];
- }
-}
-
-- (void)setDigestURI:(NSString *)newDigestURI
-{
- if(![digestURI isEqual:newDigestURI])
- {
- [digestURI release];
- digestURI = [newDigestURI copy];
- }
-}
-
-- (void)setUsername:(NSString *)newUsername password:(NSString *)newPassword
-{
- if(![username isEqual:newUsername])
- {
- [username release];
- username = [newUsername copy];
- }
-
- if(![password isEqual:newPassword])
- {
- [password release];
- password = [newPassword copy];
- }
-}
-
-- (NSString *)response
-{
- NSString *HA1str = [NSString stringWithFormat:@"%@:%@:%@", username, realm, password];
- NSString *HA2str = [NSString stringWithFormat:@"AUTHENTICATE:%@", digestURI];
-
- NSData *HA1dataA = [[HA1str dataUsingEncoding:NSUTF8StringEncoding] md5Digest];
- NSData *HA1dataB = [[NSString stringWithFormat:@":%@:%@", nonce, cnonce] dataUsingEncoding:NSUTF8StringEncoding];
-
- NSMutableData *HA1data = [NSMutableData dataWithCapacity:([HA1dataA length] + [HA1dataB length])];
- [HA1data appendData:HA1dataA];
- [HA1data appendData:HA1dataB];
-
- NSString *HA1 = [[HA1data md5Digest] hexStringValue];
-
- NSString *HA2 = [[[HA2str dataUsingEncoding:NSUTF8StringEncoding] md5Digest] hexStringValue];
-
- NSString *responseStr = [NSString stringWithFormat:@"%@:%@:00000001:%@:auth:%@",
- HA1, nonce, cnonce, HA2];
-
- NSString *response = [[[responseStr dataUsingEncoding:NSUTF8StringEncoding] md5Digest] hexStringValue];
-
- return response;
-}
-
-- (NSString *)base64EncodedFullResponse
-{
- NSMutableString *buffer = [NSMutableString stringWithCapacity:100];
- [buffer appendFormat:@"username=\"%@\",", username];
- [buffer appendFormat:@"realm=\"%@\",", realm];
- [buffer appendFormat:@"nonce=\"%@\",", nonce];
- [buffer appendFormat:@"cnonce=\"%@\",", cnonce];
- [buffer appendFormat:@"nc=00000001,"];
- [buffer appendFormat:@"qop=auth,"];
- [buffer appendFormat:@"digest-uri=\"%@\",", digestURI];
- [buffer appendFormat:@"response=%@,", [self response]];
- [buffer appendFormat:@"charset=utf-8"];
-
- XMPPLogSend(@"decoded response: %@", buffer);
-
- NSData *utf8data = [buffer dataUsingEncoding:NSUTF8StringEncoding];
-
- return [utf8data base64Encoded];
-}
-
-@end
View
37 Extensions/X-FACEBOOK-PLATFORM/XMPPStreamFacebook.h
@@ -1,37 +0,0 @@
-//
-// XMPPStreamFacebook.h
-//
-// Created by Eric Chamberlain on 10/13/10.
-// Copyright 2010 RF.com. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-
-#import "FBConnect.h"
-#import "XMPPStream.h"
-
-@interface XMPPStreamFacebook : XMPPStream <FBRequestDelegate>
-{
- Facebook *facebook;
- FBRequest *facebookRequest;
-}
-
-@property (readwrite, retain) Facebook *facebook;
-
-/**
- * returns the correct permissions for xmpp
-**/
-+ (NSArray *)permissions;
-
-- (BOOL)supportsXFacebookPlatform;
-
-- (BOOL)authenticateWithAppId:(NSString *)appId
- accessToken:(NSString *)accessToken
- error:(NSError **)errPtr;
-
-- (BOOL)authenticateWithAppId:(NSString *)appId
- accessToken:(NSString *)accessToken
- expirationDate:(NSDate *)expirationDate
- error:(NSError **)errPtr;
-
-@end
View
606 Extensions/X-FACEBOOK-PLATFORM/XMPPStreamFacebook.m
@@ -1,606 +0,0 @@
-//
-// XMPPStreamFacebook.m
-//
-// Created by Eric Chamberlain on 10/13/10.
-// Copyright 2010 RF.com. All rights reserved.
-//
-
-#import "XMPPStreamFacebook.h"
-#import "XMPPInternal.h"
-#import "XMPPLogging.h"
-#import "GCDAsyncSocket.h"
-#import "NSData+XMPP.h"
-#import "NSXMLElement+XMPP.h"
-
-/**
- * Seeing a return statements within an inner block
- * can sometimes be mistaken for a return point of the enclosing method.
- * This makes inline blocks a bit easier to read.
-**/
-#define return_from_block return
-
-// Log levels: off, error, warn, info, verbose
-#if DEBUG
- static const int xmppLogLevel = XMPP_LOG_LEVEL_INFO | XMPP_LOG_FLAG_SEND_RECV; // | XMPP_LOG_FLAG_TRACE;
-#else
- static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN | XMPP_LOG_FLAG_SEND_RECV;
-#endif
-
-
-@interface XMPPXFacebookPlatformAuthentication : NSObject
-{
- NSString *nonce;
- NSString *method;
- NSString *accessToken;
- NSString *sessionSecret;
-}
-
-@property (nonatomic,copy) NSString *accessToken;
-@property (nonatomic,copy) NSString *sessionSecret;
-@property (nonatomic,copy) NSString *nonce;
-@property (nonatomic,copy) NSString *method;
-
-@property (nonatomic,retain,readonly) NSString *appId;
-@property (nonatomic,retain,readonly) NSString *sessionKey;
-
-
-- (id)initWithChallenge:(NSXMLElement *)challenge;
-
-- (NSString *)base64EncodedFullResponse;
-
-@end
-
-#pragma mark -
-
-@implementation XMPPStreamFacebook
-
-@dynamic facebook;
-
-- (Facebook *)facebook
-{
- if (dispatch_get_current_queue() == xmppQueue)
- {
- return facebook;
- }
- else
- {
- __block Facebook *result;
-
- dispatch_sync(xmppQueue, ^{
- result = [facebook retain];
- });
-
- return [result autorelease];
- }
-}
-
-- (void)setFacebook:(Facebook *)newFacebook
-{
- dispatch_block_t block = ^{
-
- if (facebook != newFacebook)
- {
- [facebook release];
- facebook = [newFacebook retain];
- }
- };
-
- if (dispatch_get_current_queue() == xmppQueue)
- block();
- else
- dispatch_async(xmppQueue, block);
-}
-
-- (void)dealloc
-{
- [facebook release];
- [super dealloc];
-}
-
-#pragma mark Public class methods
-
-+ (NSArray *)permissions
-{
- return [NSArray arrayWithObjects:@"offline_access", @"xmpp_login", nil];
-}
-
-#pragma mark Public instance methods
-
-/**
- * This method checks the stream features of the connected server to
- * determine if X-FACEBOOK-PLATFORM authentication is supported.
- * If we are not connected to a server, this method simply returns NO.
- *
- * This is the preferred authentication technique, and will be used if
- * the server supports it.
-**/
-- (BOOL)supportsXFacebookPlatform
-{
- __block BOOL result = NO;
-
- dispatch_block_t block = ^{
-
- // The root element can be properly queried for authentication mechanisms anytime after the
- // stream:features are received, and TLS has been setup (if required)
- if (state >= STATE_XMPP_POST_NEGOTIATION)
- {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- NSXMLElement *features = [rootElement elementForName:@"stream:features"];
- NSXMLElement *mech = [features elementForName:@"mechanisms" xmlns:@"urn:ietf:params:xml:ns:xmpp-sasl"];
-
- NSArray *mechanisms = [mech elementsForName:@"mechanism"];
-
- for (NSXMLElement *mechanism in mechanisms)
- {
- if ([[mechanism stringValue] isEqualToString:@"X-FACEBOOK-PLATFORM"])
- {
- result = YES;
- break;
- }
- }
-
- [pool drain];
- }
- };
-
- if (dispatch_get_current_queue() == xmppQueue)
- block();
- else
- dispatch_sync(xmppQueue, block);
-
- return result;
-}
-
-/**
- * This method attemts to sign-in to Facebook using the access token.
-**/
-- (BOOL)authenticateWithAppId:(NSString *)appId
- accessToken:(NSString *)accessToken
- error:(NSError **)errPtr
-{
- // Hard coding expiration date, because we use offline_access in the permissions
- return [self authenticateWithAppId:appId
- accessToken:accessToken
- expirationDate:[NSDate distantFuture]
- error:errPtr];
-}
-
-- (BOOL)authenticateWithAppId:(NSString *)appId
- accessToken:(NSString *)accessToken
- expirationDate:(NSDate *)expirationDate
- error:(NSError **)errPtr
-{
- XMPPLogTrace();
-
- __block BOOL result = YES;
- __block NSError *err = nil;
-
- dispatch_block_t block = ^{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- if (state != STATE_XMPP_CONNECTED)
- {
- NSString *errMsg = @"Please wait until the stream is connected.";
- NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-
- err = [NSError errorWithDomain:XMPPStreamErrorDomain code:XMPPStreamInvalidState userInfo:info];
-
- [err retain];
- [pool drain];
-
- result = NO;
- return_from_block;
- }
-
- if (![self supportsXFacebookPlatform])
- {
- NSString *errMsg = @"The server does not support X-FACEBOOK-PLATFORM authentication.";
- NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-
- err = [NSError errorWithDomain:XMPPStreamErrorDomain code:XMPPStreamUnsupportedAction userInfo:info];
-
- [err retain];
- [pool drain];
-
- result = NO;
- return_from_block;
- }
-
- if (accessToken == nil || expirationDate == nil)
- {
- NSString *errMsg = @"Facebook accessToken and expirationDate required.";
- NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-
- err = [NSError errorWithDomain:XMPPStreamErrorDomain code:XMPPStreamInvalidProperty userInfo:info];
-
- [err retain];
- [pool drain];
-
- result = NO;
- return_from_block;
- }
-
- [facebook release];
-
- facebook = [[Facebook alloc] initWithAppId:appId];
- facebook.accessToken = accessToken;
- facebook.expirationDate = expirationDate;
-
- // Facebook uses NSURLConnection which is dependent on a RunLoop.
- // So we need to use the xmppUtilityThread.
-
- [self performSelector:@selector(sendFacebookRequest:)
- onThread:xmppUtilityThread
- withObject:facebook
- waitUntilDone:NO];
-
- // Update state
- state = STATE_XMPP_AUTH_1;
-
- [pool drain];
- };
-
-
- if (dispatch_get_current_queue() == xmppQueue)
- block();
- else
- dispatch_sync(xmppQueue, block);
-
- if (errPtr)
- *errPtr = [err autorelease];
- else
- [err release];
-
- return result;
-}
-
-- (BOOL)authenticateWithPassword:(NSString *)password error:(NSError **)errPtr
-{
- XMPPLogTrace();
-
- __block BOOL result = YES;
- __block NSError *err = nil;
-
- dispatch_block_t block = ^{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- if (state != STATE_XMPP_CONNECTED)
- {
- NSString *errMsg = @"Please wait until the stream is connected.";
- NSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];
-
- err = [NSError errorWithDomain:XMPPStreamErrorDomain code:XMPPStreamInvalidState userInfo:info];
-
- [err retain];
- [pool drain];
-
- result = NO;
- return_from_block;
- }
-
- if (facebook != nil && [self supportsXFacebookPlatform])
- {
- NSString *auth = @"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='X-FACEBOOK-PLATFORM'/>";
-
- NSData *outgoingData = [auth dataUsingEncoding:NSUTF8StringEncoding];
-
- XMPPLogSend(@"SEND: %@", auth);
- numberOfBytesSent += [outgoingData length];
-
- [asyncSocket writeData:outgoingData
- withTimeout:TIMEOUT_XMPP_WRITE
- tag:TAG_XMPP_WRITE_STREAM];
-
- // Save authentication information
- [tempPassword release];
- tempPassword = [password copy];
-
- // Update state
- state = STATE_XMPP_AUTH_1;
- }
- else
- {
- result = [super authenticateWithPassword:password error:&err];
- }
-
- [err retain];
- [pool drain];
- };
-
-
- if (dispatch_get_current_queue() == xmppQueue)
- block();
- else
- dispatch_sync(xmppQueue, block);
-
- if (errPtr)
- *errPtr = [err autorelease];
- else
- [err release];
-
- return result;
-}
-
-#pragma mark Private instance methods
-
-- (void)handleAuth1:(NSXMLElement *)response
-{
- NSAssert(dispatch_get_current_queue() == xmppQueue, @"Invoked on incorrect queue");
-
- XMPPLogTrace();
-
- if (facebook != nil && [self supportsXFacebookPlatform])
- {
- if (![[response name] isEqualToString:@"challenge"])
- {
- // Revert back to connected state (from authenticating state)
- state = STATE_XMPP_CONNECTED;
-
- [multicastDelegate xmppStream:self didNotAuthenticate:response];
- }
- else
- {
- XMPPXFacebookPlatformAuthentication *auth;
- auth = [[XMPPXFacebookPlatformAuthentication alloc] initWithChallenge:response];
-
- [auth setAccessToken:facebook.accessToken];
- [auth setSessionSecret:tempPassword];
-
- // Create and send challenge response element
- NSXMLElement *cr = [NSXMLElement elementWithName:@"response" xmlns:@"urn:ietf:params:xml:ns:xmpp-sasl"];
- [cr setStringValue:[auth base64EncodedFullResponse]];
-
- NSString *outgoingStr = [cr compactXMLString];
- NSData *outgoingData = [outgoingStr dataUsingEncoding:NSUTF8StringEncoding];
-
- XMPPLogSend(@"SEND: %@", outgoingStr);
- numberOfBytesSent += [outgoingData length];
-
- [asyncSocket writeData:outgoingData
- withTimeout:TIMEOUT_XMPP_WRITE
- tag:TAG_XMPP_WRITE_STREAM];
-
- // Release unneeded resources
- [auth release];
- [tempPassword release]; tempPassword = nil;
-
- // Update state
- state = STATE_XMPP_AUTH_3;
- }
- }
- else
- {
- [super handleAuth1:response];
- }
-}
-
-- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
-{
- [super socketDidDisconnect:sock withError:err];
-
- [facebookRequest release];
- facebookRequest = nil;
-
- [facebook release];
- facebook = nil;
-}
-
-#pragma mark FBRequest
-
-- (void)sendFacebookRequest:(Facebook *)fb
-{
- //
- // This method is run on the xmppUtilityThread.
- //
-
- FBRequest *fbRequest = [fb requestWithMethodName:@"auth.promoteSession"
- andParams:[NSMutableDictionary dictionaryWithCapacity:3]
- andHttpMethod:@"GET"
- andDelegate:self];
-
- dispatch_async(xmppQueue, ^{
-
- [facebookRequest release];
- facebookRequest = [fbRequest retain];
- });
-}
-
-/**
- * Called when an error prevents the request from completing successfully.
-**/
-- (void)request:(FBRequest *)sender didFailWithError:(NSError *)error
-{
- XMPPLogTrace();
-
- //
- // This method is invoked on the xmppUtilityThread.
- //
-
- dispatch_async(xmppQueue, ^{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- if (sender == facebookRequest)
- {
- XMPPLogWarn(@"%@: Facebook request failed - error: %@", THIS_FILE, error);
-
- // Revert back to connected state (from authenticating state)
- state = STATE_XMPP_CONNECTED;
-
- [multicastDelegate xmppStream:self didNotAuthenticate:nil];
- }
-
- [pool drain];
- });
-}
-
-/**
- * Called when a request returns and its response has been parsed into an object.
- * The resulting object may be a dictionary, an array, a string, or a number,
- * depending on thee format of the API response.
-**/
-- (void)request:(FBRequest *)sender didLoad:(id)result
-{
- XMPPLogTrace();
-
- //
- // This method is invoked on the xmppUtilityThread.
- //
-
- if ([result isKindOfClass:[NSData class]])
- {
- NSString *resultStr = [[[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding] autorelease];
- NSString *pwd = [resultStr stringByReplacingOccurrencesOfString:@"\"" withString:@""];
-
- dispatch_async(xmppQueue, ^{
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
- if (sender == facebookRequest)
- {
- // Revert back to connected state (from authenticating state)
- state = STATE_XMPP_CONNECTED;
-
- // Finish authenticating
-
- NSError *error = nil;
-
- if (![self authenticateWithPassword:pwd error:&error])
- {
- XMPPLogWarn(@"%@: Facebook auth failed - resultStr(%@) error: %@", THIS_FILE, resultStr, error);
-
- [multicastDelegate xmppStream:self didNotAuthenticate:nil];
- }
- }
-
- [pool drain];
- });
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-#pragma mark -
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-@end
-
-@implementation XMPPXFacebookPlatformAuthentication
-
-- (id)initWithChallenge:(NSXMLElement *)challenge
-{
- if ((self = [super init]))
- {
- // Convert the base 64 encoded data into a string
- NSData *base64Data = [[challenge stringValue]
- dataUsingEncoding:NSASCIIStringEncoding];
- NSData *decodedData = [base64Data base64Decoded];
-
- NSString *authStr = [[[NSString alloc] initWithData:decodedData
- encoding:NSUTF8StringEncoding] autorelease];
-
- XMPPLogVerbose(@"XMPPXFacebookPlatformAuthentication: decoded challenge: %@", authStr);
-
- // Extract all the key=value pairs, and put them in a dictionary for easy lookup
- NSMutableDictionary *auth = [NSMutableDictionary dictionaryWithCapacity:3];
-
- NSArray *components = [authStr componentsSeparatedByString:@"&"];
-
- int i;
- for(i = 0; i < [components count]; i++)
- {
- NSString *component = [components objectAtIndex:i];
-
- NSRange separator = [component rangeOfString:@"="];
- if(separator.location != NSNotFound)
- {
- NSString *key = [[component substringToIndex:separator.location]
- stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
- NSString *value = [[component substringFromIndex:separator.location+1]
- stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
-
- if([value hasPrefix:@"\""] &&
- [value hasSuffix:@"\""] &&
- [value length] > 2)
- {
- // Strip quotes from value
- value = [value substringWithRange:NSMakeRange(1,([value length]-2))];
- }
-
- [auth setObject:value forKey:key];
- }
- }
-
- // Extract and retain the elements we need
- self.nonce = [auth objectForKey:@"nonce"];
- self.method = [auth objectForKey:@"method"];
- }
- return self;
-}
-
-- (void)dealloc
-{
- [accessToken release];
- [nonce release];
- [method release];
- [sessionSecret release];
-
- [super dealloc];
-}
-
-- (NSString *)base64EncodedFullResponse
-{
- if (self.accessToken == nil ||
- self.sessionSecret == nil ||
- self.method == nil ||
- self.nonce == nil) {
- return nil;
- }
-
- srand([[NSDate date] timeIntervalSince1970]);
-
- NSMutableString *buffer = [NSMutableString stringWithCapacity:250];
- [buffer appendFormat:@"api_key=%@&", self.appId];
- [buffer appendFormat:@"call_id=%d&", rand()];
- [buffer appendFormat:@"method=%@&", self.method];
- [buffer appendFormat:@"nonce=%@&", self.nonce];
- [buffer appendFormat:@"session_key=%@&", self.sessionKey];
- [buffer appendFormat:@"v=%@&",@"1.0"];
-
- // Make the "sig" hash
- NSString* sig = [buffer stringByReplacingOccurrencesOfString:@"&"
- withString:@""];
-
- sig = [sig stringByAppendingString:self.sessionSecret];
-
- NSString* sigMD5 = [[[sig dataUsingEncoding:NSUTF8StringEncoding] md5Digest] hexStringValue];
- [buffer appendFormat:@"sig=%@", sigMD5];
-
- XMPPLogVerbose(@"XMPPXFacebookPlatformAuthentication: sig for facebook: %@", sig);
- XMPPLogVerbose(@"XMPPXFacebookPlatformAuthentication: response for facebook: %@", buffer);
-
- NSData *utf8data = [buffer dataUsingEncoding:NSUTF8StringEncoding];
-
- return [utf8data base64Encoded];
-}
-
-@synthesize nonce;
-@synthesize method;
-@synthesize accessToken;
-@synthesize sessionSecret;
-
-- (NSString *)appId {
- NSArray *parts = [self.accessToken componentsSeparatedByString:@"|"];
- if ([parts count] < 3) {
- return nil;
- }
- return [parts objectAtIndex:0];
-}
-
-- (NSString *)sessionKey {
- NSArray *parts = [self.accessToken componentsSeparatedByString:@"|"];
- if ([parts count] < 3) {
- return nil;
- }
- return [parts objectAtIndex:1];
-}
-
-@end
View
5 Extensions/XEP-0054/CoreDataStorage/XMPPvCard.xcdatamodeld/.xccurrentversion
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
-<dict/>
+<dict>
+ <key>_XCCurrentVersionName</key>
+ <string>XMPPvCard.xcdatamodel</string>
+</dict>
</plist>
View
43 Utilities/XMPPDigestAuthentication.h
@@ -0,0 +1,43 @@
+//
+// XMPPDigestAuthentication.h
+// iPhoneXMPP
+//
+// Created by Eric Chamberlain on 10/1/11.
+// Copyright 2011 __MyCompanyName__. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#if TARGET_OS_IPHONE
+#import "DDXML.h"
+#endif
+
+#import "XMPPSASLAuthentication.h"
+
+@interface XMPPDigestAuthentication : NSObject <XMPPSASLAuthentication>
+{
+ NSString *rspauth;
+ NSString *realm;
+ NSString *nonce;
+ NSString *qop;
+ NSString *username;
+ NSString *password;
+ NSString *cnonce;
+ NSString *nc;
+ NSString *digestURI;
+}
+
+- (id)initWithChallenge:(NSXMLElement *)challenge;
+
+- (NSString *)rspauth;
+
+- (NSString *)realm;
+- (void)setRealm:(NSString *)realm;
+
+- (void)setDigestURI:(NSString *)digestURI;
+
+- (void)setUsername:(NSString *)username password:(NSString *)password;
+
+- (NSString *)response;
+
+@end
View
182 Utilities/XMPPDigestAuthentication.m
@@ -0,0 +1,182 @@
+//
+// XMPPDigestAuthentication.m
+// iPhoneXMPP
+//
+// Created by Eric Chamberlain on 10/1/11.
+// Copyright 2011 __MyCompanyName__. All rights reserved.
+//
+
+#import "XMPPDigestAuthentication.h"
+
+#import "NSData+XMPP.h"
+#import "XMPPLogging.h"
+#import "XMPPStream.h"
+
+// Log levels: off, error, warn, info, verbose
+#if DEBUG
+static const int xmppLogLevel = XMPP_LOG_LEVEL_INFO | XMPP_LOG_FLAG_SEND_RECV; // | XMPP_LOG_FLAG_TRACE;
+#else
+static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
+#endif
+
+@implementation XMPPDigestAuthentication
+
+- (id)initWithChallenge:(NSXMLElement *)challenge
+{
+ if((self = [super init]))
+ {
+ // Convert the base 64 encoded data into a string
+ NSData *base64Data = [[challenge stringValue] dataUsingEncoding:NSASCIIStringEncoding];
+ NSData *decodedData = [base64Data base64Decoded];
+
+ NSString *authStr = [[[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding] autorelease];
+
+ XMPPLogVerbose(@"%@: Decoded challenge: %@", THIS_FILE, authStr);
+
+ // Extract all the key=value pairs, and put them in a dictionary for easy lookup
+ NSMutableDictionary *auth = [NSMutableDictionary dictionaryWithCapacity:5];
+
+ NSArray *components = [authStr componentsSeparatedByString:@","];
+
+ int i;
+ for(i = 0; i < [components count]; i++)
+ {
+ NSString *component = [components objectAtIndex:i];
+
+ NSRange separator = [component rangeOfString:@"="];
+ if(separator.location != NSNotFound)
+ {
+ NSMutableString *key = [[component substringToIndex:separator.location] mutableCopy];
+ NSMutableString *value = [[component substringFromIndex:separator.location+1] mutableCopy];
+
+ if(key) CFStringTrimWhitespace((CFMutableStringRef)key);
+ if(value) CFStringTrimWhitespace((CFMutableStringRef)value);
+
+ if([value hasPrefix:@"\""] && [value hasSuffix:@"\""] && [value length] > 2)
+ {
+ // Strip quotes from value
+ [value deleteCharactersInRange:NSMakeRange(0, 1)];
+ [value deleteCharactersInRange:NSMakeRange([value length]-1, 1)];
+ }
+
+ [auth setObject:value forKey:key];
+
+ [value release];
+ [key release];
+ }
+ }
+
+ // Extract and retain the elements we need
+ rspauth = [[auth objectForKey:@"rspauth"] copy];
+ realm = [[auth objectForKey:@"realm"] copy];
+ nonce = [[auth objectForKey:@"nonce"] copy];
+ qop = [[auth objectForKey:@"qop"] copy];
+
+ // Generate cnonce
+ cnonce = [[XMPPStream generateUUID] retain];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [rspauth release];
+ [realm release];
+ [nonce release];
+ [qop release];
+ [username release];
+ [password release];
+ [cnonce release];
+ [nc release];
+ [digestURI release];
+ [super dealloc];
+}
+
+- (NSString *)rspauth
+{
+ return [[rspauth copy] autorelease];
+}
+
+- (NSString *)realm
+{
+ return [[realm copy] autorelease];
+}
+
+- (void)setRealm:(NSString *)newRealm
+{
+ if(![realm isEqual:newRealm])
+ {
+ [realm release];
+ realm = [newRealm copy];
+ }
+}
+
+- (void)setDigestURI:(NSString *)newDigestURI
+{
+ if(![digestURI isEqual:newDigestURI])
+ {
+ [digestURI release];
+ digestURI = [newDigestURI copy];
+ }
+}
+
+- (void)setUsername:(NSString *)newUsername password:(NSString *)newPassword
+{
+ if(![username isEqual:newUsername])
+ {
+ [username release];
+ username = [newUsername copy];
+ }
+
+ if(![password isEqual:newPassword])
+ {
+ [password release];
+ password = [newPassword copy];
+ }
+}
+
+- (NSString *)response
+{
+ NSString *HA1str = [NSString stringWithFormat:@"%@:%@:%@", username, realm, password];
+ NSString *HA2str = [NSString stringWithFormat:@"AUTHENTICATE:%@", digestURI];
+
+ NSData *HA1dataA = [[HA1str dataUsingEncoding:NSUTF8StringEncoding] md5Digest];
+ NSData *HA1dataB = [[NSString stringWithFormat:@":%@:%@", nonce, cnonce] dataUsingEncoding:NSUTF8StringEncoding];
+
+ NSMutableData *HA1data = [NSMutableData dataWithCapacity:([HA1dataA length] + [HA1dataB length])];
+ [HA1data appendData:HA1dataA];
+ [HA1data appendData:HA1dataB];
+
+ NSString *HA1 = [[HA1data md5Digest] hexStringValue];
+
+ NSString *HA2 = [[[HA2str dataUsingEncoding:NSUTF8StringEncoding] md5Digest] hexStringValue];
+
+ NSString *responseStr = [NSString stringWithFormat:@"%@:%@:00000001:%@:auth:%@",
+ HA1, nonce, cnonce, HA2];
+
+ NSString *response = [[[responseStr dataUsingEncoding:NSUTF8StringEncoding] md5Digest] hexStringValue];
+
+ return response;
+}
+
+- (NSString *)base64EncodedFullResponse
+{
+ NSMutableString *buffer = [NSMutableString stringWithCapacity:100];
+ [buffer appendFormat:@"username=\"%@\",", username];
+ [buffer appendFormat:@"realm=\"%@\",", realm];
+ [buffer appendFormat:@"nonce=\"%@\",", nonce];
+ [buffer appendFormat:@"cnonce=\"%@\",", cnonce];
+ [buffer appendFormat:@"nc=00000001,"];
+ [buffer appendFormat:@"qop=auth,"];
+ [buffer appendFormat:@"digest-uri=\"%@\",", digestURI];
+ [buffer appendFormat:@"response=%@,", [self response]];
+ [buffer appendFormat:@"charset=utf-8"];
+
+ XMPPLogSend(@"decoded response: %@", buffer);
+
+ NSData *utf8data = [buffer dataUsingEncoding:NSUTF8StringEncoding];
+
+ return [utf8data base64Encoded];
+}
+
+@end
View
15 Utilities/XMPPSASLAuthentication.h
@@ -0,0 +1,15 @@
+//
+// XMPPSASLAuthentication.h
+// iPhoneXMPP
+//
+// Created by Eric Chamberlain on 10/1/11.
+// Copyright 2011 RingFree Mobility Inc. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@protocol XMPPSASLAuthentication <NSObject>
+
+- (NSString *)base64EncodedFullResponse;
+
+@end
View
32 Utilities/XMPPXFacebookPlatformAuthentication.h
@@ -0,0 +1,32 @@
+//
+// XMPPXFacebookPlatformAuthentication.h
+// iPhoneXMPP
+//
+// Created by Eric Chamberlain on 10/1/11.
+// Copyright 2011 __MyCompanyName__. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#if TARGET_OS_IPHONE
+#import "DDXML.h"
+#endif
+
+#import "XMPPSASLAuthentication.h"
+
+@interface XMPPXFacebookPlatformAuthentication : NSObject <XMPPSASLAuthentication>
+{
+ NSString *appId;
+ NSString *accessToken;
+ NSString *nonce;
+ NSString *method;
+}
+
+@property (nonatomic,copy) NSString *appId;
+@property (nonatomic,copy) NSString *accessToken;
+@property (nonatomic,copy) NSString *nonce;
+@property (nonatomic,copy) NSString *method;
+
+- (id)initWithChallenge:(NSXMLElement *)challenge appId:(NSString *)appId accessToken:(NSString *)accessToken;
+
+@end
View
118 Utilities/XMPPXFacebookPlatformAuthentication.m
@@ -0,0 +1,118 @@
+//
+// XMPPXFacebookPlatformAuthentication.m
+// iPhoneXMPP
+//
+// Created by Eric Chamberlain on 10/1/11.
+// Copyright 2011 __MyCompanyName__. All rights reserved.
+//
+
+#import "XMPPXFacebookPlatformAuthentication.h"
+
+#import "NSData+XMPP.h"
+#import "XMPPLogging.h"
+#import "XMPPStream.h"
+
+// Log levels: off, error, warn, info, verbose
+#if DEBUG
+ static const int xmppLogLevel = XMPP_LOG_LEVEL_INFO | XMPP_LOG_FLAG_SEND_RECV; // | XMPP_LOG_FLAG_TRACE;
+#else
+ static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
+#endif
+
+@implementation XMPPXFacebookPlatformAuthentication
+
+- (id)initWithChallenge:(NSXMLElement *)challenge appId:(NSString *)aAppId accessToken:(NSString *)aAccessToken
+{
+ if ((self = [super init]))
+ {
+ self.appId = aAppId;
+ self.accessToken = aAccessToken;
+
+ // Convert the base 64 encoded data into a string
+ NSData *base64Data = [[challenge stringValue] dataUsingEncoding:NSASCIIStringEncoding];
+ NSData *decodedData = [base64Data base64Decoded];
+
+ NSString *authStr = [[[NSString alloc] initWithData:decodedData
+ encoding:NSUTF8StringEncoding] autorelease];
+
+ XMPPLogVerbose(@"XMPPXFacebookPlatformAuthentication: decoded challenge: %@", authStr);
+
+ // Extract all the key=value pairs, and put them in a dictionary for easy lookup
+ NSMutableDictionary *auth = [NSMutableDictionary dictionaryWithCapacity:3];
+
+ NSArray *components = [authStr componentsSeparatedByString:@"&"];
+
+ int i;
+ for(i = 0; i < [components count]; i++)
+ {
+ NSString *component = [components objectAtIndex:i];
+
+ NSRange separator = [component rangeOfString:@"="];
+ if(separator.location != NSNotFound)
+ {
+ NSString *key = [[component substringToIndex:separator.location]
+ stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+ NSString *value = [[component substringFromIndex:separator.location+1]
+ stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+
+ if([value hasPrefix:@"\""] &&
+ [value hasSuffix:@"\""] &&
+ [value length] > 2)
+ {
+ // Strip quotes from value
+ value = [value substringWithRange:NSMakeRange(1,([value length]-2))];
+ }
+
+ [auth setObject:value forKey:key];
+ }
+ }
+
+ // Extract and retain the elements we need
+ self.nonce = [auth objectForKey:@"nonce"];
+ self.method = [auth objectForKey:@"method"];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [appId release];
+ [accessToken release];
+ [nonce release];
+ [method release];
+ [super dealloc];
+}
+
+- (NSString *)base64EncodedFullResponse
+{
+ if (self.appId == nil ||
+ self.accessToken == nil ||
+ self.method == nil ||
+ self.nonce == nil)
+ {
+ return nil;
+ }
+
+ srand([[NSDate date] timeIntervalSince1970]);
+
+ NSMutableString *buffer = [NSMutableString stringWithCapacity:250];
+ [buffer appendFormat:@"method=%@&", self.method];
+ [buffer appendFormat:@"nonce=%@&", self.nonce];
+ [buffer appendFormat:@"access_token=%@&", self.accessToken];
+ [buffer appendFormat:@"api_key=%@&", self.appId];
+ [buffer appendFormat:@"call_id=%d&", rand()];
+ [buffer appendFormat:@"v=%@",@"1.0"];
+
+ XMPPLogVerbose(@"XMPPXFacebookPlatformAuthentication: response for facebook: %@", buffer);
+
+ NSData *utf8data = [buffer dataUsingEncoding:NSUTF8StringEncoding];
+
+ return [utf8data base64Encoded];
+}
+
+@synthesize appId;
+@synthesize accessToken;
+@synthesize nonce;
+@synthesize method;
+
+@end
1  Vendor/facebook-ios-sdk
@@ -0,0 +1 @@
+Subproject commit 22f88dc6acf1aa935a602f62d00226058b648fcd
View
16 Xcode/DesktopXMPP/XMPPStream.xcodeproj/project.pbxproj
@@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
+ 07588E4B1438074E00134162 /* XMPPDigestAuthentication.m in Sources */ = {isa = PBXBuildFile; fileRef = 07588E471438074E00134162 /* XMPPDigestAuthentication.m */; };
+ 07588E4C1438074E00134162 /* XMPPXFacebookPlatformAuthentication.m in Sources */ = {isa = PBXBuildFile; fileRef = 07588E4A1438074E00134162 /* XMPPXFacebookPlatformAuthentication.m */; };
07AF18A9134BC3C30084D82A /* XMPPSRVResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = 07AF18A8134BC3C30084D82A /* XMPPSRVResolver.m */; };
8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; };
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
@@ -87,6 +89,11 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
+ 07588E461438074E00134162 /* XMPPDigestAuthentication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XMPPDigestAuthentication.h; path = ../../Utilities/XMPPDigestAuthentication.h; sourceTree = "<group>"; };
+ 07588E471438074E00134162 /* XMPPDigestAuthentication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = XMPPDigestAuthentication.m; path = ../../Utilities/XMPPDigestAuthentication.m; sourceTree = "<group>"; };
+ 07588E481438074E00134162 /* XMPPSASLAuthentication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XMPPSASLAuthentication.h; path = ../../Utilities/XMPPSASLAuthentication.h; sourceTree = "<group>"; };
+ 07588E491438074E00134162 /* XMPPXFacebookPlatformAuthentication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XMPPXFacebookPlatformAuthentication.h; path = ../../Utilities/XMPPXFacebookPlatformAuthentication.h; sourceTree = "<group>"; };
+ 07588E4A1438074E00134162 /* XMPPXFacebookPlatformAuthentication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = XMPPXFacebookPlatformAuthentication.m; path = ../../Utilities/XMPPXFacebookPlatformAuthentication.m; sourceTree = "<group>"; };
07AF18A7134BC3C30084D82A /* XMPPSRVResolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XMPPSRVResolver.h; path = ../../Utilities/XMPPSRVResolver.h; sourceTree = "<group>"; };
07AF18A8134BC3C30084D82A /* XMPPSRVResolver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = XMPPSRVResolver.m; path = ../../Utilities/XMPPSRVResolver.m; sourceTree = "<group>"; };
089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@@ -608,6 +615,11 @@
DC84BAE3124407B60055A459 /* GCDMulticastDelegate.m */,
DC84BAE0124407B60055A459 /* LibIDN.h */,
DC84BAE1124407B60055A459 /* LibIDN.m */,
+ 07588E461438074E00134162 /* XMPPDigestAuthentication.h */,
+ 07588E471438074E00134162 /* XMPPDigestAuthentication.m */,
+ 07588E481438074E00134162 /* XMPPSASLAuthentication.h */,
+ 07588E491438074E00134162 /* XMPPXFacebookPlatformAuthentication.h */,
+ 07588E4A1438074E00134162 /* XMPPXFacebookPlatformAuthentication.m */,
07AF18A7134BC3C30084D82A /* XMPPSRVResolver.h */,
07AF18A8134BC3C30084D82A /* XMPPSRVResolver.m */,
);
@@ -772,7 +784,7 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0410;
+ LastUpgradeCheck = 0420;
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "XMPPStream" */;
compatibilityVersion = "Xcode 3.2";
@@ -878,6 +890,8 @@
DC37317E139F04DE00A8407D /* NSXMLElement+XMPP.m in Sources */,
DCC891ED13F1D09000CDAB56 /* XMPPIDTracker.m in Sources */,
DCE112601406F52D007A2A46 /* XMPPAutoTime.m in Sources */,
+ 07588E4B1438074E00134162 /* XMPPDigestAuthentication.m in Sources */,
+ 07588E4C1438074E00134162 /* XMPPXFacebookPlatformAuthentication.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginNormal.png
Deleted file not rendered
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginNormal@2x.png
Deleted file not rendered
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginPressed.png
Deleted file not rendered
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginPressed@2x.png
Deleted file not rendered
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginWithFacebookNormal.png
Deleted file not rendered
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginWithFacebookNormal@2x.png
Deleted file not rendered
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginWithFacebookPressed.png
Deleted file not rendered
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LoginWithFacebookPressed@2x.png
Deleted file not rendered
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LogoutNormal.png
Deleted file not rendered
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LogoutNormal@2x.png
Deleted file not rendered
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LogoutPressed.png
Deleted file not rendered
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/LogoutPressed@2x.png
Deleted file not rendered
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBConnect.bundle/images/runaround_image.jpg
Deleted file not rendered
View
22 Xcode/Testing/FacebookTest/FBConnect/FBConnect.h
@@ -1,22 +0,0 @@
-/*
- * Copyright 2010 Facebook
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
-
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include "Facebook.h"
-#include "FBDialog.h"
-#include "FBLoginDialog.h"
-#include "FBRequest.h"
-#include "SBJSON.h"
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBDialog.bundle/images/close.png
Deleted file not rendered
View
BIN  Xcode/Testing/FacebookTest/FBConnect/FBDialog.bundle/images/fbicon.png
Deleted file not rendered
View
167 Xcode/Testing/FacebookTest/FBConnect/FBDialog.h
@@ -1,167 +0,0 @@
-/*
- * Copyright 2010 Facebook
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
-
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-
-#import <Foundation/Foundation.h>
-#import <UIKit/UIKit.h>
-
-@protocol FBDialogDelegate;
-
-/**
- * Do not use this interface directly, instead, use dialog in Facebook.h
- *
- * Facebook dialog interface for start the facebook webView UIServer Dialog.
- */
-
-@interface FBDialog : UIView <UIWebViewDelegate> {
- id<FBDialogDelegate> _delegate;
- NSMutableDictionary *_params;
- NSString * _serverURL;
- NSURL* _loadingURL;
- UIWebView* _webView;
- UIActivityIndicatorView* _spinner;
- UIImageView* _iconView;
- UILabel* _titleLabel;
- UIButton* _closeButton;
- UIDeviceOrientation _orientation;
- BOOL _showingKeyboard;
-
- // Ensures that UI elements behind the dialog are disabled.
- UIView* _modalBackgroundView;
-}
-
-/**
- * The delegate.
- */
-@property(nonatomic,assign) id<FBDialogDelegate> delegate;
-
-/**
- * The parameters.
- */
-@property(nonatomic, retain) NSMutableDictionary* params;
-
-/**
- * The title that is shown in the header atop the view.
- */
-@property(nonatomic,copy) NSString* title;
-
-- (NSString *) getStringFromUrl: (NSString*) url needle:(NSString *) needle;
-
-- (id)initWithURL: (NSString *) loadingURL
- params: (NSMutableDictionary *) params
- delegate: (id <FBDialogDelegate>) delegate;
-
-/**
- * Displays the view with an animation.
- *
- * The view will be added to the top of the current key window.
- */
-- (void)show;
-
-/**
- * Displays the first page of the dialog.
- *
- * Do not ever call this directly. It is intended to be overriden by subclasses.
- */
-- (void)load;
-
-/**
- * Displays a URL in the dialog.
- */
-- (void)loadURL:(NSString*)url
- get:(NSDictionary*)getParams;
-
-/**
- * Hides the view and notifies delegates of success or cancellation.
- */
-- (void)dismissWithSuccess:(BOOL)success animated:(BOOL)animated;
-
-/**
- * Hides the view and notifies delegates of an error.
- */
-- (void)dismissWithError:(NSError*)error animated:(BOOL)animated;
-
-/**
- * Subclasses may override to perform actions just prior to showing the dialog.
- */
-- (void)dialogWillAppear;
-
-/**
- * Subclasses may override to perform actions just after the dialog is hidden.
- */
-- (void)dialogWillDisappear;
-
-/**
- * Subclasses should override to process data returned from the server in a 'fbconnect' url.
- *
- * Implementations must call dismissWithSuccess:YES at some point to hide the dialog.
- */
-- (void)dialogDidSucceed:(NSURL *)url;
-
-/**
- * Subclasses should override to process data returned from the server in a 'fbconnect' url.
- *
- * Implementations must call dismissWithSuccess:YES at some point to hide the dialog.
- */
-- (void)dialogDidCancel:(NSURL *)url;
-@end
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-/*
- *Your application should implement this delegate
- */
-@protocol FBDialogDelegate <NSObject>
-
-@optional
-
-/**
- * Called when the dialog succeeds and is about to be dismissed.
- */
-- (void)dialogDidComplete:(FBDialog *)dialog;
-
-/**
- * Called when the dialog succeeds with a returning url.
- */
-- (void)dialogCompleteWithUrl:(NSURL *)url;
-
-/**
- * Called when the dialog get canceled by the user.
- */
-- (void)dialogDidNotCompleteWithUrl:(NSURL *)url;
-
-/**
- * Called when the dialog is cancelled and is about to be dismissed.
- */
-- (void)dialogDidNotComplete:(FBDialog *)dialog;
-
-/**
- * Called when dialog failed to load due to an error.
- */
-- (void)dialog:(FBDialog*)dialog didFailWithError:(NSError *)error;
-
-/**
- * Asks if a link touched by a user should be opened in an external browser.
- *
- * If a user touches a link, the default behavior is to open the link in the Safari browser,
- * which will cause your app to quit. You may want to prevent this from happening, open the link
- * in your own internal browser, or perhaps warn the user that they are about to leave your app.
- * If so, implement this method on your delegate and return NO. If you warn the user, you
- * should hold onto the URL and once you have received their acknowledgement open the URL yourself
- * using [[UIApplication sharedApplication] openURL:].
- */
-- (BOOL)dialog:(FBDialog*)dialog shouldOpenURLInExternalBrowser:(NSURL *)url;
-
-@end
View
656 Xcode/Testing/FacebookTest/FBConnect/FBDialog.m
@@ -1,656 +0,0 @@
-/*
- * Copyright 2010 Facebook
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
-
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-
-
-#import "FBDialog.h"
-#import "Facebook.h"
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// global
-
-static NSString* kDefaultTitle = @"Connect to Facebook";
-
-static CGFloat kFacebookBlue[4] = {0.42578125, 0.515625, 0.703125, 1.0};
-static CGFloat kBorderGray[4] = {0.3, 0.3, 0.3, 0.8};
-static CGFloat kBorderBlack[4] = {0.3, 0.3, 0.3, 1};
-static CGFloat kBorderBlue[4] = {0.23, 0.35, 0.6, 1.0};
-
-static CGFloat kTransitionDuration = 0.3;
-
-static CGFloat kTitleMarginX = 8;
-static CGFloat kTitleMarginY = 4;
-static CGFloat kPadding = 10;
-static CGFloat kBorderWidth = 10;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-BOOL FBIsDeviceIPad() {
-#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200
- if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
- return YES;
- }
-#endif
- return NO;
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-@implementation FBDialog
-
-@synthesize delegate = _delegate,
- params = _params;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// private
-
-- (void)addRoundedRectToPath:(CGContextRef)context rect:(CGRect)rect radius:(float)radius {
- CGContextBeginPath(context);
- CGContextSaveGState(context);
-
- if (radius == 0) {
- CGContextTranslateCTM(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
- CGContextAddRect(context, rect);
- } else {
- rect = CGRectOffset(CGRectInset(rect, 0.5, 0.5), 0.5, 0.5);
- CGContextTranslateCTM(context, CGRectGetMinX(rect)-0.5, CGRectGetMinY(rect)-0.5);
- CGContextScaleCTM(context, radius, radius);
- float fw = CGRectGetWidth(rect) / radius;
- float fh = CGRectGetHeight(rect) / radius;
-
- CGContextMoveToPoint(context, fw, fh/2);
- CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);
- CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);
- CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);
- CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
- }
-
- CGContextClosePath(context);
- CGContextRestoreGState(context);
-}
-
-- (void)drawRect:(CGRect)rect fill:(const CGFloat*)fillColors radius:(CGFloat)radius {
- CGContextRef context = UIGraphicsGetCurrentContext();
- CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
-
- if (fillColors) {
- CGContextSaveGState(context);
- CGContextSetFillColor(context, fillColors);
- if (radius) {
- [self addRoundedRectToPath:context rect:rect radius:radius];
- CGContextFillPath(context);
- } else {
- CGContextFillRect(context, rect);
- }
- CGContextRestoreGState(context);
- }
-
- CGColorSpaceRelease(space);
-}
-
-- (void)strokeLines:(CGRect)rect stroke:(const CGFloat*)strokeColor {
- CGContextRef context = UIGraphicsGetCurrentContext();
- CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
-
- CGContextSaveGState(context);
- CGContextSetStrokeColorSpace(context, space);
- CGContextSetStrokeColor(context, strokeColor);
- CGContextSetLineWidth(context, 1.0);
-
- {
- CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y-0.5},
- {rect.origin.x+rect.size.width, rect.origin.y-0.5}};
- CGContextStrokeLineSegments(context, points, 2);
- }
- {
- CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y+rect.size.height-0.5},
- {rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height-0.5}};
- CGContextStrokeLineSegments(context, points, 2);
- }
- {
- CGPoint points[] = {{rect.origin.x+rect.size.width-0.5, rect.origin.y},
- {rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height}};
- CGContextStrokeLineSegments(context, points, 2);
- }
- {
- CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y},
- {rect.origin.x+0.5, rect.origin.y+rect.size.height}};
- CGContextStrokeLineSegments(context, points, 2);
- }
-
- CGContextRestoreGState(context);
-
- CGColorSpaceRelease(space);
-}
-
-- (BOOL)shouldRotateToOrientation:(UIDeviceOrientation)orientation {
- if (orientation == _orientation) {
- return NO;
- } else {
- return orientation == UIDeviceOrientationLandscapeLeft
- || orientation == UIDeviceOrientationLandscapeRight
- || orientation == UIDeviceOrientationPortrait
- || orientation == UIDeviceOrientationPortraitUpsideDown;
- }
-}
-
-- (CGAffineTransform)transformForOrientation {
- UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
- if (orientation == UIInterfaceOrientationLandscapeLeft) {
- return CGAffineTransformMakeRotation(M_PI*1.5);
- } else if (orientation == UIInterfaceOrientationLandscapeRight) {
- return CGAffineTransformMakeRotation(M_PI/2);
- } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
- return CGAffineTransformMakeRotation(-M_PI);
- } else {
- return CGAffineTransformIdentity;
- }
-}
-
-- (void)sizeToFitOrientation:(BOOL)transform {
- if (transform) {
- self.transform = CGAffineTransformIdentity;
- }
-
- CGRect frame = [UIScreen mainScreen].applicationFrame;
- CGPoint center = CGPointMake(
- frame.origin.x + ceil(frame.size.width/2),
- frame.origin.y + ceil(frame.size.height/2));
-
- CGFloat scale_factor = 1.0f;
- if (FBIsDeviceIPad()) {
- // On the iPad the dialog's dimensions should only be 60% of the screen's
- scale_factor = 0.6f;
- }
-
- CGFloat width = floor(scale_factor * frame.size.width) - kPadding * 2;
- CGFloat height = floor(scale_factor * frame.size.height) - kPadding * 2;
-
- _orientation = [UIApplication sharedApplication].statusBarOrientation;
- if (UIInterfaceOrientationIsLandscape(_orientation)) {
- self.frame = CGRectMake(kPadding, kPadding, height, width);
- } else {
- self.frame = CGRectMake(kPadding, kPadding, width, height);
- }
- self.center = center;
-
- if (transform) {
- self.transform = [self transformForOrientation];
- }
-}
-
-- (void)updateWebOrientation {
- UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
- if (UIInterfaceOrientationIsLandscape(orientation)) {
- [_webView stringByEvaluatingJavaScriptFromString:
- @"document.body.setAttribute('orientation', 90);"];
- } else {
- [_webView stringByEvaluatingJavaScriptFromString:
- @"document.body.removeAttribute('orientation');"];
- }
-}
-
-- (void)bounce1AnimationStopped {
- [UIView beginAnimations:nil context:nil];
- [UIView setAnimationDuration:kTransitionDuration/2];
- [UIView setAnimationDelegate:self];
- [UIView setAnimationDidStopSelector:@selector(bounce2AnimationStopped)];
- self.transform = CGAffineTransformScale([self transformForOrientation], 0.9, 0.9);
- [UIView commitAnimations];
-}
-
-- (void)bounce2AnimationStopped {
- [UIView beginAnimations:nil context:nil];
- [UIView setAnimationDuration:kTransitionDuration/2];
- self.transform = [self transformForOrientation];
- [UIView commitAnimations];
-}
-
-- (NSURL*)generateURL:(NSString*)baseURL params:(NSDictionary*)params {
- if (params) {
- NSMutableArray* pairs = [NSMutableArray array];
- for (NSString* key in params.keyEnumerator) {
- NSString* value = [params objectForKey:key];
- NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes(
- NULL, /* allocator */
- (CFStringRef)value,
- NULL, /* charactersToLeaveUnescaped */
- (CFStringRef)@"!*'();:@&=+$,/?%#[]",
- kCFStringEncodingUTF8);
-
- [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, escaped_value]];
- [escaped_value release];
- }
-
- NSString* query = [pairs componentsJoinedByString:@"&"];
- NSString* url = [NSString stringWithFormat:@"%@?%@", baseURL, query];
- return [NSURL URLWithString:url];
- } else {
- return [NSURL URLWithString:baseURL];
- }
-}
-
-- (void)addObservers {
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(deviceOrientationDidChange:)
- name:@"UIDeviceOrientationDidChangeNotification" object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(keyboardWillShow:) name:@"UIKeyboardWillShowNotification" object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(keyboardWillHide:) name:@"UIKeyboardWillHideNotification" object:nil];
-}
-
-- (void)removeObservers {
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:@"UIDeviceOrientationDidChangeNotification" object:nil];
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:@"UIKeyboardWillShowNotification" object:nil];
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:@"UIKeyboardWillHideNotification" object:nil];
-}
-
-- (void)postDismissCleanup {
- [self removeObservers];
- [self removeFromSuperview];
- [_modalBackgroundView removeFromSuperview];
-}
-
-- (void)dismiss:(BOOL)animated {
- [self dialogWillDisappear];
-
- [_loadingURL release];
- _loadingURL = nil;
-
- if (animated) {
- [UIView beginAnimations:nil context:nil];
- [UIView setAnimationDuration:kTransitionDuration];
- [UIView setAnimationDelegate:self];
- [UIView setAnimationDidStopSelector:@selector(postDismissCleanup)];
- self.alpha = 0;
- [UIView commitAnimations];
- } else {
- [self postDismissCleanup];