diff --git a/SOPE/NGCards/iCalPerson.m.orig b/SOPE/NGCards/iCalPerson.m.orig deleted file mode 100644 index 7904fd0f8..000000000 --- a/SOPE/NGCards/iCalPerson.m.orig +++ /dev/null @@ -1,299 +0,0 @@ -/* - Copyright (C) 2000-2005 SKYRIX Software AG - - This file is part of SOPE. - - SOPE is free software; you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - SOPE is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with SOPE; see the file COPYING. If not, write to the - Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. -*/ - -#import - -#import "iCalPerson.h" - -@implementation iCalPerson - -+ (NSString *) descriptionForParticipationStatus: (iCalPersonPartStat) _status -{ - NSString *stat; - - switch (_status) { - case iCalPersonPartStatUndefined: - stat = @""; - break; - case iCalPersonPartStatAccepted: - stat = @"ACCEPTED"; - break; - case iCalPersonPartStatDeclined: - stat = @"DECLINED"; - break; - case iCalPersonPartStatTentative: - stat = @"TENTATIVE"; - break; - case iCalPersonPartStatDelegated: - stat = @"DELEGATED"; - break; - case iCalPersonPartStatCompleted: - stat = @"COMPLETED"; - break; - case iCalPersonPartStatInProcess: - stat = @"IN-PROCESS"; - break; - case iCalPersonPartStatExperimental: - case iCalPersonPartStatOther: -// [NSException raise:NSInternalInconsistencyException -// format:@"Attempt to set meaningless " -// @"participationStatus (%d)!", _status]; - stat = nil; /* keep compiler happy */ - break; - default: - stat = @"NEEDS-ACTION"; - break; - } - - return stat; -} - - -/* accessors */ - -- (void) setCn: (NSString *) _s -{ - [self setValue: 0 ofAttribute: @"cn" to: _s]; -} - -- (NSString *) cn -{ - return [self value: 0 ofAttribute: @"cn"]; -} - -- (NSString *) cnWithoutQuotes -{ - /* remove quotes around a CN */ - NSString *_cn; - - _cn = [self cn]; - if ([_cn length] <= 2) - return _cn; - if ([_cn characterAtIndex:0] != '"') - return _cn; - if (![_cn hasSuffix:@"\""]) - return _cn; - - return [_cn substringWithRange:NSMakeRange(1, [_cn length] - 2)]; -} - -- (void) setEmail: (NSString *)_s -{ - /* iCal.app compatibility: - - "mailto" prefix must be in lowercase; */ - [self setSingleValue: [NSString stringWithFormat: @"mailto:%@", _s] - forKey: @""]; -} - -- (NSString *) email -{ - return [self flattenedValuesForKey: @""]; -} - -- (NSString *) rfc822Email -{ - NSString *_email; - unsigned idx; - - _email = [self email]; - idx = NSMaxRange([_email rangeOfString:@":"]); - - if ((idx > 0) && ([_email length] > idx)) - return [_email substringFromIndex:idx]; - - return _email; -} - -- (void) setRsvp: (NSString *) _s -{ - [self setValue: 0 ofAttribute: @"rsvp" to: _s]; -} - -- (NSString *) rsvp -{ - return [[self value: 0 ofAttribute: @"rsvp"] lowercaseString]; -} - -// - (void)setXuid:(NSString *)_s { -// ASSIGNCOPY(self->xuid, _s); -// } -// - (NSString *)xuid { -// return self->xuid; -// } - -- (void)setRole:(NSString *)_s -{ - [self setValue: 0 ofAttribute: @"role" to: _s]; -} - -- (NSString *) role -{ - return [self value: 0 ofAttribute: @"role"]; -} - -- (void)setPartStat:(NSString *)_s -{ - [self setValue: 0 ofAttribute: @"partstat" to: _s]; -} - -- (NSString *) partStat -{ - return [self value: 0 ofAttribute: @"partstat"]; -} - -- (NSString *) partStatWithDefault -{ - NSString *s; - - s = [self partStat]; - if ([s length] > 0) - return s; - - return @"NEEDS-ACTION"; -} - -- (void) setParticipationStatus: (iCalPersonPartStat) _status -{ - NSString *stat; - - stat = [iCalPerson descriptionForParticipationStatus: _status]; - - if (stat) - [self setPartStat:stat]; -} - -- (iCalPersonPartStat) participationStatus { - NSString *stat; - - stat = [[self partStat] uppercaseString]; - if (![stat length]) - return iCalPersonPartStatUndefined; - else if ([stat isEqualToString:@"NEEDS-ACTION"]) - return iCalPersonPartStatNeedsAction; - else if ([stat isEqualToString:@"ACCEPTED"]) - return iCalPersonPartStatAccepted; - else if ([stat isEqualToString:@"DECLINED"]) - return iCalPersonPartStatDeclined; - else if ([stat isEqualToString:@"TENTATIVE"]) - return iCalPersonPartStatTentative; - else if ([stat isEqualToString:@"DELEGATED"]) - return iCalPersonPartStatDelegated; - else if ([stat isEqualToString:@"COMPLETED"]) - return iCalPersonPartStatCompleted; - else if ([stat isEqualToString:@"IN-PROCESS"]) - return iCalPersonPartStatInProcess; - else if ([stat hasPrefix:@"X-"]) - return iCalPersonPartStatExperimental; - return iCalPersonPartStatOther; -} - -- (void) _setValueOfMailtoAttribute: (NSString *) name - to: (NSString *) value -{ - if ([value length] && ![value hasPrefix: @"\""]) - value = [NSString stringWithFormat: @"\"%@\"", value]; - - [self setValue: 0 ofAttribute: name to: value]; -} - -- (NSString *) _valueOfMailtoAttribute: (NSString *) name -{ - NSString *mailTo; - - mailTo = [self value: 0 ofAttribute: name]; - if ([mailTo hasPrefix: @"\""]) - mailTo - = [mailTo substringWithRange: NSMakeRange (1, [mailTo length] - 2)]; - - return mailTo; -} - -- (void) setDelegatedTo: (NSString *) newDelegate -{ - [self _setValueOfMailtoAttribute: @"delegated-to" to: newDelegate]; -} - -- (NSString *) delegatedTo -{ - return [self _valueOfMailtoAttribute: @"delegated-to"]; -} - -- (void) setDelegatedFrom: (NSString *) newDelegator -{ - [self _setValueOfMailtoAttribute: @"delegated-from" to: newDelegator]; -} - -- (NSString *) delegatedFrom -{ - return [self _valueOfMailtoAttribute: @"delegated-from"]; -} - -- (void) setSentBy: (NSString *) newSentBy -{ - [self _setValueOfMailtoAttribute: @"sent-by" to: newSentBy]; -} - -- (NSString *) sentBy -{ - return [self _valueOfMailtoAttribute: @"sent-by"]; -} - -/* comparison */ - -- (NSUInteger) hash { - if ([self email]) - return [[self email] hash]; - return [super hash]; -} - -- (BOOL)isEqual:(id)_other { - if(_other == nil) - return NO; - if([_other class] != self->isa) - return NO; - if([_other hash] != [self hash]) - return NO; - return [self isEqualToPerson:_other]; -} - -- (BOOL)isEqualToPerson:(iCalPerson *)_other { - if(![self hasSameEmailAddress:_other]) - return NO; - if(!IS_EQUAL([self cn], [_other cn], isEqualToString:)) - return NO; - if(!IS_EQUAL([self rsvp], [_other rsvp], isEqualToString:)) - return NO; - if(!IS_EQUAL([self partStat], [_other partStat], isEqualToString:)) - return NO; - if(!IS_EQUAL([self role], [_other role], isEqualToString:)) - return NO; -// if(!IS_EQUAL([self xuid], [_other xuid], isEqualToString:)) -// return NO; - return YES; -} - -- (BOOL)hasSameEmailAddress:(iCalPerson *)_other { - return IS_EQUAL([[self email] lowercaseString], - [[_other email] lowercaseString], - isEqualToString:); -} - -@end /* iCalPerson */ diff --git a/SoObjects/Contacts/SOGoContactSourceFolder.m.orig b/SoObjects/Contacts/SOGoContactSourceFolder.m.orig deleted file mode 100644 index a52ec20b9..000000000 --- a/SoObjects/Contacts/SOGoContactSourceFolder.m.orig +++ /dev/null @@ -1,808 +0,0 @@ -/* SOGoContactSourceFolder.m - this file is part of SOGo - * - * Copyright (C) 2006-2015 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#import -#import -#import -#import -#import -#import - -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -#import "SOGoContactFolders.h" -#import "SOGoContactGCSFolder.h" -#import "SOGoContactLDIFEntry.h" -#import "SOGoContactSourceFolder.h" - -@class WOContext; - -@implementation SOGoContactSourceFolder - -+ (id) folderWithName: (NSString *) aName - andDisplayName: (NSString *) aDisplayName - inContainer: (id) aContainer -{ - id folder; - - folder = [[self alloc] initWithName: aName - andDisplayName: aDisplayName - inContainer: aContainer]; - [folder autorelease]; - - return folder; -} - -- (id) init -{ - if ((self = [super init])) - { - childRecords = [NSMutableDictionary new]; - source = nil; - } - - return self; -} - -- (id) initWithName: (NSString *) newName - andDisplayName: (NSString *) newDisplayName - inContainer: (id) newContainer -{ - if ((self = [self initWithName: newName - inContainer: newContainer])) - { - if (![newDisplayName length]) - newDisplayName = newName; - ASSIGN (displayName, newDisplayName); - } - - return self; -} - -- (void) dealloc -{ - [childRecords release]; - [source release]; - [super dealloc]; -} - -- (void) setSource: (id ) newSource -{ - ASSIGN (source, newSource); -} - -- (id ) source -{ - return source; -} - -- (void) setIsPersonalSource: (BOOL) isPersonal -{ - isPersonalSource = isPersonal; -} - -- (BOOL) isPersonalSource -{ - return isPersonalSource; -} - -- (NSString *) groupDavResourceType -{ - return @"vcard-collection"; -} - -- (NSArray *) davResourceType -{ - NSMutableArray *resourceType; - NSArray *type; - - resourceType = [NSMutableArray arrayWithArray: [super davResourceType]]; - type = [NSArray arrayWithObjects: @"addressbook", XMLNS_CARDDAV, nil]; - [resourceType addObject: type]; - type = [NSArray arrayWithObjects: @"directory", XMLNS_CARDDAV, nil]; - [resourceType addObject: type]; - - return resourceType; -} - -- (id) lookupName: (NSString *) objectName - inContext: (WOContext *) lookupContext - acquire: (BOOL) acquire -{ - NSDictionary *ldifEntry; - SOGoContactLDIFEntry *obj; - NSString *url; - BOOL isNew = NO; - NSArray *baseClasses; - - /* first check attributes directly bound to the application */ - obj = [super lookupName: objectName inContext: lookupContext acquire: NO]; - - if (!obj) - { - ldifEntry = [childRecords objectForKey: objectName]; - if (!ldifEntry) - { - ldifEntry = [source lookupContactEntry: objectName]; - if (ldifEntry) - [childRecords setObject: ldifEntry forKey: objectName]; - else if ([self isValidContentName: objectName]) - { - url = [[[lookupContext request] uri] urlWithoutParameters]; - if ([url hasSuffix: @"AsContact"]) - { - baseClasses = [NSArray arrayWithObjects: @"inetorgperson", - @"mozillaabpersonalpha", nil]; - ldifEntry = [NSMutableDictionary - dictionaryWithObject: baseClasses - forKey: @"objectclass"]; - isNew = YES; - } - } - } - if (ldifEntry) - { - obj = [SOGoContactLDIFEntry contactEntryWithName: objectName - withLDIFEntry: ldifEntry - inContainer: self]; - if (isNew) - [obj setIsNew: YES]; - } - else - obj = [NSException exceptionWithHTTPStatus: 404]; - } - - return obj; -} - -- (NSArray *) toOneRelationshipKeys -{ - NSString *userDomain; - - userDomain = [[context activeUser] domain]; - return [source allEntryIDsVisibleFromDomain: userDomain]; -} - -- (NSException *) saveLDIFEntry: (SOGoContactLDIFEntry *) ldifEntry -{ - return (([ldifEntry isNew]) - ? [source addContactEntry: [ldifEntry ldifRecord] - withID: [ldifEntry nameInContainer]] - : [source updateContactEntry: [ldifEntry ldifRecord]]); -} - -- (NSException *) deleteLDIFEntry: (SOGoContactLDIFEntry *) ldifEntry -{ - return [source removeContactEntryWithID: [ldifEntry nameInContainer]]; -} - -/** - * Normalize keys of dictionary representing a contact. - * @param oldRecord a dictionary with pairs from the source folder (LDAP or SQL) - * @see [SOGoContactGCSFolder _fixupContactRecord] - */ -- (NSDictionary *) _flattenedRecord: (NSDictionary *) oldRecord -{ - NSMutableDictionary *newRecord; - id data; - NSObject *recordSource; - - newRecord = [NSMutableDictionary dictionaryWithCapacity: 8]; - [newRecord setObject: [oldRecord objectForKey: @"c_uid"] - forKey: @"c_uid"]; - - // c_name => id - [newRecord setObject: [oldRecord objectForKey: @"c_name"] - forKey: @"c_name"]; - [newRecord setObject: [oldRecord objectForKey: @"c_name"] - forKey: @"id"]; - - // displayname || c_cn => fn - data = [oldRecord objectForKey: @"displayname"]; - if (!data) - data = [oldRecord objectForKey: @"c_cn"]; - if (data) - [newRecord setObject: data forKey: @"fn"]; - else - data = @""; - [newRecord setObject: data forKey: @"c_cn"]; - - // mail => emails[] - data = [oldRecord objectForKey: @"c_emails"]; - if (data) - { - if ([data isKindOfClass: [NSArray class]]) - { - if ([data count] > 0) - { - NSEnumerator *emails; - NSMutableArray *recordEmails; - NSString *email; - emails = [(NSArray *)data objectEnumerator]; - recordEmails = [NSMutableArray arrayWithCapacity: [data count]]; - while ((email = [emails nextObject])) - { - [recordEmails addObject: [NSDictionary dictionaryWithObject: email forKey: @"value"]]; - } - [newRecord setObject: recordEmails forKey: @"emails"]; - } - } - else if (data) - { - NSDictionary *email; - email = [NSDictionary dictionaryWithObjectsAndKeys: @"pref", @"type", data, @"value", nil]; - [newRecord setObject: [NSArray arrayWithObject: email] forKey: @"emails"]; - } - else - data = @""; - } - else - 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"]; - - // o => org - data = [oldRecord objectForKey: @"o"]; - if (data) - [newRecord setObject: data forKey: @"org"]; - else - data = @""; - [newRecord setObject: data forKey: @"c_o"]; - - // telephonenumber || cellphone || homephone => phones[] - data = [oldRecord objectForKey: @"telephonenumber"]; - if (![data length]) - data = [oldRecord objectForKey: @"cellphone"]; - if (![data length]) - data = [oldRecord objectForKey: @"homephone"]; - if (data) - { - NSDictionary *phonenumber; - phonenumber = [NSDictionary dictionaryWithObjectsAndKeys: @"pref", @"type", data, @"value", nil]; - [newRecord setObject: [NSArray arrayWithObject: phonenumber] forKey: @"phones"]; - } - else - 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"]; - [newRecord setObject: @"vlist" forKey: @"c_component"]; - } -#warning TODO: create a custom icon for resources - else - { - [newRecord setObject: @"vcard" forKey: @"c_component"]; - } - - // c_info => note - data = [oldRecord objectForKey: @"c_info"]; - if ([data length] > 0) - { - [newRecord setObject: data forKey: @"note"]; - [newRecord setObject: data forKey: @"contactInfo"]; - } - - recordSource = [oldRecord objectForKey: @"source"]; - if ([recordSource conformsToProtocol: @protocol (SOGoDNSource)] && - [[(NSObject *) recordSource MSExchangeHostname] length]) - [newRecord setObject: [NSNumber numberWithInt: 1] forKey: @"isMSExchange"]; - - return newRecord; -} - -- (NSArray *) _flattenedRecords: (NSArray *) records -{ - NSMutableArray *newRecords; - NSEnumerator *oldRecords; - NSDictionary *oldRecord; - - newRecords = [NSMutableArray arrayWithCapacity: [records count]]; - - oldRecords = [records objectEnumerator]; - while ((oldRecord = [oldRecords nextObject])) - [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 - onCriteria: (NSString *) criteria - sortBy: (NSString *) sortKey - ordering: (NSComparisonResult) sortOrdering - inDomain: (NSString *) domain -{ - NSArray *records, *result; - EOSortOrdering *ordering; - - result = nil; - - if (([filter length] > 0 && [criteria isEqualToString: @"name_or_address"]) - || ![source listRequiresDot]) - { - records = [source fetchContactsMatching: filter - inDomain: domain]; - [childRecords setObjects: records - forKeys: [records objectsForKey: @"c_name" - notFoundMarker: nil]]; - records = [self _flattenedRecords: records]; - ordering - = [EOSortOrdering sortOrderingWithKey: sortKey - selector: ((sortOrdering == NSOrderedDescending) - ? EOCompareCaseInsensitiveDescending - : EOCompareCaseInsensitiveAscending)]; - result - = [records sortedArrayUsingKeyOrderArray: - [NSArray arrayWithObject: ordering]]; - } - - return result; -} - -- (NSString *) _deduceObjectNameFromURL: (NSString *) url - fromBaseURL: (NSString *) baseURL -{ - NSRange urlRange; - NSString *name; - - urlRange = [url rangeOfString: baseURL]; - if (urlRange.location != NSNotFound) - { - name = [url substringFromIndex: NSMaxRange (urlRange)]; - if ([name hasPrefix: @"/"]) - name = [name substringFromIndex: 1]; - } - else - name = nil; - - return name; -} - -/* TODO: multiget reorg */ -- (NSString *) _nodeTagForProperty: (NSString *) property -{ - NSString *namespace, *nodeName, *nsRep; - NSRange nsEnd; - - nsEnd = [property rangeOfString: @"}"]; - namespace - = [property substringFromRange: NSMakeRange (1, nsEnd.location - 1)]; - nodeName = [property substringFromIndex: nsEnd.location + 1]; - if ([namespace isEqualToString: XMLNS_CARDDAV]) - nsRep = @"C"; - else - nsRep = @"D"; - - return [NSString stringWithFormat: @"%@:%@", nsRep, nodeName]; -} - -- (NSString *) _nodeTag: (NSString *) property -{ - static NSMutableDictionary *tags = nil; - NSString *nodeTag; - - if (!tags) - tags = [NSMutableDictionary new]; - nodeTag = [tags objectForKey: property]; - if (!nodeTag) - { - nodeTag = [self _nodeTagForProperty: property]; - [tags setObject: nodeTag forKey: property]; - } - - return nodeTag; -} - -- (NSString **) _properties: (NSString **) properties - count: (unsigned int) propertiesCount - ofObject: (NSDictionary *) object -{ - SOGoContactLDIFEntry *ldifEntry; - NSString **currentProperty; - NSString **values, **currentValue; - SEL methodSel; - -// NSLog (@"_properties:ofObject:: %@", [NSDate date]); - - values = NSZoneMalloc (NULL, - (propertiesCount + 1) * sizeof (NSString *)); - *(values + propertiesCount) = nil; - - ldifEntry = [SOGoContactLDIFEntry - contactEntryWithName: [object objectForKey: @"c_name"] - withLDIFEntry: object - inContainer: self]; - currentProperty = properties; - currentValue = values; - while (*currentProperty) - { - methodSel = SOGoSelectorForPropertyGetter (*currentProperty); - if (methodSel && [ldifEntry respondsToSelector: methodSel]) - *currentValue = [[ldifEntry performSelector: methodSel] - stringByEscapingXMLString]; - currentProperty++; - currentValue++; - } - -// NSLog (@"/_properties:ofObject:: %@", [NSDate date]); - - return values; -} - -- (NSArray *) _propstats: (NSString **) properties - count: (unsigned int) propertiesCount - ofObject: (NSDictionary *) object -{ - NSMutableArray *propstats, *properties200, *properties404, *propDict; - NSString **property, **values, **currentValue; - NSString *propertyValue, *nodeTag; - -// NSLog (@"_propstats:ofObject:: %@", [NSDate date]); - - propstats = [NSMutableArray array]; - - properties200 = [NSMutableArray array]; - properties404 = [NSMutableArray array]; - - values = [self _properties: properties count: propertiesCount - ofObject: object]; - currentValue = values; - - property = properties; - while (*property) - { - nodeTag = [self _nodeTag: *property]; - if (*currentValue) - { - propertyValue = [NSString stringWithFormat: @"<%@>%@", - nodeTag, *currentValue, nodeTag]; - propDict = properties200; - } - else - { - propertyValue = [NSString stringWithFormat: @"<%@/>", nodeTag]; - propDict = properties404; - } - [propDict addObject: propertyValue]; - property++; - currentValue++; - } - free (values); - - if ([properties200 count]) - [propstats addObject: [NSDictionary dictionaryWithObjectsAndKeys: - properties200, @"properties", - @"HTTP/1.1 200 OK", @"status", - nil]]; - if ([properties404 count]) - [propstats addObject: [NSDictionary dictionaryWithObjectsAndKeys: - properties404, @"properties", - @"HTTP/1.1 404 Not Found", @"status", - nil]]; -// NSLog (@"/_propstats:ofObject:: %@", [NSDate date]); - - return propstats; -} - -- (void) _appendPropstat: (NSDictionary *) propstat - toBuffer: (NSMutableString *) r -{ - NSArray *properties; - unsigned int count, max; - - [r appendString: @""]; - properties = [propstat objectForKey: @"properties"]; - max = [properties count]; - for (count = 0; count < max; count++) - [r appendString: [properties objectAtIndex: count]]; - [r appendString: @""]; - [r appendString: [propstat objectForKey: @"status"]]; - [r appendString: @""]; -} - -- (void) appendObject: (NSDictionary *) object - properties: (NSString **) properties - count: (unsigned int) propertiesCount - withBaseURL: (NSString *) baseURL - toBuffer: (NSMutableString *) r -{ - NSArray *propstats; - unsigned int count, max; - - [r appendFormat: @""]; - [r appendString: baseURL]; - [r appendString: [[object objectForKey: @"c_name"] stringByEscapingURL]]; - [r appendString: @""]; - - propstats = [self _propstats: properties count: propertiesCount - ofObject: object]; - max = [propstats count]; - for (count = 0; count < max; count++) - [self _appendPropstat: [propstats objectAtIndex: count] - toBuffer: r]; - - [r appendString: @""]; -} - -- (void) appendMissingObjectRef: (NSString *) href - toBuffer: (NSMutableString *) r -{ - [r appendString: @""]; - [r appendString: href]; - [r appendString: @"HTTP/1.1 404 Not Found"]; -} - -- (void) _appendComponentProperties: (NSArray *) properties - matchingURLs: (id ) refs - toResponse: (WOResponse *) response -{ - NSObject *element; - NSString *url, *baseURL, *cname; - NSString **propertiesArray; - NSMutableString *buffer; - NSDictionary *object; - - unsigned int count, max, propertiesCount; - - baseURL = [self davURLAsString]; -#warning review this when fixing http://www.scalableogo.org/bugs/view.php?id=276 - if (![baseURL hasSuffix: @"/"]) - baseURL = [NSString stringWithFormat: @"%@/", baseURL]; - - propertiesArray = [properties asPointersOfObjects]; - propertiesCount = [properties count]; - - max = [refs length]; - buffer = [NSMutableString stringWithCapacity: max*512]; - - for (count = 0; count < max; count++) - { - element = [refs objectAtIndex: count]; - url = [[[element firstChild] nodeValue] stringByUnescapingURL]; - cname = [self _deduceObjectNameFromURL: url fromBaseURL: baseURL]; - object = [source lookupContactEntry: cname]; - if (object) - [self appendObject: object - properties: propertiesArray - count: propertiesCount - withBaseURL: baseURL - toBuffer: buffer]; - else - [self appendMissingObjectRef: url - toBuffer: buffer]; - } - [response appendContentString: buffer]; -// NSLog (@"/adding properties with url"); - - NSZoneFree (NULL, propertiesArray); -} - -- (WOResponse *) performMultigetInContext: (WOContext *) queryContext - inNamespace: (NSString *) namespace -{ - WOResponse *r; - id document; - id documentElement, propElement; - - r = [context response]; - [r prepareDAVResponse]; - [r appendContentString: - [NSString stringWithFormat: @"", namespace]]; - document = [[queryContext request] contentAsDOMDocument]; - documentElement = [document documentElement]; - propElement = [(NGDOMNodeWithChildren *) documentElement - firstElementWithTag: @"prop" - inNamespace: @"DAV:"]; - [self _appendComponentProperties: [(NGDOMNodeWithChildren *) propElement flatPropertyNameOfSubElements] - matchingURLs: [documentElement getElementsByTagName: @"href"] - toResponse: r]; - [r appendContentString:@""]; - - return r; -} - -- (id) davAddressbookMultiget: (id) queryContext -{ - return [self performMultigetInContext: queryContext - inNamespace: XMLNS_CARDDAV]; -} - -- (NSString *) davDisplayName -{ - return displayName; -} - -- (BOOL) isFolderish -{ - return YES; -} - -/* folder type */ - -- (NSString *) folderType -{ - return @"Contact"; -} - -/* sorting */ -- (NSComparisonResult) compare: (id) otherFolder -{ - NSComparisonResult comparison; - BOOL otherIsPersonal; - - otherIsPersonal = ([otherFolder isKindOfClass: [SOGoContactGCSFolder class]] - || ([otherFolder isKindOfClass: isa] && [otherFolder isPersonalSource])); - - if (isPersonalSource) - { - if (otherIsPersonal && ![nameInContainer isEqualToString: @"personal"]) - { - if ([[otherFolder nameInContainer] isEqualToString: @"personal"]) - comparison = NSOrderedDescending; - else - comparison - = [[self displayName] - localizedCaseInsensitiveCompare: [otherFolder displayName]]; - } - else - comparison = NSOrderedAscending; - } - else - { - if (otherIsPersonal) - comparison = NSOrderedDescending; - else - comparison - = [[self displayName] - localizedCaseInsensitiveCompare: [otherFolder displayName]]; - } - - return comparison; -} - -/* common methods */ - -- (NSException *) delete -{ - NSException *error; - - if (isPersonalSource) - { - error = [(SOGoContactFolders *) container - removeLDAPAddressBook: nameInContainer]; - if (!error && [[context request] handledByDefaultHandler]) - [self sendFolderAdvisoryTemplate: @"Removal"]; - } - else - error = [NSException exceptionWithHTTPStatus: 501 /* not implemented */ - reason: @"delete not available on system sources"]; - - return error; -} - -- (void) renameTo: (NSString *) newName -{ - NSException *error; - - if (isPersonalSource) - { - if (![[source displayName] isEqualToString: newName]) - { - error = [(SOGoContactFolders *) container - renameLDAPAddressBook: nameInContainer - withDisplayName: newName]; - if (!error) - [self setDisplayName: newName]; - } - } - /* If public source then method is ignored, maybe we should return an - NSException instead... */ -} - -/* acls */ -- (NSString *) ownerInContext: (WOContext *) noContext -{ - NSString *sourceOwner; - - if (isPersonalSource) - sourceOwner = [[source modifiers] objectAtIndex: 0]; - else - sourceOwner = @"nobody"; - - return sourceOwner; -} - -- (NSArray *) subscriptionRoles -{ - return [NSArray arrayWithObject: SoRole_Authenticated]; -} - -- (NSArray *) aclsForUser: (NSString *) uid -{ - NSArray *acls, *modifiers; - static NSArray *modifierRoles = nil; - - if (!modifierRoles) - modifierRoles = [[NSArray alloc] initWithObjects: @"Owner", - @"ObjectViewer", - @"ObjectEditor", @"ObjectCreator", - @"ObjectEraser", nil]; - - modifiers = [source modifiers]; - if ([modifiers containsObject: uid]) - acls = [modifierRoles copy]; - else - acls = [NSArray new]; - - [acls autorelease]; - - return acls; -} - -@end diff --git a/SoObjects/SOGo/SOGoCacheGCSFolder.m.orig b/SoObjects/SOGo/SOGoCacheGCSFolder.m.orig deleted file mode 100644 index b29287fcb..000000000 --- a/SoObjects/SOGo/SOGoCacheGCSFolder.m.orig +++ /dev/null @@ -1,486 +0,0 @@ -/* SOGoCacheGCSFolder.m - this file is part of SOGo - * - * Copyright (C) 2012-2014 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 - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#import -#import -#import -#import -#import -#import -#import -#import - -#import -#import -#import -#import - -#import -#import -#import -#import -#import "EOQualifier+SOGoCacheObject.h" -#import "GCSSpecialQueries+SOGoCacheObject.h" - -#import "SOGoCacheGCSFolder.h" - -#undef DEBUG -//#include -//#include -//#include -//#include -//#include -//#include -//#include - -Class SOGoCacheGCSObjectK = Nil; - -@implementation SOGoCacheGCSFolder - -+ (void) initialize -{ - SOGoCacheGCSObjectK = [SOGoCacheGCSObject class]; -} - -- (id) init -{ - if ((self = [super init])) - { - pathPrefix = nil; - } - - return self; -} - -- (id) initWithName: (NSString *) name inContainer: (id) newContainer -{ - if ((self = [super initWithName: name inContainer: newContainer])) - { - objectType = MAPIFolderCacheObject; - aclMessage = [SOGoCacheGCSObject objectWithName: @"permissions" - inContainer: self]; - [aclMessage setObjectType: MAPIInternalCacheObject]; - [aclMessage retain]; - } - - return self; -} - -- (void) dealloc -{ - [aclMessage release]; - [pathPrefix release]; - [super dealloc]; -} - -- (BOOL) isFolderish -{ - return YES; -} - -- (void) setPathPrefix: (NSString *) newPathPrefix -{ - ASSIGN (pathPrefix, newPathPrefix); -} - -- (NSMutableString *) pathForChild: (NSString *) childName -{ - NSMutableString *path; - - path = [self path]; - [path appendFormat: @"/%@", childName]; - - return path; -} - -- (NSMutableString *) path -{ - NSMutableString *path; - - path = [super path]; - if (pathPrefix) - [path insertString: pathPrefix atIndex: 0]; - - return path; -} - -// - (SOGoMAPIDBMessage *) newMessage -// { -// NSString *newFilename; - -// newFilename = [NSString stringWithFormat: @"%@.plist", -// [SOGoObject globallyUniqueObjectId]]; - -// return [SOGoMAPIDBMessage objectWithName: filename inContainer: self]; -// } - -- (NSArray *) childKeysOfType: (SOGoCacheObjectType) type - includeDeleted: (BOOL) includeDeleted - matchingQualifier: (EOQualifier *) qualifier - andSortOrderings: (NSArray *) sortOrderings -{ - NSMutableArray *childKeys; - NSMutableString *sql// , *qualifierClause - ; - NSString *childPathPrefix, *childPath, *childKey; - NSMutableArray *whereClause; - NSArray *records; - NSDictionary *record; - NSUInteger childPathPrefixLen, count, max; - SOGoCacheGCSObject *currentChild; - - /* query construction */ - sql = [NSMutableString stringWithCapacity: 256]; - [sql appendFormat: @"SELECT * FROM %@", [self tableName]]; - - whereClause = [NSMutableArray arrayWithCapacity: 2]; - [whereClause addObject: [NSString stringWithFormat: @"c_parent_path = '%@'", - [self path]]]; - [whereClause addObject: [NSString stringWithFormat: @"c_type = %d", type]]; - if (!includeDeleted) - [whereClause addObject: @"c_deleted = 0"]; - - [sql appendFormat: @" WHERE %@", - [whereClause componentsJoinedByString: @" AND "]]; - - childPathPrefix = [NSString stringWithFormat: @"%@/", [self path]]; - - /* results */ - records = [self performSQLQuery: sql]; - if (records) - { - max = [records count]; - childKeys = [NSMutableArray arrayWithCapacity: max]; - childPathPrefixLen = [childPathPrefix length]; - for (count = 0; count < max; count++) - { - record = [records objectAtIndex: count]; - childPath = [record objectForKey: @"c_path"]; - childKey = [childPath substringFromIndex: childPathPrefixLen]; - if ([childKey rangeOfString: @"/"].location == NSNotFound) - { - if (qualifier) - { - currentChild = [SOGoCacheGCSObject objectWithName: childKey - inContainer: self]; - [currentChild setupFromRecord: record]; - if ([qualifier evaluateSOGoMAPIDBObject: currentChild]) - [childKeys addObject: childKey]; - } - else - [childKeys addObject: childKey]; - } - } - } - else - childKeys = nil; - - return childKeys; -} - -- (NSArray *) toManyRelationshipKeys -{ - return [self childKeysOfType: MAPIFolderCacheObject - includeDeleted: NO - matchingQualifier: nil - andSortOrderings: nil]; -} - -- (NSArray *) toOneRelationshipKeys -{ - return [self childKeysOfType: MAPIMessageCacheObject - includeDeleted: NO - matchingQualifier: nil - andSortOrderings: nil]; -} - -- (void) setNameInContainer: (NSString *) newName -{ - NSMutableString *sql; - NSString *oldPath, *newPath, *path, *parentPath; - NSMutableArray *queries; - NSArray *records; - NSDictionary *record; - NSUInteger count, max; - - /* change the paths in children records */ - if (nameInContainer) - oldPath = [self path]; - - [super setNameInContainer: newName]; - - if (nameInContainer) - { - newPath = [self path]; - - sql = [NSMutableString stringWithFormat: - @"SELECT c_path, c_parent_path FROM %@" - @" WHERE c_path LIKE '%@/%%'", - [self tableName], oldPath]; - records = [self performSQLQuery: sql]; - max = [records count]; - queries = [NSMutableArray arrayWithCapacity: max + 1]; - if (max > 0) - { - for (count = 0; count < max; count++) - { - record = [records objectAtIndex: count]; - path = [record objectForKey: @"c_path"]; - sql = [NSMutableString stringWithFormat: @"UPDATE %@" - @" SET c_path = '%@'", - [self tableName], - [path stringByReplacingPrefix: oldPath - withPrefix: newPath]]; - parentPath = [record objectForKey: @"c_parent_path"]; - if ([parentPath isNotNull]) - [sql appendFormat: @", c_parent_path = '%@'", - [parentPath stringByReplacingPrefix: oldPath - withPrefix: newPath]]; - [sql appendFormat: @" WHERE c_path = '%@'", path]; - [queries addObject: sql]; - } - [self performBatchSQLQueries: queries]; - } - } -} - -- (void) changePathTo: (NSString *) newPath -{ - NSMutableString *sql// , *qualifierClause - ; - NSString *oldPath, *oldPathAsPrefix, *path, *parentPath; - NSMutableArray *queries; - NSArray *records; - NSDictionary *record; - NSUInteger count, max; - - /* change the paths in children records */ - oldPath = [self path]; - oldPathAsPrefix = [NSString stringWithFormat: @"%@/", oldPath]; - - sql = [NSMutableString stringWithFormat: - @"SELECT c_path, c_parent_path FROM %@" - @" WHERE c_path LIKE '%@%%'", - [self tableName], oldPathAsPrefix]; - records = [self performSQLQuery: sql]; - max = [records count]; - queries = [NSMutableArray arrayWithCapacity: max + 1]; - if (max > 0) - { - for (count = 0; count < max; count++) - { - record = [records objectAtIndex: count]; - path = [record objectForKey: @"c_path"]; - sql = [NSMutableString stringWithFormat: @"UPDATE %@" - @" SET c_path = '%@'", - [self tableName], - [path stringByReplacingPrefix: oldPath - withPrefix: newPath]]; - parentPath = [record objectForKey: @"c_parent_path"]; - if ([parentPath isNotNull]) - [sql appendFormat: @", c_parent_path = '%@'", - [parentPath stringByReplacingPrefix: oldPath - withPrefix: newPath]]; - [sql appendFormat: @" WHERE c_path = '%@'", path]; - [queries addObject: sql]; - } - [self performBatchSQLQueries: queries]; - } - - /* change the path in this folder record */ - [super changePathTo: newPath]; -} - -- (void) changePathTo: (NSString *) newPath intoNewContainer: (id) newContainer -{ - [self changePathTo: newPath]; - container = newContainer; - if ([self doesRetainContainer]) - [container retain]; -} - -// - (NSArray *) toOneRelationshipKeysMatchingQualifier: (EOQualifier *) qualifier -// andSortOrderings: (NSArray *) sortOrderings -// { -// NSArray *allKeys; -// NSMutableArray *keys; -// NSUInteger count, max; -// NSString *messageKey; -// SOGoMAPIDBMessage *message; - -// if (sortOrderings) -// [self warnWithFormat: @"sorting is not handled yet"]; - -// allKeys = [self toOneRelationshipKeys]; -// if (qualifier) -// { -// [self logWithFormat: @"%s: getting restricted FAI keys", __PRETTY_FUNCTION__]; -// max = [allKeys count]; -// keys = [NSMutableArray arrayWithCapacity: max]; -// for (count = 0; count < max; count++) -// { -// messageKey = [allKeys objectAtIndex: count]; -// message = [self lookupName: messageKey -// inContext: nil -// acquire: NO]; -// if ([qualifier evaluateMAPIVolatileMessage: message]) -// [keys addObject: messageKey]; -// } -// } -// else -// keys = (NSMutableArray *) allKeys; - -// return keys; -// } - -- (id) lookupName: (NSString *) childName - inContext: (WOContext *) woContext - acquire: (BOOL) acquire -{ - id object; - Class objectClass; - NSString *childPath; - NSDictionary *record; - - childPath = [self pathForChild: childName]; - record = [self lookupRecord: childPath newerThanVersion: -1]; - if (record) - { - if ([[record objectForKey: @"c_type"] intValue] == MAPIFolderCacheObject) - objectClass = isa; - else - objectClass = SOGoCacheGCSObjectK; - - object = [objectClass objectWithName: childName - inContainer: self]; - [object setupFromRecord: record]; - } - else - object = nil; - - return object; -} - -- (id) lookupFolder: (NSString *) folderName - inContext: (WOContext *) woContext -{ - id object; - - object = [SOGoCacheGCSFolder objectWithName: folderName - inContainer: self]; - [object reloadIfNeeded]; - - return object; -} - -// - (id) _fileAttributeForKey: (NSString *) key -// { -// NSDictionary *attributes; - -// attributes = [[NSFileManager defaultManager] -// fileAttributesAtPath: directory -// traverseLink: NO]; - -// return [attributes objectForKey: key]; -// } - -// - (NSCalendarDate *) creationTime -// { -// return [self _fileAttributeForKey: NSFileCreationDate]; -// } - -// - (NSCalendarDate *) lastModificationTime -// { -// return [self _fileAttributeForKey: NSFileModificationDate]; -// } - -/* acl */ -- (NSString *) defaultUserID -{ - return @"default"; -} - -- (NSMutableDictionary *) _aclEntries -{ - NSMutableDictionary *aclEntries; - - [aclMessage reloadIfNeeded]; - aclEntries = [aclMessage properties]; - if (![aclEntries objectForKey: @"users"]) - [aclEntries setObject: [NSMutableArray array] forKey: @"users"]; - if (![aclEntries objectForKey: @"entries"]) - [aclEntries setObject: [NSMutableDictionary dictionary] - forKey: @"entries"]; - - return aclEntries; -} - -- (void) addUserInAcls: (NSString *) user -{ - NSMutableDictionary *acl; - NSMutableArray *users; - - acl = [self _aclEntries]; - users = [acl objectForKey: @"users"]; - [users addObjectUniquely: user]; - [aclMessage save]; -} - -- (void) removeAclsForUsers: (NSArray *) oldUsers -{ - NSDictionary *acl; - NSMutableDictionary *entries; - NSMutableArray *users; - - acl = [self _aclEntries]; - entries = [acl objectForKey: @"entries"]; - [entries removeObjectsForKeys: oldUsers]; - users = [acl objectForKey: @"users"]; - [users removeObjectsInArray: oldUsers]; - [aclMessage save]; -} - -- (NSArray *) aclUsers -{ - return [[self _aclEntries] objectForKey: @"users"]; -} - -- (NSArray *) aclsForUser: (NSString *) uid -{ - NSDictionary *entries; - - entries = [[self _aclEntries] objectForKey: @"entries"]; - - return [entries objectForKey: uid]; -} - -- (void) setRoles: (NSArray *) roles - forUser: (NSString *) uid -{ - NSMutableDictionary *acl; - NSMutableDictionary *entries; - - acl = [self _aclEntries]; - entries = [acl objectForKey: @"entries"]; - [entries setObject: roles forKey: uid]; - [aclMessage save]; -} - -@end diff --git a/SoObjects/SOGo/SQLSource.m.orig b/SoObjects/SOGo/SQLSource.m.orig deleted file mode 100644 index aa881b9d3..000000000 --- a/SoObjects/SOGo/SQLSource.m.orig +++ /dev/null @@ -1,971 +0,0 @@ -/* SQLSource.h - this file is part of SOGo - * - * Copyright (C) 2009-2012 Inverse inc. - * - * Authors: Ludovic Marcotte - * Francis Lachapelle - * - * 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 - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#import -#import -#import -#import -#import -#import -#import - -#import -#import - -#import -#import -#import -#import - -#import - -#import "SOGoConstants.h" -#import "NSString+Utilities.h" -#import "NSString+Crypto.h" - -#import "SQLSource.h" - -/** - * The view MUST contain the following columns: - * - * c_uid - will be used for authentication - it's a username or username@domain.tld) - * c_name - which can be identical to c_uid - will be used to uniquely identify entries) - * c_password - password of the user, can be encoded in {scheme}pass format, or when stored without - * scheme it uses the scheme set in userPasswordAlgorithm. - * Possible algorithms are: plain, md5, crypt-md5, sha, ssha (including 256/512 variants), - * cram-md5, smd5, crypt, crypt-md5 - * c_cn - the user's common name - * mail - the user's mail address - * - * Other columns can be defined - see LDAPSource.m for the complete list. - * - * - * A SQL source can be defined like this: - * - * { - * id = zot; - * type = sql; - * viewURL = "mysql://sogo:sogo@127.0.0.1:5432/sogo/sogo_view"; - * canAuthenticate = YES; - * isAddressBook = YES; - * userPasswordAlgorithm = md5; - * prependPasswordScheme = YES; - * } - * - * If prependPasswordScheme is set to YES, the generated passwords will have the format {scheme}password. - * If it is NO (the default), the password will be written to database without encryption scheme. - * - */ - -@implementation SQLSource - -+ (id) sourceFromUDSource: (NSDictionary *) udSource - inDomain: (NSString *) domain -{ - return [[[self alloc] initFromUDSource: udSource - inDomain: domain] autorelease]; -} - -- (id) init -{ - if ((self = [super init])) - { - _sourceID = nil; - _domainField = nil; - _authenticationFilter = nil; - _loginFields = nil; - _mailFields = nil; - _userPasswordAlgorithm = nil; - _viewURL = nil; - _kindField = nil; - _multipleBookingsField = nil; - _imapHostField = nil; - _sieveHostField = nil; - } - - return self; -} - -- (void) dealloc -{ - [_sourceID release]; - [_authenticationFilter release]; - [_loginFields release]; - [_mailFields release]; - [_userPasswordAlgorithm release]; - [_viewURL release]; - [_kindField release]; - [_multipleBookingsField release]; - [_domainField release]; - [_imapHostField release]; - [_sieveHostField release]; - - [super dealloc]; -} - -- (id) initFromUDSource: (NSDictionary *) udSource - inDomain: (NSString *) sourceDomain -{ - self = [self init]; - - ASSIGN(_sourceID, [udSource objectForKey: @"id"]); - ASSIGN(_authenticationFilter, [udSource objectForKey: @"authenticationFilter"]); - ASSIGN(_loginFields, [udSource objectForKey: @"LoginFieldNames"]); - ASSIGN(_mailFields, [udSource objectForKey: @"MailFieldNames"]); - ASSIGN(_userPasswordAlgorithm, [udSource objectForKey: @"userPasswordAlgorithm"]); - ASSIGN(_imapLoginField, [udSource objectForKey: @"IMAPLoginFieldName"]); - ASSIGN(_imapHostField, [udSource objectForKey: @"IMAPHostFieldName"]); - ASSIGN(_sieveHostField, [udSource objectForKey: @"SieveHostFieldName"]); - ASSIGN(_kindField, [udSource objectForKey: @"KindFieldName"]); - ASSIGN(_multipleBookingsField, [udSource objectForKey: @"MultipleBookingsFieldName"]); - ASSIGN(_domainField, [udSource objectForKey: @"DomainFieldName"]); - if ([udSource objectForKey: @"prependPasswordScheme"]) - _prependPasswordScheme = [[udSource objectForKey: @"prependPasswordScheme"] boolValue]; - else - _prependPasswordScheme = NO; - - if (!_userPasswordAlgorithm) - _userPasswordAlgorithm = @"none"; - - if ([udSource objectForKey: @"viewURL"]) - _viewURL = [[NSURL alloc] initWithString: [udSource objectForKey: @"viewURL"]]; - -#warning this domain code has no effect yet - if ([sourceDomain length]) - ASSIGN (_domain, sourceDomain); - - if (!_viewURL) - { - [self autorelease]; - return nil; - } - - return self; -} - -- (NSString *) domain -{ - return _domain; -} - -- (BOOL) _isPassword: (NSString *) plainPassword - equalTo: (NSString *) encryptedPassword -{ - if (!plainPassword || !encryptedPassword) - return NO; - - return [plainPassword isEqualToCrypted: encryptedPassword - withDefaultScheme: _userPasswordAlgorithm]; -} - -/** - * Encrypts a string using this source password algorithm. - * @param plainPassword the unencrypted password. - * @return a new encrypted string. - * @see _isPassword:equalTo: - */ -- (NSString *) _encryptPassword: (NSString *) plainPassword -{ - NSString *pass; - NSString* result; - - pass = [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm]; - - if (pass == nil) - { - [self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm]; - return nil; - } - - if (_prependPasswordScheme) - result = [NSString stringWithFormat: @"{%@}%@", _userPasswordAlgorithm, pass]; - else - result = pass; - - return result; -} - -// -// SQL sources don't support right now all the password policy -// stuff supported by OpenLDAP (and others). If we want to support -// this for SQL sources, we'll have to implement the same -// kind of logic in this module. -// -- (BOOL) checkLogin: (NSString *) _login - password: (NSString *) _pwd - perr: (SOGoPasswordPolicyError *) _perr - expire: (int *) _expire - grace: (int *) _grace -{ - EOAdaptorChannel *channel; - EOQualifier *qualifier; - GCSChannelManager *cm; - NSException *ex; - NSMutableString *sql; - BOOL rc; - - rc = NO; - - _login = [_login stringByReplacingString: @"'" withString: @"''"]; - cm = [GCSChannelManager defaultChannelManager]; - channel = [cm acquireOpenChannelForURL: _viewURL]; - if (channel) - { - if (_loginFields) - { - NSMutableArray *qualifiers; - NSString *field; - EOQualifier *loginQualifier; - int i; - - qualifiers = [NSMutableArray arrayWithCapacity: [_loginFields count]]; - for (i = 0; i < [_loginFields count]; i++) - { - field = [_loginFields objectAtIndex: i]; - loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: field - operatorSelector: EOQualifierOperatorEqual - value: _login]; - [loginQualifier autorelease]; - [qualifiers addObject: loginQualifier]; - } - qualifier = [[EOOrQualifier alloc] initWithQualifierArray: qualifiers]; - } - else - { - qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_uid" - operatorSelector: EOQualifierOperatorEqual - value: _login]; - } - [qualifier autorelease]; - sql = [NSMutableString stringWithFormat: @"SELECT c_password" - @" FROM %@" - @" WHERE ", - [_viewURL gcsTableName]]; - if (_authenticationFilter) - { - qualifier = [[EOAndQualifier alloc] initWithQualifiers: - qualifier, - [EOQualifier qualifierWithQualifierFormat: _authenticationFilter], - nil]; - [qualifier autorelease]; - } - [qualifier _gcsAppendToString: sql]; - - ex = [channel evaluateExpressionX: sql]; - if (!ex) - { - NSDictionary *row; - NSArray *attrs; - NSString *value; - - attrs = [channel describeResults: NO]; - row = [channel fetchAttributes: attrs withZone: NULL]; - value = [row objectForKey: @"c_password"]; - - rc = [self _isPassword: _pwd equalTo: value]; - [channel cancelFetch]; - } - else - [self errorWithFormat: @"could not run SQL '%@': %@", qualifier, ex]; - - [cm releaseChannel: channel]; - } - else - [self errorWithFormat:@"failed to acquire channel for URL: %@", - [_viewURL absoluteString]]; - - return rc; -} - -/** - * Change a user's password. - * @param login the user's login name. - * @param oldPassword the previous password. - * @param newPassword the new password. - * @param perr is not used. - * @return YES if the password was successfully changed. - */ -- (BOOL) changePasswordForLogin: (NSString *) login - oldPassword: (NSString *) oldPassword - newPassword: (NSString *) newPassword - perr: (SOGoPasswordPolicyError *) perr -{ - EOAdaptorChannel *channel; - GCSChannelManager *cm; - NSException *ex; - NSString *sqlstr; - BOOL didChange; - BOOL isOldPwdOk; - - isOldPwdOk = NO; - didChange = NO; - - // Verify current password - isOldPwdOk = [self checkLogin:login password:oldPassword perr:perr expire:0 grace:0]; - - if (isOldPwdOk) - { - // Encrypt new password - NSString *encryptedPassword = [self _encryptPassword: newPassword]; - if(encryptedPassword == nil) - return NO; - - // Save new password - login = [login stringByReplacingString: @"'" withString: @"''"]; - cm = [GCSChannelManager defaultChannelManager]; - channel = [cm acquireOpenChannelForURL: _viewURL]; - if (channel) - { - sqlstr = [NSString stringWithFormat: (@"UPDATE %@" - @" SET c_password = '%@'" - @" WHERE c_uid = '%@'"), - [_viewURL gcsTableName], encryptedPassword, login]; - - ex = [channel evaluateExpressionX: sqlstr]; - if (!ex) - { - didChange = YES; - } - else - { - [self errorWithFormat: @"could not run SQL '%@': %@", sqlstr, ex]; - } - [cm releaseChannel: channel]; - } - } - - return didChange; -} - -- (NSString *) _whereClauseFromArray: (NSArray *) theArray - value: (NSString *) theValue - exact: (BOOL) theBOOL -{ - NSMutableString *s; - int i; - - s = [NSMutableString string]; - - for (i = 0; i < [theArray count]; i++) - { - if (theBOOL) - [s appendFormat: @" OR LOWER(%@) = '%@'", [theArray objectAtIndex: i], theValue]; - else - [s appendFormat: @" OR LOWER(%@) LIKE '%%%@%%'", [theArray objectAtIndex: i], theValue]; - } - - return s; -} - -- (NSDictionary *) _lookupContactEntry: (NSString *) theID - considerEmail: (BOOL) b - inDomain: (NSString *) domain -{ - NSMutableDictionary *response; - NSMutableArray *qualifiers; - NSArray *fieldNames; - EOAdaptorChannel *channel; - EOQualifier *loginQualifier, *domainQualifier, *qualifier; - GCSChannelManager *cm; - NSMutableString *sql; - NSString *value, *field; - NSException *ex; - int i; - - response = nil; - - theID = [theID stringByReplacingString: @"'" withString: @"''"]; - cm = [GCSChannelManager defaultChannelManager]; - channel = [cm acquireOpenChannelForURL: _viewURL]; - if (channel) - { - qualifiers = [NSMutableArray arrayWithCapacity: [_loginFields count] + 1]; - - // Always compare against the c_uid field - loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_uid" - operatorSelector: EOQualifierOperatorEqual - value: theID]; - [loginQualifier autorelease]; - [qualifiers addObject: loginQualifier]; - - if (_loginFields) - { - for (i = 0; i < [_loginFields count]; i++) - { - field = [_loginFields objectAtIndex: i]; - if ([field caseInsensitiveCompare: @"c_uid"] != NSOrderedSame) - { - loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: field - operatorSelector: EOQualifierOperatorEqual - value: theID]; - [loginQualifier autorelease]; - [qualifiers addObject: loginQualifier]; - } - } - } - - domainQualifier = nil; - if (_domainField && domain) - { - domainQualifier = [[EOKeyValueQualifier alloc] initWithKey: _domainField - operatorSelector: EOQualifierOperatorEqual - value: domain]; - [domainQualifier autorelease]; - } - - if (b) - { - // Always compare againts the mail field - loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: @"mail" - operatorSelector: EOQualifierOperatorEqual - value: [theID lowercaseString]]; - [loginQualifier autorelease]; - [qualifiers addObject: loginQualifier]; - - if (_mailFields) - { - for (i = 0; i < [_mailFields count]; i++) - { - field = [_mailFields objectAtIndex: i]; - if ([field caseInsensitiveCompare: @"mail"] != NSOrderedSame - && ![_loginFields containsObject: field]) - { - loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: field - operatorSelector: EOQualifierOperatorEqual - value: [theID lowercaseString]]; - [loginQualifier autorelease]; - [qualifiers addObject: loginQualifier]; - } - } - } - } - - sql = [NSMutableString stringWithFormat: @"SELECT *" - @" FROM %@" - @" WHERE ", - [_viewURL gcsTableName]]; - qualifier = [[EOOrQualifier alloc] initWithQualifierArray: qualifiers]; - if (domainQualifier) - qualifier = [[EOAndQualifier alloc] initWithQualifiers: domainQualifier, qualifier, nil]; - [qualifier _gcsAppendToString: sql]; - - ex = [channel evaluateExpressionX: sql]; - if (!ex) - { - NSMutableArray *emails; - - response = [[channel fetchAttributes: [channel describeResults: NO] - withZone: NULL] mutableCopy]; - [response autorelease]; - [channel cancelFetch]; - - /* Convert all c_ fields to obtain their ldif equivalent */ - fieldNames = [response allKeys]; - for (i = 0; i < [fieldNames count]; i++) - { - field = [fieldNames objectAtIndex: i]; - if ([field hasPrefix: @"c_"]) - [response setObject: [response objectForKey: field] - forKey: [field substringFromIndex: 2]]; - } - - // FIXME - // We have to do this here since we do not manage modules - // constraints right now over a SQL backend. - [response setObject: [NSNumber numberWithBool: YES] forKey: @"CalendarAccess"]; - [response setObject: [NSNumber numberWithBool: YES] forKey: @"MailAccess"]; - [response setObject: [NSNumber numberWithBool: YES] forKey: @"ActiveSyncAccess"]; - - // We set the domain, if any - value = nil; - if (_domain) - value = _domain; - else if (_domainField) - value = [response objectForKey: _domainField]; - if (![value isNotNull]) - value = @""; - [response setObject: value forKey: @"c_domain"]; - - // We populate all mail fields - emails = [NSMutableArray array]; - - if ([response objectForKey: @"mail"]) - [emails addObject: [response objectForKey: @"mail"]]; - - if (_mailFields && [_mailFields count] > 0) - { - NSString *s; - int i; - - for (i = 0; i < [_mailFields count]; i++) - if ((s = [response objectForKey: [_mailFields objectAtIndex: i]]) && - [[s stringByTrimmingSpaces] length] > 0) - [emails addObject: s]; - } - - [response setObject: emails forKey: @"c_emails"]; - if (_imapHostField) - { - value = [response objectForKey: _imapHostField]; - if ([value isNotNull]) - [response setObject: value forKey: @"c_imaphostname"]; - } - - if (_sieveHostField) - { - value = [response objectForKey: _sieveHostField]; - if ([value isNotNull]) - [response setObject: value forKey: @"c_sievehostname"]; - } - - // We check if the user can authenticate - if (_authenticationFilter) - { - EOQualifier *q_uid, *q_auth; - - sql = [NSMutableString stringWithFormat: @"SELECT c_uid" - @" FROM %@" - @" WHERE ", - [_viewURL gcsTableName]]; - - q_auth = [EOQualifier qualifierWithQualifierFormat: _authenticationFilter]; - - q_uid = [[EOKeyValueQualifier alloc] initWithKey: @"c_uid" - operatorSelector: EOQualifierOperatorEqual - value: theID]; - [q_uid autorelease]; - - qualifier = [[EOAndQualifier alloc] initWithQualifiers: q_uid, q_auth, nil]; - [qualifier autorelease]; - [qualifier _gcsAppendToString: sql]; - - ex = [channel evaluateExpressionX: sql]; - if (!ex) - { - NSDictionary *authResponse; - - authResponse = [channel fetchAttributes: [channel describeResults: NO] withZone: NULL]; - [response setObject: [NSNumber numberWithBool: [authResponse count] > 0] forKey: @"canAuthenticate"]; - [channel cancelFetch]; - } - else - [self errorWithFormat: @"could not run SQL '%@': %@", sql, ex]; - } - else - [response setObject: [NSNumber numberWithBool: YES] forKey: @"canAuthenticate"]; - - // We check if we should use a different login for IMAP - if (_imapLoginField) - { - if ([[response objectForKey: _imapLoginField] isNotNull]) - [response setObject: [response objectForKey: _imapLoginField] forKey: @"c_imaplogin"]; - } - - // We check if it's a resource of not - if (_kindField) - { - if ((value = [response objectForKey: _kindField]) && [value isNotNull]) - { - if ([value caseInsensitiveCompare: @"location"] == NSOrderedSame || - [value caseInsensitiveCompare: @"thing"] == NSOrderedSame || - [value caseInsensitiveCompare: @"group"] == NSOrderedSame) - { - [response setObject: [NSNumber numberWithInt: 1] - forKey: @"isResource"]; - } - } - } - - if (_multipleBookingsField) - { - if ((value = [response objectForKey: _multipleBookingsField])) - { - [response setObject: [NSNumber numberWithInt: [value intValue]] - forKey: @"numberOfSimultaneousBookings"]; - } - } - - [response setObject: self forKey: @"source"]; - } - else - [self errorWithFormat: @"could not run SQL '%@': %@", sql, ex]; - [cm releaseChannel: channel]; - } - else - [self errorWithFormat:@"failed to acquire channel for URL: %@", - [_viewURL absoluteString]]; - - return response; -} - - -- (NSDictionary *) lookupContactEntry: (NSString *) theID -{ - return [self _lookupContactEntry: theID considerEmail: NO inDomain: nil]; -} - -- (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) entryID - inDomain: (NSString *) domain -{ - return [self _lookupContactEntry: entryID considerEmail: YES inDomain: domain]; -} - -/* Returns an EOQualifier of the following form: - * (_domainField = domain OR _domainField = visibleDomain1 [...]) - * Should only be called on SQL sources using _domainField name. - */ -- (EOQualifier *) _visibleDomainsQualifierFromDomain: (NSString *) domain -{ - int i; - EOQualifier *qualifier, *domainQualifier; - NSArray *visibleDomains; - NSMutableArray *qualifiers; - NSString *currentDomain; - - SOGoSystemDefaults *sd; - - /* Return early if no domain or if being called on a 'static' sql source */ - if (!domain || !_domainField) - return nil; - - sd = [SOGoSystemDefaults sharedSystemDefaults]; - visibleDomains = [sd visibleDomainsForDomain: domain]; - qualifier = nil; - - domainQualifier = - [[EOKeyValueQualifier alloc] initWithKey: _domainField - operatorSelector: EOQualifierOperatorEqual - value: domain]; - [domainQualifier autorelease]; - - if ([visibleDomains count]) - { - qualifiers = [NSMutableArray arrayWithCapacity: [visibleDomains count] + 1]; - [qualifiers addObject: domainQualifier]; - for(i = 0; i < [visibleDomains count]; i++) - { - currentDomain = [visibleDomains objectAtIndex: i]; - qualifier = - [[EOKeyValueQualifier alloc] initWithKey: _domainField - operatorSelector: EOQualifierOperatorEqual - value: currentDomain]; - [qualifier autorelease]; - [qualifiers addObject: qualifier]; - } - qualifier = [[EOOrQualifier alloc] initWithQualifierArray: qualifiers]; - [qualifier autorelease]; - } - - return qualifier ? qualifier : domainQualifier; -} - - -- (NSArray *) allEntryIDsVisibleFromDomain: (NSString *) domain -{ - EOAdaptorChannel *channel; - EOQualifier *domainQualifier; - GCSChannelManager *cm; - NSException *ex; - NSMutableArray *results; - NSMutableString *sql; - - results = [NSMutableArray array]; - - cm = [GCSChannelManager defaultChannelManager]; - channel = [cm acquireOpenChannelForURL: _viewURL]; - if (channel) - { - sql = [NSMutableString stringWithFormat: @"SELECT c_uid FROM %@", - [_viewURL gcsTableName]]; - - if (_domainField) - { - if ([domain length]) - { - domainQualifier = - [self _visibleDomainsQualifierFromDomain: domain]; - if (domainQualifier) - { - [sql appendString: @" WHERE "]; - [domainQualifier _gcsAppendToString: sql]; - } - } - else - { - /* Should not happen but avoid returning the whole table - * if a domain should have been defined */ - [sql appendFormat: @" WHERE %@ is NULL", _domainField]; - } - } - - ex = [channel evaluateExpressionX: sql]; - if (!ex) - { - NSDictionary *row; - NSArray *attrs; - NSString *value; - - attrs = [channel describeResults: NO]; - - while ((row = [channel fetchAttributes: attrs withZone: NULL])) - { - value = [row objectForKey: @"c_uid"]; - if (value) - [results addObject: value]; - } - } - else - [self errorWithFormat: @"could not run SQL '%@': %@", sql, ex]; - [cm releaseChannel: channel]; - } - else - [self errorWithFormat:@"failed to acquire channel for URL: %@", - [_viewURL absoluteString]]; - - - return results; -} - -- (NSArray *) allEntryIDs -{ - return [self allEntryIDsVisibleFromDomain: nil]; -} - -- (NSArray *) fetchContactsMatching: (NSString *) filter - inDomain: (NSString *) domain -{ - EOAdaptorChannel *channel; - NSMutableArray *results; - GCSChannelManager *cm; - NSException *ex; - NSMutableString *sql; - NSString *lowerFilter; - - results = [NSMutableArray array]; - - cm = [GCSChannelManager defaultChannelManager]; - channel = [cm acquireOpenChannelForURL: _viewURL]; - if (channel) - { - lowerFilter = [filter lowercaseString]; - lowerFilter = [lowerFilter stringByReplacingString: @"'" withString: @"''"]; - - sql = [NSMutableString stringWithFormat: (@"SELECT *" - @" FROM %@" - @" WHERE" - @" (LOWER(c_cn) LIKE '%%%@%%'" - @" OR LOWER(mail) LIKE '%%%@%%'"), - [_viewURL gcsTableName], - lowerFilter, lowerFilter]; - - if (_mailFields && [_mailFields count] > 0) - { - [sql appendString: [self _whereClauseFromArray: _mailFields value: lowerFilter exact: NO]]; - } - - [sql appendString: @")"]; - - if (_domainField) - { - if ([domain length]) - { - EOQualifier *domainQualifier; - domainQualifier = - [self _visibleDomainsQualifierFromDomain: domain]; - if (domainQualifier) - { - [sql appendFormat: @" AND ("]; - [domainQualifier _gcsAppendToString: sql]; - [sql appendFormat: @")"]; - } - } - else - [sql appendFormat: @" AND %@ IS NULL", _domainField]; - } - - ex = [channel evaluateExpressionX: sql]; - if (!ex) - { - NSDictionary *row; - NSArray *attrs; - - attrs = [channel describeResults: NO]; - - while ((row = [channel fetchAttributes: attrs withZone: NULL])) - { - row = [row mutableCopy]; - [(NSMutableDictionary *) row setObject: self forKey: @"source"]; - [results addObject: row]; - [row release]; - } - } - else - [self errorWithFormat: @"could not run SQL '%@': %@", sql, ex]; - [cm releaseChannel: channel]; - } - else - [self errorWithFormat:@"failed to acquire channel for URL: %@", - [_viewURL absoluteString]]; - - return results; -} - -- (void) setSourceID: (NSString *) newSourceID -{ -} - -- (NSString *) sourceID -{ - return _sourceID; -} - -- (void) setDisplayName: (NSString *) newDisplayName -{ -} - -- (NSString *) displayName -{ - /* This method is only used when supporting user "source" addressbooks, - which is only supported by the LDAP backend for now. */ - return _sourceID; -} - -- (void) setListRequiresDot: (BOOL) newListRequiresDot -{ -} - -- (BOOL) listRequiresDot -{ - /* This method is not implemented for SQLSource. It must enable a mechanism - where using "." is not required to list the content of addressbooks. */ - return YES; -} - -/* card editing */ -- (void) setModifiers: (NSArray *) newModifiers -{ -} - -- (NSArray *) modifiers -{ - /* This method is only used when supporting card editing, - which is only supported by the LDAP backend for now. */ - return nil; -} - -- (NSException *) addContactEntry: (NSDictionary *) roLdifRecord - withID: (NSString *) aId -{ - NSString *reason; - - reason = [NSString stringWithFormat: @"method '%@' is not available" - @" for class '%@'", NSStringFromSelector (_cmd), - NSStringFromClass (isa)]; - - return [NSException exceptionWithName: @"SQLSourceIOException" - reason: reason - userInfo: nil]; -} - -- (NSException *) updateContactEntry: (NSDictionary *) roLdifRecord -{ - NSString *reason; - - reason = [NSString stringWithFormat: @"method '%@' is not available" - @" for class '%@'", NSStringFromSelector (_cmd), - NSStringFromClass (isa)]; - - return [NSException exceptionWithName: @"SQLSourceIOException" - reason: reason - userInfo: nil]; -} - -- (NSException *) removeContactEntryWithID: (NSString *) aId -{ - NSString *reason; - - reason = [NSString stringWithFormat: @"method '%@' is not available" - @" for class '%@'", NSStringFromSelector (_cmd), - NSStringFromClass (isa)]; - - return [NSException exceptionWithName: @"SQLSourceIOException" - reason: reason - userInfo: nil]; -} - -/* user addressbooks */ -- (BOOL) hasUserAddressBooks -{ - return NO; -} - -- (NSArray *) addressBookSourcesForUser: (NSString *) user -{ - return nil; -} - -- (NSException *) addAddressBookSource: (NSString *) newId - withDisplayName: (NSString *) newDisplayName - forUser: (NSString *) user -{ - NSString *reason; - - reason = [NSString stringWithFormat: @"method '%@' is not available" - @" for class '%@'", NSStringFromSelector (_cmd), - NSStringFromClass (isa)]; - - return [NSException exceptionWithName: @"SQLSourceIOException" - reason: reason - userInfo: nil]; -} - -- (NSException *) renameAddressBookSource: (NSString *) newId - withDisplayName: (NSString *) newDisplayName - forUser: (NSString *) user -{ - NSString *reason; - - reason = [NSString stringWithFormat: @"method '%@' is not available" - @" for class '%@'", NSStringFromSelector (_cmd), - NSStringFromClass (isa)]; - - return [NSException exceptionWithName: @"SQLSourceIOException" - reason: reason - userInfo: nil]; -} - -- (NSException *) removeAddressBookSource: (NSString *) newId - forUser: (NSString *) user -{ - NSString *reason; - - reason = [NSString stringWithFormat: @"method '%@' is not available" - @" for class '%@'", NSStringFromSelector (_cmd), - NSStringFromClass (isa)]; - - return [NSException exceptionWithName: @"SQLSourceIOException" - reason: reason - userInfo: nil]; -} - -@end