mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-06-01 00:19:45 +00:00
Delete .orig files left over from applying patches to Stage 2.
This commit is contained in:
committed by
Ludovic Marcotte
parent
d3290dbb8d
commit
0605fdf02a
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user