From ab66b6ca55944e8393de4ccf5c4608bd34c83f5e Mon Sep 17 00:00:00 2001 From: wolfgang Date: Wed, 9 May 2007 19:35:09 +0000 Subject: [PATCH] git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1052 d1b88da0-ebda-0310-925b-ed51d893ca5b --- ChangeLog | 119 ++ SOPE/NGCards/versitCardsSaxDriver/ChangeLog | 7 + .../versitCardsSaxDriver/VSSaxDriver.m | 4 +- Scripts/sogo | 50 + Scripts/sogocron.sh | 36 + Scripts/sogod-0.9 | 9 + SoObjects/Appointments/GNUmakefile | 1 - .../Appointments/SOGoAppointmentFolder.m | 8 +- .../Appointments/SOGoAppointmentObject.m | 32 +- .../SOGoAptMailEnglishInvitation.html | 2 +- .../Appointments/SOGoCalendarComponent.h | 12 +- .../Appointments/SOGoCalendarComponent.m | 133 +- SoObjects/Appointments/SOGoFreeBusyObject.h | 10 +- SoObjects/Appointments/SOGoFreeBusyObject.m | 26 +- SoObjects/Appointments/SOGoTaskObject.m | 10 +- ...bject+Agenor.h => iCalEntityObject+LDAP.h} | 0 ...bject+Agenor.m => iCalEntityObject+LDAP.m} | 0 SoObjects/Contacts/GNUmakefile | 4 +- SoObjects/Contacts/NGLdapEntry+Contact.h | 41 - SoObjects/Contacts/NGLdapEntry+Contact.m | 81 -- SoObjects/Contacts/SOGoContactFolder.h | 6 +- SoObjects/Contacts/SOGoContactFolders.m | 82 +- SoObjects/Contacts/SOGoContactGCSFolder.h | 6 +- SoObjects/Contacts/SOGoContactGCSFolder.m | 27 +- SoObjects/Contacts/SOGoContactLDAPFolder.h | 29 +- SoObjects/Contacts/SOGoContactLDAPFolder.m | 294 +--- SoObjects/Contacts/product.plist | 15 +- SoObjects/Mailer/SOGoDraftObject.m | 21 +- SoObjects/Mailer/SOGoUser+Mail.m | 4 +- SoObjects/SOGo/AgenorUserDefaults.m | 22 +- SoObjects/SOGo/AgenorUserManager.h | 88 -- SoObjects/SOGo/AgenorUserManager.m | 1222 ----------------- SoObjects/SOGo/GNUmakefile | 14 +- SoObjects/SOGo/LDAPSource.h | 71 + SoObjects/SOGo/LDAPSource.m | 418 ++++++ SoObjects/SOGo/LDAPUserManager.h | 64 + SoObjects/SOGo/LDAPUserManager.m | 474 +++++++ SoObjects/SOGo/SOGoAuthenticator.m | 31 +- SoObjects/SOGo/SOGoFolder.h | 10 +- SoObjects/SOGo/SOGoObject.h | 16 +- SoObjects/SOGo/SOGoObject.m | 1 - SoObjects/SOGo/SOGoUser.h | 25 +- SoObjects/SOGo/SOGoUser.m | 199 ++- UI/Common/Toolbars/SOGoAclOwner.toolbar | 5 - UI/Common/UIxAclEditor.m | 21 +- UI/Common/UIxFolderActions.h | 6 +- UI/Common/UIxFolderActions.m | 19 +- UI/Common/UIxObjectActions.m | 6 +- UI/Common/UIxUserRightsEditor.m | 10 +- UI/Contacts/UIxContactEditor.m | 24 +- UI/Contacts/UIxContactFoldersView.m | 134 +- UI/Contacts/UIxContactsListViewContainer.m | 9 +- UI/Contacts/product.plist | 16 +- UI/GNUmakefile | 2 - UI/MailPartViewers/UIxMailPartICalViewer.m | 15 +- UI/MailerUI/UIxMailEditor.m | 166 +-- .../English.lproj/Localizable.strings | 2 +- UI/Scheduler/GNUmakefile | 2 +- .../Toolbars/SOGoAppointmentFolder.toolbar | 5 +- UI/Scheduler/UIxAppointmentEditor.m | 40 - UI/Scheduler/UIxAppointmentView.m | 9 +- UI/Scheduler/UIxCalInlineAptView.m | 2 +- UI/Scheduler/UIxCalView.m | 4 +- UI/Scheduler/UIxCalendarSelector.m | 1 - ...nent+Agenor.h => UIxComponent+Scheduler.h} | 4 - ...nent+Agenor.m => UIxComponent+Scheduler.m} | 28 +- UI/Scheduler/UIxComponentEditor.h | 1 + UI/Scheduler/UIxComponentEditor.m | 50 +- UI/Scheduler/UIxTaskEditor.m | 40 - UI/Scheduler/UIxTaskView.m | 11 +- .../UIxContactsListViewContainer.wox | 8 +- UI/Templates/GNUmakefile | 19 +- UI/Templates/MailerUI/UIxMailMainFrame.wox | 100 +- .../SchedulerUI/UIxAppointmentEditor.wox | 1 - UI/Templates/SchedulerUI/UIxCalMainView.wox | 13 +- .../SchedulerUI/UIxFreeBusyUserSelector.wox | 18 +- .../UIxFreeBusyUserSelectorTable.wox | 1 - UI/Templates/SchedulerUI/UIxTaskEditor.wox | 1 - UI/Templates/UIxAclEditor.wox | 35 +- UI/WebServerResources/ContactsUI.css | 10 +- UI/WebServerResources/ContactsUI.js | 2 +- UI/WebServerResources/HTMLElement.js | 7 - UI/WebServerResources/MailerUI.css | 8 +- UI/WebServerResources/MailerUI.js | 45 +- UI/WebServerResources/SOGoDragAndDrop.js | 35 +- UI/WebServerResources/SchedulerUI.css | 6 +- UI/WebServerResources/SchedulerUI.js | 1 - UI/WebServerResources/UIxAclEditor.css | 45 +- UI/WebServerResources/UIxAttendeesEditor.css | 4 +- UI/WebServerResources/UIxAttendeesEditor.js | 35 +- .../UIxCalUserRightsEditor.css | 4 +- UI/WebServerResources/UIxComponentEditor.js | 1 - UI/WebServerResources/UIxContactEditor.css | 8 +- .../UIxContactsUserFolders.css | 4 +- .../UIxContactsUserFolders.js | 3 +- .../UIxContactsUserRightsEditor.css | 4 +- UI/WebServerResources/UIxMailEditor.css | 4 +- UI/WebServerResources/generic.css | 69 +- UI/WebServerResources/generic.js | 14 + 99 files changed, 2311 insertions(+), 2550 deletions(-) create mode 100755 Scripts/sogo create mode 100755 Scripts/sogocron.sh create mode 100755 Scripts/sogod-0.9 rename SoObjects/Appointments/{iCalEntityObject+Agenor.h => iCalEntityObject+LDAP.h} (100%) rename SoObjects/Appointments/{iCalEntityObject+Agenor.m => iCalEntityObject+LDAP.m} (100%) delete mode 100644 SoObjects/Contacts/NGLdapEntry+Contact.h delete mode 100644 SoObjects/Contacts/NGLdapEntry+Contact.m delete mode 100644 SoObjects/SOGo/AgenorUserManager.h delete mode 100644 SoObjects/SOGo/AgenorUserManager.m create mode 100644 SoObjects/SOGo/LDAPSource.h create mode 100644 SoObjects/SOGo/LDAPSource.m create mode 100644 SoObjects/SOGo/LDAPUserManager.h create mode 100644 SoObjects/SOGo/LDAPUserManager.m rename UI/Scheduler/{UIxComponent+Agenor.h => UIxComponent+Scheduler.h} (93%) rename UI/Scheduler/{UIxComponent+Agenor.m => UIxComponent+Scheduler.m} (76%) delete mode 100644 UI/Templates/SchedulerUI/UIxFreeBusyUserSelectorTable.wox diff --git a/ChangeLog b/ChangeLog index 11f9fae3..ad7219dc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,122 @@ +2007-05-09 Wolfgang Sourdeau + + * SoObjects/SOGo/SOGoUser.m ([SOGoUser -primaryEmail]): new name + for "mail" method. + ([SOGoUser -systemEmail]): returns the email formed from the + username and the default mail domain. + ([SOGoUser -hasEmail:email]): test whether the user has the + specified email, in a case-insensitive way. + + * SoObjects/SOGo/SOGoAuthenticator.m ([SOGoAuthenticator + -LDAPCheckLogin:_loginpassword:_pwd]): use the user manager to + check login information. + + * SoObjects/Contacts/SOGoContactLDAPFolder.m + ([SOGoContactLDAPFolder + +contactFolderWithName:aNameandDisplayName:aDisplayNameinContainer:aContainer]): + no longer manage LDAP connections. The requests are forwarded to + the relevant LDAPSource instead. + + * SoObjects/Contacts/SOGoContactFolders.m ([SOGoContactFolders + -appendSystemSources]): pass LDAPSource objects to + SOGoContactLDAPFolder instances. + + * SoObjects/Mailer/SOGoDraftObject.m: extract the raw email + address of the "from" field before sending the message. Otherwise, + sending the mail won't work. + + * UI/MailerUI/UIxMailEditor.m ([UIxMailEditor -fromEMails]): + rewrote this method to request all the available email identities + for the current user. Also, the from field also contains the full + name of the user, not just his/her email address. + + * SoObjects/Appointments/SOGoCalendarComponent.m + ([SOGoCalendarComponent -iCalPersonWithUID:uid]): new method taken + from the previous module iCalEntityObject+Agenor. + ([SOGoCalendarComponent -getUIDForICalPerson:person]): idem. + ([SOGoCalendarComponent -getUIDsForICalPersons:iCalPersons]): + idem. + + * SoObjects/Contacts/SOGoContactLDIFEntry.[hm]: new class module + replacing the SOGoContactLDAPEntry module. It was renamed as such + because it now receives a dictionary instead of an NGLdapEntry. + It thus can now handle data from any source of LDIF data, not + only coming from LDAP. + + * SoObjects/SOGo/LDAPUserManager.[hm]: new class module + implementing most of what used to be the AgenorUserManager class. + The difference is that users are cached in the forme of + dictionaries and many sources are used. Also, it can be used to + search LDAP contacts. + + * SoObjects/SOGo/LDAPSource.[hm]: new class module implementing + the concept of "ldap source", to be used by all the classes + needing access to LDAP-provided information: addressbooks and the + user manager. Most the method thereing are transcriptions of + methods previously found in SOGoContactLDAPFolder. It also contain + utility methods for user matching and authentification. + + * SoObjects/Appointments/iCalEntityObject+Agenor.[hm]: removed + module, rendered useless by code refactoring. + + * SoObjects/SOGo/AgenorUserManager.[hm]: removed module, replaced + with the freshly written "LDAPUserManager". + +2007-05-08 Wolfgang Sourdeau + + * SoObjects/Contacts/SOGoContactLDAPEntry.[hm]: renamed to + SOGOContactLDIFEntry. + + * SoObjects/Contacts/NGLdapEntry+Contact.[hm]: removed class + module, obsoleted by code in SOGo/LDAPSource.[hm]. + +2007-05-04 Wolfgang Sourdeau + + * UI/Common/UIxAclEditor.m ([UIxAclEditor -currentUserIsOwner]): + new method with an explicit name. + +2007-05-03 Wolfgang Sourdeau + + * SoObjects/Appointments/SOGoCalendarComponent.m + ([SOGoCalendarComponent -isOrganizerOrOwner:user]): new method + replacing "isOrganizer:orOwner:" by taking only one instance of + SOGoUser as parameter. + ([SOGoCalendarComponent -participant:user]): new method replacing + the previous "isParticipant" boolean method by returning the first + participant matching the user passed as parameter. This method is + used so that both the regular email address and the "system email + address" of the user are matched against the participants emails. + + * SoObjects/SOGo/AgenorUserManager.m ([AgenorUserManager + -getSystemEMailForUID:uid]): new method that returns the email + formed with the user's uid and the default mail domain. + + * SoObjects/Appointments/SOGoCalendarComponent.m + ([SOGoCalendarComponent -rolesOfUser:login]): removed method that + was previously commented out. + + * SoObjects/SOGo/SOGoUser.m ([SOGoUser -systemEmail]): new method + forwared to [AgenorUserManager getSystemEmailForUID:]. + + * UI/Scheduler/UIxComponentEditor.m ([UIxComponentEditor + -toolbar]): method replacing the one with the same name in the + task and appointment editor classes. This method makes also use of + the new method "isOrganizerOrOwner:" and "participant:" in + SOGoCalendarComponent. + + * UI/Scheduler/UIxAppointmentEditor.m ([UIxAppointmentEditor + -toolbar]): removed method, replaced with a method with the same + name in UIxComponentEditor. + + * UI/Scheduler/UIxTaskEditor.m ([UIxTaskEditor -toolbar]): removed + method, replaced with a method with the same name in + UIxComponentEditor. + + * SoObjects/SOGo/AgenorUserDefaults.m ([AgenorUserDefaults + -primaryFetchProfile]): the values returned from the database are + converted to a put dictionary first, since the dictionary returned + is actually an immutable one, which can cause a crash afterwards. + 2007-04-27 Wolfgang Sourdeau * SoObjects/SOGo/SOGoPermissions.m: added "SOGoRole_ObjectViewer" diff --git a/SOPE/NGCards/versitCardsSaxDriver/ChangeLog b/SOPE/NGCards/versitCardsSaxDriver/ChangeLog index b2644436..454e8397 100644 --- a/SOPE/NGCards/versitCardsSaxDriver/ChangeLog +++ b/SOPE/NGCards/versitCardsSaxDriver/ChangeLog @@ -1,3 +1,10 @@ +2007-05-03 Wolfgang Sourdeau + + * VSSaxDriver.m ([VSSaxDriver +initialize]): removed the space + character from the colonAndSemicolonCharSet and + colonSemicolonAndDquoteCharSet so that fields which contain + attributes with values containing spaces don't get cut. + 2006-07-04 Helge Hess * use %p for pointer formats, fixed gcc 4.1 warnings (v4.5.24) diff --git a/SOPE/NGCards/versitCardsSaxDriver/VSSaxDriver.m b/SOPE/NGCards/versitCardsSaxDriver/VSSaxDriver.m index e59b7f0a..138df5e4 100644 --- a/SOPE/NGCards/versitCardsSaxDriver/VSSaxDriver.m +++ b/SOPE/NGCards/versitCardsSaxDriver/VSSaxDriver.m @@ -184,9 +184,9 @@ static VSStringFormatter *stringFormatter = nil; commaCharSet = [[NSCharacterSet characterSetWithCharactersInString: @","] retain]; colonAndSemicolonCharSet = - [[NSCharacterSet characterSetWithCharactersInString: @": ;"] retain]; + [[NSCharacterSet characterSetWithCharactersInString: @":;"] retain]; colonSemicolonAndDquoteCharSet = - [[NSCharacterSet characterSetWithCharactersInString: @": ;\""] retain]; + [[NSCharacterSet characterSetWithCharactersInString: @":;\""] retain]; whitespaceCharSet = [[NSCharacterSet whitespaceCharacterSet] retain]; diff --git a/Scripts/sogo b/Scripts/sogo new file mode 100755 index 00000000..5514064a --- /dev/null +++ b/Scripts/sogo @@ -0,0 +1,50 @@ +#! /bin/sh + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +DAEMON=/usr/local/sbin/sogod-0.9 +NAME=sogo +DESC="Scalable OpenGroupware.Org" + +PIDFILE=/var/run/sogo/sogod.pid + +SOGO_ARGS="" + +if [ -f /etc/default/sogo ]; then + . /etc/default/sogo +fi + +test -x $DAEMON || exit 0 + +#set -e + +case "$1" in + start) + echo -n "Starting $DESC: " + start-stop-daemon -c sogo --pidfile $PIDFILE \ + -b --start --quiet --exec $DAEMON + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + killall sogod-0.9 2> /dev/null + rm -f $PIDFILE + echo "$NAME." + ;; + restart|force-reload) + echo -n "Restarting $DESC: " + killall sogod-0.9 2> /dev/null + rm -f $PIDFILE + sleep 1 + start-stop-daemon -c sogo --pidfile $PIDFILE \ + -b --start --quiet --exec $DAEMON + echo "$NAME." + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/Scripts/sogocron.sh b/Scripts/sogocron.sh new file mode 100755 index 00000000..1b1f87d4 --- /dev/null +++ b/Scripts/sogocron.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +export PATH=/usr/local/sbin:$PATH + +cd /root/SOGo +# echo "Pulling monotone repository" + +oldversion=$(mtn status) +mtn pull >& /dev/null +mtn update >& /dev/null +newversion=$(mtn status) + +if [ "$oldversion" == "$newversion" ] +then + exit 0 +fi + +echo "SOGo mainsite updated at $(date)..." + +. /root/GNUstep/Library/Makefiles/GNUstep.sh >& /dev/null +make distclean > /dev/null +./configure --disable-strip --without-gnustep >& /dev/null +make -s > /dev/null +rm -rf /usr/local/lib/sogod-0.9 +make -s install > /dev/null +# echo "Copying templates to /usr/local/share/sogo-0.9/templates" +# rm -rf /usr/local/share/sogo-0.9/templates +# cp -a UI/Templates /usr/local/share/sogo-0.9/templates +# echo "Copying web resources to /usr/local/share/sogo-0.9/www" +# cp -a UI/WebServerResources /usr/local/share/sogo-0.9/www +# echo "Killing server" +pkill sogod-0.9 >& /dev/null +# echo "Starting sogod-0.9 (log in /var/log/sogod)" +echo "Launching on $(date)" > /var/log/sogod +sogod-0.9 >> /var/log/sogod 2>&1 & + diff --git a/Scripts/sogod-0.9 b/Scripts/sogod-0.9 new file mode 100755 index 00000000..c19d35a7 --- /dev/null +++ b/Scripts/sogod-0.9 @@ -0,0 +1,9 @@ +#!/bin/sh + +PIDFILE=/var/run/sogo/sogod.pid + +. /usr/local/lib/GNUstep-SOPE/Library/Makefiles/GNUstep.sh + +echo $$ > $PIDFILE +exec $GNUSTEP_LOCAL_ROOT/Tools/sogod-0.9 >& /var/log/sogo/sogod.log + diff --git a/SoObjects/Appointments/GNUmakefile b/SoObjects/Appointments/GNUmakefile index 57b4cb0f..c6effab6 100644 --- a/SoObjects/Appointments/GNUmakefile +++ b/SoObjects/Appointments/GNUmakefile @@ -11,7 +11,6 @@ Appointments_PRINCIPAL_CLASS = SOGoAppointmentsProduct Appointments_OBJC_FILES = \ Product.m \ NSArray+Appointments.m \ - iCalEntityObject+Agenor.m \ \ SOGoCalendarComponent.m \ SOGoAppointmentObject.m \ diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 3ca862f1..f07b81bf 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -30,7 +30,7 @@ // #import #import -#import +#import #import #import #import @@ -741,7 +741,7 @@ static NSNumber *sharedYes = nil; privacySqlString = @"and (isopaque = 1)"; else { - email = [activeUser email]; + email = [activeUser primaryEmail]; privacySqlString = [NSString stringWithFormat: @@ -1092,7 +1092,7 @@ static NSNumber *sharedYes = nil; { /* Note: can return NSNull objects in the array! */ NSMutableArray *uids; - AgenorUserManager *um; + LDAPUserManager *um; unsigned i, count; if (_persons == nil) @@ -1100,7 +1100,7 @@ static NSNumber *sharedYes = nil; count = [_persons count]; uids = [NSMutableArray arrayWithCapacity:count + 1]; - um = [AgenorUserManager sharedUserManager]; + um = [LDAPUserManager sharedUserManager]; for (i = 0; i < count; i++) { iCalPerson *person; diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index ea76ffb2..691ed36e 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -26,11 +26,9 @@ #import #import -#import -#import -#import - -#import "iCalEntityObject+Agenor.h" +#import +#import +#import #import "common.h" @@ -46,7 +44,7 @@ /* iCal handling */ - (NSArray *) attendeeUIDsFromAppointment: (iCalEvent *) _apt { - AgenorUserManager *um; + LDAPUserManager *um; NSMutableArray *uids; NSArray *attendees; unsigned i, count; @@ -60,13 +58,13 @@ count = [attendees count]; uids = [NSMutableArray arrayWithCapacity:count + 1]; - um = [AgenorUserManager sharedUserManager]; + um = [LDAPUserManager sharedUserManager]; /* add organizer */ email = [[_apt organizer] rfc822Email]; if ([email isNotNull]) { - uid = [um getUIDForEmail:email]; + uid = [um getUIDForEmail: email]; if ([uid isNotNull]) { [uids addObject:uid]; } @@ -201,7 +199,7 @@ - delete in removed folders - send iMIP mail for all folders not found */ - AgenorUserManager *um; + LDAPUserManager *um; iCalEvent *oldApt, *newApt; iCalEventChanges *changes; iCalPerson *organizer; @@ -217,7 +215,7 @@ return [NSException exceptionWithHTTPStatus: 400 /* Bad Request */ reason: @"got no iCalendar content to store!"]; - um = [AgenorUserManager sharedUserManager]; + um = [LDAPUserManager sharedUserManager]; /* handle old content */ @@ -247,12 +245,10 @@ /* diff */ changes = [iCalEventChanges changesFromEvent: oldApt toEvent: newApt]; - uids = [um getUIDsForICalPersons: [changes deletedAttendees] - applyStrictMapping: NO]; + uids = [self getUIDsForICalPersons: [changes deletedAttendees]]; removedUIDs = [NSMutableArray arrayWithArray: uids]; - uids = [um getUIDsForICalPersons: [newApt attendees] - applyStrictMapping: NO]; + uids = [self getUIDsForICalPersons: [newApt attendees]]; storeUIDs = [NSMutableArray arrayWithArray: uids]; props = [changes updatedProperties]; @@ -263,7 +259,7 @@ /* preserve organizer */ organizer = [newApt organizer]; - uid = [um getUIDForICalPerson: organizer]; + uid = [self getUIDForICalPerson: organizer]; if (!uid) uid = [self ownerInContext: nil]; if (uid) { @@ -275,7 +271,7 @@ /* organizer might have changed completely */ if (oldApt && ([props containsObject: @"organizer"])) { - uid = [um getUIDForICalPerson:[oldApt organizer]]; + uid = [self getUIDForICalPerson:[oldApt organizer]]; if (uid) { if (![storeUIDs containsObject:uid]) { if (![removedUIDs containsObject:uid]) { @@ -435,6 +431,7 @@ NSString *newContentString, *oldContentString; iCalCalendar *eventCalendar; iCalEvent *event; + iCalPerson *organizer; NSArray *organizers; oldContentString = [self contentAsString]; @@ -449,7 +446,8 @@ newContentString = contentString; else { - [event setOrganizerWithUid: [[self container] ownerInContext: nil]]; + organizer = [self iCalPersonWithUID: [self ownerInContext: context]]; + [event setOrganizer: organizer]; newContentString = [eventCalendar versitString]; } } diff --git a/SoObjects/Appointments/SOGoAptMailEnglishInvitation.wo/SOGoAptMailEnglishInvitation.html b/SoObjects/Appointments/SOGoAptMailEnglishInvitation.wo/SOGoAptMailEnglishInvitation.html index edb87f43..4d6bbab4 100644 --- a/SoObjects/Appointments/SOGoAptMailEnglishInvitation.wo/SOGoAptMailEnglishInvitation.html +++ b/SoObjects/Appointments/SOGoAptMailEnglishInvitation.wo/SOGoAptMailEnglishInvitation.html @@ -1,4 +1,4 @@ -<#IsSubject>Apt le <#AptStartDate /> at <#AptStartTime /> +<#IsSubject>Appointment on <#AptStartDate /> at <#AptStartTime /> <#IsBody> You're invited by <#Organizer /> to a meeting. <#HasHomePageURL> diff --git a/SoObjects/Appointments/SOGoCalendarComponent.h b/SoObjects/Appointments/SOGoCalendarComponent.h index 1f7299bc..50a1cfa2 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.h +++ b/SoObjects/Appointments/SOGoCalendarComponent.h @@ -29,8 +29,11 @@ @class NSString; @class iCalCalendar; +@class iCalPerson; @class iCalRepeatableEntityObject; +@class SOGoUser; + @interface SOGoCalendarComponent : SOGoContentObject { iCalCalendar *calendar; @@ -57,9 +60,12 @@ andNewObject: (iCalRepeatableEntityObject *) _newObject toAttendees: (NSArray *) _attendees; -- (BOOL) isOrganizer: (NSString *) email - orOwner: (NSString *) login; -- (BOOL) isParticipant: (NSString *) email; +- (BOOL) isOrganizerOrOwner: (SOGoUser *) user; +- (iCalPerson *) participant: (SOGoUser *) user; + +- (iCalPerson *) iCalPersonWithUID: (NSString *) uid; +- (NSString *) getUIDForICalPerson: (iCalPerson *) person; +- (NSArray *) getUIDsForICalPersons: (NSArray *) iCalPersons; @end diff --git a/SoObjects/Appointments/SOGoCalendarComponent.m b/SoObjects/Appointments/SOGoCalendarComponent.m index e1a5f598..9e8c841e 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.m +++ b/SoObjects/Appointments/SOGoCalendarComponent.m @@ -29,7 +29,7 @@ #import #import -#import +#import #import #import #import @@ -126,7 +126,7 @@ static BOOL sendEMailNotifications = NO; tmpCalendar = [iCalCalendar parseSingleFromSource: tmpContent]; tmpComponent = (iCalRepeatableEntityObject *) [tmpCalendar firstChildWithTag: [self componentTag]]; - email = [[context activeUser] email]; + email = [[context activeUser] primaryEmail]; if (!([tmpComponent isOrganizer: email] || [tmpComponent isParticipant: email])) { @@ -201,9 +201,9 @@ static BOOL sendEMailNotifications = NO; - (iCalRepeatableEntityObject *) component: (BOOL) create { - return (iCalRepeatableEntityObject *) - [[self calendar: create] - firstChildWithTag: [self componentTag]]; + return + (iCalRepeatableEntityObject *) [[self calendar: create] + firstChildWithTag: [self componentTag]]; } - (BOOL) isNew @@ -251,7 +251,7 @@ static BOOL sendEMailNotifications = NO; baseURL = @"http://localhost/"; [self warnWithFormat:@"Unable to create baseURL from context!"]; } - uid = [[AgenorUserManager sharedUserManager] + uid = [[LDAPUserManager sharedUserManager] getUIDForEmail: [_person rfc822Email]]; return ((uid) @@ -272,7 +272,7 @@ static BOOL sendEMailNotifications = NO; component = [self component: NO]; if (component) { - myEMail = [[context activeUser] email]; + myEMail = [[context activeUser] primaryEmail]; p = [component findParticipantWithEmail: myEMail]; if (p) { @@ -314,9 +314,9 @@ static BOOL sendEMailNotifications = NO; { NSString *uid; - uid = [[AgenorUserManager sharedUserManager] getUIDForEmail: email]; + uid = [[LDAPUserManager sharedUserManager] getUIDForEmail: email]; - return [[SOGoUser userWithLogin: uid andRoles: nil] timeZone]; + return [[SOGoUser userWithLogin: uid roles: nil] timeZone]; } - (void) sendEMailUsingTemplateNamed: (NSString *) _pageName @@ -443,42 +443,7 @@ static BOOL sendEMailNotifications = NO; } } -// - (NSArray *) rolesOfUser: (NSString *) login -// { -// AgenorUserManager *um; -// iCalRepeatableEntityObject *component; -// NSMutableArray *sogoRoles; -// NSString *email; -// SOGoUser *user; - -// sogoRoles = [NSMutableArray new]; -// [sogoRoles autorelease]; - -// um = [AgenorUserManager sharedUserManager]; -// email = [um getEmailForUID: login]; - -// component = [self component: NO]; -// if (component) -// { -// if ([component isOrganizer: email]) -// [sogoRoles addObject: SOGoCalendarRole_Organizer]; -// else if ([component isParticipant: email]) -// [sogoRoles addObject: SOGoCalendarRole_Participant]; -// else if ([[container ownerInContext: context] isEqualToString: login]) -// [sogoRoles addObject: SoRole_Owner]; -// } -// else -// { -// user = [SOGoUser userWithLogin: login andRoles: nil]; -// [sogoRoles addObjectsFromArray: [user rolesForObject: container -// inContext: context]]; -// } - -// return sogoRoles; -// } - -- (BOOL) isOrganizer: (NSString *) email - orOwner: (NSString *) login +- (BOOL) isOrganizerOrOwner: (SOGoUser *) user { BOOL isOrganizerOrOwner; iCalRepeatableEntityObject *component; @@ -487,27 +452,83 @@ static BOOL sendEMailNotifications = NO; component = [self component: NO]; organizerEmail = [[component organizer] rfc822Email]; if (component && [organizerEmail length] > 0) - isOrganizerOrOwner - = ([organizerEmail caseInsensitiveCompare: email] == NSOrderedSame); + isOrganizerOrOwner = [user hasEmail: organizerEmail]; else isOrganizerOrOwner - = [[container ownerInContext: context] isEqualToString: login]; + = [[container ownerInContext: context] isEqualToString: [user login]]; return isOrganizerOrOwner; } -- (BOOL) isParticipant: (NSString *) email +- (iCalPerson *) participant: (SOGoUser *) user { - BOOL isParticipant; - iCalRepeatableEntityObject *component; + iCalPerson *participant, *currentParticipant; + iCalEntityObject *component; + NSEnumerator *participants; + participant = nil; component = [self component: NO]; if (component) - isParticipant = [component isParticipant: email]; - else - isParticipant = NO; + { + participants = [[component participants] objectEnumerator]; + currentParticipant = [participants nextObject]; + while (currentParticipant && !participant) + if ([user hasEmail: [currentParticipant rfc822Email]]) + participant = currentParticipant; + else + currentParticipant = [participants nextObject]; + } + + return participant; +} + +- (iCalPerson *) iCalPersonWithUID: (NSString *) uid +{ + iCalPerson *person; + LDAPUserManager *um; + NSDictionary *contactInfos; + + um = [LDAPUserManager sharedUserManager]; + contactInfos = [um contactInfosForUserWithUIDorEmail: uid]; + + person = [iCalPerson new]; + [person autorelease]; + [person setCn: [contactInfos objectForKey: @"cn"]]; + [person setEmail: [contactInfos objectForKey: @"c_email"]]; + + return person; +} + +- (NSString *) getUIDForICalPerson: (iCalPerson *) person +{ + LDAPUserManager *um; + + um = [LDAPUserManager sharedUserManager]; + + return [um getUIDForEmail: [person rfc822Email]]; +} + +- (NSArray *) getUIDsForICalPersons: (NSArray *) iCalPersons +{ + iCalPerson *currentPerson; + NSEnumerator *persons; + NSMutableArray *uids; + NSString *email; + LDAPUserManager *um; + + uids = [NSMutableArray array]; + + um = [LDAPUserManager sharedUserManager]; + persons = [iCalPersons objectEnumerator]; + currentPerson = [persons nextObject]; + while (currentPerson) + { + email = [currentPerson rfc822Email]; + [uids addObject: [um getUIDForEmail: email]]; + currentPerson = [persons nextObject]; + } - return isParticipant; + return uids; } - (NSArray *) aclsForUser: (NSString *) uid @@ -521,7 +542,7 @@ static BOOL sendEMailNotifications = NO; component = [self component: NO]; if (component) { - email = [[AgenorUserManager sharedUserManager] getEmailForUID: uid]; + email = [[LDAPUserManager sharedUserManager] getEmailForUID: uid]; if ([component isOrganizer: email]) [roles addObject: SOGoCalendarRole_Organizer]; if ([component isParticipant: email]) diff --git a/SoObjects/Appointments/SOGoFreeBusyObject.h b/SoObjects/Appointments/SOGoFreeBusyObject.h index 6b5ea717..4b83b9dd 100644 --- a/SoObjects/Appointments/SOGoFreeBusyObject.h +++ b/SoObjects/Appointments/SOGoFreeBusyObject.h @@ -40,13 +40,13 @@ /* accessors */ -- (NSString *)iCalString; +- (NSString *) iCalString; -- (NSString *)contentAsStringFrom:(NSCalendarDate *)_startDate - to:(NSCalendarDate *)_endDate; +- (NSString *) contentAsStringFrom: (NSCalendarDate *) _startDate + to: (NSCalendarDate *) _endDate; -- (NSArray *)fetchFreeBusyInfosFrom:(NSCalendarDate *)_startDate - to:(NSCalendarDate *)_endDate; +- (NSArray *) fetchFreeBusyInfosFrom: (NSCalendarDate *) _startDate + to: (NSCalendarDate *) _endDate; @end diff --git a/SoObjects/Appointments/SOGoFreeBusyObject.m b/SoObjects/Appointments/SOGoFreeBusyObject.m index 5edd59e4..4476c0e9 100644 --- a/SoObjects/Appointments/SOGoFreeBusyObject.m +++ b/SoObjects/Appointments/SOGoFreeBusyObject.m @@ -22,10 +22,11 @@ #import #import +#import #import "common.h" -#import +#import #import #import "SOGoFreeBusyObject.h" @@ -110,11 +111,27 @@ return fbType; } +- (iCalPerson *) iCalPersonWithUID: (NSString *) uid +{ + iCalPerson *person; + LDAPUserManager *um; + NSDictionary *contactInfos; + + um = [LDAPUserManager sharedUserManager]; + contactInfos = [um contactInfosForUserWithUIDorEmail: uid]; + + person = [iCalPerson new]; + [person autorelease]; + [person setCn: [contactInfos objectForKey: @"cn"]]; + [person setEmail: [contactInfos objectForKey: @"c_email"]]; + + return person; +} + - (NSString *) iCalStringForFreeBusyInfos: (NSArray *) _infos from: (NSCalendarDate *) _startDate to: (NSCalendarDate *) _endDate { - AgenorUserManager *um; NSString *uid; NSEnumerator *events; iCalCalendar *calendar; @@ -122,7 +139,6 @@ NSDictionary *info; iCalFreeBusyType type; - um = [AgenorUserManager sharedUserManager]; uid = [[self container] login]; calendar = [iCalCalendar groupWithTag: @"vcalendar"]; @@ -130,7 +146,7 @@ [calendar setVersion: @"2.0"]; freebusy = [iCalFreeBusy groupWithTag: @"vfreebusy"]; - [freebusy addToAttendees: [um iCalPersonWithUid: uid]]; + [freebusy addToAttendees: [self iCalPersonWithUID: uid]]; [freebusy setTimeStampAsDate: [NSCalendarDate calendarDate]]; [freebusy setStartDate: _startDate]; [freebusy setEndDate: _endDate]; @@ -138,7 +154,7 @@ /* ORGANIZER - strictly required but missing for now */ /* ATTENDEE */ -// person = [um iCalPersonWithUid: uid]; +// person = [self iCalPersonWithUid: uid]; // [person setTag: @"ATTENDEE"]; // [ms appendString: [person versitString]]; diff --git a/SoObjects/Appointments/SOGoTaskObject.m b/SoObjects/Appointments/SOGoTaskObject.m index 861b32c0..cc15067f 100644 --- a/SoObjects/Appointments/SOGoTaskObject.m +++ b/SoObjects/Appointments/SOGoTaskObject.m @@ -25,7 +25,7 @@ #import #import #import -#import +#import #import #import #import @@ -66,7 +66,7 @@ static NSString *mailTemplateDefaultLanguage = nil; /* iCal handling */ - (NSArray *)attendeeUIDsFromTask:(iCalToDo *)_task { - AgenorUserManager *um; + LDAPUserManager *um; NSMutableArray *uids; NSArray *attendees; unsigned i, count; @@ -80,7 +80,7 @@ static NSString *mailTemplateDefaultLanguage = nil; count = [attendees count]; uids = [NSMutableArray arrayWithCapacity:count + 1]; - um = [AgenorUserManager sharedUserManager]; + um = [LDAPUserManager sharedUserManager]; /* add organizer */ @@ -221,7 +221,7 @@ static NSString *mailTemplateDefaultLanguage = nil; - delete in removed folders - send iMIP mail for all folders not found */ -// AgenorUserManager *um; +// LDAPUserManager *um; // iCalCalendar *calendar; // iCalToDo *oldApt, *newApt; // // iCalToDoChanges *changes; @@ -239,7 +239,7 @@ static NSString *mailTemplateDefaultLanguage = nil; // reason:@"got no iCalendar content to store!"]; // } -// um = [AgenorUserManager sharedUserManager]; +// um = [LDAPUserManager sharedUserManager]; // /* handle old content */ diff --git a/SoObjects/Appointments/iCalEntityObject+Agenor.h b/SoObjects/Appointments/iCalEntityObject+LDAP.h similarity index 100% rename from SoObjects/Appointments/iCalEntityObject+Agenor.h rename to SoObjects/Appointments/iCalEntityObject+LDAP.h diff --git a/SoObjects/Appointments/iCalEntityObject+Agenor.m b/SoObjects/Appointments/iCalEntityObject+LDAP.m similarity index 100% rename from SoObjects/Appointments/iCalEntityObject+Agenor.m rename to SoObjects/Appointments/iCalEntityObject+LDAP.m diff --git a/SoObjects/Contacts/GNUmakefile b/SoObjects/Contacts/GNUmakefile index af94111f..3c1711c1 100644 --- a/SoObjects/Contacts/GNUmakefile +++ b/SoObjects/Contacts/GNUmakefile @@ -12,10 +12,8 @@ Contacts_OBJC_FILES = \ SOGoContactFolders.m \ SOGoContactGCSEntry.m \ SOGoContactGCSFolder.m \ - SOGoContactLDAPEntry.m \ + SOGoContactLDIFEntry.m \ SOGoContactLDAPFolder.m \ - \ - NGLdapEntry+Contact.m \ Contacts_RESOURCE_FILES += \ Version \ diff --git a/SoObjects/Contacts/NGLdapEntry+Contact.h b/SoObjects/Contacts/NGLdapEntry+Contact.h deleted file mode 100644 index 0551e611..00000000 --- a/SoObjects/Contacts/NGLdapEntry+Contact.h +++ /dev/null @@ -1,41 +0,0 @@ -/* NGLdapEntry+Contact.h - this file is part of SOGo - * - * Copyright (C) 2006 Inverse groupe conseil - * - * Author: Wolfgang Sourdeau - * - * 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. - */ - -#ifndef NGLDAPENTRY_CONTACT_H -#define NGLDAPENTRY_CONTACT_H - -#import - -@class NSArray; -@class NSDictionary; -@class NSString; - -@interface NGLdapEntry (SOGoContactExtension) - -- (NSString *) singleAttributeWithName: (NSString *) key; -- (NSDictionary *) asDictionaryWithAttributeNames: (NSArray *) attributes - withUID: (NSString *) uid - andCName: (NSString *) cName; - -@end - -#endif /* NGLDAPENTRY_CONTACT_H */ diff --git a/SoObjects/Contacts/NGLdapEntry+Contact.m b/SoObjects/Contacts/NGLdapEntry+Contact.m deleted file mode 100644 index 53e9fe42..00000000 --- a/SoObjects/Contacts/NGLdapEntry+Contact.m +++ /dev/null @@ -1,81 +0,0 @@ -/* NGLdapEntry+Contact.m - this file is part of SOGo - * - * Copyright (C) 2006 Inverse groupe conseil - * - * Author: Wolfgang Sourdeau - * - * 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 -#import -#import - -#import - -#import "NGLdapEntry+Contact.h" - -@implementation NGLdapEntry (SOGoContactExtension) - -- (NSString *) singleAttributeWithName: (NSString *) key -{ - return [[self attributeWithName: key] - stringValueAtIndex: 0]; -} - -- (NSDictionary *) asDictionaryWithAttributeNames: (NSArray *) attributeNames - withUID: (NSString *) uid - andCName: (NSString *) cName -{ - NSMutableDictionary *valuesDict; - NSEnumerator *attrEnum; - NSString *attribute, *value; - - if (!attributeNames) - attributeNames = [self attributeNames]; - - valuesDict = [NSMutableDictionary dictionaryWithCapacity: [attributeNames count]]; - attrEnum = [attributeNames objectEnumerator]; - attribute = [attrEnum nextObject]; - while (attribute) - { - [valuesDict setObject: [self singleAttributeWithName: attribute] - forKey: attribute]; - attribute = [attrEnum nextObject]; - } - if (cName) - { - value = [self singleAttributeWithName: cName]; - if (!value) - value = @""; - NSLog (@"value for '%@' = '%@'", cName, value); - [valuesDict setObject: value - forKey: @"c_name"]; - } - if (uid) - { - value = [self singleAttributeWithName: uid]; - if (!value) - value = @""; - NSLog (@"value for '%@' = '%@'", uid, value); - [valuesDict setObject: value - forKey: @"c_uid"]; - } - - return valuesDict; -} - -@end diff --git a/SoObjects/Contacts/SOGoContactFolder.h b/SoObjects/Contacts/SOGoContactFolder.h index 28f180c6..904009d3 100644 --- a/SoObjects/Contacts/SOGoContactFolder.h +++ b/SoObjects/Contacts/SOGoContactFolder.h @@ -51,15 +51,13 @@ andDisplayName: (NSString *) aDisplayName inContainer: (SOGoObject *) aContainer; +- (NSString *) nameInContainer; +- (NSString *) displayName; -- (id ) lookupContactWithId: (NSString *) recordId; - (NSArray *) lookupContactsWithFilter: (NSString *) filter sortBy: (NSString *) sortKey ordering: (NSComparisonResult) sortOrdering; -- (void) setDisplayName: (NSString *) aDisplayName; -- (NSString *) displayName; - @end #endif /* __Contacts_SOGoContactFolder_H__ */ diff --git a/SoObjects/Contacts/SOGoContactFolders.m b/SoObjects/Contacts/SOGoContactFolders.m index d6c3f9db..bbe0c5f5 100644 --- a/SoObjects/Contacts/SOGoContactFolders.m +++ b/SoObjects/Contacts/SOGoContactFolders.m @@ -31,9 +31,11 @@ #import #import +#import #import #import #import +#import #import #import @@ -41,10 +43,9 @@ #import #import +#import #import -#import "common.h" - #import "SOGoContactGCSFolder.h" #import "SOGoContactLDAPFolder.h" #import "SOGoContactFolders.h" @@ -71,7 +72,7 @@ [super dealloc]; } -- (void) appendPersonalSourcesInContext: (WOContext *) context; +- (void) appendPersonalSources { SOGoContactGCSFolder *ab; GCSChannelManager *cm; @@ -87,11 +88,11 @@ fc = [cm acquireOpenChannelForURL: folderLocation]; if (fc) { - sql - = [NSString stringWithFormat: @"SELECT c_path4, c_foldername FROM %@" - @" WHERE c_path2 = '%@' AND c_folder_type = 'Contact'", - [folderLocation gcsTableName], - [self ownerInContext: nil]]; + sql = [NSString + stringWithFormat: (@"SELECT c_path4, c_foldername FROM %@" + @" WHERE c_path2 = '%@'" + @" AND c_folder_type = 'Contact'"), + [folderLocation gcsTableName], [self ownerInContext: context]]; [fc evaluateExpressionX: sql]; attrs = [fc describeResults: NO]; row = [fc fetchAttributes: attrs withZone: NULL]; @@ -112,6 +113,28 @@ } } +- (void) appendSystemSources +{ + LDAPUserManager *um; + NSEnumerator *sourceIDs; + NSString *currentSourceID, *displayName; + SOGoContactLDAPFolder *currentFolder; + + um = [LDAPUserManager sharedUserManager]; + sourceIDs = [[um addressBookSourceIDs] objectEnumerator]; + currentSourceID = [sourceIDs nextObject]; + while (currentSourceID) + { + displayName = [um displayNameForSourceWithID: currentSourceID]; + currentFolder = [SOGoContactLDAPFolder contactFolderWithName: currentSourceID + andDisplayName: displayName + inContainer: self]; + [currentFolder setLDAPSource: [um sourceWithID: currentSourceID]]; + [contactFolders setObject: currentFolder forKey: currentSourceID]; + currentSourceID = [sourceIDs nextObject]; + } +} + - (WOResponse *) newFolderWithName: (NSString *) name { SOGoContactGCSFolder *newFolder; @@ -119,7 +142,7 @@ newFolder = [SOGoContactGCSFolder contactFolderWithName: name andDisplayName: name - inContainer: [self clientObject]]; + inContainer: self]; if ([newFolder isKindOfClass: [NSException class]]) response = (WOResponse *) newFolder; else @@ -140,42 +163,13 @@ return response; } -- (void) appendSystemSourcesInContext: (WOContext *) context; -{ - NSUserDefaults *ud; - NSEnumerator *ldapABs; - NSDictionary *udAB; - SOGoContactLDAPFolder *ab; - - ud = [NSUserDefaults standardUserDefaults]; - ldapABs = [[ud objectForKey: @"SOGoLDAPAddressBooks"] objectEnumerator]; - udAB = [ldapABs nextObject]; - while (udAB) - { - ab = [SOGoContactLDAPFolder contactFolderWithName: - [udAB objectForKey: @"id"] - andDisplayName: - [udAB objectForKey: @"displayName"] - inContainer: self]; - [ab LDAPSetHostname: [udAB objectForKey: @"hostname"] - setPort: [[udAB objectForKey: @"port"] intValue] - setBindDN: [udAB objectForKey: @"bindDN"] - setBindPW: [udAB objectForKey: @"bindPW"] - setContactIdentifier: [udAB objectForKey: @"idField"] - setUserIdentifier: [udAB objectForKey: @"userIdField"] - setRootDN: [udAB objectForKey: @"rootDN"]]; - [contactFolders setObject: ab forKey: [udAB objectForKey: @"id"]]; - udAB = [ldapABs nextObject]; - } -} - - (void) initContactSources { if (!contactFolders) { contactFolders = [NSMutableDictionary new]; - [self appendPersonalSourcesInContext: context]; - [self appendSystemSourcesInContext: context]; + [self appendPersonalSources]; + [self appendSystemSources]; } } @@ -184,7 +178,6 @@ acquire: (BOOL) acquire { id obj; - id folder; /* first check attributes directly bound to the application */ obj = [super lookupName: name inContext: lookupContext acquire: NO]; @@ -193,10 +186,9 @@ if (!contactFolders) [self initContactSources]; - folder = [contactFolders objectForKey: name]; - obj = ((folder) - ? folder - : [NSException exceptionWithHTTPStatus: 404]); + obj = [contactFolders objectForKey: name]; + if (!obj) + obj = [NSException exceptionWithHTTPStatus: 404]; } return obj; diff --git a/SoObjects/Contacts/SOGoContactGCSFolder.h b/SoObjects/Contacts/SOGoContactGCSFolder.h index 71113a6f..1dd91a53 100644 --- a/SoObjects/Contacts/SOGoContactGCSFolder.h +++ b/SoObjects/Contacts/SOGoContactGCSFolder.h @@ -22,10 +22,12 @@ #ifndef __Contacts_SOGoContactGCSFolder_H__ #define __Contacts_SOGoContactGCSFolder_H__ -#import +#import + #import "SOGoContactFolder.h" -@class NSString, NSArray; +@class NSArray; +@class NSString; @interface SOGoContactGCSFolder : SOGoFolder { diff --git a/SoObjects/Contacts/SOGoContactGCSFolder.m b/SoObjects/Contacts/SOGoContactGCSFolder.m index b050b7a4..42d966dc 100644 --- a/SoObjects/Contacts/SOGoContactGCSFolder.m +++ b/SoObjects/Contacts/SOGoContactGCSFolder.m @@ -47,24 +47,21 @@ return folder; } -- (id ) initWithName: (NSString *) aName - andDisplayName: (NSString *) aDisplayName - inContainer: (SOGoObject *) aContainer +- (void) dealloc { - if ((self = [self initWithName: aName - inContainer: aContainer])) - [self setDisplayName: aDisplayName]; - - return self; + [displayName release]; + [super dealloc]; } -- (void) setDisplayName: (NSString *) aDisplayName +- (id ) initWithName: (NSString *) newName + andDisplayName: (NSString *) newDisplayName + inContainer: (SOGoObject *) newContainer { - if (displayName) - [displayName release]; - displayName = aDisplayName; - if (displayName) - [displayName retain]; + if ((self = [self initWithName: newName + inContainer: newContainer])) + ASSIGN (displayName, newDisplayName); + + return self; } - (NSString *) displayName @@ -156,7 +153,7 @@ qualifier = [self _qualifierForFilter: filter]; records = [[self ocsFolder] fetchFields: fields matchingQualifier: qualifier]; - if (records) + if ([records count] > 1) { ordering = [EOSortOrdering sortOrderingWithKey: sortKey diff --git a/SoObjects/Contacts/SOGoContactLDAPFolder.h b/SoObjects/Contacts/SOGoContactLDAPFolder.h index 88a89063..e6805070 100644 --- a/SoObjects/Contacts/SOGoContactLDAPFolder.h +++ b/SoObjects/Contacts/SOGoContactLDAPFolder.h @@ -23,34 +23,25 @@ #ifndef SOGOCONTACTLDAPFOLDER_H #define SOGOCONTACTLDAPFOLDER_H -#import #import "SOGoContactFolder.h" -@class NSString, NSArray; -@class NGLdapConnection; +@class NSMutableDictionary; + +@class LDAPSource; @interface SOGoContactLDAPFolder : SOGoObject { - NGLdapConnection *connection; - NSString *contactIdentifier; - NSString *userIdentifier; - NSString *rootDN; + NSString *name; NSString *displayName; + id container; + LDAPSource *ldapSource; NSMutableDictionary *entries; } -- (NGLdapConnection *) LDAPconnection; - -- (void) setDisplayName: (NSString *) aDisplayName; -- (NSString *) displayName; - -- (void) LDAPSetHostname: (NSString *) aHostname - setPort: (int) aPort - setBindDN: (NSString *) aBindDN - setBindPW: (NSString *) aBindPW - setContactIdentifier: (NSString *) aCI - setUserIdentifier: (NSString *) aUI - setRootDN: (NSString *) aRootDN; +- (id ) initWithName: (NSString *) newName + andDisplayName: (NSString *) newDisplayName + inContainer: (SOGoObject *) newContainer; +- (void) setLDAPSource: (LDAPSource *) newLdapSource; @end diff --git a/SoObjects/Contacts/SOGoContactLDAPFolder.m b/SoObjects/Contacts/SOGoContactLDAPFolder.m index b15ed303..75c19894 100644 --- a/SoObjects/Contacts/SOGoContactLDAPFolder.m +++ b/SoObjects/Contacts/SOGoContactLDAPFolder.m @@ -21,25 +21,19 @@ */ #import -#import - #import #import +#import +#import #import #import #import #import +#import -#import -#import -#import - -#import "common.h" - -#import "NGLdapEntry+Contact.h" - -#import "SOGoContactLDAPEntry.h" +#import +#import "SOGoContactLDIFEntry.h" #import "SOGoContactLDAPFolder.h" #define folderListingFields [NSArray arrayWithObjects: @"c_name", @"cn", \ @@ -75,44 +69,42 @@ { if ((self = [super init])) { - connection = nil; - contactIdentifier = nil; - userIdentifier = nil; - rootDN = nil; + name = nil; + displayName = nil; + container = nil; entries = nil; + ldapSource = nil; } return self; } -- (id ) initWithName: (NSString *) aName - andDisplayName: (NSString *) aDisplayName - inContainer: (SOGoObject *) aContainer +- (id ) initWithName: (NSString *) newName + andDisplayName: (NSString *) newDisplayName + inContainer: (SOGoObject *) newContainer { - if ((self = [self initWithName: aName - inContainer: aContainer])) - [self setDisplayName: aDisplayName]; - + self = [self init]; + + ASSIGN (name, newName); + ASSIGN (displayName, newDisplayName); + ASSIGN (container, newContainer); + return self; } - (void) dealloc { - [connection release]; - [contactIdentifier release]; - [userIdentifier release]; - [rootDN release]; + [name release]; + [displayName release]; + [container release]; [entries release]; + [ldapSource release]; [super dealloc]; } -- (void) setDisplayName: (NSString *) aDisplayName +- (void) setLDAPSource: (LDAPSource *) newLDAPSource { - if (displayName) - [displayName release]; - displayName = aDisplayName; - if (displayName) - [displayName retain]; + ASSIGN (ldapSource, newLDAPSource); } - (NSString *) displayName @@ -120,178 +112,30 @@ return displayName; } -- (void) LDAPSetHostname: (NSString *) aHostname - setPort: (int) aPort - setBindDN: (NSString *) aBindDN - setBindPW: (NSString *) aBindPW - setContactIdentifier: (NSString *) aCI - setUserIdentifier: (NSString *) aUI - setRootDN: (NSString *) aRootDN; -{ - connection = [[NGLdapConnection alloc] initWithHostName: aHostname - port: aPort]; - [connection bindWithMethod: nil - binddn: aBindDN - credentials: aBindPW]; - - if (rootDN) - [rootDN release]; - rootDN = [aRootDN copy]; - if (contactIdentifier) - [contactIdentifier release]; - contactIdentifier = [aCI copy]; - if (userIdentifier) - [userIdentifier release]; - userIdentifier = [aUI copy]; -} - -- (NGLdapConnection *) LDAPconnection +- (NSString *) nameInContainer { - return connection; + return name; } -- (NGLdapAttribute *) _attrWithName: (NSString *) aName -{ - return [[[NGLdapAttribute alloc] initWithAttributeName: aName] autorelease]; -} - -- (NSArray *) _searchAttributes -{ - return [NSArray arrayWithObjects: - contactIdentifier, - userIdentifier, - @"title", - @"company", - @"o", - @"displayName", - @"modifytimestamp", - @"mozillaHomeState", - @"mozillaHomeUrl", - @"homeurl", - @"st", - @"region", - @"mozillaCustom2", - @"custom2", - @"mozillaHomeCountryName", - @"description", - @"notes", - @"department", - @"departmentnumber", - @"ou", - @"orgunit", - @"mobile", - @"cellphone", - @"carphone", - @"mozillaCustom1", - @"custom1", - @"mozillaNickname", - @"xmozillanickname", - @"mozillaWorkUrl", - @"workurl", - @"fax", - @"facsimileTelephoneNumber", - @"telephoneNumber", - @"mozillaHomeStreet", - @"mozillaSecondEmail", - @"xmozillasecondemail", - @"mozillaCustom4", - @"custom4", - @"nsAIMid", - @"nscpaimscreenname", - @"street", - @"streetAddress", - @"postOfficeBox", - @"homePhone", - @"cn", - @"commonname", - @"givenName", - @"mozillaHomePostalCode", - @"mozillaHomeLocalityName", - @"mozillaWorkStreet2", - @"mozillaUseHtmlMail", - @"xmozillausehtmlmail", - @"mozillaHomeStreet2", - @"postalCode", - @"zip", - @"c", - @"countryname", - @"pager", - @"pagerphone", - @"mail", - @"sn", - @"surname", - @"mozillaCustom3", - @"custom3", - @"l", - @"locality", - @"birthyear", - @"serialNumber", - @"calFBURL", - nil]; -} - -- (void) _loadEntries: (NSString *) entryId -{ - NSEnumerator *contacts; - NGLdapEntry *entry; - NSString *key; - - if (!entries) - entries = [NSMutableDictionary new]; - - if (entryId) - { - if (![entries objectForKey: entryId]) - { - entry - = [connection entryAtDN: - [NSString stringWithFormat: @"%@=%@,%@", - contactIdentifier, entryId, rootDN] - attributes: [self _searchAttributes]]; - if (entry) - [entries setObject: entry forKey: entryId]; - } - } - else - { - contacts = [connection deepSearchAtBaseDN: rootDN - qualifier: nil - attributes: [self _searchAttributes]]; - if (contacts) - { - entry = [contacts nextObject]; - while (entry) - { - key = [[entry attributeWithName: contactIdentifier] - stringValueAtIndex: 0]; - if (key && ![entries objectForKey: key]) - [entries setObject: entry forKey: key]; - entry = [contacts nextObject]; - } - } - } -} - -- (id) lookupName: (NSString *) name +- (id) lookupName: (NSString *) objectName inContext: (WOContext *) lookupContext acquire: (BOOL) acquire { id obj; - NGLdapEntry *entry; + NSDictionary *ldifEntry; // NSLog (@"looking up name '%@'...", name); /* first check attributes directly bound to the application */ - obj = [super lookupName: name inContext: lookupContext acquire: NO]; + obj = [super lookupName: objectName inContext: lookupContext acquire: NO]; if (!obj) { - [self _loadEntries: name]; - entry = [entries objectForKey: name]; - obj = ((entry) - ? [SOGoContactLDAPEntry contactEntryWithName: name - withLDAPEntry: entry - inContainer: self] - : [NSException exceptionWithHTTPStatus: 404]); + ldifEntry = [ldapSource lookupContactEntry: objectName]; + obj = ((ldifEntry) + ? [SOGoContactLDIFEntry contactEntryWithName: name + withLDIFEntry: ldifEntry + inContainer: self] + : [NSException exceptionWithHTTPStatus: 404]); } return obj; @@ -299,83 +143,21 @@ - (NSArray *) toOneRelationshipKeys { - [self _loadEntries: nil]; - - return [entries allKeys]; -} - -- (id ) lookupContactWithId: (NSString *) recordId -{ - NGLdapEntry *entry; - - [self _loadEntries: recordId]; - - entry = [entries objectForKey: recordId]; - return ((entry) - ? [SOGoContactLDAPEntry contactEntryWithName: recordId - withLDAPEntry: entry - inContainer: self] - : nil); -} - -- (EOQualifier *) _qualifierForFilter: (NSString *) filter -{ - NSString *qs; - EOQualifier *qualifier; - - if (filter && [filter length] > 0) - { - if ([filter isEqualToString: @"."]) - qs = @"(cn='*')"; - else - qs = [NSString stringWithFormat: - @"(cn='%@*')" - @"OR (sn='%@*')" - @"OR (displayName='%@*')" - @"OR (mail='%@*')" - @"OR (telephoneNumber='*%@*')", - filter, filter, filter, filter, filter]; - qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; - } - else - qualifier = nil; - - return qualifier; + return [ldapSource allEntryIDs]; } - (NSArray *) lookupContactsWithFilter: (NSString *) filter sortBy: (NSString *) sortKey ordering: (NSComparisonResult) sortOrdering { - NSMutableArray *records; - NSArray *result; - NGLdapEntry *entry; - NSEnumerator *contacts; + NSArray *records, *result; EOSortOrdering *ordering; result = nil; if (filter && [filter length] > 0) { - NSLog (@"%@: fetching records matching '%@', sorted by '%@'" - @" in order %d", - self, filter, sortKey, sortOrdering); - - records = [NSMutableArray new]; - [records autorelease]; - - contacts = [connection deepSearchAtBaseDN: rootDN - qualifier: [self _qualifierForFilter: filter] - attributes: folderListingFields]; - entry = [contacts nextObject]; - while (entry) - { - [records addObject: [entry asDictionaryWithAttributeNames: nil - withUID: userIdentifier - andCName: contactIdentifier]]; - entry = [contacts nextObject]; - } - + records = [ldapSource fetchContactsMatching: filter]; ordering = [EOSortOrdering sortOrderingWithKey: sortKey selector: ((sortOrdering == NSOrderedDescending) diff --git a/SoObjects/Contacts/product.plist b/SoObjects/Contacts/product.plist index 349d27ec..843eda8b 100644 --- a/SoObjects/Contacts/product.plist +++ b/SoObjects/Contacts/product.plist @@ -18,25 +18,26 @@ }; SOGoContactGCSFolder = { - superclass = "SOGoFolder"; + superclass = "SOGoFolder"; }; SOGoContactGCSEntry = { - superclass = "SOGoContentObject"; + superclass = "SOGoContentObject"; defaultRoles = { "View" = ( "Owner", "Delegate", "Organizer", "Authenticated" ); }; }; SOGoContactLDAPFolder = { - superclass = "SOGoFolder"; + superclass = "SOGoFolder"; + defaultAccess = "allow"; + protectedBy = ""; }; - SOGoContactLDAPEntry = { + SOGoContactLDIFEntry = { superclass = "SOGoContentObject"; - defaultRoles = { - "View" = ( "Owner", "Delegate", "Organizer", "Authenticated" ); - }; + defaultAccess = "allow"; + protectedBy = ""; }; }; } diff --git a/SoObjects/Mailer/SOGoDraftObject.m b/SoObjects/Mailer/SOGoDraftObject.m index 8b9ad4c2..2e913702 100644 --- a/SoObjects/Mailer/SOGoDraftObject.m +++ b/SoObjects/Mailer/SOGoDraftObject.m @@ -773,6 +773,25 @@ static NSString *fromInternetSuffixPattern = nil; return ma; } +- (NSString *) _rawSender +{ + NSString *startEmail, *rawSender; + NSRange delimiter; + + startEmail = [self sender]; + delimiter = [startEmail rangeOfString: @"<"]; + if (delimiter.location == NSNotFound) + rawSender = startEmail; + else + { + rawSender = [startEmail substringFromIndex: NSMaxRange (delimiter)]; + delimiter = [rawSender rangeOfString: @">"]; + rawSender = [rawSender substringToIndex: delimiter.location]; + } + + return rawSender; +} + - (NSException *)sendMimeMessageAtPath:(NSString *)_path { static NGSendMail *mailer = nil; NSArray *recipients; @@ -781,7 +800,7 @@ static NSString *fromInternetSuffixPattern = nil; /* validate */ recipients = [self allRecipients]; - from = [self sender]; + from = [self _rawSender]; if ([recipients count] == 0) { return [NSException exceptionWithHTTPStatus:500 /* server error */ reason:@"draft has no recipients set!"]; diff --git a/SoObjects/Mailer/SOGoUser+Mail.m b/SoObjects/Mailer/SOGoUser+Mail.m index 2b3c6834..00b5561c 100644 --- a/SoObjects/Mailer/SOGoUser+Mail.m +++ b/SoObjects/Mailer/SOGoUser+Mail.m @@ -60,8 +60,8 @@ account = [self valueForKey:@"primaryIMAP4AccountString"]; identity = [[[SOGoMailIdentity alloc] init] autorelease]; - [identity setName:[self cn]]; - [identity setEmail:[self email]]; + [identity setName: [self cn]]; + [identity setEmail: [self primaryEmail]]; [identity setSentFolderName:[self agenorSentFolderForAccount:account]]; return identity; } diff --git a/SoObjects/SOGo/AgenorUserDefaults.m b/SoObjects/SOGo/AgenorUserDefaults.m index 1069645b..ff553d75 100644 --- a/SoObjects/SOGo/AgenorUserDefaults.m +++ b/SoObjects/SOGo/AgenorUserDefaults.m @@ -104,7 +104,7 @@ static NSString *uidColumnName = @"uid"; { GCSChannelManager *cm; EOAdaptorChannel *channel; - NSDictionary *row; + NSDictionary *row, *oldValues; NSException *ex; NSString *sql; NSArray *attrs; @@ -122,15 +122,15 @@ static NSString *uidColumnName = @"uid"; @" WHERE %@ = '%@'"), fieldName, [[self tableURL] gcsTableName], uidColumnName, [self uid]]; - + + [values release]; + values = [NSMutableDictionary new]; + /* run SQL */ ex = [channel evaluateExpressionX: sql]; if (ex) - { - [self errorWithFormat:@"could not run SQL '%@': %@", sql, ex]; - values = [NSMutableDictionary new]; - } + [self errorWithFormat:@"could not run SQL '%@': %@", sql, ex]; else { /* fetch schema */ @@ -142,14 +142,10 @@ static NSString *uidColumnName = @"uid"; [channel cancelFetch]; /* remember values */ - [values release]; - values = [[row objectForKey: fieldName] propertyList]; - if (values) - [values retain]; - else - values = [NSMutableDictionary new]; + oldValues = [[row objectForKey: fieldName] propertyList]; + [values setDictionary: oldValues]; - ASSIGN(lastFetch, [NSCalendarDate date]); + ASSIGN (lastFetch, [NSCalendarDate date]); defFlags.modified = NO; rc = YES; } diff --git a/SoObjects/SOGo/AgenorUserManager.h b/SoObjects/SOGo/AgenorUserManager.h deleted file mode 100644 index 2ad60909..00000000 --- a/SoObjects/SOGo/AgenorUserManager.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - Copyright (C) 2004-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. -*/ - -#ifndef __AgenorUserManager_H_ -#define __AgenorUserManager_H_ - -#import - -/* - AgenorUserManager - - TODO: document -*/ - -@class NSString, NSArray, NSURL, NSUserDefaults, NSMutableDictionary, NSTimer; -@class NSDictionary; -@class iCalPerson; - -@interface AgenorUserManager : NSObject -{ - NSMutableDictionary *cnCache; - NSMutableDictionary *serverCache; - NSMutableDictionary *uidCache; - NSMutableDictionary *emailCache; - NSMutableDictionary *shareStoreCache; - NSMutableDictionary *shareEMailCache; - NSMutableDictionary *changeInternetAccessCache; - NSMutableDictionary *internetAutoresponderFlagCache; - NSMutableDictionary *intranetAutoresponderFlagCache; - NSTimer *gcTimer; -} - -+ (id)sharedUserManager; - -- (NSString *)getUIDForEmail:(NSString *)_email; -- (NSString *)getEmailForUID:(NSString *)_uid; - -- (iCalPerson *) iCalPersonWithUid: (NSString *) uid; - -- (NSString *) getUIDForICalPerson: (iCalPerson *) _person; -/* may insert NSNulls into returned array if _mapStrictly -> YES */ -- (NSArray *)getUIDsForICalPersons:(NSArray *)_persons - applyStrictMapping:(BOOL)_mapStrictly; - -/* 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; -- (NSArray *)getSharedMailboxEMailsForUID:(NSString *)_uid; -- (NSDictionary *)getSharedMailboxesAndEMailsForUID:(NSString *)_uid; - -- (NSURL *)getFreeBusyURLForUID:(NSString *)_uid; - -- (NSUserDefaults *) getUserDefaultsForUID: (NSString *) uid; -- (NSUserDefaults *) getUserSettingsForUID: (NSString *) uid; - -- (BOOL)isUserAllowedToChangeSOGoInternetAccess:(NSString *)_uid; - -- (BOOL)isInternetAutoresponderEnabledForUser:(NSString *)_uid; -- (BOOL)isIntranetAutoresponderEnabledForUser:(NSString *)_uid; - -@end - -#endif /* __AgenorUserManager_H_ */ diff --git a/SoObjects/SOGo/AgenorUserManager.m b/SoObjects/SOGo/AgenorUserManager.m deleted file mode 100644 index 6b10fa3f..00000000 --- a/SoObjects/SOGo/AgenorUserManager.m +++ /dev/null @@ -1,1222 +0,0 @@ -/* - Copyright (C) 2004-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 "AgenorUserDefaults.h" -#include -#include -#include -#include "SOGoLRUCache.h" - -#warning we should rely on the LDAP sources instead... -#define qualifierFormat @"uid = %@" - -@interface AgenorUserManager (PrivateAPI) -- (NGLdapConnection *)ldapConnection; - -- (void)_cacheCN:(NSString *)_cn forUID:(NSString *)_uid; -- (NSString *)_cachedCNForUID:(NSString *)_uid; -- (void)_cacheServer:(NSString *)_server forUID:(NSString *)_uid; -- (NSString *)_cachedServerForUID:(NSString *)_uid; -- (void)_cacheEmail:(NSString *)_email forUID:(NSString *)_uid; -- (NSString *)_cachedEmailForUID:(NSString *)_uid; -- (void)_cacheUID:(NSString *)_uid forEmail:(NSString *)_email; -- (NSString *)_cachedUIDForEmail:(NSString *)_email; - -- (BOOL)primaryIsUserAllowedToChangeSOGoInternetAccess:(NSString *)_uid; - -- (BOOL)primaryIsInternetAutoresponderEnabledForUser:(NSString *)_uid; -- (BOOL)primaryIsIntranetAutoresponderEnabledForUser:(NSString *)_uid; -- (NGLdapAttribute *)primaryGetMailAutoresponderAttribute:(NSString *)_uid; -- (BOOL)isAutoresponderEnabledForAttribute:(NGLdapAttribute *)_attr - matchingPrefix:(NSString *)_prefix; -@end - -// TODO: add a timer to flush LRU caches every some hours - -@implementation AgenorUserManager - -static BOOL debugOn = NO; -static BOOL useLDAP = NO; -static NSString *ldapHost = nil; -static NSString *ldapBaseDN = nil; -static NSNull *sharedNull = nil; -static NSString *fallbackIMAP4Server = nil; -static NSString *defaultMailDomain = nil; -static NSString *shareLDAPClass = @"mineqMelBoite"; -static NSString *shareLoginSeparator = @".-."; -static NSString *mailEmissionAttrName = @"mineqMelmailEmission"; -static NSString *changeInternetAccessAttrName = @"mineqOgoAccesInternet"; -static NSString *mailAutoresponderAttrName = @"mineqMelReponse"; /* sic! */ -static NSURL *AgenorProfileURL = nil; - -static NSArray *fromEMailAttrs = nil; - -static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; - -+ (void) initialize -{ - static BOOL didInit = NO; - NSUserDefaults *ud; - NSString *tmp; - - if (didInit) return; - didInit = YES; - - ud = [NSUserDefaults standardUserDefaults]; - debugOn = [ud boolForKey:@"SOGoUserManagerDebugEnabled"]; - - useLDAP = [ud boolForKey:@"SOGoUserManagerUsesLDAP"]; - if (useLDAP) { - ldapHost = [[ud stringForKey:@"LDAPHost"] copy]; - ldapBaseDN = [[ud stringForKey:@"LDAPRootDN"] 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 - { - if (fallbackIMAP4Server) - [fallbackIMAP4Server release]; - fallbackIMAP4Server = nil; - } - - defaultMailDomain = [[ud stringForKey:@"SOGoDefaultMailDomain"] copy]; - if ([defaultMailDomain length] == 0) - { - if (defaultMailDomain) - [defaultMailDomain release]; - defaultMailDomain = nil; - NSLog(@"WARNING: no default mail domain (please specify" - " 'SOGoDefaultMailDomain' in the user default db)"); - } - - fromEMailAttrs = - [[NSArray alloc] initWithObjects:mailEmissionAttrName, nil]; - - sharedNull = [[NSNull null] retain]; - - /* profile database URL */ - - if ((tmp = [ud stringForKey:@"AgenorProfileURL"]) == nil) - NSLog(@"ERROR: no 'AgenorProfileURL' database URL configured!"); - else if ((AgenorProfileURL = [[NSURL alloc] initWithString:tmp]) == nil) - NSLog(@"ERROR: could not parse AgenorProfileURL: '%@'", tmp); - else - NSLog(@"Note: using profile at: %@", [AgenorProfileURL absoluteString]); - - if ((tmp = [ud stringForKey: @"SOGoDefaultMailDomain"])) - { - defaultMailDomain = [tmp copy]; - } - - 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 { - static AgenorUserManager *mgr = nil; - if (mgr == nil) - mgr = [[self alloc] init]; - return mgr; -} - -- (id)init { - self = [super init]; - if(self) { - serverCache = - [[NSMutableDictionary alloc] initWithCapacity:10000]; - cnCache = - [[NSMutableDictionary alloc] initWithCapacity:10000]; - uidCache = - [[NSMutableDictionary alloc] initWithCapacity:10000]; - emailCache = - [[NSMutableDictionary alloc] initWithCapacity:10000]; - shareStoreCache = - [[NSMutableDictionary alloc] initWithCapacity:10000]; - shareEMailCache = - [[NSMutableDictionary alloc] initWithCapacity:10000]; - changeInternetAccessCache = - [[NSMutableDictionary alloc] initWithCapacity:10000]; - internetAutoresponderFlagCache = - [[NSMutableDictionary alloc] initWithCapacity:10000]; - intranetAutoresponderFlagCache = - [[NSMutableDictionary alloc] initWithCapacity:10000]; - - gcTimer = [[NSTimer scheduledTimerWithTimeInterval: - PoolScanInterval - target:self selector:@selector(_garbageCollect:) - userInfo:nil repeats:YES] retain]; - } - return self; -} - -- (void)dealloc { - if (gcTimer) [gcTimer invalidate]; - [serverCache release]; - [cnCache release]; - [uidCache release]; - [emailCache release]; - [shareStoreCache release]; - [shareEMailCache release]; - [changeInternetAccessCache release]; - [internetAutoresponderFlagCache release]; - [intranetAutoresponderFlagCache release]; - [gcTimer release]; - [super dealloc]; -} - -/* cache */ - -- (void)flush { - [cnCache removeAllObjects]; - [serverCache removeAllObjects]; - [uidCache removeAllObjects]; - [emailCache removeAllObjects]; - [shareStoreCache removeAllObjects]; - [shareEMailCache removeAllObjects]; - - [changeInternetAccessCache removeAllObjects]; - [internetAutoresponderFlagCache removeAllObjects]; - [intranetAutoresponderFlagCache removeAllObjects]; -} - -- (void)_garbageCollect:(NSTimer *)_timer { - [self debugWithFormat:@"flushing caches."]; - [self flush]; -} - -/* LDAP */ - -- (NGLdapConnection *)ldapConnection { - static NGLdapConnection *ldapConnection = nil; - if(!ldapConnection) { - ldapConnection = [[NGLdapConnection alloc] initWithHostName: ldapHost]; -#if 0 - [ldapConnection setUseCache:YES]; -#endif - } - return ldapConnection; -} - - -/* private cache helpers */ -// TODO: this is really unnecessary, no? - -- (void)_cacheCN:(NSString *)_cn forUID:(NSString *)_uid { - if (_cn == nil) return; - [cnCache setObject:_cn forKey:_uid]; -} -- (NSString *)_cachedCNForUID:(NSString *)_uid { - return [cnCache objectForKey:_uid]; -} - -- (void)_cacheServer:(NSString *)_server forUID:(NSString *)_uid { - if (_server == nil) return; - [serverCache setObject:_server forKey:_uid]; -} -- (NSString *)_cachedServerForUID:(NSString *)_uid { - return [serverCache objectForKey:_uid]; -} - -- (void)_cacheEmail:(NSString *)_email forUID:(NSString *)_uid { - if (_email == nil) return; - [emailCache setObject:_email forKey:_uid]; -} -- (NSString *)_cachedEmailForUID:(NSString *)_uid { - return [emailCache objectForKey:_uid]; -} - -- (void)_cacheUID:(NSString *)_uid forEmail:(NSString *)_email { - if (_uid == nil) return; - [uidCache setObject:_uid forKey:_email]; -} -- (NSString *)_cachedUIDForEmail:(NSString *)_email { - return [uidCache objectForKey:_email]; -} - - -/* uid <-> email mapping */ - -/* - UPDATE: the email excerpt below has been marked by Maxime as being - wrong. This algorithm can not be expected to work, thus - the mapping has been replaced with an LDAP query. - - --- snip --- - The uid field is in bijection this the email adress : - this field can be construct from the email. Email are uniques. - - So, we can use email adresse from identifier. - The field is made like this : - _ if the email is equipement.gouv.fr then the login - is the part before the @ - for example : fisrtName.lastName - _ if the email is not equipement.gouv.fr then the login - is the full email adress where @ is change to . (dot) - for example : fisrtName.lastName.subDomain.domain.tld - --- snap --- - - NOTE: mapping email -> uid is easy, but can also generate uid's not known - to the system (i.e. for private addressbook entries, obvious). - The reverse mapping can work _only_ if "firstName.lastname." is - guaranteed, because the second dot would be mapped to '@'. This - is probably error prone. - Only LDAP fetches would guarantee correctness in both cases. -*/ - -- (NSString *)primaryGetAgenorUIDForEmail:(NSString *)_email { - 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]; - - 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; - } - uidAttr = [entry attributeWithName:@"uid"]; - if (!uidAttr) - return nil; /* can happen, not unlikely */ - uid = [uidAttr stringValueAtIndex:0]; - return uid; -} - -- (NSString *) getUIDForEmail: (NSString *)_email -{ - NSString *uid; - NSRange r; - NSString *domain; - - uid = nil; - if ([_email length] > 0) - { - uid = [self _cachedUIDForEmail:_email]; - if (!uid) - { - if (useLDAP) - uid = [self primaryGetAgenorUIDForEmail:_email]; - - if (!uid) - { - r = [_email rangeOfString:@"@"]; - if (r.length == 0) - return nil; - - domain = [_email substringFromIndex:NSMaxRange(r)]; - if (![domain isEqualToString:defaultMailDomain]) - uid = _email; - else - uid = [_email substringToIndex:r.location]; - } - if (uid) - [self _cacheUID:uid forEmail:_email]; - } - } - - return uid; -} - -#warning big ugly hack. LDAP lookup should be fixed -- (NSString *) getUIDForICalPerson: (iCalPerson *) _person -{ - NSString *domainString, *email, *uid; - - domainString = [NSString stringWithFormat: @"@%@", defaultMailDomain]; - email = [_person rfc822Email]; - if ([email hasSuffix: domainString]) - uid = [_person cn]; - else - uid = [self getUIDForEmail: email]; - - return uid; -} - - /* may insert NSNulls into returned array */ -- (NSArray *)getUIDsForICalPersons:(NSArray *)_persons - applyStrictMapping:(BOOL)_mapStrictly -{ - NSMutableArray *ma; - unsigned i, count; - - count = [_persons count]; - ma = [[[NSMutableArray alloc] initWithCapacity:count] autorelease]; - for (i = 0; i < count; i++) { - iCalPerson *p; - id uid; - - p = [_persons objectAtIndex:i]; - uid = [self getUIDForICalPerson:p]; - if (uid != nil) - [ma addObject:uid]; - else if (uid == nil && _mapStrictly) - [ma addObject:sharedNull]; - } - return ma; -} - -- (NSString *)primaryGetEmailForAgenorUID:(NSString *)_uid { - NGLdapConnection *conn; - EOQualifier *q; - NSEnumerator *resultEnum; - NGLdapEntry *entry; - NGLdapAttribute *emailAttr; - NSString *email; - unsigned count; - - q = [EOQualifier qualifierWithQualifierFormat: qualifierFormat, _uid]; - - conn = [self ldapConnection]; - resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN - qualifier:q - attributes:fromEMailAttrs]; - 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:mailEmissionAttrName]; - if (emailAttr == nil) - return nil; /* shit happens */ - - email = nil; - count = [emailAttr count]; -#if 0 // TODO: explain why this is commented out! - if (count > 1) { - unsigned i; - - /* in case there are multiple email addresses, select the first - which doesn't have '@equipement.gouv.fr' in it */ - for (i = 0; i < count; i++) { - NSString *candidate; - - candidate = [emailAttr stringValueAtIndex:i]; - if (![candidate hasSuffix:defaultMailDomain]) { - // TODO: also check for '@' - email = candidate; - break; - } - } - } -#endif - if (email == nil && count > 0) - email = [emailAttr stringValueAtIndex:0]; - - return email; -} - -- (NSString *)getEmailForUID:(NSString *)_uid -{ - NSString *email; - NSRange r; - - email = nil; - - if ([_uid length] > 0) - { - email = [self _cachedEmailForUID: _uid]; - if (!email) - { - if (useLDAP) - email = [self primaryGetEmailForAgenorUID:_uid]; - - if (!email) - { - r = [_uid rangeOfString:@"@"]; - email = ((r.length > 0) - ? _uid - : [[_uid stringByAppendingString:@"@"] - stringByAppendingString: defaultMailDomain]); - } - - if (email) - [self _cacheEmail: email forUID: _uid]; - } - } - - return email; -} - - -/* CN */ - -- (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: qualifierFormat, _uid]; - - 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 == 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]; - 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; - NSRange r; - - s = _uid; - if ([s length] < 10) - return s; - - // TODO: algorithm might be inappropriate, depends on the actual UID - r = [s rangeOfString:@"."]; - if (r.length == 0) - cn = s; - else - cn = [s substringToIndex:r.location]; - } - - [self _cacheCN:cn forUID:_uid]; - return cn; -} - - -/* Servers, IMAP */ - -- (NSString *)getIMAPAccountStringForUID:(NSString *)_uid { - NSString *server; - - server = [self getServerForUID:_uid]; - if (server == nil) - return nil; - return [NSString stringWithFormat:@"%@@%@", _uid, server]; -} - -- (NSArray *)mailServerDiscoveryAttributes { - static NSArray *attrs = nil; - - if (attrs == nil) { - attrs = [[NSArray alloc] initWithObjects: - @"uid", /* required for shares */ - @"mineqMelRoutage", - @"mineqMelServeurPrincipal", - @"mineqMelPartages", - mailEmissionAttrName, - 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: qualifierFormat, _uid]; - - conn = [self ldapConnection]; - resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN - qualifier:q - attributes:[self mailServerDiscoveryAttributes]]; - /* 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; - } - return entry; -} - -- (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]; - serverCandidates = [NSMutableArray arrayWithCapacity:count]; - 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) { -#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 - 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; - - if ((entry = [self _fetchEntryForAgenorUID:_uid]) == nil) - return nil; - - if ((server = [self serverFromEntry:entry]) != 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 { - NSString *server; - - 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 != nil) - server = fallbackIMAP4Server; - else { - [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; -} - -/* 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 = [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]; - [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))" - "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! - - 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. - */ - NSMutableDictionary *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; - } - - /* check cache */ - if ((shares = [shareStoreCache objectForKey:_uid]) != nil) - return shares; - - 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, emitterAddress; - - /* calculate server connect string */ - - 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 = [NSMutableDictionary dictionaryWithCapacity:4]; - - shareLogin = [shareLogin stringByAppendingString:@"@"]; - shareLogin = [shareLogin stringByAppendingString:server]; - - /* calculate emitter address (check for proper access right) */ - - if ([self hasUser:_uid partageAccess:"GC" inEntry:entry]) - emitterAddress = [self emissionEMailFromEntry:entry]; - else - emitterAddress = [NSNull null]; - - /* set value */ - - [shares setObject: emitterAddress - forKey: shareLogin]; - } - - /* cache */ - shares = (shares == nil) - ? [NSDictionary dictionary] - : [[shares copy] autorelease]; - [shareStoreCache setObject:shares forKey:_uid]; - return shares; -} - -/* free busy */ - -- (NSURL *)getFreeBusyURLForUID:(NSString *)_uid { - [self logWithFormat:@"TODO(%s): implement", __PRETTY_FUNCTION__]; - return nil; -} - -/* defaults */ - -- (NSUserDefaults *) _getUserDefaultsForUID: (NSString *) uid - fieldName: (NSString *) fieldName -{ - id defaults; - - if (AgenorProfileURL) - { - /* Note: do not cache, otherwise updates can be quite tricky */ - defaults = [[AgenorUserDefaults alloc] initWithTableURL: AgenorProfileURL - uid: uid fieldName: fieldName]; - [defaults autorelease]; - } - else - { - [self warnWithFormat: - @"no profile configured, cannot retrieve defaults for user: '%@'", - uid]; - return defaults = nil; - } - - return defaults; -} - -- (NSUserDefaults *) getUserDefaultsForUID: (NSString *) uid -{ - return [self _getUserDefaultsForUID: uid fieldName: @"defaults"]; -} - -- (NSUserDefaults *) getUserSettingsForUID: (NSString *) uid -{ - return [self _getUserDefaultsForUID: uid fieldName: @"settings"]; -} - -/* internet access lock */ - -- (BOOL)isUserAllowedToChangeSOGoInternetAccess:(NSString *)_uid { - NSNumber *bv; - - bv = [changeInternetAccessCache objectForKey:_uid]; - if (!bv) { - BOOL value; - - value = [self primaryIsUserAllowedToChangeSOGoInternetAccess:_uid]; - bv = [NSNumber numberWithBool:value]; - [changeInternetAccessCache setObject:bv forKey:_uid]; - } - return [bv boolValue]; -} - -- (BOOL)primaryIsUserAllowedToChangeSOGoInternetAccess:(NSString *)_uid { - static NSArray *attrs = nil; - NGLdapConnection *conn; - EOQualifier *q; - NSEnumerator *resultEnum; - NGLdapEntry *entry; - NGLdapAttribute *attr; - NSString *value; - - if (attrs == nil) - attrs = [[NSArray alloc] initWithObjects:changeInternetAccessAttrName, nil]; - - q = [EOQualifier qualifierWithQualifierFormat: qualifierFormat, _uid]; - - conn = [self ldapConnection]; - resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN - qualifier:q - attributes:attrs]; - entry = [resultEnum nextObject]; - if (entry == nil) { - if(debugOn) { - [self logWithFormat:@"%s Didn't find LDAP entry for uid '%@'!", - __PRETTY_FUNCTION__, - _uid]; - } - return NO; - } - attr = [entry attributeWithName:changeInternetAccessAttrName]; - if(attr == nil && debugOn) { - [self logWithFormat:@"%s LDAP entry for uid '%@' " - @"has no mineqOgoAccesInternet attribute?", - __PRETTY_FUNCTION__, - _uid]; - return NO; /* nothing we can do about it */ - } - value = [attr stringValueAtIndex:0]; - return [value boolValue]; -} - -- (BOOL) isInternetAutoresponderEnabledForUser: (NSString *) _uid -{ - NSNumber *bv; - BOOL value; - - bv = [internetAutoresponderFlagCache objectForKey:_uid]; - if (!bv) { - value = [self primaryIsInternetAutoresponderEnabledForUser:_uid]; - bv = [NSNumber numberWithBool:value]; - [internetAutoresponderFlagCache setObject:bv forKey:_uid]; - } - return [bv boolValue]; -} - -- (BOOL) primaryIsInternetAutoresponderEnabledForUser: (NSString *) _uid -{ - NGLdapAttribute *attr; - - attr = [self primaryGetMailAutoresponderAttribute:_uid]; - if (!attr) return NO; - - return [self isAutoresponderEnabledForAttribute: attr - matchingPrefix: @"60~"]; -} - -- (BOOL) isIntranetAutoresponderEnabledForUser: (NSString *) _uid -{ - NSNumber *bv; - BOOL value; - - bv = [intranetAutoresponderFlagCache objectForKey:_uid]; - if (!bv) - { - value = [self primaryIsIntranetAutoresponderEnabledForUser:_uid]; - bv = [NSNumber numberWithBool:value]; - [intranetAutoresponderFlagCache setObject:bv forKey:_uid]; - } - - return [bv boolValue]; -} - -- (BOOL) primaryIsIntranetAutoresponderEnabledForUser: (NSString *) _uid -{ - NGLdapAttribute *attr; - - attr = [self primaryGetMailAutoresponderAttribute:_uid]; - if (!attr) return NO; - return [self isAutoresponderEnabledForAttribute:attr matchingPrefix:@"50~"]; -} - -- (BOOL) isAutoresponderEnabledForAttribute: (NGLdapAttribute *)_attr - matchingPrefix: (NSString *)_prefix -{ - unsigned i, count; - - count = [_attr count]; - for (i = 0; i < count; i++) { - NSString *value; - - value = [_attr stringValueAtIndex:i]; - if ([value hasPrefix:_prefix]) { - if ([value rangeOfString:@"DFIN:0"].length > 0) - return NO; - return YES; - } - } - - return NO; -} - -- (NGLdapAttribute *) primaryGetMailAutoresponderAttribute: (NSString *) _uid -{ - static NSArray *attrs = nil; - NGLdapConnection *conn; - EOQualifier *q; - NSEnumerator *resultEnum; - NGLdapEntry *entry; - NGLdapAttribute *attr; - - if (attrs == nil) - attrs = [[NSArray alloc] initWithObjects:mailAutoresponderAttrName, nil]; - - q = [EOQualifier qualifierWithQualifierFormat: qualifierFormat, _uid]; - - conn = [self ldapConnection]; - resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN - qualifier:q - attributes:attrs]; - entry = [resultEnum nextObject]; - if (entry == nil) { - if(debugOn) { - [self logWithFormat:@"%s Didn't find LDAP entry for uid '%@'!", - __PRETTY_FUNCTION__, - _uid]; - } - return nil; - } - attr = [entry attributeWithName:mailAutoresponderAttrName]; - return attr; -} - -- (iCalPerson *) iCalPersonWithUid: (NSString *) uid -{ - iCalPerson *person; - - person = [iCalPerson new]; - [person autorelease]; - [person setCn: [self getCNForUID: uid]]; - [person setEmail: [self getEmailForUID: uid]]; - - return person; -} - -/* debugging */ - -- (BOOL)isDebuggingEnabled { - return debugOn; -} - -@end /* AgenorUserManager */ diff --git a/SoObjects/SOGo/GNUmakefile b/SoObjects/SOGo/GNUmakefile index 15b79276..3ad28ac9 100644 --- a/SoObjects/SOGo/GNUmakefile +++ b/SoObjects/SOGo/GNUmakefile @@ -8,10 +8,10 @@ include $(GNUSTEP_MAKEFILES)/common.make LIBRARY_NAME = libSOGo TOOL_NAME = \ - agenor_email2uid \ - agenor_shares4uid \ - agenor_emails4uid \ - agenor_defaults +# agenor_email2uid \ +# agenor_shares4uid \ +# agenor_emails4uid \ +# agenor_defaults libSOGo_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION) @@ -28,7 +28,8 @@ libSOGo_HEADER_FILES = \ SOGoGroupFolder.h \ SOGoCustomGroupFolder.h \ \ - AgenorUserManager.h \ + LDAPUserManager.h \ + LDAPSource.h \ SOGoPermissions.h \ SOGoLRUCache.h \ NSArray+Utilities.h \ @@ -53,7 +54,8 @@ libSOGo_OBJC_FILES = \ \ SOGoPermissions.m \ SOGoLRUCache.m \ - AgenorUserManager.m \ + LDAPUserManager.m \ + LDAPSource.m \ NSObject+AptComparison.m \ WOContext+Agenor.m \ SOGoDAVRendererTypes.m \ diff --git a/SoObjects/SOGo/LDAPSource.h b/SoObjects/SOGo/LDAPSource.h new file mode 100644 index 00000000..2af01024 --- /dev/null +++ b/SoObjects/SOGo/LDAPSource.h @@ -0,0 +1,71 @@ +/* LDAPSource.h - this file is part of SOGo + * + * Copyright (C) 2007 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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. + */ + +#ifndef LDAPSOURCE_H +#define LDAPSOURCE_H + +#import + +@class NSDictionary; +@class NSString; +@class NGLdapConnection; + +@interface LDAPSource : NSObject +{ + NSString *bindDN; + NSString *hostname; + unsigned int port; + NSString *password; + + NSString *baseDN; + NSString *IDField; /* the first part of a user DN */ + NSString *CNField; + NSString *UIDField; + + NGLdapConnection *ldapConnection; + NSMutableArray *searchAttributes; +} + ++ (id) sourceFromUDSource: (NSDictionary *) udSource; + +- (id) initFromUDSource: (NSDictionary *) udSource; + +- (void) setBindDN: (NSString *) newBindDN + hostname: (NSString *) newBindHostname + port: (NSString *) newBindPort + andPassword: (NSString *) newBindPassword; +- (void) setBaseDN: (NSString *) newBaseDN + IDField: (NSString *) newIDField + CNField: (NSString *) newCNField + andUIDField: (NSString *) newUIDField; + +- (BOOL) checkLogin: (NSString *) login + andPassword: (NSString *) password; + +- (NSDictionary *) lookupContactEntry: (NSString *) entryID; +- (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) entryID; +- (NSArray *) allEntryIDs; +- (NSArray *) fetchContactsMatching: (NSString *) filter; + +@end + +#endif /* LDAPSOURCE_H */ diff --git a/SoObjects/SOGo/LDAPSource.m b/SoObjects/SOGo/LDAPSource.m new file mode 100644 index 00000000..9b939066 --- /dev/null +++ b/SoObjects/SOGo/LDAPSource.m @@ -0,0 +1,418 @@ +/* LDAPSource.m - this file is part of SOGo + * + * Copyright (C) 2007 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 +#import +#import + +#import +#import +#import +#import + +#import "LDAPSource.h" + +static NSArray *commonSearchFields; + +@implementation LDAPSource + ++ (void) initialize +{ + if (!commonSearchFields) + { + commonSearchFields = [NSArray arrayWithObjects: + @"title", + @"company", + @"o", + @"displayName", + @"modifytimestamp", + @"mozillaHomeState", + @"mozillaHomeUrl", + @"homeurl", + @"st", + @"region", + @"mozillaCustom2", + @"custom2", + @"mozillaHomeCountryName", + @"description", + @"notes", + @"department", + @"departmentnumber", + @"ou", + @"orgunit", + @"mobile", + @"cellphone", + @"carphone", + @"mozillaCustom1", + @"custom1", + @"mozillaNickname", + @"xmozillanickname", + @"mozillaWorkUrl", + @"workurl", + @"fax", + @"facsimileTelephoneNumber", + @"telephoneNumber", + @"mozillaHomeStreet", + @"mozillaSecondEmail", + @"xmozillasecondemail", + @"mozillaCustom4", + @"custom4", + @"nsAIMid", + @"nscpaimscreenname", + @"street", + @"streetAddress", + @"postOfficeBox", + @"homePhone", + @"cn", + @"commonname", + @"givenName", + @"mozillaHomePostalCode", + @"mozillaHomeLocalityName", + @"mozillaWorkStreet2", + @"mozillaUseHtmlMail", + @"xmozillausehtmlmail", + @"mozillaHomeStreet2", + @"postalCode", + @"zip", + @"c", + @"countryname", + @"pager", + @"pagerphone", + @"mail", + @"sn", + @"surname", + @"mozillaCustom3", + @"custom3", + @"l", + @"locality", + @"birthyear", + @"serialNumber", + @"calFBURL", + nil]; + [commonSearchFields retain]; + } +} + ++ (id) sourceFromUDSource: (NSDictionary *) udSource +{ + id newSource; + + newSource = [[self alloc] initFromUDSource: udSource]; + [newSource autorelease]; + + return newSource; +} + +- (id) init +{ + if ((self = [super init])) + { + bindDN = nil; + hostname = nil; + port = 389; + password = nil; + + baseDN = nil; + IDField = @"cn"; /* the first part of a user DN */ + CNField = @"cn"; + UIDField = @"uid"; + + ldapConnection = nil; + searchAttributes = nil; + } + + return self; +} + +- (void) dealloc +{ + [bindDN release]; + [hostname release]; + [password release]; + [baseDN release]; + [IDField release]; + [CNField release]; + [UIDField release]; + [ldapConnection release]; + [super dealloc]; +} + +- (id) initFromUDSource: (NSDictionary *) udSource +{ + self = [self init]; + + [self setBindDN: [udSource objectForKey: @"bindDN"] + hostname: [udSource objectForKey: @"hostname"] + port: [udSource objectForKey: @"port"] + andPassword: [udSource objectForKey: @"bindPassword"]]; + [self setBaseDN: [udSource objectForKey: @"baseDN"] + IDField: [udSource objectForKey: @"IDFieldName"] + CNField: [udSource objectForKey: @"CNFieldName"] + andUIDField: [udSource objectForKey: @"UIDFieldName"]]; + + return self; +} + +- (void) setBindDN: (NSString *) newBindDN + hostname: (NSString *) newBindHostname + port: (NSString *) newBindPort + andPassword: (NSString *) newBindPassword +{ + ASSIGN (bindDN, newBindDN); + ASSIGN (hostname, newBindHostname); + if (newBindPort) + port = [newBindPort intValue]; + ASSIGN (password, newBindPassword); +} + +- (void) setBaseDN: (NSString *) newBaseDN + IDField: (NSString *) newIDField + CNField: (NSString *) newCNField + andUIDField: (NSString *) newUIDField +{ + ASSIGN (baseDN, newBaseDN); + if (newIDField) + ASSIGN (IDField, newIDField); + if (CNField) + ASSIGN (CNField, newCNField); + if (UIDField) + ASSIGN (UIDField, newUIDField); +} + +- (void) _initLDAPConnection +{ + ldapConnection = [[NGLdapConnection alloc] initWithHostName: hostname + port: port]; + [ldapConnection bindWithMethod: @"simple" + binddn: bindDN + credentials: password]; +} + +/* user management */ +- (BOOL) checkLogin: (NSString *) loginToCheck + andPassword: (NSString *) passwordToCheck +{ + BOOL didBind; + NSString *userDN; + NGLdapConnection *bindConnection; + + bindConnection = [[NGLdapConnection alloc] initWithHostName: hostname + port: port]; + userDN = [NSString stringWithFormat: @"%@=%@,%@", + IDField, loginToCheck, baseDN]; + NS_DURING + didBind = [bindConnection bindWithMethod: @"simple" binddn: userDN + credentials: passwordToCheck]; + NS_HANDLER + didBind = NO; + NS_ENDHANDLER + + [bindConnection release]; + + return didBind; +} + +/* contact management */ +- (EOQualifier *) _qualifierForFilter: (NSString *) filter +{ + NSString *qs; + EOQualifier *qualifier; + + if (filter && [filter length] > 0) + { + if ([filter isEqualToString: @"."]) + qs = @"(cn='*')"; + else + qs = [NSString stringWithFormat: + @"(cn='%@*')" + @"OR (sn='%@*')" + @"OR (displayName='%@*')" + @"OR (mail='%@*')" + @"OR (telephoneNumber='*%@*')", + filter, filter, filter, filter, filter]; + qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; + } + else + qualifier = nil; + + return qualifier; +} + +- (EOQualifier *) _qualifierForUIDFilter: (NSString *) uid +{ + NSString *qs; + + qs = [NSString stringWithFormat: (@"(%@='%@') OR (mail='%@')" + @" OR (mozillaSecondEmail='%@')" + @" OR (xmozillasecondemail='%@')"), + UIDField, uid, uid, uid, uid]; + + return [EOQualifier qualifierWithQualifierFormat: qs]; +} + +- (NSArray *) _searchAttributes +{ + if (!searchAttributes) + { + searchAttributes = [NSMutableArray new]; + if (CNField) + [searchAttributes addObject: CNField]; + if (UIDField) + [searchAttributes addObject: UIDField]; + [searchAttributes addObjectsFromArray: commonSearchFields]; + } + + return searchAttributes; +} + +- (NSArray *) allEntryIDs +{ + NSMutableArray *ids; + NSEnumerator *entries; + NGLdapEntry *currentEntry; + NSString *value; + + ids = [NSMutableArray array]; + + if (!ldapConnection) + [self _initLDAPConnection]; + entries = [ldapConnection deepSearchAtBaseDN: baseDN + qualifier: nil + attributes: [NSArray arrayWithObject: IDField]]; + if (entries) + { + currentEntry = [entries nextObject]; + while (currentEntry) + { + value = [[currentEntry attributeWithName: IDField] + stringValueAtIndex: 0]; + if ([value length] > 0) + [ids addObject: value]; + currentEntry = [entries nextObject]; + } + } + + return ids; +} + +- (NSDictionary *) _convertLDAPEntryToContact: (NGLdapEntry *) ldapEntry +{ + NSMutableDictionary *contactEntry; + NSEnumerator *attributes; + NSString *currentAttribute, *value; + + contactEntry = [NSMutableDictionary dictionary]; + attributes = [[self _searchAttributes] objectEnumerator]; + currentAttribute = [attributes nextObject]; + while (currentAttribute) + { + value = [[ldapEntry attributeWithName: currentAttribute] + stringValueAtIndex: 0]; + if (value) + [contactEntry setObject: value forKey: currentAttribute]; + currentAttribute = [attributes nextObject]; + } + value = [[ldapEntry attributeWithName: IDField] stringValueAtIndex: 0]; + if (!value) + value = @""; + [contactEntry setObject: value forKey: @"c_name"]; + value = [[ldapEntry attributeWithName: UIDField] stringValueAtIndex: 0]; + if (!value) + value = @""; + [contactEntry setObject: value forKey: @"c_uid"]; + value = [[ldapEntry attributeWithName: CNField] stringValueAtIndex: 0]; + if (!value) + value = @""; + [contactEntry setObject: value forKey: @"c_cn"]; + + return contactEntry; +} + +- (NSArray *) fetchContactsMatching: (NSString *) match +{ + NSMutableArray *contacts; + NGLdapEntry *currentEntry; + NSEnumerator *entries; + + contacts = [NSMutableArray array]; + + if (!ldapConnection) + [self _initLDAPConnection]; + entries = [ldapConnection deepSearchAtBaseDN: baseDN + qualifier: [self _qualifierForFilter: match] + attributes: [self _searchAttributes]]; + if (entries) + { + currentEntry = [entries nextObject]; + while (currentEntry) + { + [contacts addObject: + [self _convertLDAPEntryToContact: currentEntry]]; + currentEntry = [entries nextObject]; + } + } + + return contacts; +} + +- (NSDictionary *) lookupContactEntry: (NSString *) entryID; +{ + NSDictionary *contactEntry; + NGLdapEntry *ldapEntry; + + if (!ldapConnection) + [self _initLDAPConnection]; + ldapEntry + = [ldapConnection entryAtDN: [NSString stringWithFormat: @"%@=%@,%@", + IDField, entryID, baseDN] + attributes: [self _searchAttributes]]; + if (ldapEntry) + contactEntry = [self _convertLDAPEntryToContact: ldapEntry]; + else + contactEntry = nil; + + return contactEntry; +} + +- (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) uid; +{ + NSDictionary *contactEntry; + NGLdapEntry *ldapEntry; + NSEnumerator *entries; + EOQualifier *qualifier; + + if (!ldapConnection) + [self _initLDAPConnection]; + qualifier = [self _qualifierForUIDFilter: uid]; + entries = [ldapConnection deepSearchAtBaseDN: baseDN + qualifier: qualifier + attributes: [self _searchAttributes]]; + ldapEntry = [entries nextObject]; + if (ldapEntry) + contactEntry = [self _convertLDAPEntryToContact: ldapEntry]; + else + contactEntry = nil; + + return contactEntry; +} + +@end diff --git a/SoObjects/SOGo/LDAPUserManager.h b/SoObjects/SOGo/LDAPUserManager.h new file mode 100644 index 00000000..d7dd8faa --- /dev/null +++ b/SoObjects/SOGo/LDAPUserManager.h @@ -0,0 +1,64 @@ +/* LDAPUserManager.h - this file is part of SOGo + * + * Copyright (C) 2007 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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. + */ + +#ifndef LDAPUSERMANAGER_H +#define LDAPUSERMANAGER_H + +#import + +@class NSDictionary; +@class NSMutableDictionary; +@class NSString; +@class NSTimer; + +@class LDAPSource; + +@interface LDAPUserManager : NSObject +{ + NSMutableDictionary *sources; + NSMutableDictionary *sourcesMetadata; + NSTimeInterval cleanupInterval; + NSTimer *cleanupTimer; + NSMutableDictionary *users; +} + ++ (id) sharedUserManager; + +- (NSArray *) sourceIDs; +- (NSArray *) authenticationSourceIDs; +- (NSArray *) addressBookSourceIDs; + +- (LDAPSource *) sourceWithID: (NSString *) sourceID; +- (NSString *) displayNameForSourceWithID: (NSString *) sourceID; +- (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid; +- (NSArray *) fetchContactsMatching: (NSString *) match; + +- (NSString *) getCNForUID: (NSString *) uid; +- (NSString *) getEmailForUID: (NSString *) uid; +- (NSString *) getUIDForEmail: (NSString *) email; + +- (BOOL) checkLogin: (NSString *) login + andPassword: (NSString *) password; + +@end + +#endif /* LDAPUSERMANAGER_H */ diff --git a/SoObjects/SOGo/LDAPUserManager.m b/SoObjects/SOGo/LDAPUserManager.m new file mode 100644 index 00000000..6cfe52c0 --- /dev/null +++ b/SoObjects/SOGo/LDAPUserManager.m @@ -0,0 +1,474 @@ +/* LDAPUserManager.m - this file is part of SOGo + * + * Copyright (C) 2007 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 +#import +#import +#import +#import +#import + +#import "LDAPSource.h" +#import "LDAPUserManager.h" + +static NSString *defaultMailDomain = nil; + +@implementation LDAPUserManager + ++ (void) initialize +{ + NSUserDefaults *ud; + + ud = [NSUserDefaults standardUserDefaults]; + if (!defaultMailDomain) + { + defaultMailDomain = [ud stringForKey: @"SOGoDefaultMailDomain"]; + [defaultMailDomain retain]; + } +} + ++ (id) sharedUserManager +{ + static id sharedUserManager = nil; + + if (!sharedUserManager) + sharedUserManager = [self new]; + + return sharedUserManager; +} + +- (void) _registerSource: (NSDictionary *) udSource +{ + NSMutableDictionary *metadata; + LDAPSource *ldapSource; + NSString *sourceID, *value; + + sourceID = [udSource objectForKey: @"id"]; + ldapSource = [LDAPSource sourceFromUDSource: udSource]; + [sources setObject: ldapSource forKey: sourceID]; + metadata = [NSMutableDictionary dictionary]; + value = [udSource objectForKey: @"canAuthenticate"]; + if (value) + [metadata setObject: value forKey: @"canAuthenticate"]; + value = [udSource objectForKey: @"isAddressBook"]; + if (value) + [metadata setObject: value forKey: @"isAddressBook"]; + value = [udSource objectForKey: @"displayName"]; + if (value) + [metadata setObject: value forKey: @"displayName"]; + [sourcesMetadata setObject: metadata forKey: sourceID]; +} + +- (void) _prepareLDAPSourcesWithDefaults: (NSUserDefaults *) ud +{ + NSArray *udSources; + unsigned int count, max; + + sources = [NSMutableDictionary new]; + sourcesMetadata = [NSMutableDictionary new]; + + udSources = [ud arrayForKey: @"SOGoLDAPSources"]; + max = [udSources count]; + for (count = 0; count < max; count++) + [self _registerSource: [udSources objectAtIndex: count]]; +} + +- (id) init +{ + NSUserDefaults *ud; + + if ((self = [super init])) + { + ud = [NSUserDefaults standardUserDefaults]; + + sources = nil; + sourcesMetadata = nil; + users = [NSMutableDictionary new]; + cleanupInterval + = [ud integerForKey: @"SOGOLDAPUserManagerCleanupInterval"]; + if (cleanupInterval) + cleanupTimer = [NSTimer timerWithTimeInterval: cleanupInterval + target: self + selector: @selector (cleanupUsers) + userInfo: nil + repeats: YES]; + [self _prepareLDAPSourcesWithDefaults: ud]; + } + + return self; +} + +- (void) dealloc +{ + [sources release]; + [users release]; + [super dealloc]; +} + +- (NSArray *) sourceIDs +{ + return [sources allKeys]; +} + +- (NSArray *) _sourcesOfType: (NSString *) sourceType +{ + NSMutableArray *sourceIDs; + NSEnumerator *allIDs; + NSString *currentID; + NSNumber *canAuthenticate; + + sourceIDs = [NSMutableArray array]; + allIDs = [[sources allKeys] objectEnumerator]; + currentID = [allIDs nextObject]; + while (currentID) + { + canAuthenticate = [[sourcesMetadata objectForKey: currentID] + objectForKey: sourceType]; + if ([canAuthenticate boolValue]) + [sourceIDs addObject: currentID]; + currentID = [allIDs nextObject]; + } + + return sourceIDs; +} + +- (NSArray *) authenticationSourceIDs +{ + return [self _sourcesOfType: @"canAuthenticate"]; +} + +- (NSArray *) addressBookSourceIDs +{ + return [self _sourcesOfType: @"isAddressBook"]; +} + +- (LDAPSource *) sourceWithID: (NSString *) sourceID +{ + return [sources objectForKey: sourceID]; +} + +- (NSString *) displayNameForSourceWithID: (NSString *) sourceID +{ + NSDictionary *metadata; + + metadata = [sourcesMetadata objectForKey: sourceID]; + + return [metadata objectForKey: @"displayName"]; +} + +- (NSString *) getCNForUID: (NSString *) uid +{ + NSDictionary *contactInfos; + + contactInfos = [self contactInfosForUserWithUIDorEmail: uid]; + + return [contactInfos objectForKey: @"cn"]; +} + +- (NSString *) getEmailForUID: (NSString *) uid +{ + NSDictionary *contactInfos; + + contactInfos = [self contactInfosForUserWithUIDorEmail: uid]; + + return [contactInfos objectForKey: @"c_email"]; +} + +- (NSString *) getUIDForEmail: (NSString *) email +{ + NSDictionary *contactInfos; + + contactInfos = [self contactInfosForUserWithUIDorEmail: email]; + + return [contactInfos objectForKey: @"c_uid"]; +} + +- (BOOL) _ldapCheckLogin: (NSString *) login + andPassword: (NSString *) password +{ + BOOL checkOK; + LDAPSource *ldapSource; + NSEnumerator *authIDs; + NSString *currentID; + + checkOK = NO; + + authIDs = [[self authenticationSourceIDs] objectEnumerator]; + currentID = [authIDs nextObject]; + while (currentID && !checkOK) + { + ldapSource = [sources objectForKey: currentID]; + checkOK = [ldapSource checkLogin: login andPassword: password]; + if (!checkOK) + currentID = [authIDs nextObject]; + } + + return checkOK; +} + +- (BOOL) checkLogin: (NSString *) login + andPassword: (NSString *) password +{ + BOOL checkOK; + NSDate *cleanupDate; + NSMutableDictionary *currentUser; + NSString *dictPassword; + + currentUser = [users objectForKey: login]; + dictPassword = [currentUser objectForKey: @"password"]; + if (currentUser && dictPassword) + checkOK = ([dictPassword isEqualToString: password]); + else if ([self _ldapCheckLogin: login andPassword: password]) + { + checkOK = YES; + if (!currentUser) + { + currentUser = [NSMutableDictionary dictionary]; + [users setObject: currentUser forKey: login]; + } + [currentUser setObject: password forKey: @"password"]; + } + else + checkOK = NO; + + if (cleanupInterval) + { + cleanupDate = [[NSDate date] addTimeInterval: cleanupInterval]; + [currentUser setObject: cleanupDate forKey: @"cleanupDate"]; + } + + return checkOK; +} + +- (void) _fillContactMailRecords: (NSMutableDictionary *) contact +{ + NSMutableArray *emails; + NSString *uid; + + emails = [contact objectForKey: @"emails"]; + uid = [contact objectForKey: @"c_uid"]; + [emails addObject: + [NSString stringWithFormat: @"%@@%@", uid, defaultMailDomain]]; + [contact setObject: [emails objectAtIndex: 0] forKey: @"c_email"]; +} + +- (void) _fillContactInfosForUser: (NSMutableDictionary *) currentUser + withUIDorEmail: (NSString *) uid +{ + NSMutableArray *emails; + NSDictionary *userEntry; + NSEnumerator *ldapSources; + LDAPSource *currentSource; + NSString *cn, *email, *c_uid; + + emails = [NSMutableArray array]; + cn = nil; + c_uid = nil; + + ldapSources = [sources objectEnumerator]; + currentSource = [ldapSources nextObject]; + while (currentSource) + { + userEntry = [currentSource lookupContactEntryWithUIDorEmail: uid]; + if (userEntry) + { + if (!cn) + cn = [userEntry objectForKey: @"c_cn"]; + if (!c_uid) + c_uid = [userEntry objectForKey: @"c_uid"]; + email = [userEntry objectForKey: @"mail"]; + if (email && ![emails containsObject: email]) + [emails addObject: email]; + email = [userEntry objectForKey: @"mozillaSecondEmail"]; + if (email && ![emails containsObject: email]) + [emails addObject: email]; + email = [userEntry objectForKey: @"xmozillasecondemail"]; + if (email && ![emails containsObject: email]) + [emails addObject: email]; + } + currentSource = [ldapSources nextObject]; + } + + if (!cn) + cn = @""; + if (!c_uid) + c_uid = @""; + + [currentUser setObject: emails forKey: @"emails"]; + [currentUser setObject: cn forKey: @"cn"]; + [currentUser setObject: c_uid forKey: @"c_uid"]; + [self _fillContactMailRecords: currentUser]; +} + +- (void) _retainUser: (NSDictionary *) newUser +{ + NSString *key; + NSEnumerator *emails; + + key = [newUser objectForKey: @"c_uid"]; + if (key) + [users setObject: newUser forKey: key]; + emails = [[newUser objectForKey: @"emails"] objectEnumerator]; + key = [emails nextObject]; + while (key) + { + [users setObject: newUser forKey: key]; + key = [emails nextObject]; + } +} + +- (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid +{ + NSMutableDictionary *currentUser, *contactInfos; + NSDate *cleanupDate; + BOOL newUser; + + contactInfos = [NSMutableDictionary dictionary]; + currentUser = [users objectForKey: uid]; + if (!([currentUser objectForKey: @"emails"] + && [currentUser objectForKey: @"cn"])) + { + if (!currentUser) + { + newUser = YES; + currentUser = [NSMutableDictionary dictionary]; + } + else + newUser = NO; + [self _fillContactInfosForUser: currentUser + withUIDorEmail: uid]; + if (newUser) + [self _retainUser: currentUser]; + } + + if (cleanupInterval) + { + cleanupDate = [[NSDate date] addTimeInterval: cleanupInterval]; + [currentUser setObject: cleanupDate forKey: @"cleanupDate"]; + } + + return currentUser; +} + +- (void) _fillContactsMailRecords: (NSEnumerator *) contacts +{ + NSMutableDictionary *currentContact; + + currentContact = [contacts nextObject]; + while (currentContact) + { + [self _fillContactMailRecords: currentContact]; + currentContact = [contacts nextObject]; + } +} + +- (NSArray *) _compactAndCompleteContacts: (NSEnumerator *) contacts +{ + NSMutableDictionary *compactContacts, *returnContact; + NSDictionary *userEntry; + NSArray *newContacts; + NSMutableArray *emails; + NSString *uid, *email; + + compactContacts = [NSMutableDictionary dictionary]; + userEntry = [contacts nextObject]; + while (userEntry) + { + uid = [userEntry objectForKey: @"c_uid"]; + returnContact = [compactContacts objectForKey: uid]; + if (!returnContact) + { + returnContact = [NSMutableDictionary dictionary]; + [returnContact setObject: uid forKey: @"c_uid"]; + [compactContacts setObject: returnContact forKey: uid]; + } + if (![[returnContact objectForKey: @"c_name"] length]) + [returnContact setObject: [userEntry objectForKey: @"c_name"] + forKey: @"c_name"]; + if (![[returnContact objectForKey: @"cn"] length]) + [returnContact setObject: [userEntry objectForKey: @"c_cn"] + forKey: @"cn"]; + emails = [returnContact objectForKey: @"emails"]; + if (!emails) + { + emails = [NSMutableArray array]; + [returnContact setObject: emails forKey: @"emails"]; + } + email = [userEntry objectForKey: @"mail"]; + if (email && ![emails containsObject: email]) + [emails addObject: email]; + email = [userEntry objectForKey: @"mozillaSecondEmail"]; + if (email && ![emails containsObject: email]) + [emails addObject: email]; + email = [userEntry objectForKey: @"xmozillasecondemail"]; + if (email && ![emails containsObject: email]) + [emails addObject: email]; + + userEntry = [contacts nextObject]; + } + newContacts = [compactContacts allValues]; + [self _fillContactsMailRecords: [newContacts objectEnumerator]]; + + return newContacts; +} + +- (NSArray *) fetchContactsMatching: (NSString *) filter +{ + NSMutableArray *contacts; + NSEnumerator *ldapSources; + LDAPSource *currentSource; + + contacts = [NSMutableArray array]; + + ldapSources = [sources objectEnumerator]; + currentSource = [ldapSources nextObject]; + while (currentSource) + { + [contacts addObjectsFromArray: + [currentSource fetchContactsMatching: filter]]; + currentSource = [ldapSources nextObject]; + } + + return [self _compactAndCompleteContacts: [contacts objectEnumerator]]; +} + +- (void) cleanupSources +{ + NSEnumerator *userIDs; + NSString *currentID; + NSDictionary *currentUser; + NSDate *now; + + now = [NSDate date]; + userIDs = [[users allKeys] objectEnumerator]; + currentID = [userIDs nextObject]; + while (currentID) + { + currentUser = [users objectForKey: currentID]; + if ([now earlierDate: + [currentUser objectForKey: @"cleanupDate"]] == now) + [users removeObjectForKey: currentID]; + currentID = [userIDs nextObject]; + } +} + +@end diff --git a/SoObjects/SOGo/SOGoAuthenticator.m b/SoObjects/SOGo/SOGoAuthenticator.m index be10f0c8..134dba02 100644 --- a/SoObjects/SOGo/SOGoAuthenticator.m +++ b/SoObjects/SOGo/SOGoAuthenticator.m @@ -22,9 +22,11 @@ #import #import "SOGoPermissions.h" -#include "SOGoAuthenticator.h" -#include "SOGoUser.h" -#include "common.h" +#import "LDAPUserManager.h" + +#import "SOGoAuthenticator.h" +#import "SOGoUser.h" +#import "common.h" @implementation SOGoAuthenticator @@ -50,9 +52,9 @@ static SOGoAuthenticator *auth = nil; authMethod = [[ud stringForKey:@"AuthentificationMethod"] retain]; if ([authMethod isEqualToString: @"LDAP"]) { - LDAPBaseDN = [[ud stringForKey:@"LDAPRootDN"] retain]; - LDAPHost = [[ud stringForKey:@"LDAPHost"] retain]; - LDAPPort = [ud integerForKey:@"LDAPPort"]; +// LDAPBaseDN = [[ud stringForKey:@"LDAPRootDN"] retain]; +// LDAPHost = [[ud stringForKey:@"LDAPHost"] retain]; +// LDAPPort = [ud integerForKey:@"LDAPPort"]; } } @@ -87,11 +89,11 @@ static SOGoAuthenticator *auth = nil; - (BOOL) LDAPCheckLogin: (NSString *) _login password: (NSString *) _pwd { - return [NGLdapConnection checkPassword: _pwd - ofLogin: _login - atBaseDN: LDAPBaseDN - onHost: LDAPHost - port: LDAPPort]; + LDAPUserManager *um; + + um = [LDAPUserManager sharedUserManager]; + + return [um checkLogin: _login andPassword: _pwd]; } /* create SOGoUser */ @@ -105,7 +107,7 @@ static SOGoAuthenticator *auth = nil; if (!anonymous) anonymous - = [[SOGoUser alloc] initWithLogin:@"anonymous" + = [[SOGoUser alloc] initWithLogin: @"anonymous" roles: [NSArray arrayWithObject: SoRole_Anonymous]]; if (!freebusy) freebusy @@ -124,9 +126,8 @@ static SOGoAuthenticator *auth = nil; user = anonymous; } else - user = [[[SOGoUser alloc] initWithLogin: login - roles: [self rolesForLogin: login]] - autorelease]; + user = [SOGoUser userWithLogin: login + roles: [self rolesForLogin: login]]; } else user = nil; diff --git a/SoObjects/SOGo/SOGoFolder.h b/SoObjects/SOGo/SOGoFolder.h index f38fc61f..b5527d49 100644 --- a/SoObjects/SOGo/SOGoFolder.h +++ b/SoObjects/SOGo/SOGoFolder.h @@ -24,7 +24,11 @@ #import "SOGoObject.h" -@class NSString, NSArray, NSDictionary; +@class NSArray; +@class NSDictionary; +@class NSMutableDictionary; +@class NSString; + @class GCSFolder; /* @@ -37,10 +41,6 @@ cyclic references. */ -@class NSString; -@class GCSFolder; -@class NSMutableDictionary; - @interface SOGoFolder : SOGoObject { NSString *ocsPath; diff --git a/SoObjects/SOGo/SOGoObject.h b/SoObjects/SOGo/SOGoObject.h index 9d3f7a4f..5b4eecce 100644 --- a/SoObjects/SOGo/SOGoObject.h +++ b/SoObjects/SOGo/SOGoObject.h @@ -34,10 +34,20 @@ lookup. */ -@class NSString, NSArray, NSMutableString, NSException, NSTimeZone; -@class GCSFolderManager, GCSFolder; -@class SOGoUserFolder, SOGoGroupsFolder; +#import + +@class NSString; +@class NSArray; +@class NSMutableString; +@class NSException; +@class NSTimeZone; + @class WOContext; +@class GCSFolderManager; +@class GCSFolder; + +@class SOGoUserFolder; +@class SOGoGroupsFolder; @class SOGoDAVSet; #define $(class) NSClassFromString(class) diff --git a/SoObjects/SOGo/SOGoObject.m b/SoObjects/SOGo/SOGoObject.m index fff695fc..1cfc050e 100644 --- a/SoObjects/SOGo/SOGoObject.m +++ b/SoObjects/SOGo/SOGoObject.m @@ -39,7 +39,6 @@ #import "SOGoUserFolder.h" #import "SOGoDAVRendererTypes.h" -#import "AgenorUserManager.h" #import "SOGoObject.h" diff --git a/SoObjects/SOGo/SOGoUser.h b/SoObjects/SOGo/SOGoUser.h index 3b87aa84..6b52688a 100644 --- a/SoObjects/SOGo/SOGoUser.h +++ b/SoObjects/SOGo/SOGoUser.h @@ -44,29 +44,36 @@ @interface SOGoUser : SoUser { - NSString *cn; - NSString *email; + NSString *cn; + NSArray *allEmails; NSUserDefaults *userDefaults; NSUserDefaults *userSettings; NSTimeZone *userTimeZone; } + (SOGoUser *) userWithLogin: (NSString *) login - andRoles: (NSArray *) roles; + roles: (NSArray *) roles; /* properties */ -- (NSString *) email; +- (NSString *) primaryEmail; +- (NSString *) systemEmail; +- (NSArray *) allEmails; + +- (BOOL) hasEmail: (NSString *) email; + - (NSString *) cn; - (NSURL *) freeBusyURL; /* shares and identities */ - (NSString *) primaryIMAP4AccountString; -- (NSString *) primaryMailServer; -- (NSArray *) additionalIMAP4AccountStrings; -- (NSArray *) additionalEMailAddresses; -- (NSDictionary *) additionalIMAP4AccountsAndEMails; + +// - (NSString *) primaryIMAP4AccountString; +// - (NSString *) primaryMailServer; +// - (NSArray *) additionalIMAP4AccountStrings; +// - (NSArray *) additionalEMailAddresses; +// - (NSDictionary *) additionalIMAP4AccountsAndEMails; /* defaults */ @@ -79,7 +86,7 @@ /* folders */ - (id) homeFolderInContext: (id) _ctx; -- (id) schedulingCalendarInContext: (id) _ctx; +// - (id) schedulingCalendarInContext: (id) _ctx; - (NSArray *) rolesForObject: (NSObject *) object inContext: (WOContext *) context; diff --git a/SoObjects/SOGo/SOGoUser.m b/SoObjects/SOGo/SOGoUser.m index e6c5a498..c91e7573 100644 --- a/SoObjects/SOGo/SOGoUser.m +++ b/SoObjects/SOGo/SOGoUser.m @@ -27,12 +27,15 @@ #import #import -#import "AgenorUserManager.h" +#import "AgenorUserDefaults.h" +#import "LDAPUserManager.h" #import "SOGoContentObject.h" #import "SOGoUser.h" #import "SOGoPermissions.h" static NSTimeZone *serverTimeZone = nil; +static NSString *fallbackIMAP4Server = nil; +static NSURL *AgenorProfileURL = nil; @interface NSObject (SOGoRoles) @@ -45,20 +48,29 @@ static NSTimeZone *serverTimeZone = nil; + (void) initialize { NSString *tzName; + NSUserDefaults *ud; + NSString *profileURL; + ud = [NSUserDefaults standardUserDefaults]; if (!serverTimeZone) { - tzName = [[NSUserDefaults standardUserDefaults] - stringForKey: @"SOGoServerTimeZone"]; + tzName = [ud stringForKey: @"SOGoServerTimeZone"]; if (!tzName) tzName = @"Canada/Eastern"; serverTimeZone = [NSTimeZone timeZoneWithName: tzName]; [serverTimeZone retain]; } + if (!AgenorProfileURL) + { + profileURL = [ud stringForKey: @"AgenorProfileURL"]; + AgenorProfileURL = [[NSURL alloc] initWithString: profileURL]; + } + if (!fallbackIMAP4Server) + ASSIGN (fallbackIMAP4Server, [ud stringForKey: @"SOGoFallbackIMAP4Server"]); } + (SOGoUser *) userWithLogin: (NSString *) login - andRoles: (NSArray *) roles + roles: (NSArray *) roles { SOGoUser *user; @@ -74,6 +86,27 @@ static NSTimeZone *serverTimeZone = nil; { userDefaults = nil; userSettings = nil; + allEmails = nil; + } + + return self; +} + +- (id) initWithLogin: (NSString *) newLogin + roles: (NSArray *) newRoles +{ + LDAPUserManager *um; + NSDictionary *user; + + if ([newLogin isEqualToString: @"anonymous"] + || [newLogin isEqualToString: @"freebusy"]) + self = [super initWithLogin: newLogin roles: newRoles]; + else + { + um = [LDAPUserManager sharedUserManager]; + user = [um contactInfosForUserWithUIDorEmail: newLogin]; + self = [super initWithLogin: [user objectForKey: @"c_uid"] + roles: newRoles]; } return self; @@ -83,73 +116,115 @@ static NSTimeZone *serverTimeZone = nil; { [userDefaults release]; [userSettings release]; - [cn release]; - [email release]; [super dealloc]; } -/* internals */ +- (id) _fetchFieldForUser: (NSString *) field +{ + NSDictionary *contactInfos; + LDAPUserManager *um; + + um = [LDAPUserManager sharedUserManager]; + contactInfos = [um contactInfosForUserWithUIDorEmail: login]; -- (AgenorUserManager *) userManager + return [contactInfos objectForKey: field]; +} + +- (void) _fetchAllEmails { - static AgenorUserManager *um = nil; - if (um == nil) um = [[AgenorUserManager sharedUserManager] retain]; + allEmails = [self _fetchFieldForUser: @"emails"]; + [allEmails retain]; +} - return um; +- (void) _fetchCN +{ + cn = [self _fetchFieldForUser: @"cn"]; + [cn retain]; } /* properties */ -- (NSString *) email +- (NSString *) primaryEmail { - if (email == nil) - { - email = [[self userManager] getEmailForUID: [self login]]; - [email retain]; - } + if (!allEmails) + [self _fetchAllEmails]; - return email; + return [allEmails objectAtIndex: 0]; } -- (NSString *) cn +- (NSString *) systemEmail { - if (cn == nil) - { - cn = [[self userManager] getCNForUID: [self login]]; - [cn retain]; - } + if (!allEmails) + [self _fetchAllEmails]; - return cn; + return [allEmails lastObject]; } -- (NSString *) primaryIMAP4AccountString +- (NSArray *) allEmails { - return [[self userManager] getIMAPAccountStringForUID: [self login]]; -} + if (!allEmails) + [self _fetchAllEmails]; -- (NSString *) primaryMailServer -{ - return [[self userManager] getServerForUID: [self login]]; + return allEmails; } -- (NSArray *) additionalIMAP4AccountStrings +- (BOOL) hasEmail: (NSString *) email { - return [[self userManager]getSharedMailboxAccountStringsForUID: [self login]]; + BOOL hasEmail; + NSString *currentEmail, *cmpEmail; + NSEnumerator *emails; + + hasEmail = NO; + if (!allEmails) + [self _fetchAllEmails]; + cmpEmail = [email lowercaseString]; + emails = [allEmails objectEnumerator]; + currentEmail = [emails nextObject]; + while (currentEmail && !hasEmail) + if ([[currentEmail lowercaseString] isEqualToString: cmpEmail]) + hasEmail = YES; + else + currentEmail = [emails nextObject]; + + return hasEmail; } -- (NSArray *) additionalEMailAddresses +- (NSString *) cn { - return [[self userManager] getSharedMailboxEMailsForUID: [self login]]; + if (!cn) + [self _fetchCN]; + + return cn; } -- (NSDictionary *) additionalIMAP4AccountsAndEMails +- (NSString *) primaryIMAP4AccountString { - return [[self userManager] getSharedMailboxesAndEMailsForUID: [self login]]; + return [NSString stringWithFormat: @"%@@%@", login, fallbackIMAP4Server]; } +// - (NSString *) primaryMailServer +// { +// return [[self userManager] getServerForUID: [self login]]; +// } + +// - (NSArray *) additionalIMAP4AccountStrings +// { +// return [[self userManager]getSharedMailboxAccountStringsForUID: [self login]]; +// } + +// - (NSArray *) additionalEMailAddresses +// { +// return [[self userManager] getSharedMailboxEMailsForUID: [self login]]; +// } + +// - (NSDictionary *) additionalIMAP4AccountsAndEMails +// { +// return [[self userManager] getSharedMailboxesAndEMailsForUID: [self login]]; +// } + - (NSURL *) freeBusyURL { - return [[self userManager] getFreeBusyURLForUID: [self login]]; + return nil; } /* defaults */ @@ -157,10 +232,9 @@ static NSTimeZone *serverTimeZone = nil; - (NSUserDefaults *) userDefaults { if (!userDefaults) - { - userDefaults = [[self userManager] getUserDefaultsForUID: [self login]]; - [userDefaults retain]; - } + userDefaults = [[AgenorUserDefaults alloc] initWithTableURL: AgenorProfileURL + uid: login + fieldName: @"defaults"]; return userDefaults; } @@ -168,10 +242,9 @@ static NSTimeZone *serverTimeZone = nil; - (NSUserDefaults *) userSettings { if (!userSettings) - { - userSettings = [[self userManager] getUserSettingsForUID: [self login]]; - [userSettings retain]; - } + userSettings = [[AgenorUserDefaults alloc] initWithTableURL: AgenorProfileURL + uid: login + fieldName: @"settings"]; return userSettings; } @@ -223,27 +296,27 @@ static NSTimeZone *serverTimeZone = nil; return folder; } -- (id) schedulingCalendarInContext: (id) _ctx -{ - /* Note: watch out for cyclic references */ - id folder; +// - (id) schedulingCalendarInContext: (id) _ctx +// { +// /* Note: watch out for cyclic references */ +// id folder; - folder = [(WOContext *)_ctx objectForKey:@"ActiveUserCalendar"]; - if (folder != nil) - return [folder isNotNull] ? folder : nil; +// folder = [(WOContext *)_ctx objectForKey:@"ActiveUserCalendar"]; +// if (folder != nil) +// return [folder isNotNull] ? folder : nil; - folder = [self homeFolderInContext:_ctx]; - if ([folder isKindOfClass:[NSException class]]) - return folder; +// folder = [self homeFolderInContext:_ctx]; +// if ([folder isKindOfClass:[NSException class]]) +// return folder; - folder = [folder lookupName:@"Calendar" inContext:_ctx acquire:NO]; - if ([folder isKindOfClass:[NSException class]]) - return folder; +// folder = [folder lookupName:@"Calendar" inContext:_ctx acquire:NO]; +// if ([folder isKindOfClass:[NSException class]]) +// return folder; - [(WOContext *)_ctx setObject:folder ? folder : [NSNull null] - forKey:@"ActiveUserCalendar"]; - return folder; -} +// [(WOContext *)_ctx setObject:folder ? folder : [NSNull null] +// forKey:@"ActiveUserCalendar"]; +// return folder; +// } - (NSArray *) rolesForObject: (NSObject *) object inContext: (WOContext *) context diff --git a/UI/Common/Toolbars/SOGoAclOwner.toolbar b/UI/Common/Toolbars/SOGoAclOwner.toolbar index e2d8f839..6af766a4 100644 --- a/UI/Common/Toolbars/SOGoAclOwner.toolbar +++ b/UI/Common/Toolbars/SOGoAclOwner.toolbar @@ -1,10 +1,5 @@ ( /* the toolbar groups -*-cperl-*- */ ( { link = "#"; - isSafe = NO; - label = "Save"; - onclick = "return saveAcls(this);"; - image = "tb-compose-save-flat-24x24.png"; }, - { link = "#"; isSafe = NO; label = "Close"; onclick = "window.close();"; diff --git a/UI/Common/UIxAclEditor.m b/UI/Common/UIxAclEditor.m index 8c0e9df9..12a45f50 100644 --- a/UI/Common/UIxAclEditor.m +++ b/UI/Common/UIxAclEditor.m @@ -26,7 +26,7 @@ #import #import #import -#import +#import #import #import @@ -67,13 +67,12 @@ - (NSString *) _displayNameForUID: (NSString *) uid { - AgenorUserManager *um; + LDAPUserManager *um; - um = [AgenorUserManager sharedUserManager]; + um = [LDAPUserManager sharedUserManager]; return [NSString stringWithFormat: @"%@ <%@>", - [um getCNForUID: uid], - [um getEmailForUID: uid]]; + [um getCNForUID: uid], [um getEmailForUID: uid]]; } - (NSString *) ownerName @@ -177,6 +176,18 @@ return [self jsCloseWithRefreshMethod: nil]; } +- (BOOL) currentUserIsOwner +{ + SOGoObject *clientObject; + NSString *currentUserLogin, *ownerLogin; + + clientObject = [self clientObject]; + ownerLogin = [clientObject ownerInContext: context]; + currentUserLogin = [[context activeUser] login]; + + return [ownerLogin isEqualToString: currentUserLogin]; +} + // - (id ) addUserInAcls // { // SOGoObject *clientObject; diff --git a/UI/Common/UIxFolderActions.h b/UI/Common/UIxFolderActions.h index 5a08a684..88126ad3 100644 --- a/UI/Common/UIxFolderActions.h +++ b/UI/Common/UIxFolderActions.h @@ -25,16 +25,18 @@ #import -@class SOGoFolder; @class NSString; @class NSUserDefaults; @class NSMutableString; @class NSMutableDictionary; +@class LDAPUserManager; +@class SOGoFolder; + @interface UIxFolderActions : WODirectAction { SOGoFolder *clientObject; - AgenorUserManager *um; + LDAPUserManager *um; NSUserDefaults *ud; NSString *owner; NSString *login; diff --git a/UI/Common/UIxFolderActions.m b/UI/Common/UIxFolderActions.m index 4f5ff9e6..25480d1b 100644 --- a/UI/Common/UIxFolderActions.m +++ b/UI/Common/UIxFolderActions.m @@ -31,10 +31,10 @@ #import #import -#import -#import -#import -#import +#import +#import +#import +#import #import "UIxFolderActions.h" @@ -46,8 +46,10 @@ - (void) _setupContext { NSString *clientClass; + SOGoUser *activeUser; - login = [[context activeUser] login]; + activeUser = [context activeUser]; + login = [activeUser login]; clientObject = [self clientObject]; owner = [clientObject ownerInContext: nil]; @@ -59,8 +61,8 @@ else baseFolder = nil; - um = [AgenorUserManager sharedUserManager]; - ud = [um getUserSettingsForUID: login]; + um = [LDAPUserManager sharedUserManager]; + ud = [activeUser userSettings]; moduleSettings = [ud objectForKey: baseFolder]; if (!moduleSettings) { @@ -119,7 +121,8 @@ [self _setupContext]; email = [NSString stringWithFormat: @"%@ <%@>", - [um getCNForUID: owner], [um getEmailForUID: owner]]; + [um getCNForUID: owner], + [um getEmailForUID: owner]]; if ([baseFolder isEqualToString: @"Contacts"]) folderName = [NSString stringWithFormat: @"%@ (%@)", [clientObject nameInContainer], email]; diff --git a/UI/Common/UIxObjectActions.m b/UI/Common/UIxObjectActions.m index 143f677f..277d1ac6 100644 --- a/UI/Common/UIxObjectActions.m +++ b/UI/Common/UIxObjectActions.m @@ -25,7 +25,7 @@ #import #import #import -#import +#import #import #import "UIxObjectActions.h" @@ -38,7 +38,7 @@ WORequest *request; NSString *uid, *email; unsigned int code; - AgenorUserManager *um; + LDAPUserManager *um; SOGoObject *clientObject; code = 403; @@ -46,7 +46,7 @@ uid = [request formValueForKey: @"uid"]; if ([uid length] > 0) { - um = [AgenorUserManager sharedUserManager]; + um = [LDAPUserManager sharedUserManager]; email = [um getEmailForUID: uid]; if ([email length] > 0) { diff --git a/UI/Common/UIxUserRightsEditor.m b/UI/Common/UIxUserRightsEditor.m index d3792a23..35b69761 100644 --- a/UI/Common/UIxUserRightsEditor.m +++ b/UI/Common/UIxUserRightsEditor.m @@ -23,7 +23,7 @@ #import #import #import -#import +#import #import "UIxUserRightsEditor.h" @@ -54,9 +54,9 @@ - (NSString *) userDisplayName { - AgenorUserManager *um; + LDAPUserManager *um; - um = [AgenorUserManager sharedUserManager]; + um = [LDAPUserManager sharedUserManager]; return [NSString stringWithFormat: @"%@ <%@>", [um getCNForUID: uid], @@ -67,7 +67,7 @@ { BOOL response; NSString *newUID, *email; - AgenorUserManager *um; + LDAPUserManager *um; SOGoObject *clientObject; response = NO; @@ -75,7 +75,7 @@ newUID = [[context request] formValueForKey: @"uid"]; if ([newUID length] > 0) { - um = [AgenorUserManager sharedUserManager]; + um = [LDAPUserManager sharedUserManager]; email = [um getEmailForUID: newUID]; if ([email length] > 0) { diff --git a/UI/Contacts/UIxContactEditor.m b/UI/Contacts/UIxContactEditor.m index 0b6dd7b7..67d2d6b2 100644 --- a/UI/Contacts/UIxContactEditor.m +++ b/UI/Contacts/UIxContactEditor.m @@ -19,14 +19,18 @@ 02111-1307, USA. */ -#import -#import +#import +#import #import +#import +#import + +#import +#import #import #import -#import "common.h" #import "UIxContactEditor.h" @@ -536,7 +540,8 @@ - (id) writeAction { - NSString *email, *url; + NSString *email, *cn, *url; + NSMutableString *address; card = [[self clientObject] vCard]; [self initSnapshot]; @@ -546,7 +551,16 @@ email = [snapshot objectForKey: @"workMail"]; if (email) - url = [NSString stringWithFormat: @"Mail/compose?mailto=%@", email]; + { + address = [NSMutableString string]; + cn = [card fn]; + if ([cn length] > 0) + [address appendFormat: @"%@ <%@>", cn, email]; + else + [address appendString: email]; + + url = [NSString stringWithFormat: @"Mail/compose?mailto=%@", address]; + } else url = @"Mail/compose"; diff --git a/UI/Contacts/UIxContactFoldersView.m b/UI/Contacts/UIxContactFoldersView.m index 45e98dd1..de17b892 100644 --- a/UI/Contacts/UIxContactFoldersView.m +++ b/UI/Contacts/UIxContactFoldersView.m @@ -30,6 +30,7 @@ #import #import +#import #import #import #import @@ -93,28 +94,45 @@ return [self _selectActionForApplication: @"mailer-contacts"]; } -- (NSArray *) _searchResults: (NSString *) contact - ldapFoldersOnly: (BOOL) ldapFoldersOnly +- (void) _fillResults: (NSMutableDictionary *) results + inFolder: (id ) folder + withSearchOn: (NSString *) contact { - NSMutableArray *results; + NSEnumerator *folderResults; + NSDictionary *currentContact; + NSString *uid; + + folderResults = [[folder lookupContactsWithFilter: contact + sortBy: @"cn" + ordering: NSOrderedAscending] objectEnumerator]; + currentContact = [folderResults nextObject]; + while (currentContact) + { + uid = [currentContact objectForKey: @"c_uid"]; + if (uid && ![results objectForKey: uid]) + [results setObject: currentContact + forKey: uid]; + currentContact = [folderResults nextObject]; + } +} + +- (NSDictionary *) _searchResults: (NSString *) contact + ldapFoldersOnly: (BOOL) ldapOnly +{ + NSMutableDictionary *results; SOGoContactFolders *topFolder; NSEnumerator *sogoContactFolders; id currentFolder; - results = [NSMutableArray new]; - [results autorelease]; - + results = [NSMutableDictionary dictionary]; topFolder = [self clientObject]; sogoContactFolders = [[topFolder contactFolders] objectEnumerator]; currentFolder = [sogoContactFolders nextObject]; while (currentFolder) { - if (!ldapFoldersOnly - || [currentFolder isKindOfClass: [SOGoContactLDAPFolder class]]) - [results addObjectsFromArray: [currentFolder - lookupContactsWithFilter: contact - sortBy: @"cn" - ordering: NSOrderedAscending]]; + if (!ldapOnly || [currentFolder isKindOfClass: [SOGoContactLDAPFolder class]]) + [self _fillResults: results inFolder: currentFolder + withSearchOn: contact]; currentFolder = [sogoContactFolders nextObject]; } [topFolder release]; @@ -140,44 +158,34 @@ return email; } -- (NSDictionary *) _nextResultWithUid: (NSEnumerator *) results -{ - NSDictionary *result, *possibleResult; - - result = nil; - possibleResult = [results nextObject]; - while (possibleResult && !result) - if ([[possibleResult objectForKey: @"c_uid"] length]) - result = possibleResult; - else - possibleResult = [results nextObject]; - - return result; -} - -- (WOResponse *) _responseForResults: (NSArray *) results +- (WOResponse *) _responseForResults: (NSDictionary *) results { WOResponse *response; - NSString *email, *responseString, *uid; + NSEnumerator *uids; + NSString *responseString, *uid, *cn, *mail; NSDictionary *result; response = [context response]; if ([results count]) { - result = [self _nextResultWithUid: [results objectEnumerator]]; - if (!result) - result = [results objectAtIndex: 0]; - email = [self _emailForResult: result]; - uid = [result objectForKey: @"c_uid"]; - if ([uid length] == 0) - uid = @""; - responseString = [NSString stringWithFormat: @"%@:%@", - uid, email]; - [response setStatus: 200]; - [response setHeader: @"text/plain; charset=iso-8859-1" - forKey: @"Content-Type"]; - [response appendContentString: responseString]; + uids = [[results allKeys] objectEnumerator]; + uid = [uids nextObject]; + while (uid) + { + result = [results objectForKey: uid]; + cn = [result objectForKey: @"displayName"]; + if (![cn length]) + cn = [result objectForKey: @"cn"]; + mail = [result objectForKey: @"mail"]; + responseString = [NSString stringWithFormat: @"%@:%@:%@", + uid, cn, mail]; + [response setStatus: 200]; + [response setHeader: @"text/plain; charset=iso-8859-1" + forKey: @"Content-Type"]; + [response appendContentString: responseString]; + uid = [uids nextObject]; + } } else [response setStatus: 404]; @@ -302,8 +310,8 @@ WOResponse *response; NSString *uid, *foldersString; NSMutableString *responseString; - NSDictionary *result; - NSEnumerator *resultsEnum; + NSDictionary *contact; + NSEnumerator *contacts; NSArray *folders; response = [context response]; @@ -311,21 +319,26 @@ if ([results count]) { [response setStatus: 200]; - [response setHeader: @"text/plain; charset=iso-8859-1" + [response setHeader: @"text/plain; charset=utf-8" forKey: @"Content-Type"]; responseString = [NSMutableString new]; - resultsEnum = [results objectEnumerator]; - result = [resultsEnum nextObject]; - while (result) + contacts = [results objectEnumerator]; + contact = [contacts nextObject]; + while (contact) { - uid = [result objectForKey: @"c_uid"]; - folders = [self _foldersForUID: uid ofType: folderType]; - foldersString - = [self _foldersStringForFolders: [folders objectEnumerator]]; - [responseString appendFormat: @"%@:%@%@\n", - uid, [self _emailForResult: result], foldersString]; - result = [resultsEnum nextObject]; + uid = [contact objectForKey: @"c_uid"]; + if ([uid length] > 0) + { + folders = [self _foldersForUID: uid ofType: folderType]; + foldersString + = [self _foldersStringForFolders: [folders objectEnumerator]]; + [responseString appendFormat: @"%@:%@:%@%@\n", uid, + [contact objectForKey: @"cn"], + [contact objectForKey: @"c_email"], + foldersString]; + } + contact = [contacts nextObject]; } [response appendContentString: responseString]; [responseString release]; @@ -340,17 +353,16 @@ { NSString *contact, *folderType; id result; - BOOL ldapOnly; + LDAPUserManager *um; + um = [LDAPUserManager sharedUserManager]; contact = [self queryParameterForKey: @"search"]; if ([contact length] > 0) { - ldapOnly = [[self queryParameterForKey: @"ldap-only"] boolValue]; folderType = [self queryParameterForKey: @"type"]; - result = [self _foldersResponseForResults: - [self _searchResults: contact - ldapFoldersOnly: ldapOnly] - withType: folderType]; + result + = [self _foldersResponseForResults: [um fetchContactsMatching: contact] + withType: folderType]; } else result = [NSException exceptionWithHTTPStatus: 400 diff --git a/UI/Contacts/UIxContactsListViewContainer.m b/UI/Contacts/UIxContactsListViewContainer.m index 34fa3a32..2bf4f0c0 100644 --- a/UI/Contacts/UIxContactsListViewContainer.m +++ b/UI/Contacts/UIxContactsListViewContainer.m @@ -27,7 +27,6 @@ #import #import -#import #import #import @@ -128,20 +127,16 @@ - (NSString *) currentContactFolderName { - return [self labelForKey: [currentFolder displayName]]; + return [currentFolder displayName]; } - (NSArray *) additionalFolders { - AgenorUserManager *um; NSUserDefaults *ud; - NSString *login; if (!additionalFolders) { - um = [AgenorUserManager sharedUserManager]; - login = [[context activeUser] login]; - ud = [um getUserSettingsForUID: login]; + ud = [[context activeUser] userSettings]; additionalFolders = [[ud objectForKey: @"Contacts"] objectForKey: @"SubscribedFolders"]; [additionalFolders retain]; diff --git a/UI/Contacts/product.plist b/UI/Contacts/product.plist index b1c47948..48d2d3c2 100644 --- a/UI/Contacts/product.plist +++ b/UI/Contacts/product.plist @@ -28,7 +28,7 @@ actionName = "selectForMailer"; }; contactSearch = { - protectedBy = "View"; + protectedBy = ""; pageName = "UIxContactFoldersView"; actionName = "contactSearch"; }; @@ -63,6 +63,8 @@ }; }; +/* both following class should be "reparented" so as to only have + SOGoContactFolder here... */ SOGoContactGCSFolder = { slots = { toolbar = { @@ -111,21 +113,21 @@ }; methods = { view = { - protectedBy = "View"; + protectedBy = ""; pageName = "UIxContactsListView"; }; new = { - protectedBy = "View"; + protectedBy = ""; pageName = "UIxContactEditor"; actionName = "new"; }; mailer-contacts = { - protectedBy = "View"; + protectedBy = ""; pageName = "UIxContactsListView"; actionName = "mailerContacts"; }; canAccessContent = { - protectedBy = "View"; + protectedBy = ""; pageName = "UIxContactsListView"; actionName = "canAccessContent"; }; @@ -160,10 +162,10 @@ }; }; - SOGoContactLDAPEntry = { + SOGoContactLDIFEntry = { methods = { view = { - protectedBy = "View"; + protectedBy = ""; pageName = "UIxContactView"; }; delete = { diff --git a/UI/GNUmakefile b/UI/GNUmakefile index 4be5b3bd..89d5e12b 100644 --- a/UI/GNUmakefile +++ b/UI/GNUmakefile @@ -11,8 +11,6 @@ SUBPROJECTS += \ Contacts \ MailerUI \ MailPartViewers \ - -SUBPROJECTS += \ Templates include $(GNUSTEP_MAKEFILES)/aggregate.make diff --git a/UI/MailPartViewers/UIxMailPartICalViewer.m b/UI/MailPartViewers/UIxMailPartICalViewer.m index 5a3285e1..494d21d4 100644 --- a/UI/MailPartViewers/UIxMailPartICalViewer.m +++ b/UI/MailPartViewers/UIxMailPartICalViewer.m @@ -26,7 +26,7 @@ */ #import -#import +#import #import #import #import @@ -189,8 +189,15 @@ - (id)calendarFolder { /* return scheduling calendar of currently logged-in user */ - return [[[self context] activeUser] schedulingCalendarInContext: - [self context]]; + SOGoUser *user; + id folder; + + user = [context activeUser]; + folder = [[user homeFolderInContext: context] lookupName: @"Calendar" + inContext: context + acquire: NO]; + + return folder; } - (id)storedEventObject { @@ -238,7 +245,7 @@ /* organizer tracking */ - (NSString *)loggedInUserEMail { - return [[[self context] activeUser] email]; + return [[[self context] activeUser] primaryEmail]; } - (iCalEvent *)authorativeEvent { diff --git a/UI/MailerUI/UIxMailEditor.m b/UI/MailerUI/UIxMailEditor.m index 64ea6cfd..cb4954e4 100644 --- a/UI/MailerUI/UIxMailEditor.m +++ b/UI/MailerUI/UIxMailEditor.m @@ -19,6 +19,28 @@ 02111-1307, USA. */ +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import +#import #import /* @@ -37,7 +59,7 @@ NSArray *bcc; NSString *subject; NSString *text; - NSArray *fromEMails; + NSMutableArray *fromEMails; NSString *from; SOGoMailFolder *sentFolder; @@ -48,17 +70,6 @@ @end -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import "common.h" - @implementation UIxMailEditor static BOOL keepMailTmpFile = NO; @@ -97,29 +108,29 @@ static NSArray *infoKeys = nil; } - (void)dealloc { - [self->sentFolder release]; - [self->fromEMails release]; - [self->from release]; - [self->text release]; - [self->subject release]; - [self->to release]; - [self->cc release]; - [self->bcc release]; - - [self->attachmentName release]; - [self->attachmentNames release]; + [sentFolder release]; + [fromEMails release]; + [from release]; + [text release]; + [subject release]; + [to release]; + [cc release]; + [bcc release]; + + [attachmentName release]; + [attachmentNames release]; [super dealloc]; } /* accessors */ - (void)setFrom:(NSString *)_value { - ASSIGNCOPY(self->from, _value); + ASSIGNCOPY(from, _value); } - (NSString *)from { - if (![self->from isNotEmpty]) - return [[[self context] activeUser] email]; - return self->from; + if (![from isNotEmpty]) + return [[[self context] activeUser] primaryEmail]; + return from; } - (void)setReplyTo:(NSString *)_ignore { @@ -130,38 +141,38 @@ static NSArray *infoKeys = nil; } - (void)setSubject:(NSString *)_value { - ASSIGNCOPY(self->subject, _value); + ASSIGNCOPY(subject, _value); } - (NSString *)subject { - return self->subject ? self->subject : @""; + return subject ? subject : @""; } - (void)setText:(NSString *)_value { - ASSIGNCOPY(self->text, _value); + ASSIGNCOPY(text, _value); } - (NSString *)text { - return [self->text isNotNull] ? self->text : @""; + return [text isNotNull] ? text : @""; } - (void)setTo:(NSArray *)_value { - ASSIGNCOPY(self->to, _value); + ASSIGNCOPY(to, _value); } - (NSArray *)to { - return [self->to isNotNull] ? self->to : [NSArray array]; + return [to isNotNull] ? to : [NSArray array]; } - (void)setCc:(NSArray *)_value { - ASSIGNCOPY(self->cc, _value); + ASSIGNCOPY(cc, _value); } - (NSArray *)cc { - return [self->cc isNotNull] ? self->cc : [NSArray array]; + return [cc isNotNull] ? cc : [NSArray array]; } - (void)setBcc:(NSArray *)_value { - ASSIGNCOPY(self->bcc, _value); + ASSIGNCOPY(bcc, _value); } - (NSArray *)bcc { - return [self->bcc isNotNull] ? self->bcc : [NSArray array]; + return [bcc isNotNull] ? bcc : [NSArray array]; } - (BOOL)hasOneOrMoreRecipients { @@ -172,40 +183,41 @@ static NSArray *infoKeys = nil; } - (void)setAttachmentName:(NSString *)_attachmentName { - ASSIGN(self->attachmentName, _attachmentName); + ASSIGN(attachmentName, _attachmentName); } - (NSString *)attachmentName { - return self->attachmentName; + return attachmentName; } /* from addresses */ -- (NSArray *)fromEMails { - NSString *primary, *uid; - NSArray *shares; - - if (self->fromEMails != nil) - return self->fromEMails; - - uid = [[self user] login]; - primary = [[[self context] activeUser] email]; - if (![[self context] isAccessFromIntranet]) { - self->fromEMails = [[NSArray alloc] initWithObjects:&primary count:1]; - return self->fromEMails; - } - - shares = - [[[self context] activeUser] valueForKey:@"additionalEMailAddresses"]; - if ([shares count] == 0) - self->fromEMails = [[NSArray alloc] initWithObjects:&primary count:1]; - else { - id tmp; +- (NSArray *) fromEMails +{ + NSEnumerator *emails; + SOGoUser *activeUser; + NSString *cn, *fullMail, *email; + + if (!fromEMails) + { + fromEMails = [NSMutableArray new]; + activeUser = [context activeUser]; + cn = [activeUser cn]; + if ([cn length] == 0) + cn = nil; + emails = [[activeUser allEmails] objectEnumerator]; + email = [emails nextObject]; + while (email) + { + if (cn) + fullMail = [NSString stringWithFormat: @"%@ <%@>", cn, email]; + else + fullMail = email; + [fromEMails addObject: fullMail]; + email = [emails nextObject]; + } + } - tmp = [[NSArray alloc] initWithObjects:&primary count:1]; - self->fromEMails = [[tmp arrayByAddingObjectsFromArray:shares] copy]; - [tmp release]; tmp = nil; - } - return self->fromEMails; + return fromEMails; } /* title */ @@ -262,15 +274,15 @@ static NSArray *infoKeys = nil; SOGoMailAccount *account; SOGoMailFolder *folder; - if (self->sentFolder != nil) - return [self->sentFolder isNotNull] ? self->sentFolder : nil;; + if (sentFolder != nil) + return [sentFolder isNotNull] ? sentFolder : nil;; account = [[self clientObject] mailAccountFolder]; if ([account isKindOfClass:[NSException class]]) return account; folder = [account sentFolderInContext:[self context]]; if ([folder isKindOfClass:[NSException class]]) return folder; - return ((self->sentFolder = [folder retain])); + return ((sentFolder = [folder retain])); } - (void)_presetFromBasedOnAccountsQueryParameter { @@ -284,7 +296,7 @@ static NSArray *infoKeys = nil; if (useLocationBasedSentFolder) /* from will be based on location */ return; - if ([self->from isNotEmpty]) /* a from is already set */ + if ([from isNotEmpty]) /* a from is already set */ return; accountID = [[[self context] request] formValueForKey:@"account"]; @@ -341,8 +353,8 @@ static NSArray *infoKeys = nil; NSArray *sentFolderPath; NSException *error = nil; - if (self->sentFolder != nil) - return [self->sentFolder isNotNull] ? self->sentFolder : nil;; + if (sentFolder != nil) + return [sentFolder isNotNull] ? sentFolder : nil;; identity = [self selectedMailIdentity]; if ([identity isKindOfClass:[NSException class]]) return identity; @@ -365,7 +377,7 @@ static NSArray *infoKeys = nil; ctx = [[SoSubContext alloc] initWithParentContext:[self context]]; - self->sentFolder = [[accounts traversePathArray:sentFolderPath + sentFolder = [[accounts traversePathArray:sentFolderPath inContext:ctx error:&error acquire:NO] retain]; [ctx release]; ctx = nil; @@ -377,9 +389,9 @@ static NSArray *infoKeys = nil; #if 0 [self logWithFormat:@"Sent-Folder: %@", sentFolderName]; - [self logWithFormat:@" object: %@", self->sentFolder]; + [self logWithFormat:@" object: %@", sentFolder]; #endif - return self->sentFolder; + return sentFolder; } - (NSException *)storeMailInSentFolder:(NSString *)_path { @@ -433,13 +445,13 @@ static NSArray *infoKeys = nil; - (NSArray *)attachmentNames { NSArray *a; - if (self->attachmentNames != nil) - return self->attachmentNames; + if (attachmentNames != nil) + return attachmentNames; a = [[self clientObject] fetchAttachmentNames]; a = [a sortedArrayUsingSelector:@selector(compare:)]; - self->attachmentNames = [a copy]; - return self->attachmentNames; + attachmentNames = [a copy]; + return attachmentNames; } - (BOOL)hasAttachments { return [[self attachmentNames] count] > 0 ? YES : NO; diff --git a/UI/Scheduler/English.lproj/Localizable.strings b/UI/Scheduler/English.lproj/Localizable.strings index 68edabe8..62d233bf 100644 --- a/UI/Scheduler/English.lproj/Localizable.strings +++ b/UI/Scheduler/English.lproj/Localizable.strings @@ -391,7 +391,7 @@ validate_endbeforestart = "Enddate is before startdate!"; "Start" = "Start"; "End" = "End"; "Location" = "Location"; -"(Private Event)" = "(Événement privé)"; +"(Private Event)" = "(Private Event)"; "closeThisWindowMessage" = "Thank you! You may now close this window."; "Multicolumn Day View" = "Multicolumn Day View"; diff --git a/UI/Scheduler/GNUmakefile b/UI/Scheduler/GNUmakefile index 4250113d..66c045d8 100644 --- a/UI/Scheduler/GNUmakefile +++ b/UI/Scheduler/GNUmakefile @@ -18,7 +18,7 @@ SchedulerUI_OBJC_FILES = \ UIxCalDateSelector.m \ UIxCalUserRightsEditor.m \ \ - UIxComponent+Agenor.m \ + UIxComponent+Scheduler.m \ UIxCalView.m \ UIxCalAptListView.m \ UIxCalTasksListView.m \ diff --git a/UI/Scheduler/Toolbars/SOGoAppointmentFolder.toolbar b/UI/Scheduler/Toolbars/SOGoAppointmentFolder.toolbar index 64353fe2..296c3069 100644 --- a/UI/Scheduler/Toolbars/SOGoAppointmentFolder.toolbar +++ b/UI/Scheduler/Toolbars/SOGoAppointmentFolder.toolbar @@ -25,10 +25,11 @@ label="Day View"; onclick = "return onDayOverview();"; image = "day-view.png"; }, - { link = "dayoverview"; +/* disabled until we fix the view */ +/* { link = "dayoverview"; label="Multicolumn Day View"; onclick = "return onMulticolumnDayOverview();"; - image = "day-view-multicolumn.png"; }, + image = "day-view-multicolumn.png"; }, */ { link = "weekoverview"; label="Week View"; onclick = "return onWeekOverview();"; diff --git a/UI/Scheduler/UIxAppointmentEditor.m b/UI/Scheduler/UIxAppointmentEditor.m index 3f1fa9b0..3c4d20e9 100644 --- a/UI/Scheduler/UIxAppointmentEditor.m +++ b/UI/Scheduler/UIxAppointmentEditor.m @@ -28,7 +28,6 @@ #import #import -#import #import #import #import @@ -64,45 +63,6 @@ [[self clientObject] baseURL]]; } -- (NSString *) _toolbarForCalObject -{ - SOGoUser *currentUser; - SOGoAppointmentObject *clientObject; - NSString *filename, *email; - iCalPerson *person; - iCalPersonPartStat participationStatus; - - clientObject = [self clientObject]; - currentUser = [[self context] activeUser]; - email = [currentUser email]; - if ([clientObject isOrganizer: email - orOwner: [currentUser login]]) - filename = @"SOGoAppointmentObject.toolbar"; - else - { - if ([clientObject isParticipant: email]) - { - person = [[clientObject component: NO] findParticipantWithEmail: email]; - participationStatus = [person participationStatus]; - if (participationStatus == iCalPersonPartStatAccepted) - filename = @"SOGoAppointmentObjectDecline.toolbar"; - else if (participationStatus == iCalPersonPartStatDeclined) - filename = @"SOGoAppointmentObjectAccept.toolbar"; - else - filename = @"SOGoAppointmentObjectAcceptOrDecline.toolbar"; - } - else - filename = @"SOGoComponentClose.toolbar"; - } - - return filename; -} - -- (NSString *) toolbar -{ - return ([self _toolbarForCalObject]); -} - /* icalendar values */ - (BOOL) isAllDay { diff --git a/UI/Scheduler/UIxAppointmentView.m b/UI/Scheduler/UIxAppointmentView.m index 8adb3a9b..4814f714 100644 --- a/UI/Scheduler/UIxAppointmentView.m +++ b/UI/Scheduler/UIxAppointmentView.m @@ -22,9 +22,10 @@ #import "UIxAppointmentView.h" #import #import +#import #import #import -#import "UIxComponent+Agenor.h" +#import "UIxComponent+Scheduler.h" #import "common.h" @interface UIxAppointmentView (PrivateAPI) @@ -62,7 +63,7 @@ - (BOOL)isAttendeeActiveUser { NSString *email, *attEmail; - email = [[[self context] activeUser] email]; + email = [[[self context] activeUser] primaryEmail]; attendee = [self attendee]; attEmail = [attendee rfc822Email]; @@ -219,7 +220,7 @@ NSString *email; iCalPerson *organizer; - email = [[[self context] activeUser] email]; + email = [[[self context] activeUser] primaryEmail]; organizer = [[self appointment] organizer]; if (!organizer) return YES; // assume this is correct to do, right? return [[organizer rfc822Email] isEqualToString:email]; @@ -237,7 +238,7 @@ return YES; /* can access it if I'm invited :-) */ - email = [[[self context] activeUser] email]; + email = [[[self context] activeUser] primaryEmail]; partMails = [[[self appointment] participants] valueForKey:@"rfc822Email"]; return [partMails containsObject:email]; } diff --git a/UI/Scheduler/UIxCalInlineAptView.m b/UI/Scheduler/UIxCalInlineAptView.m index a0bc0d82..9fd641ac 100644 --- a/UI/Scheduler/UIxCalInlineAptView.m +++ b/UI/Scheduler/UIxCalInlineAptView.m @@ -126,7 +126,7 @@ if ((prio = [appointment valueForKey:@"priority"])) { [ms appendFormat:@" apt_prio%@", prio]; } - email = [[[self context] activeUser] email]; + email = [[context activeUser] primaryEmail]; s = [appointment valueForKey:@"orgmail"]; if ([s isNotNull]) { diff --git a/UI/Scheduler/UIxCalView.m b/UI/Scheduler/UIxCalView.m index 037a99f4..96ecf6f8 100644 --- a/UI/Scheduler/UIxCalView.m +++ b/UI/Scheduler/UIxCalView.m @@ -9,7 +9,7 @@ #import #import -#import "UIxComponent+Agenor.h" +#import "UIxComponent+Scheduler.h" #import "SoObjects/Appointments/SOGoAppointmentFolder.h" #import @@ -113,7 +113,7 @@ static BOOL shouldDisplayWeekend = NO; { count = [_apts count]; filtered = [[[NSMutableArray alloc] initWithCapacity: count] autorelease]; - email = [self emailForUser]; + email = [[context activeUser] primaryEmail]; for (i = 0; i < count; i++) { diff --git a/UI/Scheduler/UIxCalendarSelector.m b/UI/Scheduler/UIxCalendarSelector.m index 5903aecb..7205bfec 100644 --- a/UI/Scheduler/UIxCalendarSelector.m +++ b/UI/Scheduler/UIxCalendarSelector.m @@ -28,7 +28,6 @@ #import #import -#import #import #import #import diff --git a/UI/Scheduler/UIxComponent+Agenor.h b/UI/Scheduler/UIxComponent+Scheduler.h similarity index 93% rename from UI/Scheduler/UIxComponent+Agenor.h rename to UI/Scheduler/UIxComponent+Scheduler.h index 7db79e75..aa11ea4d 100644 --- a/UI/Scheduler/UIxComponent+Agenor.h +++ b/UI/Scheduler/UIxComponent+Scheduler.h @@ -30,10 +30,6 @@ - (NSArray *) getICalPersonsFromValue: (NSString *) selectorValue; -/* email, cn */ -- (NSString *) emailForUser; -- (NSString *) cnForUser; - @end #endif /* __UIxComponent_Agenor_H_ */ diff --git a/UI/Scheduler/UIxComponent+Agenor.m b/UI/Scheduler/UIxComponent+Scheduler.m similarity index 76% rename from UI/Scheduler/UIxComponent+Agenor.m rename to UI/Scheduler/UIxComponent+Scheduler.m index 20aa370d..46b92548 100644 --- a/UI/Scheduler/UIxComponent+Agenor.m +++ b/UI/Scheduler/UIxComponent+Scheduler.m @@ -19,11 +19,13 @@ 02111-1307, USA. */ -#include "UIxComponent+Agenor.h" -#include -#include -#include -#include "common.h" +#import +#import +#import + +#import + +#import "UIxComponent+Scheduler.h" @implementation UIxComponent(Agenor) @@ -32,9 +34,9 @@ NSMutableArray *persons; NSEnumerator *uids; NSString *uid; - AgenorUserManager *um; + SOGoCalendarComponent *component; - um = [AgenorUserManager sharedUserManager]; + component = [self clientObject]; persons = [NSMutableArray new]; [persons autorelease]; @@ -46,7 +48,7 @@ uid = [uids nextObject]; while (uid) { - [persons addObject: [um iCalPersonWithUid: uid]]; + [persons addObject: [component iCalPersonWithUID: uid]]; uid = [uids nextObject]; } } @@ -54,14 +56,4 @@ return persons; } -- (NSString *) emailForUser -{ - return [[context activeUser] email]; -} - -- (NSString *) cnForUser -{ - return [[context activeUser] cn]; -} - @end /* UIxComponent(Agenor) */ diff --git a/UI/Scheduler/UIxComponentEditor.h b/UI/Scheduler/UIxComponentEditor.h index 72bf704b..087fc1f0 100644 --- a/UI/Scheduler/UIxComponentEditor.h +++ b/UI/Scheduler/UIxComponentEditor.h @@ -62,6 +62,7 @@ NSString *attendeesEmails; } +- (NSString *) toolbar; - (void) setComponent: (iCalRepeatableEntityObject *) newComponent; - (void) setSaveURL: (NSString *) newSaveURL; diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m index 9684e36b..910fc8dc 100644 --- a/UI/Scheduler/UIxComponentEditor.m +++ b/UI/Scheduler/UIxComponentEditor.m @@ -40,7 +40,6 @@ #import #import -#import #import #import #import @@ -48,7 +47,7 @@ #import #import -#import "UIxComponent+Agenor.h" +#import "UIxComponent+Scheduler.h" #import "UIxComponentEditor.h" @@ -653,8 +652,7 @@ - (BOOL) isMyComponent { - // TODO: this should check a set of emails against the SoUser - return ([[organizer rfc822Email] isEqualToString: [self emailForUser]]); + return ([[context activeUser] hasEmail: [organizer rfc822Email]]); } - (BOOL) canEditComponent @@ -794,6 +792,7 @@ - (void) _handleOrganizer { NSString *organizerEmail; + SOGoUser *activeUser; organizerEmail = [[component organizer] email]; if ([organizerEmail length] == 0) @@ -801,8 +800,9 @@ if ([[component attendees] count] > 0) { ASSIGN (organizer, [iCalPerson elementWithTag: @"organizer"]); - [organizer setCn: [self cnForUser]]; - [organizer setEmail: [self emailForUser]]; + activeUser = [context activeUser]; + [organizer setCn: [activeUser cn]]; + [organizer setEmail: [activeUser primaryEmail]]; [component setOrganizer: organizer]; } } @@ -843,4 +843,42 @@ [component setLastModified: now]; } +- (NSString *) toolbar +{ + SOGoUser *currentUser; + SOGoCalendarComponent *clientObject; + NSString *toolbarFilename; + iCalPerson *person; + iCalPersonPartStat participationStatus; + + clientObject = [self clientObject]; + currentUser = [[self context] activeUser]; + if ([clientObject isOrganizerOrOwner: currentUser]) + { + if ([[clientObject componentTag] isEqualToString: @"vevent"]) + toolbarFilename = @"SOGoAppointmentObject.toolbar"; + else + toolbarFilename = @"SOGoTaskObject.toolbar"; + } + else + { + /* Lightning does not manage participation status within tasks */ + person = [clientObject participant: currentUser]; + if (person) + { + participationStatus = [person participationStatus]; + if (participationStatus == iCalPersonPartStatAccepted) + toolbarFilename = @"SOGoAppointmentObjectDecline.toolbar"; + else if (participationStatus == iCalPersonPartStatDeclined) + toolbarFilename = @"SOGoAppointmentObjectAccept.toolbar"; + else + toolbarFilename = @"SOGoAppointmentObjectAcceptOrDecline.toolbar"; + } + else + toolbarFilename = @"SOGoComponentClose.toolbar"; + } + + return toolbarFilename; +} + @end diff --git a/UI/Scheduler/UIxTaskEditor.m b/UI/Scheduler/UIxTaskEditor.m index 360cdf01..607e0adf 100644 --- a/UI/Scheduler/UIxTaskEditor.m +++ b/UI/Scheduler/UIxTaskEditor.m @@ -28,7 +28,6 @@ #import #import -#import #import #import #import @@ -79,45 +78,6 @@ [[self clientObject] baseURL]]; } -- (NSString *) _toolbarForCalObject -{ - SOGoUser *currentUser; - SOGoTaskObject *clientObject; - NSString *filename, *email; - iCalPerson *person; - iCalPersonPartStat participationStatus; - - clientObject = [self clientObject]; - currentUser = [[self context] activeUser]; - email = [currentUser email]; - if ([clientObject isOrganizer: email - orOwner: [currentUser login]]) - filename = @"SOGoTaskObject.toolbar"; - else - { - if ([clientObject isParticipant: email]) - { - person = [[clientObject component: NO] findParticipantWithEmail: email]; - participationStatus = [person participationStatus]; - if (participationStatus == iCalPersonPartStatAccepted) - filename = @"SOGoTaskObjectDecline.toolbar"; - else if (participationStatus == iCalPersonPartStatDeclined) - filename = @"SOGoTaskObjectAccept.toolbar"; - else - filename = @"SOGoTaskObjectAcceptOrDecline.toolbar"; - } - else - filename = @"SOGoComponentClose.toolbar"; - } - - return filename; -} - -- (NSString *) toolbar -{ - return ([self _toolbarForCalObject]); -} - /* icalendar values */ - (void) setTaskStartDate: (NSCalendarDate *) newTaskStartDate { diff --git a/UI/Scheduler/UIxTaskView.m b/UI/Scheduler/UIxTaskView.m index 32303413..0af81407 100644 --- a/UI/Scheduler/UIxTaskView.m +++ b/UI/Scheduler/UIxTaskView.m @@ -22,9 +22,10 @@ #import "UIxTaskView.h" #import #import +#import #import #import -#import "UIxComponent+Agenor.h" +#import "UIxComponent+Scheduler.h" #import "common.h" @interface UIxTaskView (PrivateAPI) @@ -62,7 +63,7 @@ - (BOOL)isAttendeeActiveUser { NSString *email, *attEmail; - email = [[[self context] activeUser] email]; + email = [[[self context] activeUser] primaryEmail]; attendee = [self attendee]; attEmail = [attendee rfc822Email]; @@ -221,7 +222,7 @@ NSString *email; iCalPerson *organizer; - email = [[[self context] activeUser] email]; + email = [[[self context] activeUser] primaryEmail]; organizer = [[self task] organizer]; if (!organizer) return YES; // assume this is correct to do, right? return [[organizer rfc822Email] isEqualToString:email]; @@ -239,9 +240,9 @@ return YES; /* can access it if I'm invited :-) */ - email = [[[self context] activeUser] email]; + email = [[[self context] activeUser] primaryEmail]; partMails = [[[self task] participants] valueForKey:@"rfc822Email"]; - return [partMails containsObject:email]; + return [partMails containsObject: email]; } - (BOOL)canEditApt { diff --git a/UI/Templates/ContactsUI/UIxContactsListViewContainer.wox b/UI/Templates/ContactsUI/UIxContactsListViewContainer.wox index 45d90f3b..f53445b0 100644 --- a/UI/Templates/ContactsUI/UIxContactsListViewContainer.wox +++ b/UI/Templates/ContactsUI/UIxContactsListViewContainer.wox @@ -16,10 +16,10 @@
  • -
  • -
  • +
  • +
  • -
  • +
  • @@ -28,7 +28,7 @@
  • -
  • +
  • diff --git a/UI/Templates/GNUmakefile b/UI/Templates/GNUmakefile index 8b9813f6..7a5acdd6 100644 --- a/UI/Templates/GNUmakefile +++ b/UI/Templates/GNUmakefile @@ -1,11 +1,22 @@ # GNUstep makefile -validate-wox: - xmllint --noout *.wox - +XMLLINT = xmllint +XMLLINT-BIN = $(shell which $(XMLLINT)) +ifeq ($(XMLLINT-BIN),) +all :: + @echo Utility \"$(XMLLINT)\" not found. Skipping validation. +else all :: validate-wox +endif + +WOXS = $(shell find . -name '*.wox' -type f) + +validate-wox: + for wox in $(WOXS); \ + do $(XMLLINT-BIN) --noout $$wox || exit 1; \ + done; -install :: all +install :: clean :: diff --git a/UI/Templates/MailerUI/UIxMailMainFrame.wox b/UI/Templates/MailerUI/UIxMailMainFrame.wox index 80925409..1e7be00a 100644 --- a/UI/Templates/MailerUI/UIxMailMainFrame.wox +++ b/UI/Templates/MailerUI/UIxMailMainFrame.wox @@ -9,66 +9,66 @@ popup="isPopup" >