From c2f7d106dc7d5cefe6b918c10a5f9bb1972bf04f Mon Sep 17 00:00:00 2001 From: helge Date: Thu, 7 Jul 2005 11:15:31 +0000 Subject: [PATCH] added shares discovery git-svn-id: http://svn.opengroupware.org/SOGo/trunk@682 d1b88da0-ebda-0310-925b-ed51d893ca5b --- SOGo/SoObjects/SOGo/AgenorUserManager.h | 13 +- SOGo/SoObjects/SOGo/AgenorUserManager.m | 329 ++++++++++++++++------- SOGo/SoObjects/SOGo/ChangeLog | 10 + SOGo/SoObjects/SOGo/GNUmakefile | 7 +- SOGo/SoObjects/SOGo/GNUmakefile.preamble | 4 +- SOGo/SoObjects/SOGo/Version | 2 +- SOGo/SoObjects/SOGo/agenor_email2uid.m | 1 - SOGo/SoObjects/SOGo/agenor_shares4uid.m | 79 ++++++ 8 files changed, 336 insertions(+), 109 deletions(-) create mode 100644 SOGo/SoObjects/SOGo/agenor_shares4uid.m diff --git a/SOGo/SoObjects/SOGo/AgenorUserManager.h b/SOGo/SoObjects/SOGo/AgenorUserManager.h index 5f591082..4aef5cd6 100644 --- a/SOGo/SoObjects/SOGo/AgenorUserManager.h +++ b/SOGo/SoObjects/SOGo/AgenorUserManager.h @@ -22,8 +22,15 @@ #ifndef __AgenorUserManager_H_ #define __AgenorUserManager_H_ -#import +#import +/* + AgenorUserManager + + TODO: document +*/ + +@class NSString, NSArray, NSURL; @class SOGoLRUCache; @interface AgenorUserManager : NSObject @@ -41,11 +48,15 @@ /* i.e. BUTTO Hercule, CETE Lyon/DI/ET/TEST */ - (NSString *)getCNForUID:(NSString *)_uid; + /* i.e. hercule.butto@amelie-ida01.melanie2.i2 */ - (NSString *)getIMAPAccountStringForUID:(NSString *)_uid; + /* i.e. amelie-ida01.melanie2.i2 */ - (NSString *)getServerForUID:(NSString *)_uid; +- (NSArray *)getSharedMailboxAccountStringsForUID:(NSString *)_uid; + - (NSURL *)getFreeBusyURLForUID:(NSString *)_uid; @end diff --git a/SOGo/SoObjects/SOGo/AgenorUserManager.m b/SOGo/SoObjects/SOGo/AgenorUserManager.m index a71cf177..109d8c0b 100644 --- a/SOGo/SoObjects/SOGo/AgenorUserManager.m +++ b/SOGo/SoObjects/SOGo/AgenorUserManager.m @@ -38,6 +38,7 @@ @end +// TODO: add a timer to flush LRU caches every some hours @implementation AgenorUserManager @@ -178,38 +179,37 @@ static NSString *defaultMailDomain = @"equipement.gouv.fr"; */ - (NSString *)primaryGetAgenorUIDForEmail:(NSString *)_email { - static NSArray *uidAttrs = nil; - NGLdapConnection *conn; - EOQualifier *q; - NSEnumerator *resultEnum; - NGLdapEntry *entry; - NGLdapAttribute *uidAttr; - NSString *uid; - - if(!uidAttrs) { - uidAttrs = [[NSArray alloc] initWithObjects:@"uid", nil]; - } + static NSArray *uidAttrs = nil; + NGLdapConnection *conn; + EOQualifier *q; + NSEnumerator *resultEnum; + NGLdapEntry *entry; + NGLdapAttribute *uidAttr; + NSString *uid; + + if (uidAttrs == nil) + uidAttrs = [[NSArray alloc] initWithObjects:@"uid", nil]; - q = [EOQualifier qualifierWithQualifierFormat:@"mail = %@", _email]; + q = [EOQualifier qualifierWithQualifierFormat:@"mail = %@", _email]; - conn = [self ldapConnection]; - resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN - qualifier:q - attributes:uidAttrs]; - entry = [resultEnum nextObject]; - if (entry == nil) { - if(debugOn) { - [self logWithFormat:@"%s Didn't find LDAP entry for email '%@'!", - __PRETTY_FUNCTION__, - _email]; - } - return nil; + conn = [self ldapConnection]; + resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN + qualifier:q + attributes:uidAttrs]; + entry = [resultEnum nextObject]; + if (entry == nil) { + if(debugOn) { + [self logWithFormat:@"%s Didn't find LDAP entry for email '%@'!", + __PRETTY_FUNCTION__, + _email]; } - uidAttr = [entry attributeWithName:@"uid"]; - if (!uidAttr) - return nil; /* can happen, not unlikely */ - uid = [uidAttr stringValueAtIndex:0]; - return uid; + return nil; + } + uidAttr = [entry attributeWithName:@"uid"]; + if (!uidAttr) + return nil; /* can happen, not unlikely */ + uid = [uidAttr stringValueAtIndex:0]; + return uid; } - (NSString *)getUIDForEmail:(NSString *)_email { @@ -342,7 +342,7 @@ static NSString *defaultMailDomain = @"equipement.gouv.fr"; cnAttrs = [[NSArray alloc] initWithObjects:@"cn", nil]; q = [EOQualifier qualifierWithQualifierFormat:@"uid = %@", _uid]; - + conn = [self ldapConnection]; resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN qualifier:q @@ -408,26 +408,33 @@ static NSString *defaultMailDomain = @"equipement.gouv.fr"; return [NSString stringWithFormat:@"%@@%@", _uid, server]; } -- (NGLdapEntry *)_fetchEntryForAgenorUID:(NSString *)_uid { - static NSArray *attrs = nil; - NGLdapConnection *conn; - EOQualifier *q; - NSEnumerator *resultEnum; - NGLdapEntry *entry; - +- (NSArray *)mailServerDiscoveryAttributes { + static NSArray *attrs = nil; + if (attrs == nil) { attrs = [[NSArray alloc] initWithObjects: + @"uid", /* required for shares */ @"mineqMelRoutage", @"mineqMelServeurPrincipal", nil]; } + return attrs; +} + +- (NGLdapEntry *)_fetchEntryForAgenorUID:(NSString *)_uid { + // TODO: badly named, this fetches the mail server discovery attributes + /* called by -primaryGetServerForAgenorUID: */ + NGLdapConnection *conn; + EOQualifier *q; + NSEnumerator *resultEnum; + NGLdapEntry *entry; q = [EOQualifier qualifierWithQualifierFormat:@"uid = %@", _uid]; - + conn = [self ldapConnection]; resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN qualifier:q - attributes:attrs]; + attributes:[self mailServerDiscoveryAttributes]]; /* we just expect one entry, thus drop the rest */ entry = [resultEnum nextObject]; if (entry == nil) { @@ -442,45 +449,109 @@ static NSString *defaultMailDomain = @"equipement.gouv.fr"; } - (NSArray *)_serverCandidatesForMineqMelRoutage:(NGLdapAttribute *)attr { + /* + eg: + "Baluh.Hommes.Tests-Montee-En-Charge-Ogo%equipement.gouv.fr@\ + amelie-01.ac.melanie2.i2" + */ NSMutableArray *serverCandidates; - unsigned i, count; - count = [attr count]; + count = [attr count]; serverCandidates = [NSMutableArray arrayWithCapacity:count]; - for(i = 0; i < count; i++) { - NSRange r; + for (i = 0; i < count; i++) { + NSRange r; NSString *route; - + unsigned length; + unsigned start; + NSRange serverNameRange; + NSString *serverName; + route = [attr stringValueAtIndex:i]; + + /* check for melanie suffix and ignore other entries */ + r = [route rangeOfString:@".melanie2.i2" options:NSBackwardsSearch]; - if(r.length > 0) { - unsigned length; - - /* be clever */ - length = [route length]; - r = NSMakeRange(0, length - r.length); - r = [route rangeOfString:@"@" options:NSBackwardsSearch range:r]; - if(r.length > 0) { - unsigned start; - NSRange serverNameRange; - - start = NSMaxRange(r); - serverNameRange = NSMakeRange(start, length - start); - r = NSMakeRange(0, length - start); - r = [route rangeOfString:@"%" options:NSBackwardsSearch range:r]; - if(r.length > 0) { - NSString *serverName; - - serverName = [route substringWithRange:serverNameRange]; - [serverCandidates addObject:serverName]; - } - } + if (r.length == 0) { +#if 0 + [self logWithFormat:@"found no melanie in route: '%@'", route]; +#endif + continue; } + + /* check for @ inside the string, searching backwards (ignoring suffix) */ + + // be clever: TODO: in what way is this clever? + length = [route length]; + r = NSMakeRange(0, length - r.length); /* cut of suffix (.melanie2.i2) */ + r = [route rangeOfString:@"@" options:NSBackwardsSearch range:r]; + if (r.length == 0) { +#if 0 + [self logWithFormat:@"found no @ in route: '%@'", route]; +#endif + continue; + } + + /* check for percent sign */ + + start = NSMaxRange(r); /* start behind the @ */ + + /* this range covers everything after @: 'amelie-01.ac.melanie2.i2' */ + serverNameRange = NSMakeRange(start, length - start); + + /* and this range covers everything to the @ */ + r = NSMakeRange(0, start - 1); + r = [route rangeOfString:@"%" options:NSBackwardsSearch range:r]; + if (r.length == 0) { +#if 0 + [self logWithFormat:@"found no %% in route: '%@' / '%@'", + route, [route substringWithRange:NSMakeRange(0, length - start)]]; +#endif + continue; + } + + serverName = [route substringWithRange:serverNameRange]; + [serverCandidates addObject:serverName]; } return serverCandidates; } +- (NSString *)serverFromEntry:(NGLdapEntry *)_entry { + NSString *server; + NGLdapAttribute *attr; + + server = nil; + + attr = [_entry attributeWithName:@"mineqMelRoutage"]; + if (attr != nil) { + NSArray *serverCandidates; + + serverCandidates = [self _serverCandidatesForMineqMelRoutage:attr]; + if ([serverCandidates count] > 0) + server = [serverCandidates objectAtIndex:0]; + + if ([serverCandidates count] > 1) { + [self logWithFormat: + @"WARNING: more than one value for 'mineqMelRoutage': %@", + serverCandidates]; + } + } + else { + [self debugWithFormat: + @"%s LDAP entry '%@' has no mineqMelRoutage entry?", + __PRETTY_FUNCTION__, [_entry dn]]; + } + + /* last resort */ + if (server == nil) { + attr = [_entry attributeWithName:@"mineqMelServeurPrincipal"]; + if ([attr count] > 0) + server = [attr stringValueAtIndex:0]; + } + + return server; +} + - (NSString *)primaryGetServerForAgenorUID:(NSString *)_uid { /* First of all : for a particular user IMAP and SMTP are served on the same @@ -502,46 +573,21 @@ static NSString *defaultMailDomain = @"equipement.gouv.fr"; 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; - + */ + NSString *server; + NGLdapEntry *entry; + 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]; - } + if ((server = [self serverFromEntry:entry]) != nil) + return server; - /* last resort */ - if (server == nil) { - attr = [entry attributeWithName:@"mineqMelServeurPrincipal"]; - if ([attr count] > 0) - server = [attr stringValueAtIndex:0]; - } - - if (server == nil) { - [self debugWithFormat: - @"%s no chance of getting at server info for user '%@', " - @"tried everything. Sorry.", - __PRETTY_FUNCTION__, - _uid]; - return nil; - } - return server; + [self debugWithFormat: + @"%s no chance of getting at server info for user '%@', " + @"tried everything. Sorry.", + __PRETTY_FUNCTION__, _uid]; + return nil; } - (NSString *)getServerForUID:(NSString *)_uid { @@ -555,7 +601,7 @@ static NSString *defaultMailDomain = @"equipement.gouv.fr"; if (useLDAP) server = [self primaryGetServerForAgenorUID:_uid]; - else if (fallbackIMAP4Server) + else if (fallbackIMAP4Server != nil) server = fallbackIMAP4Server; else { [self logWithFormat:@"ERROR: could not get server for uid '%@', " @@ -569,7 +615,84 @@ static NSString *defaultMailDomain = @"equipement.gouv.fr"; return server; } +/* shared mailboxes */ + +- (NSArray *)getSharedMailboxAccountStringsForUID:(NSString *)_uid { + /* + Sample: + "(&(mineqMelPartages=guizmo.g:*)(objectclass=mineqMelBoite))" + "guizmo.g" is the uid of the user + + Login: + guizmo.g.-.baluh.hommes.tests-montee-en-charge-ogo + (uid + ".-." + share-uid) + + Note: shared mailboxes can be on different hosts! + */ + static NSString *shareLDAPClass = @"mineqMelBoite"; + static NSString *shareLoginSeparator = @".-."; + NSMutableArray *shares = nil; + NGLdapConnection *conn; + EOQualifier *q; + NSString *sharePattern; + NSEnumerator *resultEnum; + NGLdapEntry *entry; + + if ([_uid length] == 0) + return nil; + + if (!useLDAP) { + [self logWithFormat: + @"Note: LDAP access is disabled, returning no shared accounts."]; + return nil; + } + + sharePattern = [_uid stringByAppendingString:@":*"]; + + q = [EOQualifier qualifierWithQualifierFormat: + @"(mineqMelPartages = %@) AND (objectclass = %@)", + sharePattern, shareLDAPClass]; + + conn = [self ldapConnection]; + + resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN + qualifier:q + attributes:[self mailServerDiscoveryAttributes]]; + + while ((entry = [resultEnum nextObject]) != nil) { + NSString *server, *shareLogin; + id shareUid; + + if ([(server = [self serverFromEntry:entry]) length] == 0) { + [self errorWithFormat:@"found no mail server host for share: %@", + [entry dn]]; + continue; + } + + shareUid = [entry attributeWithName:@"uid"]; + if ([shareUid count] < 1) { + [self errorWithFormat:@"found no 'uid' for share: %@", [entry dn]]; + continue; + } + shareUid = [shareUid stringValueAtIndex:0]; + + shareLogin = [_uid stringByAppendingString:shareLoginSeparator]; + shareLogin = [shareLogin stringByAppendingString:shareUid]; + + if (shares == nil) + shares = [NSMutableArray arrayWithCapacity:4]; + + shareLogin = [shareLogin stringByAppendingString:@"@"]; + shareLogin = [shareLogin stringByAppendingString:server]; + [shares addObject:shareLogin]; + } + return shares; +} + +/* free busy */ + - (NSURL *)getFreeBusyURLForUID:(NSString *)_uid { + [self logWithFormat:@"TODO(%s): implement", __PRETTY_FUNCTION__]; return nil; } diff --git a/SOGo/SoObjects/SOGo/ChangeLog b/SOGo/SoObjects/SOGo/ChangeLog index 82084cda..c868afe2 100644 --- a/SOGo/SoObjects/SOGo/ChangeLog +++ b/SOGo/SoObjects/SOGo/ChangeLog @@ -1,3 +1,13 @@ +2005-07-07 Helge Hess + + * added agenor_shares4uid tool to check whether the uid=>shared mailbox + discovery in AgenorUserManager works + + * AgenorUserManager.m: fixed a major string scanning bug in + _serverCandidatesForMineqMelRoutage: method, + added -getSharedMailboxAccountStringsForUID: method to discover + shared IMAP4 accounts (v0.9.39) + 2005-07-07 Helge Hess * AgenorUserManager.m: added a simple -description method (v0.9.38) diff --git a/SOGo/SoObjects/SOGo/GNUmakefile b/SOGo/SoObjects/SOGo/GNUmakefile index 1a00ae02..e60ad52c 100644 --- a/SOGo/SoObjects/SOGo/GNUmakefile +++ b/SOGo/SoObjects/SOGo/GNUmakefile @@ -6,7 +6,7 @@ include $(GNUSTEP_MAKEFILES)/common.make -include ./Version LIBRARY_NAME = libSOGo -TOOL_NAME = agenor_email2uid +TOOL_NAME = agenor_email2uid agenor_shares4uid libSOGo_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) @@ -50,6 +50,11 @@ agenor_email2uid_OBJC_FILES += \ AgenorUserManager.m \ SOGoLRUCache.m \ +agenor_shares4uid_OBJC_FILES += \ + agenor_shares4uid.m \ + AgenorUserManager.m \ + SOGoLRUCache.m \ + -include GNUmakefile.preamble include $(GNUSTEP_MAKEFILES)/library.make include $(GNUSTEP_MAKEFILES)/tool.make diff --git a/SOGo/SoObjects/SOGo/GNUmakefile.preamble b/SOGo/SoObjects/SOGo/GNUmakefile.preamble index a5b52736..9ecfb265 100644 --- a/SOGo/SoObjects/SOGo/GNUmakefile.preamble +++ b/SOGo/SoObjects/SOGo/GNUmakefile.preamble @@ -24,5 +24,5 @@ libSOGo_LIBRARIES_DEPEND_UPON += \ -lXmlRpc -lDOM -lSaxObjC \ -lNGLdap -agenor_email2uid_TOOL_LIBS += \ - -lNGLdap +agenor_email2uid_TOOL_LIBS += -lNGLdap +agenor_shares4uid_TOOL_LIBS += -lNGLdap diff --git a/SOGo/SoObjects/SOGo/Version b/SOGo/SoObjects/SOGo/Version index 4797ab0b..7638e783 100644 --- a/SOGo/SoObjects/SOGo/Version +++ b/SOGo/SoObjects/SOGo/Version @@ -1,6 +1,6 @@ # version file -SUBMINOR_VERSION:=38 +SUBMINOR_VERSION:=39 # v0.9.34 requires libGDLContentStore v4.5.26 # v0.9.26 requires libOGoContentStore v0.9.13 diff --git a/SOGo/SoObjects/SOGo/agenor_email2uid.m b/SOGo/SoObjects/SOGo/agenor_email2uid.m index 09c36c3e..056fda79 100644 --- a/SOGo/SoObjects/SOGo/agenor_email2uid.m +++ b/SOGo/SoObjects/SOGo/agenor_email2uid.m @@ -38,7 +38,6 @@ static void doIt(NSArray *args) { } userManager = [AgenorUserManager sharedUserManager]; - NSLog(@"We are using user manager: %@", userManager); e = [args objectEnumerator]; [e nextObject]; /* consume the command name */ diff --git a/SOGo/SoObjects/SOGo/agenor_shares4uid.m b/SOGo/SoObjects/SOGo/agenor_shares4uid.m new file mode 100644 index 00000000..eb95bce8 --- /dev/null +++ b/SOGo/SoObjects/SOGo/agenor_shares4uid.m @@ -0,0 +1,79 @@ +/* + Copyright (C) 2005 SKYRIX Software AG + + 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; either version 2, or (at your option) any + later version. + + OGo is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with OGo; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#include "AgenorUserManager.h" +#include "common.h" + +static void usage(NSArray *args) { + fprintf(stderr, "usage: %s \n", + [[args objectAtIndex:0] cString]); +} + +static void handleUID(NSString *uid, AgenorUserManager *userManager) { + NSArray *shares; + unsigned i, count; + + shares = [userManager getSharedMailboxAccountStringsForUID:uid]; + + printf("%s:", [uid cString]); + + if ((count = [shares count]) == 0) { + printf(" \n"); + return; + } + + puts(""); + for (i = 0; i < count; i++) + printf(" %s\n", [[shares objectAtIndex:i] cString]); +} + +static void doIt(NSArray *args) { + AgenorUserManager *userManager; + NSEnumerator *e; + NSString *uid; + + if ([args count] < 2) { + usage(args); + return; + } + + userManager = [AgenorUserManager sharedUserManager]; + + e = [args objectEnumerator]; + [e nextObject]; /* consume the command name */ + + while ((uid = [e nextObject]) != nil) + handleUID(uid, userManager); +} + +int main(int argc, char **argv, char **env) { + NSAutoreleasePool *pool; + + pool = [[NSAutoreleasePool alloc] init]; +#if LIB_FOUNDATION_LIBRARY + [NSProcessInfo initializeWithArguments:argv count:argc environment:env]; +#endif + + doIt([[NSProcessInfo processInfo] argumentsWithoutDefaults]); + + [pool release]; + return 0; +} -- 2.39.5