2010-09-20 19:44:17 -05:00
|
|
|
//
|
|
|
|
// MGMGoogleContacts.m
|
|
|
|
// VoiceBase
|
|
|
|
//
|
|
|
|
// Created by Mr. Gecko on 8/17/10.
|
2011-03-07 19:02:53 -06:00
|
|
|
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). http://mrgeckosmedia.com/
|
|
|
|
//
|
|
|
|
// Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
|
|
// with or without fee is hereby granted, provided that the above copyright notice
|
|
|
|
// and this permission notice appear in all copies.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
|
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
|
|
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
|
|
|
|
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
|
|
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
|
|
|
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
2010-09-20 19:44:17 -05:00
|
|
|
//
|
|
|
|
|
|
|
|
#import "MGMGoogleContacts.h"
|
|
|
|
#import "MGMContactsProtocol.h"
|
|
|
|
#import "MGMInstance.h"
|
|
|
|
#import "MGMAddons.h"
|
2010-09-24 12:46:38 -05:00
|
|
|
#import "MGMXML.h"
|
2010-09-20 19:44:17 -05:00
|
|
|
#import <MGMUsers/MGMUsers.h>
|
|
|
|
|
|
|
|
NSString * const MGMGCAuthenticationURL = @"https://www.google.com/accounts/ClientLogin";
|
|
|
|
NSString * const MGMGCAuthenticationBody = @"Email=%@&Passwd=%@&source=MrGeckosMedia-VoiceBase-0.1&service=cp&accountType=HOSTED_OR_GOOGLE";
|
|
|
|
NSString * const MGMGCUseragent = @"VoiceBase/0.1";
|
|
|
|
|
|
|
|
NSString * const MGMGCContactsURL = @"https://www.google.com/m8/feeds/contacts/default/full?max-results=10000";
|
|
|
|
NSString * const MGMGCGroupsURL = @"https://www.google.com/m8/feeds/groups/default/full?max-results=10000";
|
|
|
|
NSString * const MGMGCAuthorization = @"Authorization";
|
|
|
|
|
|
|
|
const BOOL MGMGoogleContactsInvisible = YES;
|
|
|
|
|
|
|
|
@implementation MGMGoogleContacts
|
|
|
|
- (id)initWithDelegate:(id)theDelegate {
|
2011-02-22 12:00:36 -06:00
|
|
|
if ((self = [super init])) {
|
2010-09-20 19:44:17 -05:00
|
|
|
gettingContacts = NO;
|
|
|
|
delegate = theDelegate;
|
|
|
|
user = [[MGMUser userWithID:[[delegate user] settingForKey:MGMCGoogleContactsUser]] retain];
|
|
|
|
if (user==nil)
|
|
|
|
user = [[delegate user] retain];
|
|
|
|
NSString *username = [user settingForKey:MGMUserName];
|
|
|
|
if (![username containsString:@"@"])
|
|
|
|
username = [username stringByAppendingString:@"@gmail.com"];
|
|
|
|
NSURLCredential *credentials = [NSURLCredential credentialWithUser:username password:[user password] persistence:NSURLCredentialPersistenceForSession];
|
|
|
|
connectionManager = [[MGMURLConnectionManager managerWithCookieStorage:[user cookieStorage]] retain];
|
|
|
|
[connectionManager setCredentials:credentials];
|
2011-02-24 11:24:19 -06:00
|
|
|
[connectionManager setUserAgent:MGMGCUseragent];
|
2010-09-20 19:44:17 -05:00
|
|
|
isAuthenticating = YES;
|
|
|
|
afterAuthentication = [NSMutableArray new];
|
|
|
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMGCAuthenticationURL] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:15.0];
|
|
|
|
[request setHTTPMethod:MGMPostMethod];
|
|
|
|
[request setValue:MGMURLForm forHTTPHeaderField:MGMContentType];
|
|
|
|
[request setHTTPBody:[[NSString stringWithFormat:MGMGCAuthenticationBody, [username addPercentEscapes], [[user password] addPercentEscapes]] dataUsingEncoding:NSUTF8StringEncoding]];
|
2011-02-24 11:24:19 -06:00
|
|
|
MGMURLBasicHandler *handler = [MGMURLBasicHandler handlerWithRequest:request delegate:self];
|
|
|
|
[handler setFailWithError:@selector(authentication:didFailWithError:)];
|
|
|
|
[handler setFinish:@selector(authenticationDidFinish:)];
|
|
|
|
[handler setInvisible:MGMGoogleContactsInvisible];
|
|
|
|
[connectionManager addHandler:handler];
|
2010-09-20 19:44:17 -05:00
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
- (void)dealloc {
|
2011-02-22 12:00:36 -06:00
|
|
|
[user release];
|
|
|
|
[connectionManager cancelAll];
|
|
|
|
[connectionManager release];
|
|
|
|
[authenticationString release];
|
|
|
|
[afterAuthentication release];
|
|
|
|
[releaseTimer fire];
|
|
|
|
[contactEntries release];
|
|
|
|
[contactPhoto release];
|
2010-09-20 19:44:17 -05:00
|
|
|
[super dealloc];
|
|
|
|
}
|
2011-02-24 11:24:19 -06:00
|
|
|
- (void)authentication:(MGMURLBasicHandler *)theHandler didFailWithError:(NSError *)theError {
|
2010-09-20 19:44:17 -05:00
|
|
|
NSLog(@"MGMGoogleContacts Error: %@", theError);
|
|
|
|
}
|
2011-02-24 11:24:19 -06:00
|
|
|
+ (NSDictionary *)dictionaryWithString:(NSString *)theString {
|
|
|
|
NSArray *values = [theString componentsSeparatedByString:@"\n"];
|
2010-09-20 19:44:17 -05:00
|
|
|
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
|
|
|
|
for (int i=0; i<[values count]; i++) {
|
|
|
|
if (![[values objectAtIndex:i] isEqual:@""]) {
|
|
|
|
NSMutableArray *info = [NSMutableArray arrayWithArray:[[values objectAtIndex:i] componentsSeparatedByString:@"="]];
|
|
|
|
NSString *key = [info objectAtIndex:0];
|
|
|
|
[info removeObjectAtIndex:0];
|
|
|
|
NSString *value = [info componentsJoinedByString:@"="];
|
|
|
|
[dictionary setObject:value forKey:key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dictionary;
|
|
|
|
}
|
2011-02-24 11:24:19 -06:00
|
|
|
- (void)authenticationDidFinish:(MGMURLBasicHandler *)theHandler {
|
|
|
|
NSDictionary *info = [MGMGoogleContacts dictionaryWithString:[theHandler string]];
|
2011-02-22 12:00:36 -06:00
|
|
|
[authenticationString release];
|
2010-09-20 19:44:17 -05:00
|
|
|
authenticationString = [[NSString stringWithFormat:@"GoogleLogin auth=%@", [info objectForKey:@"Auth"]] retain];
|
|
|
|
isAuthenticating = NO;
|
|
|
|
while ([afterAuthentication count]!=0) {
|
|
|
|
[[afterAuthentication objectAtIndex:0] invoke];
|
|
|
|
[afterAuthentication removeObjectAtIndex:0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
- (MGMUser *)user {
|
|
|
|
return user;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)stop {
|
|
|
|
shouldStop = YES;
|
|
|
|
[connectionManager cancelAll];
|
|
|
|
if (gettingContacts || gettingGroups)
|
|
|
|
[connectionManager cancelAll];
|
|
|
|
shouldStop = NO;
|
|
|
|
}
|
|
|
|
- (void)getContacts:(id)sender {
|
|
|
|
if (isAuthenticating) {
|
|
|
|
SEL selector = @selector(getContacts:);
|
|
|
|
NSMethodSignature *signature = [self methodSignatureForSelector:selector];
|
|
|
|
if (signature!=nil) {
|
|
|
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
|
|
|
[invocation setSelector:selector];
|
|
|
|
[invocation setTarget:self];
|
|
|
|
[invocation setArgument:&sender atIndex:2];
|
|
|
|
[afterAuthentication addObject:invocation];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (gettingContacts) {
|
|
|
|
NSDictionary *info = [NSDictionary dictionaryWithObject:contactsSender forKey:MGMCRecallSender];
|
|
|
|
NSError *error = [NSError errorWithDomain:MGMCRecallError code:1 userInfo:info];
|
|
|
|
if ([sender respondsToSelector:@selector(contactsError:)]) [sender contactsError:error];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
gettingContacts = YES;
|
|
|
|
contactsSender = sender;
|
|
|
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMGCContactsURL] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0];
|
|
|
|
[request setValue:authenticationString forHTTPHeaderField:MGMGCAuthorization];
|
2011-02-24 11:24:19 -06:00
|
|
|
MGMURLBasicHandler *handler = [MGMURLBasicHandler handlerWithRequest:request delegate:self];
|
|
|
|
[handler setFailWithError:@selector(contacts:didFailWithError:)];
|
|
|
|
[handler setFinish:@selector(contactsDidFinish:)];
|
|
|
|
[handler setInvisible:MGMGoogleContactsInvisible];
|
|
|
|
[connectionManager addHandler:handler];
|
2010-09-20 19:44:17 -05:00
|
|
|
}
|
2011-02-24 11:24:19 -06:00
|
|
|
- (void)contacts:(MGMURLBasicHandler *)theHandler didFailWithError:(NSError *)theError {
|
2010-09-20 19:44:17 -05:00
|
|
|
gettingContacts = NO;
|
|
|
|
NSLog(@"MGMGoogleContacts Error: %@", theError);
|
|
|
|
if ([contactsSender respondsToSelector:@selector(contactsError:)]) [contactsSender contactsError:theError];
|
|
|
|
}
|
2011-02-24 11:24:19 -06:00
|
|
|
- (void)contactsDidFinish:(MGMURLBasicHandler *)theHandler {
|
2011-02-22 12:00:36 -06:00
|
|
|
[releaseTimer invalidate];
|
|
|
|
[releaseTimer release];
|
|
|
|
releaseTimer = nil;
|
|
|
|
[contacts release];
|
2010-09-20 19:44:17 -05:00
|
|
|
contacts = [NSMutableArray new];
|
2011-02-24 11:24:19 -06:00
|
|
|
MGMXMLElement *XML = [(MGMXMLDocument *)[[[MGMXMLDocument alloc] initWithData:[theHandler data] options:MGMXMLDocumentTidyXML error:nil] autorelease] rootElement];
|
2010-09-20 19:44:17 -05:00
|
|
|
contactEntries = [[XML elementsForName:@"entry"] retain];
|
|
|
|
contactsIndex=0;
|
|
|
|
[self continueContacts];
|
|
|
|
}
|
2011-02-24 11:24:19 -06:00
|
|
|
- (void)photo:(MGMURLBasicHandler *)theHandler didFailWithError:(NSError *)theError {
|
2010-09-20 19:44:17 -05:00
|
|
|
NSLog(@"MGMGoogleContacts Photo Error: %@", theError);
|
|
|
|
[self parseContact];
|
|
|
|
contactsIndex++;
|
|
|
|
[self continueContacts];
|
|
|
|
}
|
2011-02-24 11:24:19 -06:00
|
|
|
- (void)photoDidFinish:(MGMURLBasicHandler *)theHandler {
|
|
|
|
contactPhoto = [[theHandler data] retain];
|
2010-09-20 19:44:17 -05:00
|
|
|
[self parseContact];
|
|
|
|
contactsIndex++;
|
|
|
|
[self continueContacts];
|
|
|
|
}
|
|
|
|
- (void)parseContact {
|
|
|
|
if (shouldStop) return;
|
2010-09-24 12:46:38 -05:00
|
|
|
MGMXMLElement *entry = [contactEntries objectAtIndex:contactsIndex];
|
2010-09-20 19:44:17 -05:00
|
|
|
NSArray *titles = [entry elementsForName:@"title"];
|
|
|
|
NSString *name = @"";
|
|
|
|
if ([titles count]!=0)
|
|
|
|
name = [[titles objectAtIndex:0] stringValue];
|
|
|
|
NSArray *organizations = [entry elementsForName:@"gd:organization"];
|
|
|
|
NSString *company = @"";
|
|
|
|
if ([organizations count]!=0) {
|
|
|
|
NSArray *organizationName = [[organizations objectAtIndex:0] elementsForName:@"gd:orgName"];
|
|
|
|
if ([organizationName count]!=0)
|
|
|
|
company = [[organizationName objectAtIndex:0] stringValue];
|
|
|
|
}
|
|
|
|
NSArray *phones = [entry elementsForName:@"gd:phoneNumber"];
|
|
|
|
NSData *image = nil;
|
|
|
|
if ([phones count]>0) {
|
|
|
|
if (contactPhoto!=nil) {
|
2010-09-24 12:46:38 -05:00
|
|
|
image = [contactPhoto resizeTo:MGMABPhotoSize];
|
2010-09-20 19:44:17 -05:00
|
|
|
[contactPhoto release];
|
|
|
|
contactPhoto = nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int p=0; p<[phones count]; p++) {
|
|
|
|
if (shouldStop) break;
|
2010-09-24 12:46:38 -05:00
|
|
|
MGMXMLElement *phone = [phones objectAtIndex:p];
|
2010-09-20 19:44:17 -05:00
|
|
|
NSMutableDictionary *contact = [NSMutableDictionary dictionary];
|
|
|
|
[contact setObject:name forKey:MGMCName];
|
|
|
|
[contact setObject:company forKey:MGMCCompany];
|
|
|
|
if (delegate!=nil)
|
|
|
|
[contact setObject:[[phone stringValue] phoneFormatWithAreaCode:[delegate areaCode]] forKey:MGMCNumber];
|
|
|
|
else
|
|
|
|
[contact setObject:[[phone stringValue] phoneFormat] forKey:MGMCNumber];
|
|
|
|
NSString *label = @"";
|
2010-09-24 12:46:38 -05:00
|
|
|
MGMXMLNode *labelXML = [phone attributeForName:@"label"];
|
2010-09-20 19:44:17 -05:00
|
|
|
if (labelXML==nil) {
|
2010-09-24 12:46:38 -05:00
|
|
|
MGMXMLNode *rel = [phone attributeForName:@"rel"];
|
2010-09-20 19:44:17 -05:00
|
|
|
if (rel!=nil) {
|
|
|
|
NSString *string = [rel stringValue];
|
|
|
|
NSRange range = [string rangeOfString:@"#"];
|
|
|
|
if (range.location!=NSNotFound) {
|
|
|
|
label = [string substringFromIndex:range.location+range.length];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
label = [labelXML stringValue];
|
|
|
|
}
|
|
|
|
[contact setObject:[label capitalizedString] forKey:MGMCLabel];
|
|
|
|
[contacts addObject:[[contact copy] autorelease]];
|
|
|
|
if (image!=nil)
|
|
|
|
[contact setObject:image forKey:MGMCPhoto];
|
|
|
|
if ([contactsSender respondsToSelector:@selector(gotContact:)]) [contactsSender gotContact:contact];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
- (void)continueContacts {
|
|
|
|
for (; contactsIndex<[contactEntries count]; contactsIndex++) {
|
|
|
|
if (shouldStop) break;
|
2010-09-24 12:46:38 -05:00
|
|
|
MGMXMLElement *entry = [contactEntries objectAtIndex:contactsIndex];
|
2010-09-20 19:44:17 -05:00
|
|
|
NSArray *phones = [entry elementsForName:@"gd:phoneNumber"];
|
|
|
|
if ([phones count]!=0) {
|
|
|
|
NSArray *links = [entry elementsForName:@"link"];
|
|
|
|
BOOL loadingPhoto = NO;
|
|
|
|
for (int i=0; i<[links count]; i++) {
|
2010-09-24 12:46:38 -05:00
|
|
|
MGMXMLNode *rel = [(MGMXMLElement *)[links objectAtIndex:i] attributeForName:@"rel"];
|
2010-09-20 19:44:17 -05:00
|
|
|
if (rel!=nil) {
|
|
|
|
if ([[rel stringValue] containsString:@"#photo"]) {
|
|
|
|
NSString *url = [[[links objectAtIndex:i] attributeForName:@"href"] stringValue];
|
|
|
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0];
|
|
|
|
[request setValue:authenticationString forHTTPHeaderField:MGMGCAuthorization];
|
2011-02-24 11:24:19 -06:00
|
|
|
MGMURLBasicHandler *handler = [MGMURLBasicHandler handlerWithRequest:request delegate:self];
|
|
|
|
[handler setFailWithError:@selector(photo:didFailWithError:)];
|
|
|
|
[handler setFinish:@selector(photoDidFinish:)];
|
|
|
|
[connectionManager addHandler:handler];
|
2010-09-20 19:44:17 -05:00
|
|
|
loadingPhoto = YES;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!loadingPhoto)
|
|
|
|
[self parseContact];
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (contactsIndex>=[contactEntries count]) {
|
|
|
|
releaseTimer = [[NSTimer scheduledTimerWithTimeInterval:20.0 target:self selector:@selector(releaseContacts) userInfo:nil repeats:NO] retain];
|
|
|
|
if ([contactsSender respondsToSelector:@selector(doneGettingContacts)]) [contactsSender doneGettingContacts];
|
|
|
|
[contactEntries release];
|
|
|
|
contactEntries = nil;
|
|
|
|
contactsSender = nil;
|
|
|
|
gettingContacts = NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
- (void)releaseContacts {
|
2011-02-22 12:00:36 -06:00
|
|
|
[releaseTimer invalidate];
|
|
|
|
[releaseTimer release];
|
|
|
|
releaseTimer = nil;
|
|
|
|
[contacts release];
|
|
|
|
contacts = nil;
|
2010-09-20 19:44:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)getGroups:(id)sender {
|
|
|
|
if (isAuthenticating) {
|
|
|
|
SEL selector = @selector(getGroups:);
|
|
|
|
NSMethodSignature *signature = [self methodSignatureForSelector:selector];
|
|
|
|
if (signature!=nil) {
|
|
|
|
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
|
|
|
[invocation setSelector:selector];
|
|
|
|
[invocation setTarget:self];
|
|
|
|
[invocation setArgument:&sender atIndex:2];
|
|
|
|
[afterAuthentication addObject:invocation];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (gettingGroups) {
|
|
|
|
NSDictionary *info = [NSDictionary dictionaryWithObject:groupsSender forKey:MGMCRecallSender];
|
|
|
|
NSError *error = [NSError errorWithDomain:MGMCRecallError code:1 userInfo:info];
|
|
|
|
if ([sender respondsToSelector:@selector(groupsError:)]) [sender groupsError:error];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ([sender respondsToSelector:@selector(groupsError:)]) [sender groupsError:nil];
|
|
|
|
return;
|
|
|
|
gettingGroups = YES;
|
|
|
|
groupsSender = sender;
|
|
|
|
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:MGMGCGroupsURL]];
|
|
|
|
[request setValue:authenticationString forHTTPHeaderField:MGMGCAuthorization];
|
2011-02-24 11:24:19 -06:00
|
|
|
MGMURLBasicHandler *handler = [MGMURLBasicHandler handlerWithRequest:request delegate:self];
|
|
|
|
[handler setFailWithError:@selector(groups:didFailWithError:)];
|
|
|
|
[handler setFinish:@selector(groupsDidFinish:)];
|
|
|
|
[handler setInvisible:MGMGoogleContactsInvisible];
|
|
|
|
[connectionManager addHandler:handler];
|
2010-09-20 19:44:17 -05:00
|
|
|
}
|
2011-02-24 11:24:19 -06:00
|
|
|
- (void)groups:(MGMURLBasicHandler *)theHandler didFailWithError:(NSError *)theError {
|
2010-09-20 19:44:17 -05:00
|
|
|
gettingGroups = NO;
|
|
|
|
NSLog(@"MGMGoogleContacts Error: %@", theError);
|
|
|
|
}
|
2011-02-24 11:24:19 -06:00
|
|
|
- (void)groupsDidFinish:(MGMURLBasicHandler *)theHandler {
|
|
|
|
MGMXMLElement *XML = [(MGMXMLDocument *)[[[MGMXMLDocument alloc] initWithData:[theHandler data] options:MGMXMLDocumentTidyXML error:nil] autorelease] rootElement];
|
2010-09-20 19:44:17 -05:00
|
|
|
NSLog(@"%@", XML);
|
|
|
|
gettingGroups = NO;
|
|
|
|
}
|
|
|
|
@end
|