diff --git a/SOPE/NGCards/NGVList.m b/SOPE/NGCards/NGVList.m index 6301131b4..b8b1e141b 100644 --- a/SOPE/NGCards/NGVList.m +++ b/SOPE/NGCards/NGVList.m @@ -179,12 +179,12 @@ NSMutableArray *deletedRefs; deletedRefs = [NSMutableArray array]; - cardReferences - = [[self childrenWithTag: @"card"] objectEnumerator]; + cardReferences = [[self childrenWithTag: @"card"] objectEnumerator]; while ((currentRef = [cardReferences nextObject])) - if ([[currentRef reference] - isEqualToString: [cardRef reference]]) - [deletedRefs addObject: currentRef]; + { + if ([[currentRef reference] isEqualToString: [cardRef reference]]) + [deletedRefs addObject: currentRef]; + } [children removeObjectsInArray: deletedRefs]; } diff --git a/SoObjects/Contacts/NGVList+SOGo.h b/SoObjects/Contacts/NGVList+SOGo.h index 286a65faa..3bf8ecb90 100644 --- a/SoObjects/Contacts/NGVList+SOGo.h +++ b/SoObjects/Contacts/NGVList+SOGo.h @@ -1,6 +1,6 @@ /* NGVCard+SOGo.h - this file is part of SOGo * - * Copyright (C) 2009-2014 Inverse inc. + * Copyright (C) 2009-2021 Inverse inc. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,7 +25,16 @@ @interface NGVList (SOGoExtensions) +- (CardElement *) elementWithTag: (NSString *) elementTag + ofType: (NSString *) type; + - (NSString *) ldifString; +- (void) updateFromLDIFRecord: (NSDictionary *) ldifRecord + inContainer: (id) container; +- (void) setCardReference: (NSString *) newCardReference + inContainer: (id) container; +- (void) setCardReferences: (NSArray *) newCardReferences + inContainer: (id) container; @end diff --git a/SoObjects/Contacts/NGVList+SOGo.m b/SoObjects/Contacts/NGVList+SOGo.m index 8726e9e21..ec2264488 100644 --- a/SoObjects/Contacts/NGVList+SOGo.m +++ b/SoObjects/Contacts/NGVList+SOGo.m @@ -1,6 +1,6 @@ /* NGVCard+SOGo.m - this file is part of SOGo * - * Copyright (C) 2009-2016 Inverse inc. + * Copyright (C) 2009-2021 Inverse inc. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,13 +22,37 @@ #import #import +#import +#import +#import "SOGoContactFolder.h" #import "NSDictionary+LDIF.h" #import "NGVList+SOGo.h" @implementation NGVList (SOGoExtensions) +/* LDIF -> VCARD */ +- (CardElement *) elementWithTag: (NSString *) elementTag + ofType: (NSString *) type +{ + NSArray *elements; + CardElement *element; + + elements = [self childrenWithTag: elementTag + andAttribute: @"type" havingValue: type]; + if ([elements count] > 0) + element = [elements objectAtIndex: 0]; + else + { + element = [CardElement elementWithTag: elementTag]; + [element addType: type]; + [self addChild: element]; + } + + return element; +} + - (NSString *) ldifString { NSMutableString *rc; @@ -56,7 +80,7 @@ for (i = 0; i < count; i++) { tmp = [array objectAtIndex: i]; - [members addObject: [NSString stringWithFormat: + [members addObject: [NSString stringWithFormat: @"cn=%@,mail=%@", [tmp fn], [tmp email]]]; } [entry setObject: members forKey: @"member"]; @@ -69,14 +93,14 @@ - (NSMutableDictionary *) quickRecordFromContent: (NSString *) theContent container: (id) theContainer - nameInContainer: (NSString *) nameInContainer + nameInContainer: (NSString *) nameInContainer { NSMutableDictionary *fields; NSString *value; - + fields = [NSMutableDictionary dictionaryWithCapacity: 1]; - + value = [self fn]; if (value) [fields setObject: value forKey: @"c_cn"]; @@ -85,4 +109,102 @@ return fields; } +- (void) updateFromLDIFRecord: (NSDictionary *) ldifRecord + inContainer: (id) container +{ + NSString *fn; + id o; + + fn = [ldifRecord objectForKey: @"displayname"]; + if (!fn) + fn = [ldifRecord objectForKey: @"cn"]; + [self setFn: fn]; + + o = [ldifRecord objectForKey: @"description"]; + if ([o isNotNull]) + [self setDescription: o]; + + o = [ldifRecord objectForKey: @"member"]; + if ([o isKindOfClass: [NSArray class]]) + [self setCardReferences: o + inContainer: container]; + else if ([o isNotNull]) + [self setCardReference: o + inContainer: container]; + + [self cleanupEmptyChildren]; +} + +- (void) setCardReference: (NSString *) newCardReference + inContainer: (id) container +{ + NGVCardReference *cardReference; + NSDictionary *record; + NSEnumerator *attrsList; + NSMutableDictionary *attrs; + NSArray *pair, *records; + NSString *value; + + attrs = [NSMutableDictionary dictionary]; + attrsList = [[newCardReference componentsSeparatedByString: @","] objectEnumerator]; + while ((value = [attrsList nextObject])) + { + pair = [value componentsSeparatedByString: @"="]; + if ([pair count] == 2 && [[pair objectAtIndex: 1] length]) + { + [attrs setObject: [pair objectAtIndex: 1] + forKey: [[pair objectAtIndex: 0] lowercaseString]]; + } + else + { + [self warnWithFormat: @"Unexpected LDAP member: %@", value]; + } + } + + records = nil; + if ((value = [attrs objectForKey: @"mail"])) + { + records = [container lookupContactsWithFilter: value + onCriteria: [NSArray arrayWithObject: @"c_mail"] + sortBy: nil + ordering: NSOrderedAscending + inDomain: nil]; + } + else if ((value = [attrs objectForKey: @"cn"])) + { + records = [container lookupContactsWithFilter: value + onCriteria: [NSArray arrayWithObject: @"c_cn"] + sortBy: nil + ordering: NSOrderedAscending + inDomain: nil]; + } + if (records && [records count] > 0) + { + record = [records objectAtIndex: 0]; + cardReference = [NGVCardReference elementWithTag: @"card"]; + [cardReference setReference: [record objectForKey: @"c_name"]]; + if ((value = [attrs objectForKey: @"mail"]) && [value length]) + [cardReference setEmail: value]; + if ((value = [attrs objectForKey: @"cn"]) && [value length]) + [cardReference setFn: value]; + [self addCardReference: cardReference]; + } +} + +- (void) setCardReferences: (NSArray *) newCardReferences + inContainer: (id) container +{ + NSEnumerator *referencesList; + NSString *cardReference; + + referencesList = [newCardReferences objectEnumerator]; + while ((cardReference = [referencesList nextObject])) + { + [self setCardReference: cardReference + inContainer: container]; + } +} + + + @end /* NGVList */ diff --git a/SoObjects/Contacts/SOGoContactGCSEntry.m b/SoObjects/Contacts/SOGoContactGCSEntry.m index 3bae22db1..6f3291a4f 100644 --- a/SoObjects/Contacts/SOGoContactGCSEntry.m +++ b/SoObjects/Contacts/SOGoContactGCSEntry.m @@ -205,7 +205,7 @@ [card release]; card = nil; - // We now check if we must update lisst where this contact is present + // We now check if we must update lists where this contact is present qualifier = [EOQualifier qualifierWithQualifierFormat: @"c_component = 'vlist'"]; lists = [[self container] lookupContactsWithQualifier: qualifier]; diff --git a/SoObjects/Contacts/SOGoContactLDIFEntry.h b/SoObjects/Contacts/SOGoContactLDIFEntry.h index 1f3d889a9..5a20a3735 100644 --- a/SoObjects/Contacts/SOGoContactLDIFEntry.h +++ b/SoObjects/Contacts/SOGoContactLDIFEntry.h @@ -1,6 +1,6 @@ /* SOGoContactLDIFEntry.h - this file is part of SOGo * - * Copyright (C) 2006-2017 Inverse inc. + * Copyright (C) 2006-2021 Inverse inc. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ @class NSDictionary; @class NSString; +@class NGVList; @interface SOGoContactLDIFEntry : SOGoObject { @@ -42,6 +43,9 @@ - (BOOL) isNew; - (void) setIsNew: (BOOL) newIsNew; +- (BOOL) isList; + +- (NGVList *) vList; - (NSString *) davEntityTag; diff --git a/SoObjects/Contacts/SOGoContactLDIFEntry.m b/SoObjects/Contacts/SOGoContactLDIFEntry.m index f91580b54..322f30ebb 100644 --- a/SoObjects/Contacts/SOGoContactLDIFEntry.m +++ b/SoObjects/Contacts/SOGoContactLDIFEntry.m @@ -1,6 +1,6 @@ /* SOGoContactLDIFEntry.m - this file is part of SOGo * - * Copyright (C) 2006-2017 Inverse inc. + * Copyright (C) 2006-2021 Inverse inc. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ #import #import "NGVCard+SOGo.h" +#import "NGVList+SOGo.h" #import "SOGoContactEntryPhoto.h" #import "SOGoContactGCSEntry.h" #import "SOGoContactLDIFEntry.h" @@ -76,6 +77,11 @@ isNew = newIsNew; } +- (BOOL) isList +{ + return [ldifEntry objectForKey: @"member"] != nil; +} + - (NSString *) contentAsString { return [[self vCard] versitString]; @@ -94,6 +100,20 @@ return vcard; } +- (NGVList *) vList +{ + NGVList *vlist; + + vlist = [NGVList listWithUid: [self nameInContainer]]; + [vlist setProdID: [NSString + stringWithFormat: @"-//Inverse inc./SOGo %@//EN", + SOGoVersion]]; + [vlist updateFromLDIFRecord: [self ldifRecord] + inContainer: container]; + + return vlist; +} + - (BOOL) isFolderish { return NO; diff --git a/UI/Contacts/UIxContactFolderActions.h b/UI/Contacts/UIxContactFolderActions.h index 92f730ccb..178cdefeb 100644 --- a/UI/Contacts/UIxContactFolderActions.h +++ b/UI/Contacts/UIxContactFolderActions.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2006-2016 Inverse inc. + Copyright (C) 2006-2021 Inverse inc. This file is part of SOGo @@ -34,6 +34,7 @@ - (int) importLdifData: (NSString *) ldifData; - (int) importVcardData: (NSString *) vcardData; - (BOOL) importVcard: (NGVCard *) card; +- (BOOL) importVlist: (NGVList *) list; @end diff --git a/UI/Contacts/UIxContactFolderActions.m b/UI/Contacts/UIxContactFolderActions.m index 2ca2a962b..0a3f7c7fc 100644 --- a/UI/Contacts/UIxContactFolderActions.m +++ b/UI/Contacts/UIxContactFolderActions.m @@ -1,5 +1,5 @@ /* - Copyright (C) 2006-2016 Inverse inc. + Copyright (C) 2006-2021 Inverse inc. This file is part of SOGo @@ -36,6 +36,10 @@ #import #import +#import +#import +#import + #import #import @@ -129,7 +133,7 @@ static NSArray *photoTags = nil; data = [[[data parts] lastObject] body]; - fileContent = [[NSString alloc] initWithData: (NSData *) data + fileContent = [[NSString alloc] initWithData: (NSData *) data encoding: NSUTF8StringEncoding]; [fileContent autorelease]; @@ -154,6 +158,7 @@ static NSArray *photoTags = nil; - (int) importLdifData: (NSString *) ldifData { + NSMutableArray *ldifListEntries; NSMutableDictionary *entry, *encodedEntry; SOGoContactLDIFEntry *ldifEntry; NSArray *ldifContacts, *lines; @@ -161,13 +166,15 @@ static NSArray *photoTags = nil; NSEnumerator *keyEnumerator; NSString *key, *uid, *line; NGVCard *vCard; - id value; + NGVList *vList; + id value, values; NSRange r; int i, j, count, linesCount, len; int rc; folder = [self clientObject]; + ldifListEntries = [NSMutableArray array]; ldifContacts = [ldifData componentsSeparatedByString: @"\ndn"]; count = [ldifContacts count]; rc = 0; @@ -175,7 +182,7 @@ static NSArray *photoTags = nil; for (i = 0; i < count; i++) { encodedEntry = [NSMutableDictionary dictionary]; - lines = [[ldifContacts objectAtIndex: i] + lines = [[ldifContacts objectAtIndex: i] componentsSeparatedByString: @"\n"]; key = NULL; @@ -201,9 +208,20 @@ static NSArray *photoTags = nil; { if (key != NULL) { - value = [[encodedEntry valueForKey: key] - stringByAppendingString: [line substringFromIndex: 1]]; - [encodedEntry setValue: value forKey: key]; + values = [encodedEntry objectForKey: key]; + if ([values isKindOfClass: [NSArray class]]) + { + // Multiple values for key + value = [[values lastObject] stringByAppendingString: [line substringFromIndex: 1]]; + [values replaceObjectAtIndex: [values count] - 1 + withObject: value]; + } + else + { + // Single value for key + value = [values stringByAppendingString: [line substringFromIndex: 1]]; + [encodedEntry setValue: value forKey: key]; + } } continue; } @@ -217,7 +235,15 @@ static NSArray *photoTags = nil; if ([key length] == 0) key = @"dn"; - [encodedEntry setValue: value forKey: key]; + if ((values = [encodedEntry objectForKey: key])) + { + if (![values isKindOfClass: [NSArray class]]) + values = [NSMutableArray arrayWithObject: values]; + [values addObject: value]; + [encodedEntry setValue: values forKey: key]; + } + else + [encodedEntry setValue: value forKey: key]; } else { @@ -230,21 +256,31 @@ static NSArray *photoTags = nil; keyEnumerator = [encodedEntry keyEnumerator]; while ((key = [keyEnumerator nextObject])) { - value = [encodedEntry valueForKey: key]; + values = [encodedEntry valueForKey: key]; if ([key hasSuffix: @":"]) { key = [key substringToIndex: [key length] - 1]; if ([photoTags containsObject: key]) - value = [value dataByDecodingBase64]; - else - value = [value stringByDecodingBase64]; + values = [values dataByDecodingBase64]; + else if ([values isKindOfClass: [NSArray class]]) + { + for (j = 0; j < [values count]; j++) + { + value = [values objectAtIndex: j]; + value = [value stringByDecodingBase64]; + [values replaceObjectAtIndex: j + withObject: value]; + } + } + else + values = [values stringByDecodingBase64]; } // Standard key recognized in NGCards if ([photoTags containsObject: key]) key = @"photo"; - [entry setValue: value forKey: key]; + [entry setValue: values forKey: key]; } uid = [folder globallyUniqueObjectId]; @@ -253,12 +289,35 @@ static NSArray *photoTags = nil; inContainer: folder]; if (ldifEntry) { - vCard = [ldifEntry vCard]; - if ([self importVcard: vCard]) - rc++; - + if ([ldifEntry isList]) + { + // Postpone importation of lists + [ldifListEntries addObject: ldifEntry]; + } + else + { + vCard = [ldifEntry vCard]; + if ([self importVcard: vCard]) + { + rc++; + } + } + } } + + // Force update of quick table + [[[[[self clientObject] ocsFolder] acquireQuickChannel] adaptorContext] commitTransaction]; + + // Convert groups to vLists + count = [ldifListEntries count]; + for (i = 0; i < count; i++) + { + vList = [[ldifListEntries objectAtIndex: i] vList]; + if ([self importVlist: vList]) + rc++; + } + return rc; } @@ -308,16 +367,42 @@ static NSArray *photoTags = nil; { pool = [[NSAutoreleasePool alloc] init]; folder = [self clientObject]; - uid = [folder globallyUniqueObjectId]; - [card setUid: uid]; // TODO: shall we add .vcf as in [SOGoContactGCSEntry copyToFolder:] + uid = [card uid]; contact = [SOGoContactGCSEntry objectWithName: uid inContainer: folder]; [contact setIsNew: YES]; - [contact saveComponent: card]; - + + rc = YES; + RELEASE(pool); + } + + return rc; +} + + - (BOOL) importVlist: (NGVList *) list +{ + SOGoContactGCSFolder *folder; + SOGoContactGCSList *contact; + NSAutoreleasePool *pool; + NSString *uid; + + BOOL rc = NO; + + if (list) + { + pool = [[NSAutoreleasePool alloc] init]; + folder = [self clientObject]; + + // TODO: shall we add .vcf as in [SOGoContactGCSEntry copyToFolder:] + uid = [list uid]; + contact = [SOGoContactGCSList objectWithName: uid + inContainer: folder]; + [contact setIsNew: YES]; + [contact saveComponent: list]; + rc = YES; RELEASE(pool); }