/*
- Copyright (C) 2000-2004 SKYRIX Software AG
+ Copyright (C) 2004-2005 SKYRIX Software AG
- This file is part of OGo
+ This file is part of OpenGroupware.org.
OGo 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, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
-// $Id$
-
#include "AgenorUserManager.h"
#include <NGExtensions/NGExtensions.h>
static BOOL useLDAP = NO;
static NSString *ldapHost = nil;
static NSString *ldapBaseDN = nil;
+static NSString *fallbackIMAP4Server = nil;
+static NSString *defaultMailDomain = @"equipement.gouv.fr";
+ (void)initialize {
static BOOL didInit = NO;
NSUserDefaults *ud;
- if(didInit)
+ if (didInit)
return;
didInit = YES;
- ud = [NSUserDefaults standardUserDefaults];
+ ud = [NSUserDefaults standardUserDefaults];
debugOn = [ud boolForKey:@"SOGoUserManagerDebugEnabled"];
+
useLDAP = [ud boolForKey:@"SOGoUserManagerUsesLDAP"];
- if(useLDAP) {
- ldapHost = [[ud stringForKey:@"SOGoLDAPHost"] retain];
- ldapBaseDN = [[ud stringForKey:@"SOGoLDAPBaseDN"] retain];
+ if (useLDAP) {
+ ldapHost = [[ud stringForKey:@"SOGoLDAPHost"] copy];
+ ldapBaseDN = [[ud stringForKey:@"SOGoLDAPBaseDN"] copy];
+ NSLog(@"Note: using LDAP host to manage accounts: %@", ldapHost);
}
+ else
+ NSLog(@"Note: LDAP access is disabled.");
+
+ fallbackIMAP4Server = [[ud stringForKey:@"SOGoFallbackIMAP4Server"] copy];
+ if ([fallbackIMAP4Server length] > 0)
+ NSLog(@"Note: using fallback IMAP4 server: '%@'", fallbackIMAP4Server);
+ else
+ fallbackIMAP4Server = nil;
}
+ (id)sharedUserManager {
- static id mgr = nil;
- if(mgr == nil) {
+ static AgenorUserManager *mgr = nil;
+ if (mgr == nil)
mgr = [[self alloc] init];
- }
return mgr;
}
/* private cache helpers */
+// TODO: this is really unnecessary, no?
- (void)_cacheCN:(NSString *)_cn forUID:(NSString *)_uid {
+ if (_cn == nil) return;
[self->cnCache addObject:_cn forKey:_uid];
}
-
- (NSString *)_cachedCNForUID:(NSString *)_uid {
return [self->cnCache objectForKey:_uid];
}
- (void)_cacheServer:(NSString *)_server forUID:(NSString *)_uid {
+ if (_server == nil) return;
[self->serverCache addObject:_server forKey:_uid];
}
-
- (NSString *)_cachedServerForUID:(NSString *)_uid {
return [self->serverCache objectForKey:_uid];
}
- (void)_cacheEmail:(NSString *)_email forUID:(NSString *)_uid {
+ if (_email == nil) return;
[self->emailCache addObject:_email forKey:_uid];
}
-
- (NSString *)_cachedEmailForUID:(NSString *)_uid {
return [self->emailCache objectForKey:_uid];
}
- (void)_cacheUID:(NSString *)_uid forEmail:(NSString *)_email {
+ if (_uid == nil) return;
[self->uidCache addObject:_uid forKey:_email];
}
-
- (NSString *)_cachedUIDForEmail:(NSString *)_email {
return [self->uidCache objectForKey:_email];
}
Only LDAP fetches would guarantee correctness in both cases.
*/
-- (NSString *)getUIDForEmail:(NSString *)_email {
- if(useLDAP) {
+- (NSString *)primaryGetAgenorUIDForEmail:(NSString *)_email {
static NSArray *uidAttrs = nil;
NGLdapConnection *conn;
EOQualifier *q;
uidAttrs = [[NSArray alloc] initWithObjects:@"uid", nil];
}
- if((uid = [self _cachedUIDForEmail:_email]))
- return uid;
-
q = [EOQualifier qualifierWithQualifierFormat:@"mail = %@", _email];
conn = [self ldapConnection];
qualifier:q
attributes:uidAttrs];
entry = [resultEnum nextObject];
- if(!entry) {
+ if (entry == nil) {
if(debugOn) {
[self logWithFormat:@"%s Didn't find LDAP entry for email '%@'!",
__PRETTY_FUNCTION__,
if (!uidAttr)
return nil; /* can happen, not unlikely */
uid = [uidAttr stringValueAtIndex:0];
- [self _cacheUID:uid forEmail:_email];
return uid;
+}
+
+- (NSString *)getUIDForEmail:(NSString *)_email {
+ NSString *uid;
+
+ if ((uid = [self _cachedUIDForEmail:_email]) != nil)
+ return uid;
+
+ if (useLDAP) {
+ uid = [self primaryGetAgenorUIDForEmail:_email];
}
else {
NSRange r;
return nil;
r = [_email rangeOfString:@"@"];
- if(r.length == 0)
+ if (r.length == 0)
return nil;
+
domain = [_email substringFromIndex:NSMaxRange(r)];
- if(![domain isEqualToString:@"equipement.gouv.fr"])
- return _email;
- return [_email substringToIndex:r.location];
+ if (![domain isEqualToString:defaultMailDomain])
+ uid = _email;
+ else
+ uid = [_email substringToIndex:r.location];
}
+
+ [self _cacheUID:uid forEmail:_email];
+ return uid;
}
-- (NSString *)getEmailForUID:(NSString *)_uid {
- if(useLDAP) {
- static NSArray *emailAttrs = nil;
- NGLdapConnection *conn;
- EOQualifier *q;
- NSEnumerator *resultEnum;
- NGLdapEntry *entry;
- NGLdapAttribute *emailAttr;
- NSString *email;
-
- if(!emailAttrs) {
- emailAttrs = [[NSArray alloc] initWithObjects:@"mineqMelmailEmission", nil];
- }
+- (NSString *)primaryGetEmailForAgenorUID:(NSString *)_uid {
+ static NSArray *emailAttrs = nil;
+ NGLdapConnection *conn;
+ EOQualifier *q;
+ NSEnumerator *resultEnum;
+ NGLdapEntry *entry;
+ NGLdapAttribute *emailAttr;
+ NSString *email;
+ unsigned count;
- if((email = [self _cachedEmailForUID:_uid]))
- return email;
+ if (emailAttrs == nil)
+ emailAttrs = [[NSArray alloc] initWithObjects:@"mineqMelmailEmission",nil];
- q = [EOQualifier qualifierWithQualifierFormat:@"uid = %@", _uid];
+ q = [EOQualifier qualifierWithQualifierFormat:@"uid = %@", _uid];
- conn = [self ldapConnection];
- resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
- qualifier:q
- attributes:emailAttrs];
- entry = [resultEnum nextObject];
- if(!entry) {
+ conn = [self ldapConnection];
+ resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
+ qualifier:q
+ attributes:emailAttrs];
+ entry = [resultEnum nextObject];
+ if (entry == nil) {
if(debugOn) {
[self logWithFormat:@"%s Didn't find LDAP entry for uid '%@'!",
__PRETTY_FUNCTION__,
_uid];
}
return nil;
- }
- emailAttr = [entry attributeWithName:@"mineqMelmailEmission"];
- if (!emailAttr) {
- return nil; /* shit happens */
- }
- else {
- unsigned count;
-
- email = nil;
- count = [emailAttr count];
+ }
+ emailAttr = [entry attributeWithName:@"mineqMelmailEmission"];
+ if (emailAttr == nil)
+ return nil; /* shit happens */
+
+ email = nil;
+ count = [emailAttr count];
#if 0
- if (count > 1) {
+ if (count > 1) {
unsigned i;
/* in case there are multiple email addresses, select the first
NSString *candidate;
candidate = [emailAttr stringValueAtIndex:i];
- if (![candidate hasSuffix:@"@equipement.gouv.fr"]) {
+ if (![candidate hasSuffix:defaultMailDomain]) {
+ // TODO: also check for '@'
email = candidate;
break;
}
}
- }
+ }
#endif
- if (email == nil && count > 0) {
- email = [emailAttr stringValueAtIndex:0];
- }
- [self _cacheEmail:email forUID:_uid];
- return email;
- }
+ if (email == nil && count > 0)
+ email = [emailAttr stringValueAtIndex:0];
+
+ return email;
+}
+
+- (NSString *)getEmailForUID:(NSString *)_uid {
+ NSString *email;
+
+ if (![_uid isNotNull] || [_uid length] == 0)
+ return nil;
+ if ((email = [self _cachedEmailForUID:_uid]) != nil)
+ return email;
+
+ if (useLDAP) {
+ email = [self primaryGetEmailForAgenorUID:_uid];
}
else {
NSRange r;
- if(!_uid || [_uid length] == 0)
- return nil;
r = [_uid rangeOfString:@"@"];
- if(r.length > 0)
- return _uid;
- return [NSString stringWithFormat:@"%@@equipement.gouv.fr", _uid];
+ email = (r.length > 0)
+ ? _uid
+ : [[_uid stringByAppendingString:@"@"]
+ stringByAppendingString:defaultMailDomain];
}
+
+ [self _cacheEmail:email forUID:_uid];
+ return email;
}
/* CN */
-- (NSString *)getCNForUID:(NSString *)_uid {
- if(useLDAP) {
- static NSArray *cnAttrs = nil;
- NGLdapConnection *conn;
- EOQualifier *q;
- NSEnumerator *resultEnum;
- NGLdapEntry *entry;
- NGLdapAttribute *cnAttr;
- NSString *cn;
-
- if(!cnAttrs) {
- cnAttrs = [[NSArray alloc] initWithObjects:@"cn", nil];
- }
-
- if((cn = [self _cachedCNForUID:_uid]))
- return cn;
-
- q = [EOQualifier qualifierWithQualifierFormat:@"uid = %@", _uid];
+- (NSString *)primaryGetCNForAgenorUID:(NSString *)_uid {
+ static NSArray *cnAttrs = nil;
+ NGLdapConnection *conn;
+ EOQualifier *q;
+ NSEnumerator *resultEnum;
+ NGLdapEntry *entry;
+ NGLdapAttribute *cnAttr;
+ NSString *cn;
+
+ if (cnAttrs == nil)
+ cnAttrs = [[NSArray alloc] initWithObjects:@"cn", nil];
+
+ q = [EOQualifier qualifierWithQualifierFormat:@"uid = %@", _uid];
- conn = [self ldapConnection];
- resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
- qualifier:q
- attributes:cnAttrs];
- entry = [resultEnum nextObject];
- if(!entry) {
+ conn = [self ldapConnection];
+ resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
+ qualifier:q
+ attributes:cnAttrs];
+ entry = [resultEnum nextObject];
+ if (entry == nil) {
if(debugOn) {
[self logWithFormat:@"%s Didn't find LDAP entry for uid '%@'!",
__PRETTY_FUNCTION__,
_uid];
}
return nil;
- }
- cnAttr = [entry attributeWithName:@"cn"];
- if(!cnAttr && debugOn) {
+ }
+ cnAttr = [entry attributeWithName:@"cn"];
+ if(cnAttr == nil && debugOn) {
[self logWithFormat:@"%s LDAP entry for uid '%@' has no common name?",
__PRETTY_FUNCTION__,
_uid];
return nil; /* nothing we can do about it */
- }
- cn = [cnAttr stringValueAtIndex:0];
- [self _cacheCN:cn forUID:_uid];
+ }
+ cn = [cnAttr stringValueAtIndex:0];
+ return cn;
+}
+
+- (NSString *)getCNForUID:(NSString *)_uid {
+ NSString *cn;
+
+ if ((cn = [self _cachedCNForUID:_uid]) != nil)
return cn;
+
+ if (useLDAP) {
+ cn = [self primaryGetCNForAgenorUID:_uid];
}
else {
NSString *s;
// TODO: algorithm might be inappropriate, depends on the actual UID
r = [s rangeOfString:@"."];
if (r.length == 0)
- return s;
-
- return [s substringToIndex:r.location];
+ cn = s;
+ else
+ cn = [s substringToIndex:r.location];
}
+
+ [self _cacheCN:cn forUID:_uid];
+ return cn;
}
NSString *server;
server = [self getServerForUID:_uid];
- if(!server)
+ if (server == nil)
return nil;
return [NSString stringWithFormat:@"%@@%@", _uid, server];
}
-- (NSString *)getServerForUID:(NSString *)_uid {
- /*
- First of all : for a particular user IMAP and SMTP are served on the same
- host.
-
- The name of the machine is determined by applying a regex on every values of
- the mineqMelRoutage LDAP attribute.
- The regex is : .*%.*@(.*\.melanie2\.i2$)
- It extracts the substring that follows '@', ends with 'melanie2', on
- adresses which have a '%' before the '@'
-
- Example: helge.hesse%opengroupware.org@servername1.melanie2.i2
- -> servername1.melanie2.i2
-
- If only one server name is found by applying the regex on every value of the
- attribute, then this name is the IMAP/SMTP server for that user.
- Note that this is the case when we got a unique (well formed) value for the
- attribute.
- If the regex finds more than one servername when applied to the differents
- values, then the IMAP/SMTP server name is to be found in the
- mineqMelServeurPrincipal attribute of the user.
- */
- if(useLDAP) {
- static NSArray *attrs = nil;
- NGLdapConnection *conn;
- EOQualifier *q;
- NSEnumerator *resultEnum;
- NGLdapEntry *entry;
- NGLdapAttribute *attr;
- NSMutableArray *serverCandidates;
- NSString *server;
-
- if(!attrs) {
- attrs = [[NSArray alloc] initWithObjects:@"mineqMelRoutage",
- @"mineqMelServeurPrincipal",
- nil];
- }
-
- if((server = [self _cachedServerForUID:_uid]))
- return server;
-
- q = [EOQualifier qualifierWithQualifierFormat:@"uid = %@", _uid];
-
- conn = [self ldapConnection];
- resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
- qualifier:q
- attributes:attrs];
- /* we just expect one entry, thus drop the rest */
- entry = [resultEnum nextObject];
- if(!entry) {
+- (NGLdapEntry *)_fetchEntryForAgenorUID:(NSString *)_uid {
+ static NSArray *attrs = nil;
+ NGLdapConnection *conn;
+ EOQualifier *q;
+ NSEnumerator *resultEnum;
+ NGLdapEntry *entry;
+
+ if (attrs == nil) {
+ attrs = [[NSArray alloc] initWithObjects:
+ @"mineqMelRoutage",
+ @"mineqMelServeurPrincipal",
+ nil];
+ }
+
+ q = [EOQualifier qualifierWithQualifierFormat:@"uid = %@", _uid];
+
+ conn = [self ldapConnection];
+ resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
+ qualifier:q
+ attributes:attrs];
+ /* we just expect one entry, thus drop the rest */
+ entry = [resultEnum nextObject];
+ if (entry == nil) {
if(debugOn) {
NSLog(@"%s Didn't find LDAP entry for uid '%@'!",
__PRETTY_FUNCTION__,
_uid);
}
return nil;
- }
- attr = [entry attributeWithName:@"mineqMelRoutage"];
- if(attr) {
+ }
+ return entry;
+}
+
+- (NSArray *)_serverCandidatesForMineqMelRoutage:(NGLdapAttribute *)attr {
+ NSMutableArray *serverCandidates;
+
unsigned i, count;
count = [attr count];
}
}
}
- }
- else {
- if(debugOn) {
- NSLog(@"%s LDAP entry for uid '%@' has no mineqMelRoutage entry?",
- __PRETTY_FUNCTION__,
- _uid);
- }
- serverCandidates = nil;
- }
- if([serverCandidates count] == 1) {
- server = [serverCandidates objectAtIndex:0];
- }
+ return serverCandidates;
+}
- /* last resort */
- if(!server) {
+- (NSString *)primaryGetServerForAgenorUID:(NSString *)_uid {
+ /*
+ First of all : for a particular user IMAP and SMTP are served on the same
+ host.
+
+ The name of the machine is determined by applying a regex on every values of
+ the mineqMelRoutage LDAP attribute.
+ The regex is : .*%.*@(.*\.melanie2\.i2$)
+ It extracts the substring that follows '@', ends with 'melanie2', on
+ adresses which have a '%' before the '@'
+
+ Example: helge.hesse%opengroupware.org@servername1.melanie2.i2
+ -> servername1.melanie2.i2
+
+ If only one server name is found by applying the regex on every value of the
+ attribute, then this name is the IMAP/SMTP server for that user.
+ Note that this is the case when we got a unique (well formed) value for the
+ attribute.
+ If the regex finds more than one servername when applied to the differents
+ values, then the IMAP/SMTP server name is to be found in the
+ mineqMelServeurPrincipal attribute of the user.
+ */
+ NSString *server;
+ NGLdapEntry *entry;
+ NGLdapAttribute *attr;
+
+ if ((entry = [self _fetchEntryForAgenorUID:_uid]) == nil)
+ return nil;
+
+ attr = [entry attributeWithName:@"mineqMelRoutage"];
+ if (attr != nil) {
+ NSArray *serverCandidates;
+
+ serverCandidates = [self _serverCandidatesForMineqMelRoutage:attr];
+
+ if ([serverCandidates count] > 0)
+ server = [serverCandidates objectAtIndex:0];
+ }
+ else {
+ [self debugWithFormat:
+ @"%s LDAP entry for uid '%@' has no mineqMelRoutage entry?",
+ __PRETTY_FUNCTION__,
+ _uid];
+ }
+
+ /* last resort */
+ if (server == nil) {
attr = [entry attributeWithName:@"mineqMelServeurPrincipal"];
- if([attr count] > 0)
+ if ([attr count] > 0)
server = [attr stringValueAtIndex:0];
- }
-
- if(!server) {
- if(debugOn) {
- NSLog(@"%s no chance of getting at server info for user '%@', "
+ }
+
+ if (server == nil) {
+ [self debugWithFormat:
+ @"%s no chance of getting at server info for user '%@', "
@"tried everything. Sorry.",
__PRETTY_FUNCTION__,
- _uid);
- }
- return nil;
- }
+ _uid];
+ return nil;
+ }
+ return server;
+}
+
+- (NSString *)getServerForUID:(NSString *)_uid {
+ NSString *server;
- [self _cacheServer:server forUID:_uid];
+ if (_uid == nil || [_uid length] == 0)
+ return nil;
+
+ if ((server = [self _cachedServerForUID:_uid]) != nil)
return server;
- }
+
+ if (useLDAP)
+ server = [self primaryGetServerForAgenorUID:_uid];
+ else if (fallbackIMAP4Server)
+ server = fallbackIMAP4Server;
else {
- return @"mail.opengroupware.org";
+ [self logWithFormat:@"ERROR: could not get server for uid '%@', "
+ @"neither LDAP (SOGoUserManagerUsesLDAP) nor "
+ @"a fallback (SOGoFallbackIMAP4Server) is configured.",
+ _uid];
+ server = nil;
}
+
+ [self _cacheServer:server forUID:_uid];
+ return server;
}
-@end
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+ return debugOn;
+}
+
+@end /* AgenorUserManager */