2 Copyright (C) 2004-2005 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "AgenorUserManager.h"
23 #include "AgenorUserDefaults.h"
24 #include <NGExtensions/NGExtensions.h>
25 #include <NGLdap/NGLdap.h>
26 #include <NGCards/NGCards.h>
27 #include "SOGoLRUCache.h"
29 #warning we should rely on the LDAP sources instead...
30 #define qualifierFormat @"mailNickname = %@"
32 @interface AgenorUserManager (PrivateAPI)
33 - (NGLdapConnection *)ldapConnection;
35 - (void)_cacheCN:(NSString *)_cn forUID:(NSString *)_uid;
36 - (NSString *)_cachedCNForUID:(NSString *)_uid;
37 - (void)_cacheServer:(NSString *)_server forUID:(NSString *)_uid;
38 - (NSString *)_cachedServerForUID:(NSString *)_uid;
39 - (void)_cacheEmail:(NSString *)_email forUID:(NSString *)_uid;
40 - (NSString *)_cachedEmailForUID:(NSString *)_uid;
41 - (void)_cacheUID:(NSString *)_uid forEmail:(NSString *)_email;
42 - (NSString *)_cachedUIDForEmail:(NSString *)_email;
44 - (BOOL)primaryIsUserAllowedToChangeSOGoInternetAccess:(NSString *)_uid;
46 - (BOOL)primaryIsInternetAutoresponderEnabledForUser:(NSString *)_uid;
47 - (BOOL)primaryIsIntranetAutoresponderEnabledForUser:(NSString *)_uid;
48 - (NGLdapAttribute *)primaryGetMailAutoresponderAttribute:(NSString *)_uid;
49 - (BOOL)isAutoresponderEnabledForAttribute:(NGLdapAttribute *)_attr
50 matchingPrefix:(NSString *)_prefix;
53 // TODO: add a timer to flush LRU caches every some hours
55 @implementation AgenorUserManager
57 static BOOL debugOn = NO;
58 static BOOL useLDAP = NO;
59 static NSString *ldapHost = nil;
60 static NSString *ldapBaseDN = nil;
61 static NSNull *sharedNull = nil;
62 static NSString *fallbackIMAP4Server = nil;
63 static NSString *defaultMailDomain = nil;
64 static NSString *shareLDAPClass = @"mineqMelBoite";
65 static NSString *shareLoginSeparator = @".-.";
66 static NSString *mailEmissionAttrName = @"mineqMelmailEmission";
67 static NSString *changeInternetAccessAttrName = @"mineqOgoAccesInternet";
68 static NSString *mailAutoresponderAttrName = @"mineqMelReponse"; /* sic! */
69 static NSURL *AgenorProfileURL = nil;
71 static NSArray *fromEMailAttrs = nil;
73 static unsigned PoolScanInterval = 5 * 60 /* every five minutes */;
77 static BOOL didInit = NO;
84 ud = [NSUserDefaults standardUserDefaults];
85 debugOn = [ud boolForKey:@"SOGoUserManagerDebugEnabled"];
87 useLDAP = [ud boolForKey:@"SOGoUserManagerUsesLDAP"];
89 ldapHost = [[ud stringForKey:@"SOGoLDAPHost"] copy];
90 ldapBaseDN = [[ud stringForKey:@"SOGoLDAPBaseDN"] copy];
91 NSLog(@"Note: using LDAP host to manage accounts: %@", ldapHost);
94 NSLog(@"Note: LDAP access is disabled.");
96 fallbackIMAP4Server = [[ud stringForKey:@"SOGoFallbackIMAP4Server"] copy];
97 if ([fallbackIMAP4Server length] > 0)
98 NSLog(@"Note: using fallback IMAP4 server: '%@'", fallbackIMAP4Server);
101 if (fallbackIMAP4Server)
102 [fallbackIMAP4Server release];
103 fallbackIMAP4Server = nil;
106 defaultMailDomain = [[ud stringForKey:@"SOGoDefaultMailDomain"] copy];
107 if ([defaultMailDomain length] == 0)
109 if (defaultMailDomain)
110 [defaultMailDomain release];
111 defaultMailDomain = nil;
112 NSLog(@"WARNING: no default mail domain (please specify"
113 " 'SOGoDefaultMailDomain' in the user default db)");
117 [[NSArray alloc] initWithObjects:mailEmissionAttrName, nil];
119 sharedNull = [[NSNull null] retain];
121 /* profile database URL */
123 if ((tmp = [ud stringForKey:@"AgenorProfileURL"]) == nil)
124 NSLog(@"ERROR: no 'AgenorProfileURL' database URL configured!");
125 else if ((AgenorProfileURL = [[NSURL alloc] initWithString:tmp]) == nil)
126 NSLog(@"ERROR: could not parse AgenorProfileURL: '%@'", tmp);
128 NSLog(@"Note: using profile at: %@", [AgenorProfileURL absoluteString]);
130 if ((tmp = [ud stringForKey: @"SOGoDefaultMailDomain"]))
132 defaultMailDomain = [tmp copy];
135 PoolScanInterval = [[ud objectForKey:@"AgenorCacheCheckInterval"] intValue];
136 if (PoolScanInterval == 0)
137 PoolScanInterval = 60 * 60 /* every hour */;
138 NSLog(@"AgenorUserManager: flushing caches every %d minutes "
139 @"(AgenorCacheCheckInterval)",
140 PoolScanInterval / 60);
143 + (id)sharedUserManager {
144 static AgenorUserManager *mgr = nil;
146 mgr = [[self alloc] init];
154 [[NSMutableDictionary alloc] initWithCapacity:10000];
156 [[NSMutableDictionary alloc] initWithCapacity:10000];
158 [[NSMutableDictionary alloc] initWithCapacity:10000];
160 [[NSMutableDictionary alloc] initWithCapacity:10000];
161 self->shareStoreCache =
162 [[NSMutableDictionary alloc] initWithCapacity:10000];
163 self->shareEMailCache =
164 [[NSMutableDictionary alloc] initWithCapacity:10000];
165 self->changeInternetAccessCache =
166 [[NSMutableDictionary alloc] initWithCapacity:10000];
167 self->internetAutoresponderFlagCache =
168 [[NSMutableDictionary alloc] initWithCapacity:10000];
169 self->intranetAutoresponderFlagCache =
170 [[NSMutableDictionary alloc] initWithCapacity:10000];
172 self->gcTimer = [[NSTimer scheduledTimerWithTimeInterval:
174 target:self selector:@selector(_garbageCollect:)
175 userInfo:nil repeats:YES] retain];
181 if (self->gcTimer) [self->gcTimer invalidate];
182 [self->serverCache release];
183 [self->cnCache release];
184 [self->uidCache release];
185 [self->emailCache release];
186 [self->shareStoreCache release];
187 [self->shareEMailCache release];
188 [self->changeInternetAccessCache release];
189 [self->internetAutoresponderFlagCache release];
190 [self->intranetAutoresponderFlagCache release];
191 [self->gcTimer release];
198 [self->cnCache removeAllObjects];
199 [self->serverCache removeAllObjects];
200 [self->uidCache removeAllObjects];
201 [self->emailCache removeAllObjects];
202 [self->shareStoreCache removeAllObjects];
203 [self->shareEMailCache removeAllObjects];
205 [self->changeInternetAccessCache removeAllObjects];
206 [self->internetAutoresponderFlagCache removeAllObjects];
207 [self->intranetAutoresponderFlagCache removeAllObjects];
210 - (void)_garbageCollect:(NSTimer *)_timer {
211 [self debugWithFormat:@"flushing caches."];
217 - (NGLdapConnection *)ldapConnection {
218 static NGLdapConnection *ldapConnection = nil;
219 if(!ldapConnection) {
220 ldapConnection = [[NGLdapConnection alloc] initWithHostName:ldapHost];
222 [ldapConnection setUseCache:YES];
225 return ldapConnection;
229 /* private cache helpers */
230 // TODO: this is really unnecessary, no?
232 - (void)_cacheCN:(NSString *)_cn forUID:(NSString *)_uid {
233 if (_cn == nil) return;
234 [self->cnCache setObject:_cn forKey:_uid];
236 - (NSString *)_cachedCNForUID:(NSString *)_uid {
237 return [self->cnCache objectForKey:_uid];
240 - (void)_cacheServer:(NSString *)_server forUID:(NSString *)_uid {
241 if (_server == nil) return;
242 [self->serverCache setObject:_server forKey:_uid];
244 - (NSString *)_cachedServerForUID:(NSString *)_uid {
245 return [self->serverCache objectForKey:_uid];
248 - (void)_cacheEmail:(NSString *)_email forUID:(NSString *)_uid {
249 if (_email == nil) return;
250 [self->emailCache setObject:_email forKey:_uid];
252 - (NSString *)_cachedEmailForUID:(NSString *)_uid {
253 return [self->emailCache objectForKey:_uid];
256 - (void)_cacheUID:(NSString *)_uid forEmail:(NSString *)_email {
257 if (_uid == nil) return;
258 [self->uidCache setObject:_uid forKey:_email];
260 - (NSString *)_cachedUIDForEmail:(NSString *)_email {
261 return [self->uidCache objectForKey:_email];
265 /* uid <-> email mapping */
268 UPDATE: the email excerpt below has been marked by Maxime as being
269 wrong. This algorithm can not be expected to work, thus
270 the mapping has been replaced with an LDAP query.
273 The uid field is in bijection this the email adress :
274 this field can be construct from the email. Email are uniques.
276 So, we can use email adresse from identifier.
277 The field is made like this :
278 _ if the email is equipement.gouv.fr then the login
279 is the part before the @
280 for example : fisrtName.lastName
281 _ if the email is not equipement.gouv.fr then the login
282 is the full email adress where @ is change to . (dot)
283 for example : fisrtName.lastName.subDomain.domain.tld
286 NOTE: mapping email -> uid is easy, but can also generate uid's not known
287 to the system (i.e. for private addressbook entries, obvious).
288 The reverse mapping can work _only_ if "firstName.lastname." is
289 guaranteed, because the second dot would be mapped to '@'. This
290 is probably error prone.
291 Only LDAP fetches would guarantee correctness in both cases.
294 - (NSString *)primaryGetAgenorUIDForEmail:(NSString *)_email {
295 static NSArray *uidAttrs = nil;
296 NGLdapConnection *conn;
298 NSEnumerator *resultEnum;
300 NGLdapAttribute *uidAttr;
304 uidAttrs = [[NSArray alloc] initWithObjects:@"uid", nil];
306 q = [EOQualifier qualifierWithQualifierFormat:@"mail = %@", _email];
308 conn = [self ldapConnection];
309 resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
311 attributes:uidAttrs];
312 entry = [resultEnum nextObject];
315 [self logWithFormat:@"%s Didn't find LDAP entry for email '%@'!",
321 uidAttr = [entry attributeWithName:@"uid"];
323 return nil; /* can happen, not unlikely */
324 uid = [uidAttr stringValueAtIndex:0];
328 - (NSString *) getUIDForEmail: (NSString *)_email
335 if ([_email length] > 0)
337 uid = [self _cachedUIDForEmail:_email];
341 uid = [self primaryGetAgenorUIDForEmail:_email];
345 r = [_email rangeOfString:@"@"];
349 domain = [_email substringFromIndex:NSMaxRange(r)];
350 if (![domain isEqualToString:defaultMailDomain])
353 uid = [_email substringToIndex:r.location];
356 [self _cacheUID:uid forEmail:_email];
363 #warning big ugly hack. LDAP lookup should be fixed
364 - (NSString *) getUIDForICalPerson: (iCalPerson *) _person
366 NSString *domainString, *email, *uid;
368 domainString = [NSString stringWithFormat: @"@%@", defaultMailDomain];
369 email = [_person rfc822Email];
370 if ([email hasSuffix: domainString])
373 uid = [self getUIDForEmail: email];
378 /* may insert NSNulls into returned array */
379 - (NSArray *)getUIDsForICalPersons:(NSArray *)_persons
380 applyStrictMapping:(BOOL)_mapStrictly
385 count = [_persons count];
386 ma = [[[NSMutableArray alloc] initWithCapacity:count] autorelease];
387 for (i = 0; i < count; i++) {
391 p = [_persons objectAtIndex:i];
392 uid = [self getUIDForICalPerson:p];
395 else if (uid == nil && _mapStrictly)
396 [ma addObject:sharedNull];
401 - (NSString *)primaryGetEmailForAgenorUID:(NSString *)_uid {
402 NGLdapConnection *conn;
404 NSEnumerator *resultEnum;
406 NGLdapAttribute *emailAttr;
410 q = [EOQualifier qualifierWithQualifierFormat:qualifierFormat, _uid];
412 conn = [self ldapConnection];
413 resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
415 attributes:fromEMailAttrs];
416 entry = [resultEnum nextObject];
419 [self logWithFormat:@"%s Didn't find LDAP entry for uid '%@'!",
425 emailAttr = [entry attributeWithName:mailEmissionAttrName];
426 if (emailAttr == nil)
427 return nil; /* shit happens */
430 count = [emailAttr count];
431 #if 0 // TODO: explain why this is commented out!
435 /* in case there are multiple email addresses, select the first
436 which doesn't have '@equipement.gouv.fr' in it */
437 for (i = 0; i < count; i++) {
440 candidate = [emailAttr stringValueAtIndex:i];
441 if (![candidate hasSuffix:defaultMailDomain]) {
442 // TODO: also check for '@'
449 if (email == nil && count > 0)
450 email = [emailAttr stringValueAtIndex:0];
455 - (NSString *)getEmailForUID:(NSString *)_uid
462 if ([_uid length] > 0)
464 email = [self _cachedEmailForUID: _uid];
468 email = [self primaryGetEmailForAgenorUID:_uid];
472 r = [_uid rangeOfString:@"@"];
473 email = ((r.length > 0)
475 : [[_uid stringByAppendingString:@"@"]
476 stringByAppendingString: defaultMailDomain]);
480 [self _cacheEmail: email forUID: _uid];
490 - (NSString *)primaryGetCNForAgenorUID:(NSString *)_uid {
491 static NSArray *cnAttrs = nil;
492 NGLdapConnection *conn;
494 NSEnumerator *resultEnum;
496 NGLdapAttribute *cnAttr;
500 cnAttrs = [[NSArray alloc] initWithObjects:@"cn", nil];
502 q = [EOQualifier qualifierWithQualifierFormat:qualifierFormat, _uid];
504 conn = [self ldapConnection];
505 resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
508 entry = [resultEnum nextObject];
511 [self logWithFormat:@"%s Didn't find LDAP entry for uid '%@'!",
517 cnAttr = [entry attributeWithName:@"cn"];
518 if(cnAttr == nil && debugOn) {
519 [self logWithFormat:@"%s LDAP entry for uid '%@' has no common name?",
522 return nil; /* nothing we can do about it */
524 cn = [cnAttr stringValueAtIndex:0];
528 - (NSString *)getCNForUID:(NSString *)_uid {
531 if ((cn = [self _cachedCNForUID:_uid]) != nil)
535 cn = [self primaryGetCNForAgenorUID:_uid];
545 // TODO: algorithm might be inappropriate, depends on the actual UID
546 r = [s rangeOfString:@"."];
550 cn = [s substringToIndex:r.location];
553 [self _cacheCN:cn forUID:_uid];
560 - (NSString *)getIMAPAccountStringForUID:(NSString *)_uid {
563 server = [self getServerForUID:_uid];
566 return [NSString stringWithFormat:@"%@@%@", _uid, server];
569 - (NSArray *)mailServerDiscoveryAttributes {
570 static NSArray *attrs = nil;
573 attrs = [[NSArray alloc] initWithObjects:
574 @"uid", /* required for shares */
576 @"mineqMelServeurPrincipal",
578 mailEmissionAttrName,
584 - (NGLdapEntry *)_fetchEntryForAgenorUID:(NSString *)_uid {
585 // TODO: badly named, this fetches the mail server discovery attributes
586 /* called by -primaryGetServerForAgenorUID: */
587 NGLdapConnection *conn;
589 NSEnumerator *resultEnum;
592 q = [EOQualifier qualifierWithQualifierFormat:qualifierFormat, _uid];
594 conn = [self ldapConnection];
595 resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
597 attributes:[self mailServerDiscoveryAttributes]];
598 /* we just expect one entry, thus drop the rest */
599 entry = [resultEnum nextObject];
602 NSLog(@"%s Didn't find LDAP entry for uid '%@'!",
611 - (NSArray *)_serverCandidatesForMineqMelRoutage:(NGLdapAttribute *)attr {
614 "Baluh.Hommes.Tests-Montee-En-Charge-Ogo%equipement.gouv.fr@\
615 amelie-01.ac.melanie2.i2"
617 NSMutableArray *serverCandidates;
620 count = [attr count];
621 serverCandidates = [NSMutableArray arrayWithCapacity:count];
622 for (i = 0; i < count; i++) {
627 NSRange serverNameRange;
628 NSString *serverName;
630 route = [attr stringValueAtIndex:i];
632 /* check for melanie suffix and ignore other entries */
634 r = [route rangeOfString:@".melanie2.i2" options:NSBackwardsSearch];
637 [self logWithFormat:@"found no melanie in route: '%@'", route];
642 /* check for @ inside the string, searching backwards (ignoring suffix) */
644 // be clever: TODO: in what way is this clever?
645 length = [route length];
646 r = NSMakeRange(0, length - r.length); /* cut of suffix (.melanie2.i2) */
647 r = [route rangeOfString:@"@" options:NSBackwardsSearch range:r];
650 [self logWithFormat:@"found no @ in route: '%@'", route];
655 /* check for percent sign */
657 start = NSMaxRange(r); /* start behind the @ */
659 /* this range covers everything after @: 'amelie-01.ac.melanie2.i2' */
660 serverNameRange = NSMakeRange(start, length - start);
662 /* and this range covers everything to the @ */
663 r = NSMakeRange(0, start - 1);
664 r = [route rangeOfString:@"%" options:NSBackwardsSearch range:r];
667 [self logWithFormat:@"found no %% in route: '%@' / '%@'",
668 route, [route substringWithRange:NSMakeRange(0, length - start)]];
673 serverName = [route substringWithRange:serverNameRange];
674 [serverCandidates addObject:serverName];
676 return serverCandidates;
679 - (NSString *)serverFromEntry:(NGLdapEntry *)_entry {
681 NGLdapAttribute *attr;
685 attr = [_entry attributeWithName:@"mineqMelRoutage"];
687 NSArray *serverCandidates;
689 serverCandidates = [self _serverCandidatesForMineqMelRoutage:attr];
690 if ([serverCandidates count] > 0)
691 server = [serverCandidates objectAtIndex:0];
693 if ([serverCandidates count] > 1) {
695 @"WARNING: more than one value for 'mineqMelRoutage': %@",
700 [self debugWithFormat:
701 @"%s LDAP entry '%@' has no mineqMelRoutage entry?",
702 __PRETTY_FUNCTION__, [_entry dn]];
707 attr = [_entry attributeWithName:@"mineqMelServeurPrincipal"];
708 if ([attr count] > 0)
709 server = [attr stringValueAtIndex:0];
715 - (NSString *)primaryGetServerForAgenorUID:(NSString *)_uid {
717 First of all : for a particular user IMAP and SMTP are served on the same
720 The name of the machine is determined by applying a regex on every values of
721 the mineqMelRoutage LDAP attribute.
722 The regex is : .*%.*@(.*\.melanie2\.i2$)
723 It extracts the substring that follows '@', ends with 'melanie2', on
724 adresses which have a '%' before the '@'
726 Example: helge.hesse%opengroupware.org@servername1.melanie2.i2
727 -> servername1.melanie2.i2
729 If only one server name is found by applying the regex on every value of the
730 attribute, then this name is the IMAP/SMTP server for that user.
731 Note that this is the case when we got a unique (well formed) value for the
733 If the regex finds more than one servername when applied to the differents
734 values, then the IMAP/SMTP server name is to be found in the
735 mineqMelServeurPrincipal attribute of the user.
740 if ((entry = [self _fetchEntryForAgenorUID:_uid]) == nil)
743 if ((server = [self serverFromEntry:entry]) != nil)
746 [self debugWithFormat:
747 @"%s no chance of getting at server info for user '%@', "
748 @"tried everything. Sorry.",
749 __PRETTY_FUNCTION__, _uid];
753 - (NSString *)getServerForUID:(NSString *)_uid {
756 if (_uid == nil || [_uid length] == 0)
759 if ((server = [self _cachedServerForUID:_uid]) != nil)
763 server = [self primaryGetServerForAgenorUID:_uid];
764 else if (fallbackIMAP4Server != nil)
765 server = fallbackIMAP4Server;
767 [self logWithFormat:@"ERROR: could not get server for uid '%@', "
768 @"neither LDAP (SOGoUserManagerUsesLDAP) nor "
769 @"a fallback (SOGoFallbackIMAP4Server) is configured.",
774 [self _cacheServer:server forUID:_uid];
778 /* shared mailboxes */
780 - (NSArray *)getSharedMailboxAccountStringsForUID:(NSString *)_uid {
783 k = [[self getSharedMailboxesAndEMailsForUID:_uid] allKeys];
785 /* ensure that ordering is always the same */
786 return [k sortedArrayUsingSelector:@selector(compare:)];
789 - (NSString *)emissionEMailFromEntry:(NGLdapEntry *)_entry {
792 emissionAttr = [_entry attributeWithName:mailEmissionAttrName];
793 if ([emissionAttr count] == 0) {
794 [self logWithFormat:@"WARNING: share has no %@ attr: %@",
795 mailEmissionAttrName, [_entry dn]];
799 if ([emissionAttr count] > 1) {
801 @"WARNING: share has more than one value in %@ attr: %@",
802 mailEmissionAttrName, [_entry dn]];
806 return [emissionAttr stringValueAtIndex:0];
809 - (NSArray *)getSharedMailboxEMailsForUID:(NSString *)_uid {
810 NSMutableArray *shares = nil;
811 NGLdapConnection *conn;
813 NSString *gPattern, *cPattern;
814 NSEnumerator *resultEnum;
817 if ([_uid length] == 0)
822 @"Note: LDAP access is disabled, returning no shared froms."];
827 if ((shares = [self->shareEMailCache objectForKey:_uid]) != nil)
830 /* G and C mean "emission access" */
831 gPattern = [_uid stringByAppendingString:@":G"];
832 cPattern = [_uid stringByAppendingString:@":C"];
834 q = [EOQualifier qualifierWithQualifierFormat:
835 @"((mineqMelPartages = %@) OR (mineqMelPartages = %@)) "
836 @"AND (objectclass = %@)",
837 gPattern, cPattern, shareLDAPClass];
839 conn = [self ldapConnection];
841 resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
843 attributes:fromEMailAttrs];
845 while ((entry = [resultEnum nextObject]) != nil) {
846 NSString *emissionAttr;
848 if ((emissionAttr = [self emissionEMailFromEntry:entry]) == nil)
851 if (shares == nil) shares = [NSMutableArray arrayWithCapacity:4];
852 [shares addObject:emissionAttr];
855 /* ensure that ordering is always the same */
856 [shares sortUsingSelector:@selector(compare:)];
859 shares = (shares == nil) ? [NSArray array] : [[shares copy] autorelease];
860 [self->shareEMailCache setObject:shares forKey:_uid];
866 - (BOOL)hasUser:(NSString *)_uid partageAccess:(char *)_rightset
867 inEntry:(NGLdapEntry *)_entry
869 NGLdapAttribute *attr;
872 attr = [_entry attributeWithName:@"mineqMelPartages"];
873 if ((count = [attr count]) == 0) {
874 [self logWithFormat:@"WARNING: share has no 'mineqMelPartages' attr: %@",
879 for (i = 0; i < count; i++) {
885 p = [attr stringValueAtIndex:i];
886 r = [p rangeOfString:@":"];
888 [self errorWithFormat:@"Invalid mineqMelPartages value: '%@'", p];
892 /* check whether prefix matches, eg: "helian.h:G" */
893 if (r.location != [_uid length]) /* check length */
895 if (![p hasPrefix:_uid])
898 c = [p characterAtIndex:(r.location + r.length)];
900 /* check whether permissions match */
901 for (j = 0; _rightset[j] != '\0'; j++) {
902 if (c == _rightset[j])
909 - (NSDictionary *)getSharedMailboxesAndEMailsForUID:(NSString *)_uid {
912 "(&(mineqMelPartages=guizmo.g:*)(objectclass=mineqMelBoite))"
913 "guizmo.g" is the uid of the user
916 guizmo.g.-.baluh.hommes.tests-montee-en-charge-ogo
917 (uid + ".-." + share-uid)
919 Note: shared mailboxes can be on different hosts!
921 This returns a dictionary where the keys are the IMAP4 connect strings
922 while the values are the emitter addresses for the box or NSNull if the
923 uid is not allowed to emit for this box.
925 NSMutableDictionary *shares = nil;
926 NGLdapConnection *conn;
928 NSString *sharePattern;
929 NSEnumerator *resultEnum;
932 if ([_uid length] == 0)
937 @"Note: LDAP access is disabled, returning no shared accounts."];
942 if ((shares = [self->shareStoreCache objectForKey:_uid]) != nil)
945 sharePattern = [_uid stringByAppendingString:@":*"];
947 q = [EOQualifier qualifierWithQualifierFormat:
948 @"(mineqMelPartages = %@) AND (objectclass = %@)",
949 sharePattern, shareLDAPClass];
951 conn = [self ldapConnection];
953 resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
955 attributes:[self mailServerDiscoveryAttributes]];
957 while ((entry = [resultEnum nextObject]) != nil) {
958 NSString *server, *shareLogin;
959 id shareUid, emitterAddress;
961 /* calculate server connect string */
963 if ([(server = [self serverFromEntry:entry]) length] == 0) {
964 [self errorWithFormat:@"found no mail server host for share: %@",
969 shareUid = [entry attributeWithName:@"uid"];
970 if ([shareUid count] < 1) {
971 [self errorWithFormat:@"found no 'uid' for share: %@", [entry dn]];
974 shareUid = [shareUid stringValueAtIndex:0];
976 shareLogin = [_uid stringByAppendingString:shareLoginSeparator];
977 shareLogin = [shareLogin stringByAppendingString:shareUid];
980 shares = [NSMutableDictionary dictionaryWithCapacity:4];
982 shareLogin = [shareLogin stringByAppendingString:@"@"];
983 shareLogin = [shareLogin stringByAppendingString:server];
985 /* calculate emitter address (check for proper access right) */
987 if ([self hasUser:_uid partageAccess:"GC" inEntry:entry])
988 emitterAddress = [self emissionEMailFromEntry:entry];
990 emitterAddress = [NSNull null];
994 [shares setObject: emitterAddress
999 shares = (shares == nil)
1000 ? [NSDictionary dictionary]
1001 : [[shares copy] autorelease];
1002 [self->shareStoreCache setObject:shares forKey:_uid];
1008 - (NSURL *)getFreeBusyURLForUID:(NSString *)_uid {
1009 [self logWithFormat:@"TODO(%s): implement", __PRETTY_FUNCTION__];
1015 - (NSUserDefaults *) _getUserDefaultsForUID: (NSString *) uid
1016 fieldName: (NSString *) fieldName
1020 if (AgenorProfileURL)
1022 /* Note: do not cache, otherwise updates can be quite tricky */
1023 defaults = [[AgenorUserDefaults alloc] initWithTableURL: AgenorProfileURL
1024 uid: uid fieldName: fieldName];
1025 [defaults autorelease];
1029 [self warnWithFormat:
1030 @"no profile configured, cannot retrieve defaults for user: '%@'",
1032 return defaults = nil;
1038 - (NSUserDefaults *) getUserDefaultsForUID: (NSString *) uid
1040 return [self _getUserDefaultsForUID: uid fieldName: @"defaults"];
1043 - (NSUserDefaults *) getUserSettingsForUID: (NSString *) uid
1045 return [self _getUserDefaultsForUID: uid fieldName: @"settings"];
1048 /* internet access lock */
1050 - (BOOL)isUserAllowedToChangeSOGoInternetAccess:(NSString *)_uid {
1053 bv = [self->changeInternetAccessCache objectForKey:_uid];
1057 value = [self primaryIsUserAllowedToChangeSOGoInternetAccess:_uid];
1058 bv = [NSNumber numberWithBool:value];
1059 [self->changeInternetAccessCache setObject:bv forKey:_uid];
1061 return [bv boolValue];
1064 - (BOOL)primaryIsUserAllowedToChangeSOGoInternetAccess:(NSString *)_uid {
1065 static NSArray *attrs = nil;
1066 NGLdapConnection *conn;
1068 NSEnumerator *resultEnum;
1070 NGLdapAttribute *attr;
1074 attrs = [[NSArray alloc] initWithObjects:changeInternetAccessAttrName, nil];
1076 q = [EOQualifier qualifierWithQualifierFormat:qualifierFormat, _uid];
1078 conn = [self ldapConnection];
1079 resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
1082 entry = [resultEnum nextObject];
1085 [self logWithFormat:@"%s Didn't find LDAP entry for uid '%@'!",
1086 __PRETTY_FUNCTION__,
1091 attr = [entry attributeWithName:changeInternetAccessAttrName];
1092 if(attr == nil && debugOn) {
1093 [self logWithFormat:@"%s LDAP entry for uid '%@' "
1094 @"has no mineqOgoAccesInternet attribute?",
1095 __PRETTY_FUNCTION__,
1097 return NO; /* nothing we can do about it */
1099 value = [attr stringValueAtIndex:0];
1100 return [value boolValue];
1103 - (BOOL)isInternetAutoresponderEnabledForUser:(NSString *)_uid {
1106 bv = [self->internetAutoresponderFlagCache objectForKey:_uid];
1110 value = [self primaryIsInternetAutoresponderEnabledForUser:_uid];
1111 bv = [NSNumber numberWithBool:value];
1112 [self->internetAutoresponderFlagCache setObject:bv forKey:_uid];
1114 return [bv boolValue];
1117 - (BOOL)primaryIsInternetAutoresponderEnabledForUser:(NSString *)_uid {
1118 NGLdapAttribute *attr;
1120 attr = [self primaryGetMailAutoresponderAttribute:_uid];
1121 if (!attr) return NO;
1122 return [self isAutoresponderEnabledForAttribute:attr matchingPrefix:@"60~"];
1125 - (BOOL)isIntranetAutoresponderEnabledForUser:(NSString *)_uid {
1128 bv = [self->intranetAutoresponderFlagCache objectForKey:_uid];
1132 value = [self primaryIsIntranetAutoresponderEnabledForUser:_uid];
1133 bv = [NSNumber numberWithBool:value];
1134 [self->intranetAutoresponderFlagCache setObject:bv forKey:_uid];
1136 return [bv boolValue];
1139 - (BOOL)primaryIsIntranetAutoresponderEnabledForUser:(NSString *)_uid {
1140 NGLdapAttribute *attr;
1142 attr = [self primaryGetMailAutoresponderAttribute:_uid];
1143 if (!attr) return NO;
1144 return [self isAutoresponderEnabledForAttribute:attr matchingPrefix:@"50~"];
1147 - (BOOL)isAutoresponderEnabledForAttribute:(NGLdapAttribute *)_attr
1148 matchingPrefix:(NSString *)_prefix
1152 count = [_attr count];
1153 for (i = 0; i < count; i++) {
1156 value = [_attr stringValueAtIndex:i];
1157 if ([value hasPrefix:_prefix]) {
1158 if ([value rangeOfString:@"DFIN:0"].length > 0)
1166 - (NGLdapAttribute *)primaryGetMailAutoresponderAttribute:(NSString *)_uid {
1167 static NSArray *attrs = nil;
1168 NGLdapConnection *conn;
1170 NSEnumerator *resultEnum;
1172 NGLdapAttribute *attr;
1175 attrs = [[NSArray alloc] initWithObjects:mailAutoresponderAttrName, nil];
1177 q = [EOQualifier qualifierWithQualifierFormat:qualifierFormat, _uid];
1179 conn = [self ldapConnection];
1180 resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
1183 entry = [resultEnum nextObject];
1186 [self logWithFormat:@"%s Didn't find LDAP entry for uid '%@'!",
1187 __PRETTY_FUNCTION__,
1192 attr = [entry attributeWithName:mailAutoresponderAttrName];
1196 - (iCalPerson *) iCalPersonWithUid: (NSString *) uid
1200 person = [iCalPerson new];
1201 [person autorelease];
1202 [person setCn: [self getCNForUID: uid]];
1203 [person setEmail: [self getEmailForUID: uid]];
1210 - (BOOL)isDebuggingEnabled {
1214 @end /* AgenorUserManager */