static NSArray *fromEMailAttrs = nil;
+static unsigned PoolScanInterval = 5 * 60 /* every five minutes */;
+
+ (void)initialize {
static BOOL didInit = NO;
NSUserDefaults *ud;
NSLog(@"ERROR: could not parse AgenorProfileURL: '%@'", tmp);
else
NSLog(@"Note: using profile at: %@", [AgenorProfileURL absoluteString]);
+
+ PoolScanInterval = [[ud objectForKey:@"AgenorCacheCheckInterval"] intValue];
+ if (PoolScanInterval == 0)
+ PoolScanInterval = 60 * 60 /* every hour */;
+ NSLog(@"AgenorUserManager: flushing caches every %d minutes "
+ @"(AgenorCacheCheckInterval)",
+ PoolScanInterval / 60);
}
+ (id)sharedUserManager {
- (id)init {
self = [super init];
if(self) {
- self->serverCache = [[SOGoLRUCache alloc] initWithCacheSize:10000];
- self->cnCache = [[SOGoLRUCache alloc] initWithCacheSize:10000];
- self->uidCache = [[SOGoLRUCache alloc] initWithCacheSize:10000];
- self->emailCache = [[SOGoLRUCache alloc] initWithCacheSize:10000];
- self->shareStoreCache = [[SOGoLRUCache alloc] initWithCacheSize:10000];
- self->shareEMailCache = [[SOGoLRUCache alloc] initWithCacheSize:10000];
+ self->serverCache =
+ [[NSMutableDictionary alloc] initWithCapacity:10000];
+ self->cnCache =
+ [[NSMutableDictionary alloc] initWithCapacity:10000];
+ self->uidCache =
+ [[NSMutableDictionary alloc] initWithCapacity:10000];
+ self->emailCache =
+ [[NSMutableDictionary alloc] initWithCapacity:10000];
+ self->shareStoreCache =
+ [[NSMutableDictionary alloc] initWithCapacity:10000];
+ self->shareEMailCache =
+ [[NSMutableDictionary alloc] initWithCapacity:10000];
self->changeInternetAccessCache =
- [[SOGoLRUCache alloc] initWithCacheSize:10000];
+ [[NSMutableDictionary alloc] initWithCapacity:10000];
self->internetAutoresponderFlagCache =
- [[SOGoLRUCache alloc] initWithCacheSize:10000];
+ [[NSMutableDictionary alloc] initWithCapacity:10000];
self->intranetAutoresponderFlagCache =
- [[SOGoLRUCache alloc] initWithCacheSize:10000];
+ [[NSMutableDictionary alloc] initWithCapacity:10000];
+
+ self->gcTimer = [[NSTimer scheduledTimerWithTimeInterval:
+ PoolScanInterval
+ target:self selector:@selector(_garbageCollect:)
+ userInfo:nil repeats:YES] retain];
}
return self;
}
- (void)dealloc {
+ if (self->gcTimer) [self->gcTimer invalidate];
[self->serverCache release];
[self->cnCache release];
[self->uidCache release];
[self->changeInternetAccessCache release];
[self->internetAutoresponderFlagCache release];
[self->intranetAutoresponderFlagCache release];
+ [self->gcTimer release];
[super dealloc];
}
+/* cache */
+
+- (void)flush {
+ [self->cnCache removeAllObjects];
+ [self->serverCache removeAllObjects];
+ [self->uidCache removeAllObjects];
+ [self->emailCache removeAllObjects];
+ [self->shareStoreCache removeAllObjects];
+ [self->shareEMailCache removeAllObjects];
+
+ [self->changeInternetAccessCache removeAllObjects];
+ [self->internetAutoresponderFlagCache removeAllObjects];
+ [self->intranetAutoresponderFlagCache removeAllObjects];
+}
+
+- (void)_garbageCollect:(NSTimer *)_timer {
+ [self debugWithFormat:@"flushing caches."];
+ [self flush];
+}
+
+/* LDAP */
+
- (NGLdapConnection *)ldapConnection {
static NGLdapConnection *ldapConnection = nil;
if(!ldapConnection) {
- (void)_cacheCN:(NSString *)_cn forUID:(NSString *)_uid {
if (_cn == nil) return;
- [self->cnCache addObject:_cn forKey:_uid];
+ [self->cnCache setObject:_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];
+ [self->serverCache setObject:_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];
+ [self->emailCache setObject:_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];
+ [self->uidCache setObject:_uid forKey:_email];
}
- (NSString *)_cachedUIDForEmail:(NSString *)_email {
return [self->uidCache objectForKey:_email];
for (i = 0; i < count; i++) {
iCalPerson *p;
id uid;
-
+
p = [_persons objectAtIndex:i];
uid = [self getUIDForICalPerson:p];
- if (uid) {
+ if (uid != nil)
[ma addObject:uid];
- }
- else if (!uid && _mapStrictly) {
+ else if (uid == nil && _mapStrictly)
[ma addObject:sharedNull];
- }
}
return ma;
}
@"uid", /* required for shares */
@"mineqMelRoutage",
@"mineqMelServeurPrincipal",
+ @"mineqMelPartages",
+ mailEmissionAttrName,
nil];
}
return attrs;
/* shared mailboxes */
- (NSArray *)getSharedMailboxAccountStringsForUID:(NSString *)_uid {
+ NSArray *k;
+
+ k = [[self getSharedMailboxesAndEMailsForUID:_uid] allKeys];
+
+ /* ensure that ordering is always the same */
+ return [k sortedArrayUsingSelector:@selector(compare:)];
+}
+
+- (NSString *)emissionEMailFromEntry:(NGLdapEntry *)_entry {
+ id emissionAttr;
+
+ emissionAttr = [_entry attributeWithName:mailEmissionAttrName];
+ if ([emissionAttr count] == 0) {
+ [self logWithFormat:@"WARNING: share has no %@ attr: %@",
+ mailEmissionAttrName, [_entry dn]];
+ return nil;
+ }
+
+ if ([emissionAttr count] > 1) {
+ [self logWithFormat:
+ @"WARNING: share has more than one value in %@ attr: %@",
+ mailEmissionAttrName, [_entry dn]];
+ return nil;
+ }
+
+ return [emissionAttr stringValueAtIndex:0];
+}
+
+- (NSArray *)getSharedMailboxEMailsForUID:(NSString *)_uid {
+ NSMutableArray *shares = nil;
+ NGLdapConnection *conn;
+ EOQualifier *q;
+ NSString *gPattern, *cPattern;
+ NSEnumerator *resultEnum;
+ NGLdapEntry *entry;
+
+ if ([_uid length] == 0)
+ return nil;
+
+ if (!useLDAP) {
+ [self logWithFormat:
+ @"Note: LDAP access is disabled, returning no shared froms."];
+ return nil;
+ }
+
+ /* check cache */
+ if ((shares = [self->shareEMailCache objectForKey:_uid]) != nil)
+ return shares;
+
+ /* G and C mean "emission access" */
+ gPattern = [_uid stringByAppendingString:@":G"];
+ cPattern = [_uid stringByAppendingString:@":C"];
+
+ q = [EOQualifier qualifierWithQualifierFormat:
+ @"((mineqMelPartages = %@) OR (mineqMelPartages = %@)) "
+ @"AND (objectclass = %@)",
+ gPattern, cPattern, shareLDAPClass];
+
+ conn = [self ldapConnection];
+
+ resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
+ qualifier:q
+ attributes:fromEMailAttrs];
+
+ while ((entry = [resultEnum nextObject]) != nil) {
+ NSString *emissionAttr;
+
+ if ((emissionAttr = [self emissionEMailFromEntry:entry]) == nil)
+ continue;
+
+ if (shares == nil) shares = [NSMutableArray arrayWithCapacity:4];
+ [shares addObject:emissionAttr];
+ }
+
+ /* ensure that ordering is always the same */
+ [shares sortUsingSelector:@selector(compare:)];
+
+ /* cache */
+ shares = (shares == nil) ? [NSArray array] : [[shares copy] autorelease];
+ [self->shareEMailCache setObject:shares forKey:_uid];
+ return shares;
+}
+
+/* identities */
+
+- (BOOL)hasUser:(NSString *)_uid partageAccess:(char *)_rightset
+ inEntry:(NGLdapEntry *)_entry
+{
+ NGLdapAttribute *attr;
+ unsigned i, count;
+
+ attr = [_entry attributeWithName:@"mineqMelPartages"];
+ if ((count = [attr count]) == 0) {
+ [self logWithFormat:@"WARNING: share has no 'mineqMelPartages' attr: %@",
+ [_entry dn]];
+ return NO;
+ }
+
+ for (i = 0; i < count; i++) {
+ NSString *p;
+ NSRange r;
+ unichar c;
+ register unsigned j;
+
+ p = [attr stringValueAtIndex:i];
+ r = [p rangeOfString:@":"];
+ if (r.length == 0) {
+ [self errorWithFormat:@"Invalid mineqMelPartages value: '%@'", p];
+ continue;
+ }
+
+ /* check whether prefix matches, eg: "helian.h:G" */
+ if (r.location != [_uid length]) /* check length */
+ continue;
+ if (![p hasPrefix:_uid])
+ continue;
+
+ c = [p characterAtIndex:(r.location + r.length)];
+
+ /* check whether permissions match */
+ for (j = 0; _rightset[j] != '\0'; j++) {
+ if (c == _rightset[j])
+ return YES;
+ }
+ }
+ return NO;
+}
+
+- (NSDictionary *)getSharedMailboxesAndEMailsForUID:(NSString *)_uid {
/*
Sample:
"(&(mineqMelPartages=guizmo.g:*)(objectclass=mineqMelBoite))"
(uid + ".-." + share-uid)
Note: shared mailboxes can be on different hosts!
+
+ This returns a dictionary where the keys are the IMAP4 connect strings
+ while the values are the emitter addresses for the box or NSNull if the
+ uid is not allowed to emit for this box.
*/
- NSMutableArray *shares = nil;
+ NSMutableDictionary *shares = nil;
NGLdapConnection *conn;
EOQualifier *q;
NSString *sharePattern;
attributes:[self mailServerDiscoveryAttributes]];
while ((entry = [resultEnum nextObject]) != nil) {
- NSString *server, *shareLogin;
+ NSString *server, *shareLogin, *emitterAddress;
id shareUid;
+
+ /* calculate server connect string */
if ([(server = [self serverFromEntry:entry]) length] == 0) {
[self errorWithFormat:@"found no mail server host for share: %@",
shareLogin = [shareLogin stringByAppendingString:shareUid];
if (shares == nil)
- shares = [NSMutableArray arrayWithCapacity:4];
+ shares = [NSMutableDictionary dictionaryWithCapacity:4];
shareLogin = [shareLogin stringByAppendingString:@"@"];
shareLogin = [shareLogin stringByAppendingString:server];
- [shares addObject:shareLogin];
- }
-
- /* ensure that ordering is always the same */
- [shares sortUsingSelector:@selector(compare:)];
-
- /* cache */
- shares = (shares == nil) ? [NSArray array] : [[shares copy] autorelease];
- [self->shareStoreCache addObject:shares forKey:_uid];
- return shares;
-}
-
-- (NSArray *)getSharedMailboxEMailsForUID:(NSString *)_uid {
- NSMutableArray *shares = nil;
- NGLdapConnection *conn;
- EOQualifier *q;
- NSString *gPattern, *cPattern;
- NSEnumerator *resultEnum;
- NGLdapEntry *entry;
-
- if ([_uid length] == 0)
- return nil;
-
- if (!useLDAP) {
- [self logWithFormat:
- @"Note: LDAP access is disabled, returning no shared froms."];
- return nil;
- }
-
- /* check cache */
- if ((shares = [self->shareEMailCache objectForKey:_uid]) != nil)
- return shares;
-
- /* G and C mean "emission access" */
- gPattern = [_uid stringByAppendingString:@":G"];
- cPattern = [_uid stringByAppendingString:@":C"];
-
- q = [EOQualifier qualifierWithQualifierFormat:
- @"((mineqMelPartages = %@) OR (mineqMelPartages = %@)) "
- @"AND (objectclass = %@)",
- gPattern, cPattern, shareLDAPClass];
-
- conn = [self ldapConnection];
-
- resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN
- qualifier:q
- attributes:fromEMailAttrs];
-
- while ((entry = [resultEnum nextObject]) != nil) {
- id emissionAttr;
- emissionAttr = [entry attributeWithName:mailEmissionAttrName];
- if ([emissionAttr count] == 0) {
- [self logWithFormat:@"WARNING: share has no %@ attr: %@",
- mailEmissionAttrName, [entry dn]];
- continue;
- }
+ /* calculate emitter address (check for proper access right) */
- if ([emissionAttr count] > 1) {
- [self logWithFormat:
- @"WARNING: share has more than one value in %@ attr: %@",
- mailEmissionAttrName, [entry dn]];
- continue;
- }
+ emitterAddress = [self hasUser:_uid partageAccess:"GC" inEntry:entry]
+ ? [self emissionEMailFromEntry:entry]
+ : nil;
- emissionAttr = [emissionAttr stringValueAtIndex:0];
- if (shares == nil) shares = [NSMutableArray arrayWithCapacity:4];
- [shares addObject:emissionAttr];
+ /* set value */
+
+ [shares setObject:(emitterAddress ? emitterAddress : (id)[NSNull null])
+ forKey:shareLogin];
}
- /* ensure that ordering is always the same */
- [shares sortUsingSelector:@selector(compare:)];
-
/* cache */
- shares = (shares == nil) ? [NSArray array] : [[shares copy] autorelease];
- [self->shareEMailCache addObject:shares forKey:_uid];
+ shares = (shares == nil)
+ ? [NSDictionary dictionary]
+ : [[shares copy] autorelease];
+ [self->shareStoreCache setObject:shares forKey:_uid];
return shares;
}
value = [self primaryIsUserAllowedToChangeSOGoInternetAccess:_uid];
bv = [NSNumber numberWithBool:value];
- [self->changeInternetAccessCache addObject:bv forKey:_uid];
+ [self->changeInternetAccessCache setObject:bv forKey:_uid];
}
return [bv boolValue];
}
value = [self primaryIsInternetAutoresponderEnabledForUser:_uid];
bv = [NSNumber numberWithBool:value];
- [self->internetAutoresponderFlagCache addObject:bv forKey:_uid];
+ [self->internetAutoresponderFlagCache setObject:bv forKey:_uid];
}
return [bv boolValue];
}
value = [self primaryIsIntranetAutoresponderEnabledForUser:_uid];
bv = [NSNumber numberWithBool:value];
- [self->intranetAutoresponderFlagCache addObject:bv forKey:_uid];
+ [self->intranetAutoresponderFlagCache setObject:bv forKey:_uid];
}
return [bv boolValue];
}