-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improved AB integration. Now merges cards nicely. If you have duplica…
…tes, try deleting the Jabber People group created by a previous version and let the client recreate it. git-svn-id: http://svn.gna.org/svn/etoile/trunk/Etoile/Services/User/Jabber/xmpp@2638 7b3f36aa-e6db-49c1-8b4c-66eac1997e64
- Loading branch information
1 parent
d5f818b
commit e04d499
Showing
5 changed files
with
233 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// | ||
// ABPerson+merging.h | ||
// Jabber | ||
// | ||
// Created by David Chisnall on 19/11/2007. | ||
// Copyright 2007 __MyCompanyName__. All rights reserved. | ||
// | ||
|
||
#import <Cocoa/Cocoa.h> | ||
#import <AddressBook/AddressBook.h> | ||
|
||
@interface ABPerson (Merging) | ||
/** | ||
* Attempts to find an existing person in the address book who | ||
* might correspond to this one. | ||
*/ | ||
- (ABPerson*) findExistingPerson; | ||
/** | ||
* Attempts to merge the fields in the argument in to | ||
* this person. Returns an array of conlicting properties. | ||
*/ | ||
- (NSArray*) mergePerson:(ABPerson*)aPerson; | ||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// | ||
// ABPerson+merging.m | ||
// Jabber | ||
// | ||
// Created by David Chisnall on 19/11/2007. | ||
// Copyright 2007 __MyCompanyName__. All rights reserved. | ||
// | ||
|
||
#import "ABPerson+merging.h" | ||
#import "Macros.h" | ||
|
||
#define MATCH(x) [ABPerson searchElementForProperty:x\ | ||
label:nil\ | ||
key:nil\ | ||
value:[self valueForProperty:x]\ | ||
comparison:kABEqual]; | ||
#define MATCH_IM_ADDRESS(type) if((addresses = [self valueForProperty:type]) != nil)\ | ||
{\ | ||
for(unsigned int i=0 ; i<[addresses count] ; i++)\ | ||
{\ | ||
id address = [addresses valueAtIndex:i];\ | ||
ABSearchElement * search = [ABPerson searchElementForProperty:type\ | ||
label:nil\ | ||
key:nil\ | ||
value:address\ | ||
comparison:kABEqual];\ | ||
NSArray * people = [ab recordsMatchingSearchElement:search];\ | ||
if([people count] == 1)\ | ||
{\ | ||
return [people objectAtIndex:0];\ | ||
}\ | ||
}\ | ||
} | ||
|
||
|
||
|
||
@implementation ABPerson (merging) | ||
- (ABPerson*) findExistingPerson | ||
{ | ||
ABAddressBook * ab = [ABAddressBook sharedAddressBook]; | ||
NSString * firstName = [self valueForProperty:kABFirstNameProperty]; | ||
if([self valueForProperty:kABLastNameProperty] && firstName) | ||
{ | ||
ABSearchElement * search = MATCH(kABLastNameProperty); | ||
NSArray * people = [ab recordsMatchingSearchElement:search]; | ||
FOREACH(people, person, ABPerson*) | ||
{ | ||
if([firstName isEqualToString:[person valueForProperty:kABFirstNameProperty]]) | ||
{ | ||
return person; | ||
} | ||
} | ||
} | ||
else | ||
{ | ||
ABMultiValue * addresses; | ||
MATCH_IM_ADDRESS(kABJabberInstantProperty) | ||
MATCH_IM_ADDRESS(kABMSNInstantProperty) | ||
MATCH_IM_ADDRESS(kABAIMInstantProperty) | ||
MATCH_IM_ADDRESS(kABICQInstantProperty) | ||
MATCH_IM_ADDRESS(kABYahooInstantProperty) | ||
} | ||
return nil; | ||
} | ||
- (NSArray*) mergePerson:(ABPerson*)aPerson | ||
{ | ||
NSArray * properties = [ABPerson properties]; | ||
NSMutableArray * failedProperties = [NSMutableArray array]; | ||
FOREACH(properties, property, NSString*) | ||
{ | ||
//Don't update implicit properties. | ||
if(!([property isEqualToString:kABUIDProperty] | ||
|| | ||
[property isEqualToString:kABCreationDateProperty] | ||
|| | ||
[property isEqualToString:kABModificationDateProperty])) | ||
{ | ||
id otherValue = [aPerson valueForProperty:property]; | ||
if(otherValue != nil) | ||
{ | ||
id value = [self valueForProperty:property]; | ||
//If we have no copy of this, just add it | ||
if(value == nil) | ||
{ | ||
[self setValue:otherValue forProperty:property]; | ||
} | ||
else | ||
{ | ||
//If it's a multivalue with compatible types, merge it: | ||
if([value isKindOfClass:[ABMultiValue class]] && | ||
([value propertyType] == [otherValue propertyType])) | ||
{ | ||
ABMutableMultiValue * old = [value mutableCopy]; | ||
for(unsigned int i=0 ; i<[otherValue count] ; i++) | ||
{ | ||
id v = [(ABMultiValue*)otherValue valueAtIndex:i]; | ||
BOOL duplicate = NO; | ||
for(unsigned int j=0 ; i<[old count] ; i++) | ||
{ | ||
if([v isEqual:[old valueAtIndex:j]]) | ||
{ | ||
duplicate = YES; | ||
break; | ||
} | ||
} | ||
if(!duplicate) | ||
{ | ||
[old addValue:v withLabel:[otherValue labelAtIndex:i]]; | ||
} | ||
} | ||
[self setValue:old forProperty:property]; | ||
} | ||
else | ||
{ | ||
if(![otherValue isEqual:value]) | ||
{ | ||
NSLog(@"Not merging %@. %@ => %@", property, value, otherValue); | ||
[failedProperties addObject:property]; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
if([self imageData] == nil) | ||
{ | ||
[self setImageData:[aPerson imageData]]; | ||
} | ||
return failedProperties; | ||
} | ||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
#import "XMPPConnection.h" | ||
#import "ServiceDiscovery.h" | ||
#import "NSData+Base64.h" | ||
#import "ABPerson+merging.h" | ||
#import "../Macros.h" | ||
|
||
@implementation JabberPerson | ||
|
@@ -41,7 +42,8 @@ - (id) init | |
{ | ||
SUPERINIT | ||
identities = [[NSMutableDictionary alloc] init]; | ||
identityList = [[NSMutableArray alloc] init]; | ||
identityList = [[NSMutableArray alloc] init]; | ||
photoHashes = [[NSMutableDictionary alloc] init]; | ||
return self; | ||
} | ||
|
||
|
@@ -165,11 +167,11 @@ - (void) handlePresence:(Presence*)aPresence | |
NSString * newPhotoHash = [[aPresence children] objectForKey:@"vCardUpdate"]; | ||
if(newPhotoHash) | ||
{ | ||
if(photoHash == nil) | ||
if(currentHash == nil) | ||
{ | ||
photoHash = [[[vCard imageData] sha1] retain]; | ||
currentHash = [[[vCard imageData] sha1] retain]; | ||
} | ||
if(![photoHash isEqualToString:newPhotoHash]) | ||
if(![photoHashes objectForKey:newPhotoHash]) | ||
{ | ||
[self requestvCard:from]; | ||
} | ||
|
@@ -209,7 +211,12 @@ - (void) handleIq:(Iq*)anIq | |
ABAddressBook * ab = [ABAddressBook sharedAddressBook]; | ||
if(vCard != nil) | ||
{ | ||
//TODO: Merge the vCard data | ||
//Merge the vCard data | ||
NSArray * unmerged = [vCard mergePerson:identityvCard]; | ||
if([unmerged count] > 0) | ||
{ | ||
//TODO: Ask about which ones to merge | ||
} | ||
} | ||
else | ||
{ | ||
|
@@ -218,7 +225,7 @@ - (void) handleIq:(Iq*)anIq | |
{ | ||
[vCard setValue:name forProperty:kABNicknameProperty]; | ||
} | ||
//TODO: Parse bridged JIDs correctly (i.e. parse [email protected] | ||
//Parse bridged JIDs correctly (i.e. parse [email protected] | ||
//as an ICQ UIN, not a JID) | ||
id property = kABJabberInstantProperty; | ||
id label = kABJabberHomeLabel; | ||
|
@@ -264,25 +271,40 @@ - (void) handleIq:(Iq*)anIq | |
[vCard setValue:vCardJID forProperty:property]; | ||
[vCardJID release]; | ||
} | ||
//Get the group that contains Jabber people | ||
ABGroup * jabberGroup = nil; | ||
NSArray * groups = [ab groups]; | ||
FOREACH(groups, abgroup, ABRecord*) | ||
ABPerson * oldPerson = [vCard findExistingPerson]; | ||
if(oldPerson != nil) | ||
{ | ||
if([[abgroup valueForProperty:kABGroupNameProperty] isEqualToString:@"Jabber People"]) | ||
NSString * notes = [oldPerson valueForProperty:kABNoteProperty]; | ||
if(notes == nil) | ||
{ | ||
jabberGroup = (ABGroup*)abgroup; | ||
notes = @""; | ||
} | ||
notes = [notes stringByAppendingFormat:@"\nMerged properties from %@", [jid jidString]]; | ||
[oldPerson setValue:notes forProperty:kABNoteProperty]; | ||
[oldPerson mergePerson:vCard]; | ||
vCard = oldPerson; | ||
} | ||
if(jabberGroup == nil) | ||
else | ||
{ | ||
jabberGroup = [[[ABGroup alloc] init] autorelease]; | ||
[jabberGroup setValue:@"Jabber People" forProperty:kABGroupNameProperty]; | ||
[ab addRecord:jabberGroup]; | ||
//Get the group that contains Jabber people | ||
ABGroup * jabberGroup = nil; | ||
NSArray * groups = [ab groups]; | ||
FOREACH(groups, abgroup, ABRecord*) | ||
{ | ||
if([[abgroup valueForProperty:kABGroupNameProperty] isEqualToString:@"Jabber People"]) | ||
{ | ||
jabberGroup = (ABGroup*)abgroup; | ||
} | ||
} | ||
if(jabberGroup == nil) | ||
{ | ||
jabberGroup = [[[ABGroup alloc] init] autorelease]; | ||
[jabberGroup setValue:@"Jabber People" forProperty:kABGroupNameProperty]; | ||
[ab addRecord:jabberGroup]; | ||
} | ||
[ab addRecord:vCard]; | ||
[jabberGroup addMember:vCard]; | ||
} | ||
// | ||
[ab addRecord:vCard]; | ||
[jabberGroup addMember:vCard]; | ||
[ab save]; | ||
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; | ||
NSDictionary * vCards = [defaults dictionaryForKey:@"vCards"]; | ||
|
@@ -293,8 +315,19 @@ - (void) handleIq:(Iq*)anIq | |
NSMutableDictionary * newvCards = [vCards mutableCopy]; | ||
[newvCards setObject:[vCard uniqueId] forKey:[NSString stringWithFormat:@"%@!%@", group, name]]; | ||
[defaults setObject:newvCards forKey:@"vCards"]; | ||
[photoHash release]; | ||
photoHash = [[[vCard imageData] sha1] retain]; | ||
} | ||
NSData * imageData = [vCard imageData]; | ||
if(imageData != nil) | ||
{ | ||
NSString * imageHash = [imageData sha1]; | ||
if(![imageHash isEqualToString:currentHash]) | ||
{ | ||
[photoHashes setObject:imageData forKey:imageHash]; | ||
[avatar release]; | ||
avatar = nil; | ||
[currentHash release]; | ||
currentHash = [imageHash retain]; | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -326,7 +359,16 @@ - (NSImage*) avatar | |
{ | ||
if(avatar == nil) | ||
{ | ||
NSData * avatarData = [vCard imageData]; | ||
NSData * avatarData = [photoHashes objectForKey:currentHash]; | ||
if(avatarData == nil) | ||
{ | ||
avatarData = [vCard imageData]; | ||
if(avatarData != nil) | ||
{ | ||
currentHash = [[avatarData sha1] retain]; | ||
[photoHashes setObject:avatarData forKey:currentHash]; | ||
} | ||
} | ||
if(avatarData != nil) | ||
{ | ||
avatar = [[NSImage alloc] initWithData:avatarData]; | ||
|
@@ -340,6 +382,7 @@ - (void) dealloc | |
[group release]; | ||
[name release]; | ||
[identities release]; | ||
[photoHashes release]; | ||
[super dealloc]; | ||
} | ||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters