diff --git a/ChangeLog b/ChangeLog index 195bbe157..045e7af1e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2010-04-23 Wolfgang Sourdeau + + * Tools/SOGoSockDOperation.m (-_performSearch): we now support an + additional identifier in the object DN, for specifying specific + objects. + + * SoObjects/Contacts/SOGoContactSourceFolder.m + (_flattenedRecord:): new method with the repetitive code from + _flattenedRecords. Snipped to offer the same functionality with + single records. + (-lookupContactWithName:): implemented this method to ensure + compatibility with SOGoGCSFolder (and ). + + * SoObjects/Contacts/SOGoContactGCSFolder.m + (_qualifierForFilter:): adjusted qualifiers to perform the same + search that Thundebird perform in its local abooks. + (-lookupContactWithName:): fixed method to use an equality + qualifier. Simplified code by reducing the amount of required + variables. + 2010-04-22 Wolfgang Sourdeau * SoObjects/SOGo/SOGoGCSFolder.m (-renameTo:): when the active diff --git a/SoObjects/Contacts/SOGoContactFolder.h b/SoObjects/Contacts/SOGoContactFolder.h index cb643ddbc..dfcb4287f 100644 --- a/SoObjects/Contacts/SOGoContactFolder.h +++ b/SoObjects/Contacts/SOGoContactFolder.h @@ -49,6 +49,7 @@ - (NSArray *) lookupContactsWithFilter: (NSString *) filter sortBy: (NSString *) sortKey ordering: (NSComparisonResult) sortOrdering; +- (NSDictionary *) lookupContactWithName: (NSString *) aName; @end diff --git a/SoObjects/Contacts/SOGoContactGCSFolder.m b/SoObjects/Contacts/SOGoContactGCSFolder.m index e32a6ba8b..7c75371e9 100644 --- a/SoObjects/Contacts/SOGoContactGCSFolder.m +++ b/SoObjects/Contacts/SOGoContactGCSFolder.m @@ -166,13 +166,11 @@ filter = [[filter stringByReplacingString: @"\\" withString: @"\\\\"] stringByReplacingString: @"'" withString: @"\\'\\'"]; qs = [NSString stringWithFormat: - @"(c_sn isCaseInsensitiveLike: '%@%%') OR " - @"(c_givenname isCaseInsensitiveLike: '%@%%') OR " - @"(c_cn isCaseInsensitiveLike: '%@%%') OR " - @"(c_mail isCaseInsensitiveLike: '%@%%') OR " - @"(c_telephonenumber isCaseInsensitiveLike: '%%%@%%') OR " - @"(c_o isCaseInsensitiveLike: '%%%@%%')", - filter, filter, filter, filter, filter, filter]; + @"(c_sn isCaseInsensitiveLike: '%%%@%%') OR " + @"(c_givenname isCaseInsensitiveLike: '%%%@%%') OR " + @"(c_cn isCaseInsensitiveLike: '%%%@%%') OR " + @"(c_mail isCaseInsensitiveLike: '%%%@%%')", + filter, filter, filter, filter]; qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; } else @@ -224,31 +222,30 @@ return newRecords; } +/* This method returns the quick entry corresponding to the name passed as + parameter. */ - (NSDictionary *) lookupContactWithName: (NSString *) aName { - NSArray *fields, *dbRecords, *records; - NSDictionary *record; + NSArray *dbRecords; + NSMutableDictionary *record; EOQualifier *qualifier; NSString *qs; - fields = folderListingFields; record = nil; if (aName && [aName length] > 0) { aName = [[aName stringByReplacingString: @"\\" withString: @"\\\\"] stringByReplacingString: @"'" withString: @"\\'\\'"]; - qs = [NSString stringWithFormat: @"(c_name isCaseInsensitiveLike: '%@')", aName]; + qs = [NSString stringWithFormat: @"(c_name='%@')", aName]; qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; - - dbRecords = [[self ocsFolder] fetchFields: fields + dbRecords = [[self ocsFolder] fetchFields: folderListingFields matchingQualifier: qualifier]; - if ([dbRecords count] > 0) - { - records = [self _flattenedRecords: dbRecords]; - record = [records lastObject]; - } + { + record = [dbRecords objectAtIndex: 0]; + [self fixupContactRecord: record]; + } } return record; @@ -258,13 +255,12 @@ sortBy: (NSString *) sortKey ordering: (NSComparisonResult) sortOrdering { - NSArray *fields, *dbRecords, *records; + NSArray *dbRecords, *records; EOQualifier *qualifier; EOSortOrdering *ordering; - fields = folderListingFields; qualifier = [self _qualifierForFilter: filter]; - dbRecords = [[self ocsFolder] fetchFields: fields + dbRecords = [[self ocsFolder] fetchFields: folderListingFields matchingQualifier: qualifier]; if ([dbRecords count] > 0) diff --git a/SoObjects/Contacts/SOGoContactSourceFolder.m b/SoObjects/Contacts/SOGoContactSourceFolder.m index e8cbd5863..5a7b85ed8 100644 --- a/SoObjects/Contacts/SOGoContactSourceFolder.m +++ b/SoObjects/Contacts/SOGoContactSourceFolder.m @@ -199,75 +199,92 @@ return [source allEntryIDs]; } +- (NSDictionary *) _flattenedRecord: (NSDictionary *) oldRecord +{ + NSMutableDictionary *newRecord; + NSString *data; + + newRecord = [NSMutableDictionary dictionaryWithCapacity: 8]; + [newRecord setObject: [oldRecord objectForKey: @"c_uid"] + forKey: @"c_uid"]; + [newRecord setObject: [oldRecord objectForKey: @"c_name"] + forKey: @"c_name"]; + + data = [oldRecord objectForKey: @"displayname"]; + if (!data) + data = [oldRecord objectForKey: @"c_cn"]; + if (!data) + data = @""; + [newRecord setObject: data forKey: @"c_cn"]; + + data = [oldRecord objectForKey: @"mail"]; + if (!data) + data = @""; + [newRecord setObject: data forKey: @"c_mail"]; + + data = [oldRecord objectForKey: @"nsaimid"]; + if (![data length]) + data = [oldRecord objectForKey: @"nscpaimscreenname"]; + if (![data length]) + data = @""; + [newRecord setObject: data forKey: @"c_screenname"]; + + data = [oldRecord objectForKey: @"o"]; + if (!data) + data = @""; + [newRecord setObject: data forKey: @"c_o"]; + + data = [oldRecord objectForKey: @"telephonenumber"]; + if (![data length]) + data = [oldRecord objectForKey: @"cellphone"]; + if (![data length]) + data = [oldRecord objectForKey: @"homephone"]; + if (![data length]) + data = @""; + [newRecord setObject: data forKey: @"c_telephonenumber"]; + + // Custom attribute for group-lookups. See LDAPSource.m where + // it's set. + data = [oldRecord objectForKey: @"isGroup"]; + if (data) + [newRecord setObject: data forKey: @"isGroup"]; + + data = [oldRecord objectForKey: @"c_info"]; + if ([data length] > 0) + [newRecord setObject: data forKey: @"contactInfo"]; + + return newRecord; +} + - (NSArray *) _flattenedRecords: (NSArray *) records { NSMutableArray *newRecords; NSEnumerator *oldRecords; NSDictionary *oldRecord; - NSMutableDictionary *newRecord; - NSString *data; newRecords = [NSMutableArray arrayWithCapacity: [records count]]; oldRecords = [records objectEnumerator]; while ((oldRecord = [oldRecords nextObject])) - { - newRecord = [NSMutableDictionary new]; - [newRecord setObject: [oldRecord objectForKey: @"c_uid"] - forKey: @"c_uid"]; - [newRecord setObject: [oldRecord objectForKey: @"c_name"] - forKey: @"c_name"]; - - data = [oldRecord objectForKey: @"displayname"]; - if (!data) - data = [oldRecord objectForKey: @"c_cn"]; - if (!data) - data = @""; - [newRecord setObject: data forKey: @"c_cn"]; - - data = [oldRecord objectForKey: @"mail"]; - if (!data) - data = @""; - [newRecord setObject: data forKey: @"c_mail"]; - - data = [oldRecord objectForKey: @"nsaimid"]; - if (![data length]) - data = [oldRecord objectForKey: @"nscpaimscreenname"]; - if (![data length]) - data = @""; - [newRecord setObject: data forKey: @"c_screenname"]; - - data = [oldRecord objectForKey: @"o"]; - if (!data) - data = @""; - [newRecord setObject: data forKey: @"c_o"]; - - data = [oldRecord objectForKey: @"telephonenumber"]; - if (![data length]) - data = [oldRecord objectForKey: @"cellphone"]; - if (![data length]) - data = [oldRecord objectForKey: @"homephone"]; - if (![data length]) - data = @""; - [newRecord setObject: data forKey: @"c_telephonenumber"]; - - // Custom attribute for group-lookups. See LDAPSource.m where - // it's set. - data = [oldRecord objectForKey: @"isGroup"]; - if (data) - [newRecord setObject: data forKey: @"isGroup"]; - - data = [oldRecord objectForKey: @"c_info"]; - if ([data length] > 0) - [newRecord setObject: data forKey: @"contactInfo"]; - - [newRecords addObject: newRecord]; - [newRecord release]; - } + [newRecords addObject: [self _flattenedRecord: oldRecord]]; return newRecords; } +/* This method returns the entry corresponding to the name passed as + parameter. */ +- (NSDictionary *) lookupContactWithName: (NSString *) aName +{ + NSDictionary *record; + + if (aName && [aName length] > 0) + record = [self _flattenedRecord: [source lookupContactEntry: aName]]; + else + record = nil; + + return record; +} + - (NSArray *) lookupContactsWithFilter: (NSString *) filter sortBy: (NSString *) sortKey ordering: (NSComparisonResult) sortOrdering diff --git a/Tools/SOGoSockDOperation.m b/Tools/SOGoSockDOperation.m index 85cbd6114..1e481d1da 100644 --- a/Tools/SOGoSockDOperation.m +++ b/Tools/SOGoSockDOperation.m @@ -27,8 +27,8 @@ #import #import +#import #import -#import #import #import #import @@ -102,7 +102,7 @@ } [result appendFormat: @"dn: cn=%@,%@\n", - [entry objectForKey: @"c_name"], [parameters objectForKey: @"base"]]; + [entry objectForKey: @"c_name"], [parameters objectForKey: @"suffix"]]; [result appendString: @"objectClass: person\nobjectClass: inetOrgPerson\n"]; max = [ldifFields count]; @@ -153,12 +153,46 @@ charRange = [dn rangeOfString: @"="]; valueRange.location = charRange.location + 1; charRange = [dn rangeOfString: @","]; - valueRange.length = charRange.location - valueRange.location; + if (charRange.location == NSNotFound) + valueRange.length = [dn length] - valueRange.location; + else + valueRange.length = charRange.location - valueRange.location; firstValue = [dn substringFromRange: valueRange]; return firstValue; } +- (NSArray *) _extractIdsFromDN: (NSString *) dn +{ + NSRange suffixRange; + NSString *prefix, *identifier; + NSMutableArray *ids; + NSArray *components; + int count, max; + + ids = nil; + + suffixRange = [dn rangeOfString: [parameters objectForKey: @"suffix"]]; + if (suffixRange.length > 0) + { + if (suffixRange.location > 0) + prefix = [dn substringToIndex: suffixRange.location - 1]; + else + prefix = @""; + components = [prefix componentsSeparatedByString: @","]; + max = [components count]; + ids = [NSMutableArray arrayWithCapacity: max]; + for (count = 0; count < max; count++) + { + identifier = [self _extractFirstValueFromDN: + [components objectAtIndex: count]]; + [ids addObject: identifier]; + } + } + + return ids; +} + - (NSString *) _convertLDAPFilter: (NSString *) ldapFilter { /* Ultra hackish: we extract the value between the first "=" and the first @@ -183,12 +217,12 @@ return filter; } -- (SOGoContactGCSFolder *) _getFolderWithId: (NSString *) folderId +- (id ) _getFolderWithId: (NSString *) folderId forUser: (NSString *) uid { SOGoUserFolder *userFolder; SOGoContactFolders *parentFolder; - SOGoContactGCSFolder *folder; + id folder; userFolder = [SOGoUserFolder objectWithName: uid inContainer: nil]; parentFolder = [userFolder lookupName: @"Contacts" @@ -200,27 +234,42 @@ - (void) _performSearch { - NSString *bindDN, *baseDN, *uid, *folderId, *filter; - SOGoContactGCSFolder *folder; + NSString *bindDN, *baseDN, *uid, *filter; + id folder; + id singleEntry; + NSArray *dnIDs; + int idCount; bindDN = [parameters objectForKey: @"binddn"]; baseDN = [parameters objectForKey: @"base"]; if ([bindDN length] && [baseDN length]) { uid = [self _extractFirstValueFromDN: bindDN]; - folderId = [self _extractFirstValueFromDN: baseDN]; - folder = [self _getFolderWithId: folderId forUser: uid]; - if (folder) + dnIDs = [self _extractIdsFromDN: baseDN]; + idCount = [dnIDs count]; + if (idCount && idCount < 3) { - filter - = [self _convertLDAPFilter: [parameters objectForKey: @"filter"]]; - // if (![filter length] - // && [folder isKindOfClass: [SOGoContactSourceFolder class]]) - // filter = @"*"; - resultEntries - = [folder lookupContactsWithFilter: filter - sortBy: @"c_cn" - ordering: NSOrderedAscending]; + folder = [self _getFolderWithId: [dnIDs lastObject] forUser: uid]; + if (folder) + { + if (idCount == 1) + { + filter = [self _convertLDAPFilter: + [parameters objectForKey: @"filter"]]; + resultEntries + = [folder lookupContactsWithFilter: filter + sortBy: @"c_cn" + ordering: NSOrderedAscending]; + } + else + { + singleEntry = [folder lookupContactWithName: + [dnIDs objectAtIndex: 0]]; + resultEntries = [NSArray arrayWithObject: singleEntry]; + } + } + else + resultCode = LDAP_NO_SUCH_OBJECT; } else resultCode = LDAP_NO_SUCH_OBJECT;