Delete .orig files left over from applying patches to Stage 2.

pull/109/head
Euan Thoms 2015-11-04 03:40:53 +08:00
parent 212ff64828
commit 9a3f8549ea
4 changed files with 0 additions and 2564 deletions

View File

@ -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 <Foundation/NSString.h>
#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 */

View File

@ -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 <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSString.h>
#import <Foundation/NSURL.h>
#import <Foundation/NSValue.h>
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/WOApplication.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <NGObjWeb/WORequest.h>
#import <NGObjWeb/WOResponse.h>
#import <NGObjWeb/SoObject.h>
#import <NGObjWeb/SoSelectorInvocation.h>
#import <NGObjWeb/SoUser.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
#import <DOM/DOMElement.h>
#import <DOM/DOMProtocols.h>
#import <EOControl/EOSortOrdering.h>
#import <SaxObjC/XMLNamespaces.h>
#import <SOGo/DOMNode+SOGo.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSDictionary+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/NSObject+DAV.h>
#import <SOGo/SOGoPermissions.h>
#import <SOGo/SOGoSource.h>
#import <SOGo/SOGoUserSettings.h>
#import <SOGo/WORequest+SOGo.h>
#import <SOGo/WOResponse+SOGo.h>
#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 <SOGoSource>) newSource
{
ASSIGN (source, newSource);
}
- (id <SOGoSource>) 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 <SOGoSource> *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 <SOGoDNSource>*) 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: @"<D:propstat><D:prop>"];
properties = [propstat objectForKey: @"properties"];
max = [properties count];
for (count = 0; count < max; count++)
[r appendString: [properties objectAtIndex: count]];
[r appendString: @"</D:prop><D:status>"];
[r appendString: [propstat objectForKey: @"status"]];
[r appendString: @"</D:status></D:propstat>"];
}
- (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: @"<D:response><D:href>"];
[r appendString: baseURL];
[r appendString: [[object objectForKey: @"c_name"] stringByEscapingURL]];
[r appendString: @"</D:href>"];
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: @"</D:response>"];
}
- (void) appendMissingObjectRef: (NSString *) href
toBuffer: (NSMutableString *) r
{
[r appendString: @"<D:response><D:href>"];
[r appendString: href];
[r appendString: @"</D:href><D:status>HTTP/1.1 404 Not Found</D:status></D:response>"];
}
- (void) _appendComponentProperties: (NSArray *) properties
matchingURLs: (id <DOMNodeList>) refs
toResponse: (WOResponse *) response
{
NSObject <DOMElement> *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 <DOMDocument> document;
id <DOMElement> documentElement, propElement;
r = [context response];
[r prepareDAVResponse];
[r appendContentString:
[NSString stringWithFormat: @"<D:multistatus xmlns:D=\"DAV:\""
@" xmlns:C=\"%@\">", 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:@"</D:multistatus>"];
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

View File

@ -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 <Foundation/NSArray.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
#import <Foundation/NSPropertyList.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#import <Foundation/NSURL.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSNull+misc.h>
#import <GDLAccess/EOAdaptorChannel.h>
#import <GDLContentStore/GCSChannelManager.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoUser.h>
#import "EOQualifier+SOGoCacheObject.h"
#import "GCSSpecialQueries+SOGoCacheObject.h"
#import "SOGoCacheGCSFolder.h"
#undef DEBUG
//#include <stdbool.h>
//#include <talloc.h>
//#include <util/time.h>
//#include <mapistore/mapistore.h>
//#include <mapistore/mapistore_errors.h>
//#include <libmapiproxy.h>
//#include <param.h>
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

View File

@ -1,971 +0,0 @@
/* SQLSource.h - this file is part of SOGo
*
* Copyright (C) 2009-2012 Inverse inc.
*
* Authors: Ludovic Marcotte <lmarcotte@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
*
* 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 <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#import <Foundation/NSURL.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <GDLContentStore/GCSChannelManager.h>
#import <GDLContentStore/NSURL+GCS.h>
#import <GDLContentStore/EOQualifier+GCS.h>
#import <GDLAccess/EOAdaptorChannel.h>
#import <SOGo/SOGoSystemDefaults.h>
#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