From 669db242c5b76ea4004bd93121fac5aab8a06084 Mon Sep 17 00:00:00 2001 From: wolfgang Date: Fri, 27 Apr 2007 22:15:40 +0000 Subject: [PATCH] git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1050 d1b88da0-ebda-0310-925b-ed51d893ca5b --- ChangeLog | 191 +++++++++ Main/SOGo.m | 397 ++++++++---------- Main/sogod.m | 7 +- SOPE/NGCards/ChangeLog | 5 + SOPE/NGCards/NGVCard.m | 10 +- .../Appointments/SOGoAppointmentFolder.h | 4 + .../Appointments/SOGoAppointmentFolder.m | 94 ++++- .../Appointments/SOGoCalendarComponent.m | 139 +++--- .../Appointments/SOGoGroupAppointmentFolder.m | 1 + SoObjects/Appointments/product.plist | 41 +- SoObjects/Contacts/SOGoContactFolders.m | 6 + SoObjects/Contacts/SOGoContactGCSFolder.m | 2 +- SoObjects/Contacts/SOGoContactLDAPEntry.m | 5 + SoObjects/Contacts/SOGoContactLDAPFolder.m | 50 +-- SoObjects/Mailer/SOGoDraftObject.m | 12 +- SoObjects/Mailer/SOGoMailAccounts.m | 7 + SoObjects/Mailer/SOGoMailBaseObject.m | 13 +- SoObjects/Mailer/product.plist | 42 +- SoObjects/SOGo/AgenorUserManager.m | 194 +++++---- SoObjects/SOGo/GNUmakefile | 2 - SoObjects/SOGo/NSCalendarDate+SOGo.h | 2 + SoObjects/SOGo/NSCalendarDate+SOGo.m | 26 ++ SoObjects/SOGo/SOGoAclsFolder.m | 230 ---------- SoObjects/SOGo/SOGoContentObject.h | 26 +- SoObjects/SOGo/SOGoContentObject.m | 182 ++++---- SoObjects/SOGo/SOGoFolder.h | 16 +- SoObjects/SOGo/SOGoFolder.m | 246 +++++++++-- SoObjects/SOGo/SOGoObject.h | 11 +- SoObjects/SOGo/SOGoObject.m | 83 +++- SoObjects/SOGo/SOGoPermissions.h | 51 ++- SoObjects/SOGo/SOGoPermissions.m | 58 ++- SoObjects/SOGo/SOGoUser.m | 35 +- UI/Common/English.lproj/Localizable.strings | 2 + UI/Common/French.lproj/Localizable.strings | 2 + UI/Common/GNUmakefile | 2 + UI/Common/Toolbars/SOGoAclOwner.toolbar | 7 +- UI/Common/UIxAclEditor.h | 13 +- UI/Common/UIxAclEditor.m | 165 +++----- UI/Common/UIxFolderActions.m | 1 + .../Common/UIxObjectActions.h | 31 +- UI/Common/UIxObjectActions.m | 66 +++ UI/Common/UIxUserRightsEditor.h | 53 +++ UI/Common/UIxUserRightsEditor.m | 162 +++++++ UI/Common/product.plist | 48 ++- UI/Contacts/English.lproj/Localizable.strings | 12 + UI/Contacts/French.lproj/Localizable.strings | 12 + UI/Contacts/GNUmakefile | 1 + UI/Contacts/UIxContactsUserRightsEditor.h | 46 ++ UI/Contacts/UIxContactsUserRightsEditor.m | 111 +++++ UI/Contacts/product.plist | 31 +- UI/MailerUI/product.plist | 1 - UI/MainUI/product.plist | 37 +- .../English.lproj/Localizable.strings | 26 +- UI/Scheduler/French.lproj/Localizable.strings | 27 +- UI/Scheduler/GNUmakefile | 2 +- UI/Scheduler/UIxCalDayView.h | 2 - UI/Scheduler/UIxCalDayView.m | 1 - UI/Scheduler/UIxCalInlineAptView.m | 19 - UI/Scheduler/UIxCalUserRightsEditor.h | 58 +++ UI/Scheduler/UIxCalUserRightsEditor.m | 206 +++++++++ UI/Scheduler/UIxCalView.m | 110 +++-- UI/Scheduler/UIxComponentEditor.h | 7 - UI/Scheduler/UIxComponentEditor.m | 119 +++--- UI/Scheduler/product.plist | 57 +-- .../UIxContactsUserRightsEditor.wox | 47 +++ .../SchedulerUI/UIxCalInlineAptView.wox | 7 +- .../SchedulerUI/UIxCalUserRightsEditor.wox | 60 +++ .../SchedulerUI/UIxComponentEditor.wox | 12 +- UI/Templates/UIxAclEditor.wox | 27 +- UI/Templates/UIxUserRightsEditor.wox | 14 + UI/WebServerResources/ContactsUI.js | 3 + UI/WebServerResources/MailerUI.js | 6 +- UI/WebServerResources/SchedulerUI.css | 10 +- UI/WebServerResources/SchedulerUI.js | 8 + UI/WebServerResources/UIxAclEditor.js | 136 +++--- .../UIxCalUserRightsEditor.css | 49 +++ .../UIxCalUserRightsEditor.js | 9 + UI/WebServerResources/UIxComponentEditor.js | 31 +- .../UIxContactsUserRightsEditor.css | 49 +++ .../UIxContactsUserRightsEditor.js | 9 + UI/WebServerResources/generic.css | 30 +- UI/WebServerResources/generic.js | 37 +- 82 files changed, 2754 insertions(+), 1415 deletions(-) delete mode 100644 SoObjects/SOGo/SOGoAclsFolder.m rename SoObjects/SOGo/SOGoAclsFolder.h => UI/Common/UIxObjectActions.h (54%) create mode 100644 UI/Common/UIxObjectActions.m create mode 100644 UI/Common/UIxUserRightsEditor.h create mode 100644 UI/Common/UIxUserRightsEditor.m create mode 100644 UI/Contacts/UIxContactsUserRightsEditor.h create mode 100644 UI/Contacts/UIxContactsUserRightsEditor.m create mode 100644 UI/Scheduler/UIxCalUserRightsEditor.h create mode 100644 UI/Scheduler/UIxCalUserRightsEditor.m create mode 100644 UI/Templates/ContactsUI/UIxContactsUserRightsEditor.wox create mode 100644 UI/Templates/SchedulerUI/UIxCalUserRightsEditor.wox create mode 100644 UI/Templates/UIxUserRightsEditor.wox create mode 100644 UI/WebServerResources/UIxCalUserRightsEditor.css create mode 100644 UI/WebServerResources/UIxCalUserRightsEditor.js create mode 100644 UI/WebServerResources/UIxContactsUserRightsEditor.css create mode 100644 UI/WebServerResources/UIxContactsUserRightsEditor.js diff --git a/ChangeLog b/ChangeLog index f3d2c8f4..11f9fae3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,194 @@ +2007-04-27 Wolfgang Sourdeau + + * SoObjects/SOGo/SOGoPermissions.m: added "SOGoRole_ObjectViewer" + and "SOGoRole_ObjectEditor". + + * UI/Common/UIxUserRightsEditor.m ([UIxUserRightsEditor + -prepareRightsForm]): this method is no longer mandatory. + + * UI/Contacts/UIxContactsUserRightsEditor.m + ([UIxContactsUserRightsEditor + -setUserCanCreateObjects:userCanCreateObjects]): new subclass + module to handle acls related to the address books. Partial + implementation. + + * SoObjects/SOGo/SOGoFolder.m ([SOGoFolder + -setRoles:rolesforUser:uidforObjectAtPath:objectPathArray]): cache + newly set roles. + ([SOGoFolder + -removeAclsForUsers:usersforObjectAtPath:objectPathArray]): remove + specified roles from cache. + ([SOGoFolder -aclsForUser:uidforObjectAtPath:objectPathArray]): + put resulting roles in cache. + + * SoObjects/SOGo/SOGoObject.m ([SOGoObject -init]): do not invoke + initWithName:inContainer:. Instead, directly initialize the ivars + as it is supposed to be to avoid an infinite loop whenever one of + those two methods are overriden. + + * SoObjects/SOGo/SOGoContentObject.m ([-rolesOfUser:login]): + removed method. + + * SoObjects/Contacts/SOGoContactLDAPEntry.m ([SOGoContactLDAPEntry + -aclsForUser:uid]): override method so that SOGo won't crash when + loading the contact card. + +2007-04-26 Wolfgang Sourdeau + + * SoObjects/Appointments/SOGoAppointmentFolder.m + ([SOGoAppointmentFolder -_privacySqlString]): the string for the + "freebusy" special user should only require opaque elements. + +2007-04-25 Wolfgang Sourdeau + + * SoObjects/Appointments/SOGoAppointmentFolder.m + ([SOGoAppointmentFolder -davResourceType]): fixed a problem with + our double declaration where the resulting XML would be screwed. + There is only one collection per namespace. + + * SoObjects/SOGo/NSCalendarDate+SOGo.m ([NSCalendarDate + rfc822DateString]): new method that returns a string conform to + rfc 822 and suitable for email headers. + + * SoObjects/Mailer/SOGoDraftObject.m: invoke the new + "rfc822DateString" category method on the date we put in the + header. + +2007-04-24 Wolfgang Sourdeau + + * UI/Common/UIxUserRightsEditor.m ([UIxUserRightsEditor -defaultAction]) + ([UIxUserRightsEditor -saveUserRightsAction]): new action methods + which should never be overriden. + ([UIxUserRightsEditor -appendRight:newRight]) + ([UIxUserRightsEditor -removeRight:right]) + ([UIxUserRightsEditor -appendExclusiveRight:newRightfromList:list]) + ([UIxUserRightsEditor -removeAllRightsFromList:list]): new utility + methods that can be used by the subclasses. + ([UIxUserRightsEditor -prepareRightsForm]): new method that should + mandatorily be overriden to prepare the elements of the subclassed + form. + ([UIxUserRightsEditor -updateRights]): new method that should + mandatorily be overriden to update the user rights from the + elements of the subclassed form. + + * UI/Common/UIxAclEditor.m ([UIxAclEditor -_prepareUsers]): we + check if the uid is already listed before adding it to our array. + This is because the acl table can contain more than one record per + user/object relationship. + + * SoObjects/SOGo/SOGoFolder.m ([SOGoFolder + -setRoles:rolesforUser:uidforObjectAtPath:objectPathArray]): the + "roles" parameter is now an NSArray instead of a string. Therefore + we loop throughout the array to populate the table. All the + relevant records are removed prior to the addition of the new + rights. + + * SoObjects/Mailer/SOGoMailBaseObject.m ([SOGoMailBaseObject + -aclsForUser:uid]): new override that returns nil until we add + support for IMAP acls. + + * SoObjects/Mailer/SOGoMailAccounts.m + ([SOGoMailAccounts -aclsForUser:uid]): same as below. + + * SoObjects/Contacts/SOGoContactLDAPFolder.m + ([SOGoContactLDAPFolder -aclsForUser:uid]): same as below. + + * SoObjects/Contacts/SOGoContactFolders.m ([SOGoContactFolders + -aclsForUser:uid]): override this method which will always return + nil. + + * SoObjects/SOGo/SOGoPermissions.[hm]: added + [Public,Private,Confidential] + x[Viewer,DAndTViewer,Responder,Modifier]. Renamed + SOGoRole_ORganizer to SOGoCalendarRole_Organizer. Same for + ..._Participant. Removed SOGoRole_Assistant and SOGoRole_Delegate. + + * SoObjects/Appointments/SOGoAppointmentFolder.m + ([SOGoAppointmentFolder -defaultAclRoles]): new overriden method + that defines default roles for new elements in the acl. + + * UI/Scheduler/UIxCalUserRightsEditor.[hm]: new component class + module and subclass of UIxUserRightsEditor specific to the + handling of user rights on calendar folders. + +2007-04-23 Wolfgang Sourdeau + + * SoObjects/Appointments/SOGoAppointmentFolder.m + ([SOGoAppointmentFolder -groupDavResourceType]): return both + "vevent-collection" and "vtodo-collection". + + * UI/Common/UIxUserRightsEditor.[hm]: new template class module + that implements the detailed editor of user rights per-object. + +2007-04-17 Wolfgang Sourdeau + + * SoObjects/SOGo/SOGoUser.m ([SOGoUser + -rolesForObject:objectinContext:context]): no longer query objects + for "roleForUser:". Instead, all objects should implement + "rolesForUser:". + + * SoObjects/SOGo/SOGoContentObject.m ([SOGoContentObject -acls]): + new method to comply with the new acl "protocol" in SOGoObject. + Uses SOGoFolder's new facilities for ACLS. + ([SOGoContentObject -aclsForUser:uid]): idem. + ([SOGoContentObject -setRoles:rolesforUser:uid]): idem. + ([SOGoContentObject -removeAclsForUsers:users]): idem. + + * SoObjects/SOGo/SOGoFolder.m ([SOGoFolder + -aclsForObjectAtPath:objectPathArray]): new method generic to GCS + based folders. This method is derived from the code that was in + UIxAclFolder before its removal. + ([SOGoFolder -aclsForUser:uidforObjectAtPath:objectPathArray]): + idem. + ([SOGoFolder + -removeAclsForUsers:usersforObjectAtPath:objectPathArray]): idem. + ([SOGoFolder + -setRoles:rolesforUser:uidforObjectAtPath:objectPathArray]): idem. + ([SOGoFolder -setRoleForUsers:uidsto:role]) + ([SOGoFolder -setRoleForUsers:uidsto:role]): removed method. + + * SoObjects/SOGo/SOGoObject.m ([SOGoObject -acls]): stub method + that requires overriding by subclasses. + ([SOGoObject -aclsForUser:uid]): idem. + ([SOGoObject -defaultAclRoles]): idem. + ([SOGoObject -setRoles:rolesforUser:uid]): idem. + ([SOGoObject -removeAclsForUsers:users]): idem. + + * UI/Common/UIxObjectActions.m: new module implementing the web + actions common to SOGoObject and all its subclasses. + ([UIxObjectActions -addUserInAclsAction]): new method that adds a + user with the clientObject defaults user rights to the object's + acl. + + * UI/Common/UIxAclEditor.m: modified module so as to simplify it + to the point where it will only list the users (and their name) + associated with an object acl. + + * SoObjects/SOGo/SOGoAclsFolder.m: removed module because its + methods have been moved into SOGoObject and SOGoFolder during a + refactoring. + + * UI/Scheduler/UIxComponentEditor.m ([UIxComponentEditor + -iCalParticipantsAndResourcesStringFromQueryParameters]): removed + method made useless by the programmatic handling of iCalendar + objects. + ([UIxComponentEditor -iCalParticipantsStringFromQueryParameters]): idem. + ([UIxComponentEditor -iCalResourcesStringFromQueryParameters]): idem. + ([UIxComponentEditor -iCalStringFromQueryParameter:_qpformat:_format]): idem. + + * UI/WebServerResources/MailerUI.js (initDnd): enable drag and + drop on all folder nodes, not just on leaves. + + * SoObjects/Contacts/SOGoContactLDAPFolder.m + ([SOGoContactLDAPFolder + -lookupContactsWithFilter:filtersortBy:sortKeyordering:sortOrdering]): request field "uid" when doing a search. + +2007-04-16 Wolfgang Sourdeau + + * Main/SOGo.m ([SOGo +initialize]): on GNUstep, trigger some + debugging facilities when the SOGoDebugObjectAllocation user + default is set. + 2007-04-11 Wolfgang Sourdeau * SoObjects/SOGo/NSString+Utilities.m ([NSString -boolValue]): new diff --git a/Main/SOGo.m b/Main/SOGo.m index a427bd78..b6406ceb 100644 --- a/Main/SOGo.m +++ b/Main/SOGo.m @@ -21,92 +21,6 @@ #include -// @interface classtree : NSObject -// { -// Class topClass; -// int indentLevel; -// } - -// - (id) initWithTopClass: (Class) newTopClass; -// - (void) dumpSiblings: (Class) node; - -// @end - -// @implementation classtree - -// + (id) newWithTopClass: (Class) newTopClass -// { -// id newTree; - -// newTree = [[self alloc] initWithTopClass: newTopClass]; -// [newTree autorelease]; - -// return newTree; -// } - -// - (id) initWithTopClass: (Class) newTopClass -// { -// if ((self = [self init])) -// topClass = newTopClass; - -// return self; -// } - -// #define indentGap 2 - -// - (NSString *) indentSpaces -// { -// char *spaceString; - -// spaceString = malloc(sizeof (char *) * indentGap * indentLevel + 1); -// *(spaceString + indentGap * indentLevel) = 0; -// memset (spaceString, ' ', indentGap * indentLevel); - -// return [[NSString alloc] initWithCStringNoCopy: spaceString -// length: indentGap * indentLevel -// freeWhenDone: YES]; -// } - -// - (void) dumpNode: (Class) node -// { -// Class currentSubclass; -// unsigned int count; - -// count = 0; -// currentSubclass = node->subclass_list; -// if (currentSubclass) -// { -// NSLog(@"%@%@:", -// [[self indentSpaces] autorelease], NSStringFromClass(node)); -// indentLevel++; -// [self dumpSiblings: currentSubclass]; -// indentLevel--; -// } -// else -// NSLog(@"%@%@", [self indentSpaces], NSStringFromClass(node)); -// } - -// - (void) dumpSiblings: (Class) node -// { -// Class currentNode; - -// currentNode = node; -// while (currentNode && currentNode->instance_size) -// { -// [self dumpNode: currentNode]; -// currentNode = currentNode->sibling_class; -// } -// } - -// - (void) dumpTree -// { -// indentLevel = 0; - -// [self dumpSiblings: topClass]; -// } - -// @end - @interface SOGo : SoApplication { NSMutableDictionary *localeLUT; @@ -129,27 +43,37 @@ static unsigned int vMemSizeLimit = 0; static BOOL doCrashOnSessionCreate = NO; -+ (void)initialize { +#ifdef GNUSTEP_BASE_LIBRARY +static BOOL debugObjectAllocation = NO; +#endif + ++ (void) initialize +{ NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; SoClassSecurityInfo *sInfo; NSArray *basicRoles; id tmp; doCrashOnSessionCreate = [ud boolForKey:@"SOGoCrashOnSessionCreate"]; +#ifdef GNUSTEP_BASE_LIBRARY + debugObjectAllocation = [ud boolForKey: @"SOGoDebugObjectAllocation"]; + if (debugObjectAllocation) + { + NSLog (@"activating stats on object allocation"); + GSDebugAllocationActive (YES); + } +#endif /* vMem size check - default is 200MB */ - tmp = [ud objectForKey:@"SxVMemLimit"]; - vMemSizeLimit = (tmp != nil) - ? [tmp intValue] - : 200; - if (vMemSizeLimit > 0) { + tmp = [ud objectForKey: @"SxVMemLimit"]; + vMemSizeLimit = ((tmp != nil) ? [tmp intValue] : 200); + if (vMemSizeLimit > 0) NSLog(@"Note: vmem size check enabled: shutting down app when " @"vmem > %d MB", vMemSizeLimit); - } #if LIB_FOUNDATION_LIBRARY if ([ud boolForKey:@"SOGoEnableDoubleReleaseCheck"]) - [NSAutoreleasePool enableDoubleReleaseCheck:YES]; + [NSAutoreleasePool enableDoubleReleaseCheck: YES]; #endif /* SoClass security declarations */ @@ -168,42 +92,49 @@ static BOOL doCrashOnSessionCreate = NO; [sInfo declareRoles: basicRoles asDefaultForPermission: SoPerm_WebDAVAccess]; } -- (id)init { - if ((self = [super init])) { - WOResourceManager *rm; - - /* ensure core SoClass'es are setup */ - [$(@"SOGoObject") soClass]; - [$(@"SOGoContentObject") soClass]; - [$(@"SOGoFolder") soClass]; - - /* setup locale cache */ - self->localeLUT = [[NSMutableDictionary alloc] initWithCapacity:2]; +- (id) init +{ + if ((self = [super init])) + { + WOResourceManager *rm; + + /* ensure core SoClass'es are setup */ + [$(@"SOGoObject") soClass]; + [$(@"SOGoContentObject") soClass]; + [$(@"SOGoFolder") soClass]; + + /* setup locale cache */ + localeLUT = [[NSMutableDictionary alloc] initWithCapacity:2]; - /* load products */ - [[SOGoProductLoader productLoader] loadProducts]; + /* load products */ + [[SOGoProductLoader productLoader] loadProducts]; - /* setup resource manager */ - rm = [[WEResourceManager alloc] init]; - [self setResourceManager:rm]; - } + /* setup resource manager */ + rm = [[WEResourceManager alloc] init]; + [self setResourceManager:rm]; + } + return self; } -- (void)dealloc { - [self->localeLUT release]; +- (void) dealloc +{ + [localeLUT release]; [super dealloc]; } /* authenticator */ -- (id)authenticatorInContext:(id)_ctx { +- (id) authenticatorInContext: (id) _ctx +{ return [$(@"SOGoAuthenticator") sharedSOGoAuthenticator]; } /* name lookup */ -- (BOOL)isUserName:(NSString *)_key inContext:(id)_ctx { +- (BOOL) isUserName: (NSString *) _key + inContext: (id) _ctx +{ if ([_key length] < 1) return NO; @@ -218,21 +149,29 @@ static BOOL doCrashOnSessionCreate = NO; initWithName:_key inContainer:self] autorelease]; } -- (void)_setupLocaleInContext:(WOContext *)_ctx { +- (void) _setupLocaleInContext: (WOContext *) _ctx +{ NSArray *langs; NSDictionary *locale; if ([[_ctx valueForKey:@"locale"] isNotNull]) return; - langs = [[(WOContext *)_ctx request] browserLanguages]; + langs = [[_ctx request] browserLanguages]; locale = [self currentLocaleConsideringLanguages:langs]; [_ctx takeValue:locale forKey:@"locale"]; } -- (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag { +- (id) lookupName: (NSString *) _key + inContext: (id) _ctx + acquire: (BOOL) _flag +{ id obj; +#ifdef GNUSTEP_BASE_LIBRARY + if (debugObjectAllocation) + NSLog(@"objects allocated\n%s", GSDebugAllocationList (YES)); +#endif /* put locale info into the context in case it's not there */ [self _setupLocaleInContext:_ctx]; @@ -259,15 +198,16 @@ static BOOL doCrashOnSessionCreate = NO; /* WebDAV */ -- (NSString *)davDisplayName { +- (NSString *) davDisplayName +{ /* this is used in the UI, eg in the navigation */ return @"SOGo"; } /* exception handling */ -- (WOResponse *)handleException:(NSException *)_exc - inContext:(WOContext *)_ctx +- (WOResponse *) handleException: (NSException *) _exc + inContext: (WOContext *) _ctx { printf("EXCEPTION: %s\n", [[_exc description] cString]); abort(); @@ -275,56 +215,54 @@ static BOOL doCrashOnSessionCreate = NO; /* runtime maintenance */ -// - (void) _dumpClassAllocation -// { -// classtree *ct; - -// ct = [classtree newWithTopClass: [NSObject class]]; -// [ct dumpTree]; -// } - -- (void)checkIfDaemonHasToBeShutdown { - unsigned int limit, vmem; - - if ((limit = vMemSizeLimit) == 0) - return; - - vmem = [[NSProcessInfo processInfo] virtualMemorySize]/1048576; - - if (vmem > limit) { - [self logWithFormat: - @"terminating app, vMem size limit (%d MB) has been reached" - @" (currently %d MB)", - limit, vmem]; -// [self _dumpClassAllocation]; - [self terminate]; - } +- (void) checkIfDaemonHasToBeShutdown +{ + unsigned int vmem; + + if (vMemSizeLimit > 0) + { + vmem = [[NSProcessInfo processInfo] virtualMemorySize]/1048576; + + if (vmem > vMemSizeLimit) + { + [self logWithFormat: + @"terminating app, vMem size limit (%d MB) has been reached" + @" (currently %d MB)", + vMemSizeLimit, vmem]; +// if (debugObjectAllocation) +// [self _dumpClassAllocation]; + [self terminate]; + } + } } -- (WOResponse *)dispatchRequest:(WORequest *)_request { +- (WOResponse *) dispatchRequest: (WORequest *) _request +{ static NSArray *runLoopModes = nil; WOResponse *resp; - resp = [super dispatchRequest:_request]; + resp = [super dispatchRequest: _request]; - if ([self isTerminating]) - return resp; - - if (runLoopModes == nil) - runLoopModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode, nil]; + if (![self isTerminating]) + { + if (!runLoopModes) + runLoopModes = [[NSArray alloc] initWithObjects: NSDefaultRunLoopMode, nil]; - // TODO: a bit complicated? (-perform:afterDelay: doesn't work?) - [[NSRunLoop currentRunLoop] performSelector: - @selector(checkIfDaemonHasToBeShutdown) - target:self argument:nil - order:1 modes:runLoopModes]; + // TODO: a bit complicated? (-perform:afterDelay: doesn't work?) + [[NSRunLoop currentRunLoop] performSelector: + @selector (checkIfDaemonHasToBeShutdown) + target: self argument: nil + order:1 modes:runLoopModes]; + } + return resp; } /* session management */ -- (id)createSessionForRequest:(WORequest *)_request { - [self warnWithFormat:@"session creation requested!"]; +- (id) createSessionForRequest: (WORequest *) _request +{ + [self warnWithFormat: @"session creation requested!"]; if (doCrashOnSessionCreate) abort(); return [super createSessionForRequest:_request]; @@ -332,87 +270,102 @@ static BOOL doCrashOnSessionCreate = NO; /* localization */ -- (NSDictionary *)currentLocaleConsideringLanguages:(NSArray *)_langs { - unsigned i, count; +- (NSDictionary *) currentLocaleConsideringLanguages: (NSArray *) langs +{ + NSEnumerator *enumerator; + NSString *lname; + NSDictionary *locale; + + enumerator = [langs objectEnumerator]; + lname = nil; + locale = nil; + lname = [enumerator nextObject]; + while (lname && !locale) + { + locale = [self localeForLanguageNamed: lname]; + lname = [enumerator nextObject]; + } + + if (!locale) + locale = [self localeForLanguageNamed: @"English"]; - /* assume _langs is ordered by priority */ - count = [_langs count]; - for (i = 0; i < count; i++) { - NSString *lname; - NSDictionary *locale; - - lname = [_langs objectAtIndex:i]; - locale = [self localeForLanguageNamed:lname]; - if (locale != nil) - return locale; - } /* no appropriate language, fallback to default */ - return [self localeForLanguageNamed:@"English"]; + return locale; } -- (NSString *)pathToLocaleForLanguageNamed:(NSString *)_name { +- (NSString *) pathToLocaleForLanguageNamed: (NSString *) _name +{ static Class MainProduct = Nil; NSString *lpath; - lpath = [[self resourceManager] pathForResourceNamed:@"Locale" - inFramework:nil - languages:[NSArray arrayWithObject:_name]]; - if ([lpath isNotNull]) - return lpath; - - if (MainProduct == Nil) { - if ((MainProduct = $(@"MainUIProduct")) == Nil) - [self errorWithFormat:@"did not find MainUIProduct class!"]; - } - - lpath = [(id)MainProduct pathToLocaleForLanguageNamed:_name]; - if ([lpath isNotNull]) - return lpath; - - return nil; + lpath = [[self resourceManager] pathForResourceNamed: @"Locale" + inFramework: nil + languages: [NSArray arrayWithObject:_name]]; + if (![lpath length]) + { + if (!MainProduct) + { + MainProduct = $(@"MainUIProduct"); + if (!MainProduct) + [self errorWithFormat: @"did not find MainUIProduct class!"]; + } + + lpath = [(id) MainProduct pathToLocaleForLanguageNamed: _name]; + if (![lpath length]) + lpath = nil; + } + + return lpath; } -- (NSDictionary *)localeForLanguageNamed:(NSString *)_name { +- (NSDictionary *) localeForLanguageNamed: (NSString *) _name +{ NSString *lpath; id data; NSDictionary *locale; - - if (![_name isNotNull]) { + + locale = nil; + if ([_name length] > 0) + { + locale = [localeLUT objectForKey: _name]; + if (!locale) + { + lpath = [self pathToLocaleForLanguageNamed:_name]; + if (lpath) + { + data = [NSData dataWithContentsOfFile: lpath]; + if (data) + { + data = [[[NSString alloc] initWithData: data + encoding: NSUTF8StringEncoding] autorelease]; + locale = [data propertyList]; + if (locale) + [localeLUT setObject: locale forKey: _name]; + else + [self logWithFormat:@"%s couldn't load locale with name:%@", + __PRETTY_FUNCTION__, + _name]; + } + else + [self logWithFormat:@"%s didn't find locale with name: %@", + __PRETTY_FUNCTION__, + _name]; + } + else + [self errorWithFormat:@"did not find Locale for language: %@", _name]; + } + } + else [self errorWithFormat:@"%s: name parameter must not be nil!", - __PRETTY_FUNCTION__]; - return nil; - } - - if ((locale = [self->localeLUT objectForKey:_name]) != nil) - return locale; - - if ((lpath = [self pathToLocaleForLanguageNamed:_name]) == nil) { - [self errorWithFormat:@"did not find Locale for language: %@", _name]; - return nil; - } - - if ((data = [NSData dataWithContentsOfFile:lpath]) == nil) { - [self logWithFormat:@"%s didn't find locale with name:%@", - __PRETTY_FUNCTION__, - _name]; - return nil; - } - data = [[[NSString alloc] initWithData:data - encoding:NSUTF8StringEncoding] autorelease]; - locale = [data propertyList]; - if (locale == nil) { - [self logWithFormat:@"%s couldn't load locale with name:%@", - __PRETTY_FUNCTION__, - _name]; - return nil; - } - [self->localeLUT setObject:locale forKey:_name]; + __PRETTY_FUNCTION__]; + return locale; } /* name (used by the WEResourceManager) */ -- (NSString *)name { +- (NSString *) name +{ return @"SOGo-0.9"; } diff --git a/Main/sogod.m b/Main/sogod.m index 308b2fc0..821bb1db 100644 --- a/Main/sogod.m +++ b/Main/sogod.m @@ -25,7 +25,8 @@ #import #import "common.h" -int main(int argc, char **argv, char **env) +int +main (int argc, char **argv, char **env) { NSString *tzName; NSUserDefaults *ud; @@ -33,7 +34,7 @@ int main(int argc, char **argv, char **env) pool = [NSAutoreleasePool new]; #if LIB_FOUNDATION_LIBRARY - [NSProcessInfo initializeWithArguments:argv count:argc environment:env]; + [NSProcessInfo initializeWithArguments: argv count: argc environment: env]; #endif [NGBundleManager defaultBundleManager]; @@ -43,7 +44,7 @@ int main(int argc, char **argv, char **env) tzName = @"Canada/Eastern"; [NSTimeZone setDefaultTimeZone: [NSTimeZone timeZoneWithName: tzName]]; - WOWatchDogApplicationMain(@"SOGo", argc, (void*)argv); + WOWatchDogApplicationMain (@"SOGo", argc, (void *) argv); [pool release]; return 0; diff --git a/SOPE/NGCards/ChangeLog b/SOPE/NGCards/ChangeLog index c8f0df09..dc09aa58 100644 --- a/SOPE/NGCards/ChangeLog +++ b/SOPE/NGCards/ChangeLog @@ -1,3 +1,8 @@ +2007-04-27 Wolfgang Sourdeau + + * NGVCard.m ([NGVCard -n]): simplified method by returning the + values of the element returned by uniqueChildWithTag:. + 2007-03-07 Wolfgang Sourdeau * iCalEntityObject.m ([iCalEntityObject -symbolicAccessClass]): diff --git a/SOPE/NGCards/NGVCard.m b/SOPE/NGCards/NGVCard.m index 6e9ec01c..faf7eaa5 100644 --- a/SOPE/NGCards/NGVCard.m +++ b/SOPE/NGCards/NGVCard.m @@ -297,15 +297,7 @@ - (NSArray *) n { - NSArray *elements, *n; - - elements = [self childrenWithTag: @"n"]; - if ([elements count] > 0) - n = [[elements objectAtIndex: 0] values]; - else - n = nil; - - return n; + return [[self uniqueChildWithTag: @"n"] values]; } - (void) setOrg: (NSString *) anOrg diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.h b/SoObjects/Appointments/SOGoAppointmentFolder.h index 0ca7c086..f3e71cd8 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.h +++ b/SoObjects/Appointments/SOGoAppointmentFolder.h @@ -46,6 +46,7 @@ @class NSTimeZone; @class GCSFolder; +#import @interface SOGoAppointmentFolder : SOGoFolder { NSTimeZone *timeZone; @@ -114,6 +115,9 @@ - (NSArray *) calendarFolders; +- (NSString *) roleForComponentsWithAccessClass: (iCalAccessClass) accessClass + forUser: (NSString *) uid; + @end #endif /* __Appointments_SOGoAppointmentFolder_H__ */ diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index b877f300..3ca862f1 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -412,22 +412,27 @@ static NSNumber *sharedYes = nil; return classes; } -- (NSString *) groupDavResourceType +- (NSArray *) groupDavResourceType { - return @"vevent-collection"; + return [NSArray arrayWithObjects: @"vevent-collection", + @"vtodo-collection", nil]; } - (NSArray *) davResourceType { static NSArray *colType = nil; - NSArray *gdCol, *cdCol; + NSArray *cdCol, *gdRT, *gdVEventCol, *gdVTodoCol; if (!colType) { + gdRT = [self groupDavResourceType]; + gdVEventCol = [NSArray arrayWithObjects: [gdRT objectAtIndex: 0], + XMLNS_GROUPDAV, nil]; + gdVTodoCol = [NSArray arrayWithObjects: [gdRT objectAtIndex: 1], + XMLNS_GROUPDAV, nil]; cdCol = [NSArray arrayWithObjects: @"calendar", XMLNS_CALDAV, nil]; - gdCol = [NSArray arrayWithObjects: [self groupDavResourceType], - XMLNS_GROUPDAV, nil]; - colType = [NSArray arrayWithObjects: @"collection", cdCol, gdCol, nil]; + colType = [NSArray arrayWithObjects: @"collection", cdCol, + gdVEventCol, gdVTodoCol, nil]; [colType retain]; } @@ -700,31 +705,85 @@ static NSNumber *sharedYes = nil; end, start]; } +- (NSString *) _privacyClassificationStringsForUID: (NSString *) uid +{ + NSMutableString *classificationString; + NSString *currentRole; + unsigned int counter; + iCalAccessClass classes[] = {iCalAccessPublic, iCalAccessPrivate, + iCalAccessConfidential}; + + classificationString = [NSMutableString string]; + for (counter = 0; counter < 3; counter++) + { + currentRole = [self roleForComponentsWithAccessClass: classes[counter] + forUser: uid]; + if ([currentRole length] > 0) + [classificationString appendFormat: @"classification = %d or ", + classes[counter]]; + } + + return classificationString; +} + - (NSString *) _privacySqlString { - NSString *privacySqlString, *owner, *currentUser, *email; + NSString *privacySqlString, *owner, *login, *email; SOGoUser *activeUser; activeUser = [context activeUser]; - currentUser = [activeUser login]; + login = [activeUser login]; owner = [self ownerInContext: context]; - if ([currentUser isEqualToString: owner]) + if ([login isEqualToString: owner]) privacySqlString = @""; + else if ([login isEqualToString: @"freebusy"]) + privacySqlString = @"and (isopaque = 1)"; else { email = [activeUser email]; + privacySqlString = [NSString stringWithFormat: - @"(classification != %d or (orgmail = '%@')" + @"(%@(orgmail = '%@')" @" or ((partmails caseInsensitiveLike '%@%%'" @" or partmails caseInsensitiveLike '%%\\n%@%%')))", - iCalAccessPrivate, email, email, email]; + [self _privacyClassificationStringsForUID: login], + email, email, email]; } return privacySqlString; } +- (NSString *) roleForComponentsWithAccessClass: (iCalAccessClass) accessClass + forUser: (NSString *) uid +{ + NSString *accessRole, *prefix, *currentRole, *suffix; + NSEnumerator *acls; + + accessRole = nil; + + if (accessClass == iCalAccessPublic) + prefix = @"Public"; + else if (accessClass == iCalAccessPrivate) + prefix = @"Private"; + else + prefix = @"Confidential"; + + acls = [[self aclsForUser: uid] objectEnumerator]; + currentRole = [acls nextObject]; + while (currentRole && !accessRole) + if ([currentRole hasPrefix: prefix]) + { + suffix = [currentRole substringFromIndex: [prefix length]]; + accessRole = [NSString stringWithFormat: @"Component%@", suffix]; + } + else + currentRole = [acls nextObject]; + + return accessRole; +} + - (NSArray *) fetchFields: (NSArray *) _fields fromFolder: (GCSFolder *) _folder from: (NSCalendarDate *) _startDate @@ -884,11 +943,9 @@ static NSNumber *sharedYes = nil; { Class objectClass; unsigned int count, max; - NSString *currentId, *currentUser; + NSString *currentId; id deleteObject; - currentUser = [[context activeUser] login]; - max = [ids count]; for (count = 0; count < max; count++) { @@ -1212,4 +1269,13 @@ static NSNumber *sharedYes = nil; return @"IPF.Appointment"; } +/* acls */ +- (NSArray *) defaultAclRoles +{ + return [NSArray arrayWithObjects: + SOGoCalendarRole_PublicViewer, + SOGoCalendarRole_ConfidentialDAndTViewer, + nil]; +} + @end /* SOGoAppointmentFolder */ diff --git a/SoObjects/Appointments/SOGoCalendarComponent.m b/SoObjects/Appointments/SOGoCalendarComponent.m index d240805a..e1a5f598 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.m +++ b/SoObjects/Appointments/SOGoCalendarComponent.m @@ -32,6 +32,7 @@ #import #import #import +#import #import "common.h" @@ -96,7 +97,7 @@ static BOOL sendEMailNotifications = NO; return nil; } -- (void) _filterPrivateComponent: (iCalEntityObject *) component +- (void) _filterComponent: (iCalEntityObject *) component { [component setSummary: @""]; [component setComment: @""]; @@ -110,7 +111,7 @@ static BOOL sendEMailNotifications = NO; - (NSString *) contentAsString { - NSString *tmpContent, *email; + NSString *tmpContent, *email, *uid, *role; iCalCalendar *tmpCalendar; iCalRepeatableEntityObject *tmpComponent; @@ -118,20 +119,30 @@ static BOOL sendEMailNotifications = NO; { tmpContent = [super contentAsString]; calContent = tmpContent; - if ([tmpContent length] > 0) + uid = [[context activeUser] login]; + if (![[self ownerInContext: context] isEqualToString: uid] + && [tmpContent length] > 0) { tmpCalendar = [iCalCalendar parseSingleFromSource: tmpContent]; - tmpComponent = (iCalRepeatableEntityObject *) [tmpCalendar firstChildWithTag: [self componentTag]]; - if (![tmpComponent isPublic]) - { - email = [[context activeUser] email]; - if (!([tmpComponent isOrganizer: email] - || [tmpComponent isParticipant: email])) - { - // content = tmpContent; - [self _filterPrivateComponent: tmpComponent]; - calContent = [tmpCalendar versitString]; - } + tmpComponent = (iCalRepeatableEntityObject *) + [tmpCalendar firstChildWithTag: [self componentTag]]; + email = [[context activeUser] email]; + if (!([tmpComponent isOrganizer: email] + || [tmpComponent isParticipant: email])) + { + role = [container roleForComponentsWithAccessClass: [tmpComponent symbolicAccessClass] + forUser: uid]; + if ([role length] > 0) + { + if ([role isEqualToString: SOGoCalendarPerm_ViewDAndT]) + { + // content = tmpContent; + [self _filterComponent: tmpComponent]; + calContent = [tmpCalendar versitString]; + } + } + else + calContent = nil; } } @@ -178,7 +189,7 @@ static BOOL sendEMailNotifications = NO; newComponent = [[calendar classForTag: componentTag] groupWithTag: componentTag]; [calendar addChild: newComponent]; - isNew = YES; + isNew = YES; } } if (calendar) @@ -432,39 +443,39 @@ 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: SOGoRole_Organizer]; - else if ([component isParticipant: email]) - [sogoRoles addObject: SOGoRole_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; -} +// - (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 @@ -499,4 +510,36 @@ static BOOL sendEMailNotifications = NO; return isParticipant; } +- (NSArray *) aclsForUser: (NSString *) uid +{ + NSMutableArray *roles; + NSArray *superAcls; + iCalRepeatableEntityObject *component; + NSString *email, *accessRole; + + roles = [NSMutableArray array]; + component = [self component: NO]; + if (component) + { + email = [[AgenorUserManager sharedUserManager] getEmailForUID: uid]; + if ([component isOrganizer: email]) + [roles addObject: SOGoCalendarRole_Organizer]; + if ([component isParticipant: email]) + [roles addObject: SOGoCalendarRole_Participant]; + accessRole = [container roleForComponentsWithAccessClass: + [component symbolicAccessClass] + forUser: uid]; + if ([accessRole length] > 0) + [roles addObject: accessRole]; + } + + superAcls = [super aclsForUser: uid]; + if ([superAcls count] > 0) + [roles addObjectsFromArray: superAcls]; + if ([roles containsObject: SOGoRole_ObjectCreator]) + [roles addObject: SOGoCalendarRole_ComponentModifier]; + + return roles; +} + @end diff --git a/SoObjects/Appointments/SOGoGroupAppointmentFolder.m b/SoObjects/Appointments/SOGoGroupAppointmentFolder.m index 099fdf4f..80985e7f 100644 --- a/SoObjects/Appointments/SOGoGroupAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoGroupAppointmentFolder.m @@ -19,6 +19,7 @@ 02111-1307, USA. */ +#import #import #include "SOGoGroupAppointmentFolder.h" diff --git a/SoObjects/Appointments/product.plist b/SoObjects/Appointments/product.plist index a45e744d..91f693d4 100644 --- a/SoObjects/Appointments/product.plist +++ b/SoObjects/Appointments/product.plist @@ -9,35 +9,40 @@ classes = { SOGoAppointmentFolder = { - superclass = "SOGoFolder"; + superclass = "SOGoFolder"; defaultRoles = { - "View" = ( "Owner", "Delegate", "Assistant" ); - "FreeBusyLookup" = ( "Owner", "Delegate", "Assistant", "FreeBusy" ); - "Add Documents, Images, and Files" = ( "Owner", "Delegate" ); - "Access Contents Information" = ( "Owner", "Delegate", "Assistant" ); - "Delete Objects" = ( "Owner", "Organizer", "Delegate" ); + "FreeBusyLookup" = ( "Owner", "FreeBusy", "AuthorizedSubscriber" ); + "ViewWholePublicRecords" = ( "Owner", "PublicResponder", "PublicModifier", "PublicViewer" ); + "ViewDAndTOfPublicRecords" = ( "Owner", "PublicDAndTViewer" ); + "ModifyPublicRecords" = ( "Owner", "PublicModifier" ); + "RespondToPublicRecords" = ( "Owner", "PublicModifier", "PublicResponder" ); + "ViewWholePrivateRecords" = ( "Owner", "PrivateResponder", "PrivateModifier", "PrivateViewer" ); + "ViewDAndTOfPrivateRecords" = ( "Owner", "PrivateDAndTViewer" ); + "ModifyPrivateRecords" = ( "Owner", "PrivateModifier" ); + "RespondToPrivateRecords" = ( "Owner", "PrivateModifier", "PrivateResponder" ); + "ViewWholeConfidentialRecords" = ( "Owner", "ConfidentialResponder", "ConfidentialModifier", "ConfidentialViewer" ); + "ViewDAndTOfConfidentialRecords" = ( "Owner", "ConfidentialDAndTViewer" ); + "ModifyConfidentialRecords" = ( "Owner", "ConfidentialModifier" ); + "RespondToConfidentialRecords" = ( "Owner", "ConfidentialModifier", "ConfidentialResponder" ); }; }; - SOGoGroupAppointmentFolder = { superclass = "SOGoAppointmentFolder"; }; - - SOGoAppointmentObject = { + SOGoCalendarComponent = { superclass = "SOGoContentObject"; defaultRoles = { - "View" = ( "Owner", "Delegate", "Organizer", "Authenticated" ); - "Change Images and Files" = ( "Owner", "Delegate", "Organizer" ); - "Access Contents Information" = ( "Owner", "Delegate", "Assistant" ); + "ViewAllComponent" = ( "Owner", "Organizer", "Participant", "ComponentViewer", "ComponentModifier" ); + "ViewDAndT" = ( "Organizer", "Participant", "ComponentDAndTViewer" ); + "ModifyComponent" = ( "Owner", "ComponentModifier" ); + "RespondToComponent" = ( "Participant", "ComponentResponder" ); }; }; + SOGoAppointmentObject = { + superclass = "SOGoCalendarComponent"; + }; SOGoTaskObject = { - superclass = "SOGoContentObject"; - defaultRoles = { - "View" = ( "Owner", "Delegate", "Organizer", "Authenticated" ); - "Change Images and Files" = ( "Owner", "Delegate", "Organizer" ); - "Access Contents Information" = ( "Owner", "Delegate", "Assistant" ); - }; + superclass = "SOGoCalendarComponent"; }; SOGoFreeBusyObject = { superclass = "SOGoContentObject"; diff --git a/SoObjects/Contacts/SOGoContactFolders.m b/SoObjects/Contacts/SOGoContactFolders.m index c2f0a717..d6c3f9db 100644 --- a/SoObjects/Contacts/SOGoContactFolders.m +++ b/SoObjects/Contacts/SOGoContactFolders.m @@ -218,6 +218,12 @@ return [contactFolders allValues]; } +/* acls */ +- (NSArray *) aclsForUser: (NSString *) uid +{ + return nil; +} + // - (NSString *) roleOfUser: (NSString *) uid // { // NSArray *roles, *traversalPath; diff --git a/SoObjects/Contacts/SOGoContactGCSFolder.m b/SoObjects/Contacts/SOGoContactGCSFolder.m index cc15b14a..b050b7a4 100644 --- a/SoObjects/Contacts/SOGoContactGCSFolder.m +++ b/SoObjects/Contacts/SOGoContactGCSFolder.m @@ -149,7 +149,7 @@ EOQualifier *qualifier; EOSortOrdering *ordering; - NSLog (@"fetching records matching '*%@*', sorted by '%@' in order %d", + NSLog (@"fetching records matching '%@', sorted by '%@' in order %d", filter, sortKey, sortOrdering); fields = folderListingFields; diff --git a/SoObjects/Contacts/SOGoContactLDAPEntry.m b/SoObjects/Contacts/SOGoContactLDAPEntry.m index 7e047e4c..9168ed31 100644 --- a/SoObjects/Contacts/SOGoContactLDAPEntry.m +++ b/SoObjects/Contacts/SOGoContactLDAPEntry.m @@ -203,6 +203,11 @@ return @"text/x-vcard"; } +- (NSArray *) aclsForUser: (NSString *) uid +{ + return nil; +} + - (void) save { } diff --git a/SoObjects/Contacts/SOGoContactLDAPFolder.m b/SoObjects/Contacts/SOGoContactLDAPFolder.m index 3338f05c..b15ed303 100644 --- a/SoObjects/Contacts/SOGoContactLDAPFolder.m +++ b/SoObjects/Contacts/SOGoContactLDAPFolder.m @@ -50,6 +50,7 @@ @"mail", @"telephonenumber", \ @"mailNickname", \ @"sAMAccountName", \ + @"uid", \ nil] @class WOContext; @@ -97,20 +98,11 @@ - (void) dealloc { - if (connection) - { - if ([connection isBound]) - [connection unbind]; - [connection release]; - } - if (contactIdentifier) - [contactIdentifier release]; - if (userIdentifier) - [userIdentifier release]; - if (rootDN) - [rootDN release]; - if (entries) - [entries release]; + [connection release]; + [contactIdentifier release]; + [userIdentifier release]; + [rootDN release]; + [entries release]; [super dealloc]; } @@ -333,13 +325,16 @@ if (filter && [filter length] > 0) { - qs = [NSString stringWithFormat: - @"(cn='%@*')" - @"OR (sn='%@*')" - @"OR (displayName='%@*')" - @"OR (mail='%@*')" - @"OR (telephoneNumber='*%@*')", - filter, filter, filter, filter, filter]; + 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 @@ -362,9 +357,9 @@ if (filter && [filter length] > 0) { -// NSLog (@"%@: fetching records matching '*%@*', sorted by '%@'" -// @" in order %d", -// self, filter, sortKey, sortOrdering); + NSLog (@"%@: fetching records matching '%@', sorted by '%@'" + @" in order %d", + self, filter, sortKey, sortOrdering); records = [NSMutableArray new]; [records autorelease]; @@ -400,4 +395,11 @@ return @"vcard-collection"; } +/* acls */ +/* TODO: this might change one day when we support LDAP acls */ +- (NSArray *) aclsForUser: (NSString *) uid +{ + return nil; +} + @end diff --git a/SoObjects/Mailer/SOGoDraftObject.m b/SoObjects/Mailer/SOGoDraftObject.m index 9f66bb9e..8b9ad4c2 100644 --- a/SoObjects/Mailer/SOGoDraftObject.m +++ b/SoObjects/Mailer/SOGoDraftObject.m @@ -21,6 +21,7 @@ #include "SOGoDraftObject.h" #include +#include #include #include #include @@ -608,7 +609,7 @@ static NSString *fromInternetSuffixPattern = nil; NGMutableHashMap *map; NSDictionary *lInfo; // TODO: this should be some kind of object? NSArray *emails; - NSString *s; + NSString *s, *dateString; id from, replyTo; if ((lInfo = [self fetchInfo]) == nil) @@ -657,10 +658,11 @@ static NSString *fromInternetSuffixPattern = nil; [map setObject: [s asQPSubjectString] forKey:@"subject"]; /* add standard headers */ - - [map addObject:[NSCalendarDate date] forKey:@"date"]; - [map addObject:@"1.0" forKey:@"MIME-Version"]; - [map addObject:userAgent forKey:@"X-Mailer"]; + + dateString = [[NSCalendarDate date] rfc822DateString]; + [map addObject: dateString forKey:@"date"]; + [map addObject: @"1.0" forKey:@"MIME-Version"]; + [map addObject: userAgent forKey:@"X-Mailer"]; /* add custom headers */ diff --git a/SoObjects/Mailer/SOGoMailAccounts.m b/SoObjects/Mailer/SOGoMailAccounts.m index d33c58c9..836ee554 100644 --- a/SoObjects/Mailer/SOGoMailAccounts.m +++ b/SoObjects/Mailer/SOGoMailAccounts.m @@ -189,4 +189,11 @@ static NSString *AgenorShareLoginMarker = @".-."; return YES; } +/* acls */ +- (NSArray *) aclsForUser: (NSString *) uid +{ + return nil; +} + + @end /* SOGoMailAccounts */ diff --git a/SoObjects/Mailer/SOGoMailBaseObject.m b/SoObjects/Mailer/SOGoMailBaseObject.m index 7fbbbfc6..8a715c86 100644 --- a/SoObjects/Mailer/SOGoMailBaseObject.m +++ b/SoObjects/Mailer/SOGoMailBaseObject.m @@ -183,12 +183,11 @@ static BOOL debugOn = YES; return NO; } -/* debugging */ - -- (NSString *)loggingPrefix { - /* improve perf ... */ - return [NSString stringWithFormat:@"<0x%08X[%@]:%@>", - self, NSStringFromClass([self class]), - [self nameInContainer]]; +/* acls */ +#warning one day there will be code here to support IMAP acls +- (NSArray *) aclsForUser: (NSString *) uid +{ + return nil; } + @end /* SOGoMailBaseObject */ diff --git a/SoObjects/Mailer/product.plist b/SoObjects/Mailer/product.plist index 2ace375a..a2805164 100644 --- a/SoObjects/Mailer/product.plist +++ b/SoObjects/Mailer/product.plist @@ -11,59 +11,54 @@ SOGoMailBaseObject = { superclass = "SOGoObject"; }; - SOGoMailAccounts = { superclass = "SOGoMailBaseObject"; defaultRoles = { - "Add Documents, Images, and Files" = ( "Owner", "Delegate" ); - "View" = ( "Owner", "Delegate", "Assistant" ); - "WebDAV Access" = ( "Owner", "Delegate", "Assistant" ); - "Access Contents Information" = ( "Owner", "Assistant", "Delegate" ); - "ReadAcls" = ( "Owner", "Delegate", "Assistant" ); + "View" = ( "Owner", "AuthorizedSubscriber" ); + "Access Contents Information" = ( "Owner", "AuthorizedSubscriber" ); + "Add Documents, Images, and Files" = ( "Owner", "ObjectCreator" ); + "Delete Objects" = ( "Owner", "ObjectEraser" ); + "WebDAV Access" = ( "Owner", "AuthorizedSubscriber" ); + "ReadAcls" = ( "Owner", "AuthorizedSubscriber" ); "SaveAcls" = ( "Owner" ); }; }; - SOGoMailAccount = { superclass = "SOGoMailBaseObject"; defaultRoles = { - "Add Folders" = ( "Owner", "Delegate" ); - "Add Documents, Images, and Files" = ( "Owner", "Delegate" ); - "View" = ( "Owner", "Delegate", "Assistant" ); - "WebDAV Access" = ( "Owner", "Delegate", "Assistant" ); - "Access Contents Information" = ( "Owner", "Assistant", "Delegate" ); - "ReadAcls" = ( "Owner", "Delegate", "Assistant" ); + "View" = ( "Owner", "AuthorizedSubscriber" ); + "Access Contents Information" = ( "Owner", "AuthorizedSubscriber" ); + "Add Documents, Images, and Files" = ( "Owner", "ObjectCreator" ); + "Delete Objects" = ( "Owner", "ObjectEraser" ); + "WebDAV Access" = ( "Owner", "AuthorizedSubscriber" ); + "ReadAcls" = ( "Owner", "AuthorizedSubscriber" ); "SaveAcls" = ( "Owner" ); }; }; SOGoSharedMailAccount = { superclass = "SOGoMailAccount"; }; - SOGoMailFolder = { superclass = "SOGoMailBaseObject"; defaultRoles = { - "Add Folders" = ( "Owner", "Delegate" ); - "Add Documents, Images, and Files" = ( "Owner", "Delegate" ); - "View" = ( "Owner", "Delegate", "Assistant" ); - "WebDAV Access" = ( "Owner", "Delegate", "Assistant" ); - "Access Contents Information" = ( "Owner", "Assistant", "Delegate" ); - "ReadAcls" = ( "Owner", "Delegate", "Assistant" ); + "View" = ( "Owner", "AuthorizedSubscriber" ); + "Access Contents Information" = ( "Owner", "AuthorizedSubscriber" ); + "Add Documents, Images, and Files" = ( "Owner", "ObjectCreator" ); + "Delete Objects" = ( "Owner", "ObjectEraser" ); + "WebDAV Access" = ( "Owner", "AuthorizedSubscriber" ); + "ReadAcls" = ( "Owner", "AuthorizedSubscriber" ); "SaveAcls" = ( "Owner" ); }; }; SOGoSharedInboxFolder = { superclass = "SOGoMailFolder"; }; - SOGoTrashFolder = { superclass = "SOGoMailFolder"; }; - SOGoMailObject = { superclass = "SOGoMailBaseObject"; }; - SOGoMailBodyPart = { superclass = "SOGoMailBaseObject"; }; @@ -79,7 +74,6 @@ SOGoVCardMailBodyPart = { superclass = "SOGoMailBodyPart"; }; - SOGoDraftsFolder = { superclass = "SOGoMailBaseObject"; }; diff --git a/SoObjects/SOGo/AgenorUserManager.m b/SoObjects/SOGo/AgenorUserManager.m index 619e6662..6b10fa3f 100644 --- a/SoObjects/SOGo/AgenorUserManager.m +++ b/SoObjects/SOGo/AgenorUserManager.m @@ -27,7 +27,7 @@ #include "SOGoLRUCache.h" #warning we should rely on the LDAP sources instead... -#define qualifierFormat @"mailNickname = %@" +#define qualifierFormat @"uid = %@" @interface AgenorUserManager (PrivateAPI) - (NGLdapConnection *)ldapConnection; @@ -54,19 +54,19 @@ @implementation AgenorUserManager -static BOOL debugOn = NO; -static BOOL useLDAP = NO; -static NSString *ldapHost = nil; +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 *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 NSString *mailAutoresponderAttrName = @"mineqMelReponse"; /* sic! */ +static NSURL *AgenorProfileURL = nil; static NSArray *fromEMailAttrs = nil; @@ -81,13 +81,13 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; if (didInit) return; didInit = YES; - ud = [NSUserDefaults standardUserDefaults]; + ud = [NSUserDefaults standardUserDefaults]; debugOn = [ud boolForKey:@"SOGoUserManagerDebugEnabled"]; useLDAP = [ud boolForKey:@"SOGoUserManagerUsesLDAP"]; if (useLDAP) { - ldapHost = [[ud stringForKey:@"SOGoLDAPHost"] copy]; - ldapBaseDN = [[ud stringForKey:@"SOGoLDAPBaseDN"] copy]; + ldapHost = [[ud stringForKey:@"LDAPHost"] copy]; + ldapBaseDN = [[ud stringForKey:@"LDAPRootDN"] copy]; NSLog(@"Note: using LDAP host to manage accounts: %@", ldapHost); } else @@ -150,26 +150,26 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; - (id)init { self = [super init]; if(self) { - self->serverCache = + serverCache = [[NSMutableDictionary alloc] initWithCapacity:10000]; - self->cnCache = + cnCache = [[NSMutableDictionary alloc] initWithCapacity:10000]; - self->uidCache = + uidCache = [[NSMutableDictionary alloc] initWithCapacity:10000]; - self->emailCache = + emailCache = [[NSMutableDictionary alloc] initWithCapacity:10000]; - self->shareStoreCache = + shareStoreCache = [[NSMutableDictionary alloc] initWithCapacity:10000]; - self->shareEMailCache = + shareEMailCache = [[NSMutableDictionary alloc] initWithCapacity:10000]; - self->changeInternetAccessCache = + changeInternetAccessCache = [[NSMutableDictionary alloc] initWithCapacity:10000]; - self->internetAutoresponderFlagCache = + internetAutoresponderFlagCache = [[NSMutableDictionary alloc] initWithCapacity:10000]; - self->intranetAutoresponderFlagCache = + intranetAutoresponderFlagCache = [[NSMutableDictionary alloc] initWithCapacity:10000]; - self->gcTimer = [[NSTimer scheduledTimerWithTimeInterval: + gcTimer = [[NSTimer scheduledTimerWithTimeInterval: PoolScanInterval target:self selector:@selector(_garbageCollect:) userInfo:nil repeats:YES] retain]; @@ -178,33 +178,33 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; } - (void)dealloc { - if (self->gcTimer) [self->gcTimer invalidate]; - [self->serverCache release]; - [self->cnCache release]; - [self->uidCache release]; - [self->emailCache release]; - [self->shareStoreCache release]; - [self->shareEMailCache release]; - [self->changeInternetAccessCache release]; - [self->internetAutoresponderFlagCache release]; - [self->intranetAutoresponderFlagCache release]; - [self->gcTimer release]; + 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 { - [self->cnCache removeAllObjects]; - [self->serverCache removeAllObjects]; - [self->uidCache removeAllObjects]; - [self->emailCache removeAllObjects]; - [self->shareStoreCache removeAllObjects]; - [self->shareEMailCache removeAllObjects]; + [cnCache removeAllObjects]; + [serverCache removeAllObjects]; + [uidCache removeAllObjects]; + [emailCache removeAllObjects]; + [shareStoreCache removeAllObjects]; + [shareEMailCache removeAllObjects]; - [self->changeInternetAccessCache removeAllObjects]; - [self->internetAutoresponderFlagCache removeAllObjects]; - [self->intranetAutoresponderFlagCache removeAllObjects]; + [changeInternetAccessCache removeAllObjects]; + [internetAutoresponderFlagCache removeAllObjects]; + [intranetAutoresponderFlagCache removeAllObjects]; } - (void)_garbageCollect:(NSTimer *)_timer { @@ -217,7 +217,7 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; - (NGLdapConnection *)ldapConnection { static NGLdapConnection *ldapConnection = nil; if(!ldapConnection) { - ldapConnection = [[NGLdapConnection alloc] initWithHostName:ldapHost]; + ldapConnection = [[NGLdapConnection alloc] initWithHostName: ldapHost]; #if 0 [ldapConnection setUseCache:YES]; #endif @@ -231,34 +231,34 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; - (void)_cacheCN:(NSString *)_cn forUID:(NSString *)_uid { if (_cn == nil) return; - [self->cnCache setObject:_cn forKey:_uid]; + [cnCache setObject:_cn forKey:_uid]; } - (NSString *)_cachedCNForUID:(NSString *)_uid { - return [self->cnCache objectForKey:_uid]; + return [cnCache objectForKey:_uid]; } - (void)_cacheServer:(NSString *)_server forUID:(NSString *)_uid { if (_server == nil) return; - [self->serverCache setObject:_server forKey:_uid]; + [serverCache setObject:_server forKey:_uid]; } - (NSString *)_cachedServerForUID:(NSString *)_uid { - return [self->serverCache objectForKey:_uid]; + return [serverCache objectForKey:_uid]; } - (void)_cacheEmail:(NSString *)_email forUID:(NSString *)_uid { if (_email == nil) return; - [self->emailCache setObject:_email forKey:_uid]; + [emailCache setObject:_email forKey:_uid]; } - (NSString *)_cachedEmailForUID:(NSString *)_uid { - return [self->emailCache objectForKey:_uid]; + return [emailCache objectForKey:_uid]; } - (void)_cacheUID:(NSString *)_uid forEmail:(NSString *)_email { if (_uid == nil) return; - [self->uidCache setObject:_uid forKey:_email]; + [uidCache setObject:_uid forKey:_email]; } - (NSString *)_cachedUIDForEmail:(NSString *)_email { - return [self->uidCache objectForKey:_email]; + return [uidCache objectForKey:_email]; } @@ -305,7 +305,7 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; q = [EOQualifier qualifierWithQualifierFormat:@"mail = %@", _email]; - conn = [self ldapConnection]; + conn = [self ldapConnection]; resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN qualifier:q attributes:uidAttrs]; @@ -383,12 +383,12 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; unsigned i, count; count = [_persons count]; - ma = [[[NSMutableArray alloc] initWithCapacity:count] autorelease]; + ma = [[[NSMutableArray alloc] initWithCapacity:count] autorelease]; for (i = 0; i < count; i++) { iCalPerson *p; id uid; - p = [_persons objectAtIndex:i]; + p = [_persons objectAtIndex:i]; uid = [self getUIDForICalPerson:p]; if (uid != nil) [ma addObject:uid]; @@ -407,9 +407,9 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; NSString *email; unsigned count; - q = [EOQualifier qualifierWithQualifierFormat:qualifierFormat, _uid]; + q = [EOQualifier qualifierWithQualifierFormat: qualifierFormat, _uid]; - conn = [self ldapConnection]; + conn = [self ldapConnection]; resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN qualifier:q attributes:fromEMailAttrs]; @@ -499,7 +499,7 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; if (cnAttrs == nil) cnAttrs = [[NSArray alloc] initWithObjects:@"cn", nil]; - q = [EOQualifier qualifierWithQualifierFormat:qualifierFormat, _uid]; + q = [EOQualifier qualifierWithQualifierFormat: qualifierFormat, _uid]; conn = [self ldapConnection]; resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN @@ -589,7 +589,7 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; NSEnumerator *resultEnum; NGLdapEntry *entry; - q = [EOQualifier qualifierWithQualifierFormat:qualifierFormat, _uid]; + q = [EOQualifier qualifierWithQualifierFormat: qualifierFormat, _uid]; conn = [self ldapConnection]; resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN @@ -617,7 +617,7 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; NSMutableArray *serverCandidates; unsigned i, count; - count = [attr count]; + count = [attr count]; serverCandidates = [NSMutableArray arrayWithCapacity:count]; for (i = 0; i < count; i++) { NSRange r; @@ -824,7 +824,7 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; } /* check cache */ - if ((shares = [self->shareEMailCache objectForKey:_uid]) != nil) + if ((shares = [shareEMailCache objectForKey:_uid]) != nil) return shares; /* G and C mean "emission access" */ @@ -857,7 +857,7 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; /* cache */ shares = (shares == nil) ? [NSArray array] : [[shares copy] autorelease]; - [self->shareEMailCache setObject:shares forKey:_uid]; + [shareEMailCache setObject:shares forKey:_uid]; return shares; } @@ -939,7 +939,7 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; } /* check cache */ - if ((shares = [self->shareStoreCache objectForKey:_uid]) != nil) + if ((shares = [shareStoreCache objectForKey:_uid]) != nil) return shares; sharePattern = [_uid stringByAppendingString:@":*"]; @@ -999,7 +999,7 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; shares = (shares == nil) ? [NSDictionary dictionary] : [[shares copy] autorelease]; - [self->shareStoreCache setObject:shares forKey:_uid]; + [shareStoreCache setObject:shares forKey:_uid]; return shares; } @@ -1050,13 +1050,13 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; - (BOOL)isUserAllowedToChangeSOGoInternetAccess:(NSString *)_uid { NSNumber *bv; - bv = [self->changeInternetAccessCache objectForKey:_uid]; + bv = [changeInternetAccessCache objectForKey:_uid]; if (!bv) { BOOL value; value = [self primaryIsUserAllowedToChangeSOGoInternetAccess:_uid]; - bv = [NSNumber numberWithBool:value]; - [self->changeInternetAccessCache setObject:bv forKey:_uid]; + bv = [NSNumber numberWithBool:value]; + [changeInternetAccessCache setObject:bv forKey:_uid]; } return [bv boolValue]; } @@ -1073,9 +1073,9 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; if (attrs == nil) attrs = [[NSArray alloc] initWithObjects:changeInternetAccessAttrName, nil]; - q = [EOQualifier qualifierWithQualifierFormat:qualifierFormat, _uid]; + q = [EOQualifier qualifierWithQualifierFormat: qualifierFormat, _uid]; - conn = [self ldapConnection]; + conn = [self ldapConnection]; resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN qualifier:q attributes:attrs]; @@ -1100,43 +1100,49 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; return [value boolValue]; } -- (BOOL)isInternetAutoresponderEnabledForUser:(NSString *)_uid { +- (BOOL) isInternetAutoresponderEnabledForUser: (NSString *) _uid +{ NSNumber *bv; + BOOL value; - bv = [self->internetAutoresponderFlagCache objectForKey:_uid]; + bv = [internetAutoresponderFlagCache objectForKey:_uid]; if (!bv) { - BOOL value; - value = [self primaryIsInternetAutoresponderEnabledForUser:_uid]; - bv = [NSNumber numberWithBool:value]; - [self->internetAutoresponderFlagCache setObject:bv forKey:_uid]; + bv = [NSNumber numberWithBool:value]; + [internetAutoresponderFlagCache setObject:bv forKey:_uid]; } return [bv boolValue]; } -- (BOOL)primaryIsInternetAutoresponderEnabledForUser:(NSString *)_uid { +- (BOOL) primaryIsInternetAutoresponderEnabledForUser: (NSString *) _uid +{ NGLdapAttribute *attr; attr = [self primaryGetMailAutoresponderAttribute:_uid]; if (!attr) return NO; - return [self isAutoresponderEnabledForAttribute:attr matchingPrefix:@"60~"]; + + return [self isAutoresponderEnabledForAttribute: attr + matchingPrefix: @"60~"]; } -- (BOOL)isIntranetAutoresponderEnabledForUser:(NSString *)_uid { +- (BOOL) isIntranetAutoresponderEnabledForUser: (NSString *) _uid +{ NSNumber *bv; + BOOL value; - bv = [self->intranetAutoresponderFlagCache objectForKey:_uid]; - if (!bv) { - BOOL value; - - value = [self primaryIsIntranetAutoresponderEnabledForUser:_uid]; - bv = [NSNumber numberWithBool:value]; - [self->intranetAutoresponderFlagCache setObject:bv forKey:_uid]; - } + 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 { +- (BOOL) primaryIsIntranetAutoresponderEnabledForUser: (NSString *) _uid +{ NGLdapAttribute *attr; attr = [self primaryGetMailAutoresponderAttribute:_uid]; @@ -1144,8 +1150,8 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; return [self isAutoresponderEnabledForAttribute:attr matchingPrefix:@"50~"]; } -- (BOOL)isAutoresponderEnabledForAttribute:(NGLdapAttribute *)_attr - matchingPrefix:(NSString *)_prefix +- (BOOL) isAutoresponderEnabledForAttribute: (NGLdapAttribute *)_attr + matchingPrefix: (NSString *)_prefix { unsigned i, count; @@ -1160,10 +1166,12 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; return YES; } } + return NO; } -- (NGLdapAttribute *)primaryGetMailAutoresponderAttribute:(NSString *)_uid { +- (NGLdapAttribute *) primaryGetMailAutoresponderAttribute: (NSString *) _uid +{ static NSArray *attrs = nil; NGLdapConnection *conn; EOQualifier *q; @@ -1174,9 +1182,9 @@ static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; if (attrs == nil) attrs = [[NSArray alloc] initWithObjects:mailAutoresponderAttrName, nil]; - q = [EOQualifier qualifierWithQualifierFormat:qualifierFormat, _uid]; + q = [EOQualifier qualifierWithQualifierFormat: qualifierFormat, _uid]; - conn = [self ldapConnection]; + conn = [self ldapConnection]; resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN qualifier:q attributes:attrs]; diff --git a/SoObjects/SOGo/GNUmakefile b/SoObjects/SOGo/GNUmakefile index e5e5dc49..15b79276 100644 --- a/SoObjects/SOGo/GNUmakefile +++ b/SoObjects/SOGo/GNUmakefile @@ -23,7 +23,6 @@ libSOGo_HEADER_FILES = \ SOGoObject.h \ SOGoFolder.h \ SOGoContentObject.h \ - SOGoAclsFolder.h \ SOGoUserFolder.h \ SOGoGroupsFolder.h \ SOGoGroupFolder.h \ @@ -47,7 +46,6 @@ libSOGo_OBJC_FILES = \ SOGoObject.m \ SOGoFolder.m \ SOGoContentObject.m \ - SOGoAclsFolder.m \ SOGoUserFolder.m \ SOGoGroupsFolder.m \ SOGoGroupFolder.m \ diff --git a/SoObjects/SOGo/NSCalendarDate+SOGo.h b/SoObjects/SOGo/NSCalendarDate+SOGo.h index 84c2c66a..ca6d710d 100644 --- a/SoObjects/SOGo/NSCalendarDate+SOGo.h +++ b/SoObjects/SOGo/NSCalendarDate+SOGo.h @@ -39,6 +39,8 @@ - (NSCalendarDate *) sundayOfWeek; - (NSString *) shortDateString; +- (NSString *) rfc822DateString; + @end #endif /* NSCALENDARDATE_SCHEDULER_H */ diff --git a/SoObjects/SOGo/NSCalendarDate+SOGo.m b/SoObjects/SOGo/NSCalendarDate+SOGo.m index a6160cad..c3cd2492 100644 --- a/SoObjects/SOGo/NSCalendarDate+SOGo.m +++ b/SoObjects/SOGo/NSCalendarDate+SOGo.m @@ -19,10 +19,18 @@ 02111-1307, USA. */ +#import +#import #import #import "NSCalendarDate+SOGo.h" +static NSString *rfc822Days[] = {@"Sun", @"Mon", @"Tue", @"Wed", @"Thu", + @"Fri", @"Sat"}; +static NSString *rfc822Months[] = {@"", @"Jan", @"Feb", @"Mar", @"Apr", + @"May", @"Jun", @"Jul", @"Aug" , @"Sep", + @"Oct", @"Nov", @"Dec"}; + @implementation NSCalendarDate (SOGoExtensions) + (id) dateFromShortDateString: (NSString *) dateString @@ -110,4 +118,22 @@ return str; } +- (NSString *) rfc822DateString +{ + int timeZoneShift, tzSeconds; + + tzSeconds = [[self timeZone] secondsFromGMT]; + timeZoneShift = (tzSeconds / 3600); + tzSeconds -= timeZoneShift * 3600; + timeZoneShift *= 100; + timeZoneShift += tzSeconds / 60; + + return + [NSString stringWithFormat: @"%@, %.2d %@ %d %.2d:%.2d:%.2d %.4d", + rfc822Days[[self dayOfWeek]], [self dayOfMonth], + rfc822Months[[self monthOfYear]], [self yearOfCommonEra], + [self hourOfDay], [self minuteOfHour], [self secondOfMinute], + timeZoneShift]; +} + @end diff --git a/SoObjects/SOGo/SOGoAclsFolder.m b/SoObjects/SOGo/SOGoAclsFolder.m deleted file mode 100644 index 64c97106..00000000 --- a/SoObjects/SOGo/SOGoAclsFolder.m +++ /dev/null @@ -1,230 +0,0 @@ -/* SOGoAclsFolder.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 -#import -#import -#import -#import - -#import "SOGoFolder.h" -#import "SOGoAclsFolder.h" - -@implementation SOGoAclsFolder - -+ (id) aclsFolder -{ - id aclsFolder; - - aclsFolder = [self new]; - [aclsFolder autorelease]; - - return aclsFolder; -} - -- (id) init -{ - if ((self = [super init])) - { - ocsPath = nil; - ocsFolder = nil; - } - - return self; -} - -- (void) dealloc -{ - if (ocsPath) - [ocsPath release]; - if (ocsFolder) - [ocsFolder release]; - [super dealloc]; -} - -- (void) setOCSPath: (NSString *) newOCSPath -{ - if (ocsPath) - [ocsPath release]; - ocsPath = newOCSPath; - if (ocsPath) - [ocsPath retain]; -} - -- (GCSFolderManager *)folderManager { - return [GCSFolderManager defaultFolderManager]; -} - -- (GCSFolder *)ocsFolderForPath:(NSString *)_path { - return [[self folderManager] folderAtPath:_path]; -} - -- (GCSFolder *) ocsFolder { - GCSFolder *folder; - - if (!ocsFolder) - ocsFolder = [[self ocsFolderForPath: ocsPath] retain]; - - if ([ocsFolder isNotNull]) - folder = ocsFolder; - else - folder = nil; - - return folder; -} - -- (NSString *) _ocsPathForObject: (SOGoObject *) object -{ - NSString *pathForObject; - id currentObject; - BOOL done; - - pathForObject = nil; - currentObject = object; - done = NO; - while (currentObject && !done) - if ([currentObject isKindOfClass: [SOGoFolder class]]) - { - pathForObject = [(SOGoFolder *) currentObject ocsPath]; - done = YES; -// if (!pathForObject) -// currentObject = [currentObject container]; - } - else - currentObject = [currentObject container]; - - return pathForObject; -} - -- (NSArray *) aclsForObject: (SOGoObject *) object -{ - EOQualifier *qualifier; - NSString *objectPath; - - [self setOCSPath: [self _ocsPathForObject: object]]; - - objectPath - = [NSString stringWithFormat: @"/%@", - [[object pathArrayToSoObject] componentsJoinedByString: @"/"]]; - qualifier - = [EOQualifier qualifierWithQualifierFormat: @"c_object = %@", objectPath]; - - return [[self ocsFolder] fetchAclMatchingQualifier: qualifier]; -} - -- (NSArray *) aclsForObject: (SOGoObject *) object - forUser: (NSString *) uid -{ - EOQualifier *qualifier; - NSString *objectPath; - NSArray *records; - - [self setOCSPath: [self _ocsPathForObject: object]]; - - objectPath - = [NSString stringWithFormat: @"/%@", - [[object pathArrayToSoObject] componentsJoinedByString: @"/"]]; - qualifier = [EOQualifier - qualifierWithQualifierFormat: @"(c_object = %@) AND (c_uid = %@)", - objectPath, uid]; - - records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier]; - - return [records valueForKey: @"c_role"]; -} - -- (void) removeUsersWithRole: (NSString *) role - forObjectAtPath: (NSString *) objectPath - inFolder: (GCSFolder *) folder -{ - NSString *deleteSQL; - EOAdaptorChannel *channel; - - channel = [folder acquireAclChannel]; - - deleteSQL = [NSString stringWithFormat: @"DELETE FROM %@" - @" WHERE c_object = '%@'" - @" AND c_role = '%@'", - [folder aclTableName], objectPath, role]; - [channel evaluateExpressionX: deleteSQL]; -} - -- (void) setRoleForObjectAtPath: (NSString *) objectPath - forUser: (NSString *) uid - to: (NSString *) role - inFolder: (GCSFolder *) folder -{ - NSString *SQL; - EOAdaptorChannel *channel; - - channel = [folder acquireAclChannel]; - - SQL = [NSString stringWithFormat: @"DELETE FROM %@" - @" WHERE c_object = '%@'" - @" AND c_uid = '%@'", - [folder aclTableName], objectPath, uid]; - [channel evaluateExpressionX: SQL]; - SQL = [NSString stringWithFormat: @"INSERT INTO %@" - @" (c_object, c_uid, c_role)" - @" VALUES ('%@', '%@', '%@')", [folder aclTableName], - objectPath, uid, role]; - [channel evaluateExpressionX: SQL]; -} - -/* FIXME: part of this code should be moved to sope-gdl/GCSFolder.m */ -- (void) setRoleForObject: (SOGoObject *) object - forUsers: (NSArray *) uids - to: (NSString *) role -{ - GCSFolder *aclsFolder; - NSString *objectPath, *currentUID; - NSEnumerator *userUIDs; - - [self setOCSPath: [self _ocsPathForObject: object]]; - aclsFolder = [self ocsFolder]; - - objectPath - = [NSString stringWithFormat: @"/%@", - [[object pathArrayToSoObject] componentsJoinedByString: @"/"]]; - [self removeUsersWithRole: role - forObjectAtPath: objectPath - inFolder: aclsFolder]; - - userUIDs = [uids objectEnumerator]; - currentUID = [userUIDs nextObject]; - while (currentUID) - { - if ([currentUID length] > 0) - [self setRoleForObjectAtPath: objectPath - forUser: currentUID - to: role - inFolder: aclsFolder]; - currentUID = [userUIDs nextObject]; - } -} - -@end diff --git a/SoObjects/SOGo/SOGoContentObject.h b/SoObjects/SOGo/SOGoContentObject.h index 5c22cda9..9d3545b4 100644 --- a/SoObjects/SOGo/SOGoContentObject.h +++ b/SoObjects/SOGo/SOGoContentObject.h @@ -25,7 +25,9 @@ #import -@class NSString, NSException; +@class NSArray; +@class NSException; +@class NSString; @interface SOGoContentObject : SOGoObject { @@ -35,29 +37,29 @@ /* accessors */ -- (void)setOCSPath:(NSString *)_path; -- (NSString *)ocsPath; +- (void) setOCSPath: (NSString *) _path; +- (NSString *) ocsPath; /* folder */ -- (NSString *)ocsPathOfContainer; -- (GCSFolder *)ocsFolder; +- (NSString *) ocsPathOfContainer; +- (GCSFolder *) ocsFolder; /* content */ -- (NSString *)contentAsString; -- (NSException *)saveContentString:(NSString *)_str - baseVersion:(unsigned int)_baseVersion; -- (NSException *)saveContentString:(NSString *)_str; -- (NSException *)delete; +- (NSString *) contentAsString; +- (NSException *) saveContentString: (NSString *) _str + baseVersion: (unsigned int) _baseVersion; +- (NSException *) saveContentString: (NSString *)_str; +- (NSException *) delete; /* etag support */ -- (id)davEntityTag; +- (id) davEntityTag; /* message type */ -- (NSString *)outlookMessageClass; +- (NSString *) outlookMessageClass; @end diff --git a/SoObjects/SOGo/SOGoContentObject.m b/SoObjects/SOGo/SOGoContentObject.m index bfacb66c..ed75b3ce 100644 --- a/SoObjects/SOGo/SOGoContentObject.m +++ b/SoObjects/SOGo/SOGoContentObject.m @@ -21,10 +21,10 @@ #import -#import - #import "common.h" #import "SOGoFolder.h" +#import "SOGoUser.h" +#import "SOGoPermissions.h" #import "SOGoContentObject.h" @interface SOGoContentObject(ETag) @@ -36,15 +36,15 @@ // TODO: check superclass version - (void)dealloc { - [self->content release]; - [self->ocsPath release]; + [content release]; + [ocsPath release]; [super dealloc]; } /* notifications */ - (void)sleep { - [self->content release]; self->content = nil; + [content release]; content = nil; [super sleep]; } @@ -55,26 +55,32 @@ } - (void)setOCSPath:(NSString *)_path { - if ([self->ocsPath isEqualToString:_path]) + if ([ocsPath isEqualToString:_path]) return; - if (self->ocsPath) + if (ocsPath) [self warnWithFormat:@"GCS path is already set! '%@'", _path]; - ASSIGNCOPY(self->ocsPath, _path); + ASSIGNCOPY(ocsPath, _path); } -- (NSString *)ocsPath { - if (self->ocsPath == nil) { - NSString *p; +- (NSString *) ocsPath +{ + NSString *p; - if ((p = [self ocsPathOfContainer]) != nil) { - if (![p hasSuffix:@"/"]) p = [p stringByAppendingString:@"/"]; - p = [p stringByAppendingString:[self nameInContainer]]; - self->ocsPath = [p copy]; + if (!ocsPath) + { + p = [self ocsPathOfContainer]; + if (p) + { + if (![p hasSuffix:@"/"]) + p = [p stringByAppendingString: @"/"]; + ocsPath = [p stringByAppendingString: [self nameInContainer]]; + [ocsPath retain]; + } } - } - return self->ocsPath; + + return ocsPath; } - (NSString *)ocsPathOfContainer { @@ -84,32 +90,26 @@ return [[self container] ocsPath]; } -- (GCSFolder *)ocsFolder { - if (![[self container] respondsToSelector:@selector(ocsFolder)]) - return nil; - - return [[self container] ocsFolder]; +- (GCSFolder *) ocsFolder +{ + return [container ocsFolder]; } /* content */ -- (NSString *)contentAsString { - GCSFolder *folder; +- (NSString *) contentAsString +{ + if (!content) + { + content = [[self ocsFolder] fetchContentWithName: nameInContainer]; + [content retain]; + } - if (self->content != nil) - return self->content; - - if ((folder = [self ocsFolder]) == nil) { - [self errorWithFormat:@"Did not find folder of content object."]; - return nil; - } - - self->content = [[folder fetchContentWithName:[self nameInContainer]] copy]; - return self->content; + return content; } -- (NSException *)saveContentString:(NSString *)_str - baseVersion:(unsigned int)_baseVersion +- (NSException *) saveContentString: (NSString *) _str + baseVersion: (unsigned int) _baseVersion { /* Note: "iCal multifolder saves" are implemented in the apt subclass! */ GCSFolder *folder; @@ -184,8 +184,8 @@ @"reassigned a new location for special new-location: %@", tmp]; /* kinda dangerous */ - ASSIGNCOPY(self->nameInContainer, tmp); - ASSIGN(self->ocsPath, nil); + ASSIGNCOPY(nameInContainer, tmp); + ASSIGN(ocsPath, nil); } /* determine base version from etag in if-match header */ @@ -239,48 +239,37 @@ return [_ctx response]; } -/* security */ -- (NSArray *) rolesOfUser: (NSString *) login -{ - NSMutableArray *sogoRoles; - SOGoUser *user; - - sogoRoles = [NSMutableArray new]; - [sogoRoles autorelease]; - - if (![container nameExistsInFolder: nameInContainer]) - { - user = [[SOGoUser alloc] initWithLogin: login roles: nil]; - [sogoRoles addObjectsFromArray: [user rolesForObject: container - inContext: context]]; - [user release]; - } - - return sogoRoles; -} - /* E-Tags */ -- (id)davEntityTag { +- (id) davEntityTag +{ // TODO: cache tag in ivar? => if you do, remember to flush after PUT GCSFolder *folder; char buf[64]; + NSString *entityTag; + NSNumber *versionValue; - if ((folder = [self ocsFolder]) == nil) { - [self errorWithFormat:@"Did not find folder of content object."]; - return nil; - } - - sprintf(buf, "\"gcs%08d\"", - [[folder versionOfContentWithName:[self nameInContainer]] - unsignedIntValue]); - return [NSString stringWithCString:buf]; + folder = [self ocsFolder]; + if (folder) + { + versionValue = [folder versionOfContentWithName: [self nameInContainer]]; + sprintf (buf, "\"gcs%08d\"", [versionValue unsignedIntValue]); + entityTag = [NSString stringWithCString: buf]; + } + else + { + [self errorWithFormat:@"Did not find folder of content object."]; + entityTag = nil; + } + + return entityTag; } /* WebDAV */ -- (NSException *)davMoveToTargetObject:(id)_target newName:(NSString *)_name - inContext:(id)_ctx +- (NSException *) davMoveToTargetObject: (id) _target + newName: (NSString *) _name + inContext: (id) _ctx { /* Note: even for new objects we won't get a new name but a preinstantiated @@ -293,8 +282,9 @@ reason:@"this object cannot be copied via WebDAV"]; } -- (NSException *)davCopyToTargetObject:(id)_target newName:(NSString *)_name - inContext:(id)_ctx +- (NSException *) davCopyToTargetObject: (id)_target + newName: (NSString *) _name + inContext: (id) _ctx { /* Note: even for new objects we won't get a new name but a preinstantiated @@ -311,15 +301,59 @@ return [self isFolderish]; } +/* acls */ + +- (NSArray *) acls +{ + return [container aclsForObjectAtPath: [self pathArrayToSoObject]]; +} + +- (NSArray *) aclsForUser: (NSString *) uid +{ + NSMutableArray *acls; + NSArray *ownAcls, *containerAcls; + + acls = [NSMutableArray array]; + ownAcls = [container aclsForUser: uid + forObjectAtPath: [self pathArrayToSoObject]]; + [acls addObjectsFromArray: ownAcls]; + containerAcls = [container aclsForUser: uid]; + if ([containerAcls count] > 0) + { + if ([containerAcls containsObject: SOGoRole_ObjectCreator]) + [acls addObject: SOGoRole_ObjectCreator]; + if ([containerAcls containsObject: SOGoRole_ObjectEraser]) + [acls addObject: SOGoRole_ObjectEraser]; + } + + return acls; +} + +- (void) setRoles: (NSArray *) roles + forUser: (NSString *) uid +{ + return [container setRoles: roles + forUser: uid + forObjectAtPath: [self pathArrayToSoObject]]; +} + +- (void) removeAclsForUsers: (NSArray *) users +{ + return [container removeAclsForUsers: users + forObjectAtPath: [self pathArrayToSoObject]]; +} + /* message type */ -- (NSString *)outlookMessageClass { +- (NSString *) outlookMessageClass +{ return nil; } /* description */ -- (void)appendAttributesToDescription:(NSMutableString *)_ms { +- (void) appendAttributesToDescription: (NSMutableString *) _ms +{ [super appendAttributesToDescription:_ms]; [_ms appendFormat:@" ocs=%@", [self ocsPath]]; diff --git a/SoObjects/SOGo/SOGoFolder.h b/SoObjects/SOGo/SOGoFolder.h index b3af1fc3..f38fc61f 100644 --- a/SoObjects/SOGo/SOGoFolder.h +++ b/SoObjects/SOGo/SOGoFolder.h @@ -26,7 +26,6 @@ @class NSString, NSArray, NSDictionary; @class GCSFolder; -@class SOGoAclsFolder; /* SOGoFolder @@ -38,10 +37,15 @@ cyclic references. */ +@class NSString; +@class GCSFolder; +@class NSMutableDictionary; + @interface SOGoFolder : SOGoObject { NSString *ocsPath; GCSFolder *ocsFolder; + NSMutableDictionary *aclCache; } + (NSString *) globallyUniqueObjectId; @@ -67,6 +71,16 @@ - (BOOL) create; - (NSException *) delete; +/* acls as a container */ +- (NSArray *) aclsForObjectAtPath: (NSArray *) objectPathArray; +- (NSArray *) aclsForUser: (NSString *) uid + forObjectAtPath: (NSArray *) objectPathArray; +- (void) setRoles: (NSArray *) roles + forUser: (NSString *) uid + forObjectAtPath: (NSArray *) objectPathArray; +- (void) removeAclsForUsers: (NSArray *) users + forObjectAtPath: (NSArray *) objectPathArray; + @end @interface SOGoFolder (GroupDAVExtensions) diff --git a/SoObjects/SOGo/SOGoFolder.m b/SoObjects/SOGo/SOGoFolder.m index c79c0df9..43bc8e1c 100644 --- a/SoObjects/SOGo/SOGoFolder.m +++ b/SoObjects/SOGo/SOGoFolder.m @@ -20,76 +20,101 @@ */ #import +#import #import #import #import +#import "SOGoPermissions.h" #import "SOGoFolder.h" #import "common.h" #import #import -#import "SOGoAclsFolder.h" +static NSString *defaultUser = @""; @implementation SOGoFolder -+ (int)version { ++ (int) version +{ return [super version] + 0 /* v0 */; } -+ (void)initialize { + ++ (void) initialize +{ NSAssert2([super version] == 0, @"invalid superclass (%@) version %i !", NSStringFromClass([self superclass]), [super version]); } -+ (NSString *)globallyUniqueObjectId { ++ (NSString *) globallyUniqueObjectId +{ /* 4C08AE1A-A808-11D8-AC5A-000393BBAFF6 SOGo-Web-28273-18283-288182 printf( "%x", *(int *) &f); */ - static int pid = 0; - static int sequence = 0; + static int pid = 0; + static int sequence = 0; static float rndm = 0; float f; - if (pid == 0) { /* break if we fork ;-) */ - pid = getpid(); - rndm = random(); - } + if (pid == 0) + { /* break if we fork ;-) */ + pid = getpid(); + rndm = random(); + } sequence++; f = [[NSDate date] timeIntervalSince1970]; return [NSString stringWithFormat:@"%0X-%0X-%0X-%0X", pid, *(int *)&f, sequence++, random]; } -- (void)dealloc { - [self->ocsFolder release]; - [self->ocsPath release]; +- (id) init +{ + if ((self = [super init])) + { + ocsPath = nil; + ocsFolder = nil; + aclCache = [NSMutableDictionary new]; + } + + return self; +} + +- (void) dealloc +{ + [ocsFolder release]; + [ocsPath release]; + [aclCache release]; [super dealloc]; } /* accessors */ -- (BOOL)isFolderish { +- (BOOL) isFolderish +{ return YES; } -- (void)setOCSPath:(NSString *)_path { - if ([self->ocsPath isEqualToString:_path]) +- (void) setOCSPath: (NSString *) _path +{ + if ([ocsPath isEqualToString:_path]) return; - if (self->ocsPath) + if (ocsPath) [self warnWithFormat:@"GCS path is already set! '%@'", _path]; - ASSIGNCOPY(self->ocsPath, _path); + ASSIGNCOPY(ocsPath, _path); } -- (NSString *)ocsPath { - return self->ocsPath; +- (NSString *) ocsPath +{ + return ocsPath; } -- (GCSFolderManager *)folderManager { +- (GCSFolderManager *) folderManager +{ static GCSFolderManager *folderManager = nil; if (!folderManager) @@ -101,11 +126,13 @@ return folderManager; } -- (GCSFolder *)ocsFolderForPath:(NSString *)_path { +- (GCSFolder *) ocsFolderForPath: (NSString *) _path +{ return [[self folderManager] folderAtPath:_path]; } -- (GCSFolder *) ocsFolder { +- (GCSFolder *) ocsFolder +{ GCSFolder *folder; if (!ocsFolder) @@ -239,9 +266,180 @@ return names; } +/* acls as a container */ + +- (NSArray *) aclsForObjectAtPath: (NSArray *) objectPathArray; +{ + EOQualifier *qualifier; + NSString *qs; + + qs = [NSString stringWithFormat: @"c_object = '/%@'", + [objectPathArray componentsJoinedByString: @"/"]]; + qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; + + return [[self ocsFolder] fetchAclMatchingQualifier: qualifier]; +} + +- (NSArray *) _fetchAclsForUser: (NSString *) uid + forObjectAtPath: (NSString *) objectPath +{ + EOQualifier *qualifier; + NSArray *records; + NSMutableArray *acls; + NSString *qs; + + qs = [NSString stringWithFormat: @"(c_object = '/%@') AND (c_uid = '%@')", + objectPath, uid]; + qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; + records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier]; + + acls = [NSMutableArray array]; + if ([records count] > 0) + { + [acls addObject: SOGoRole_AuthorizedSubscriber]; + [acls addObjectsFromArray: [records valueForKey: @"c_role"]]; + } + + return acls; +} + +- (void) _cacheRoles: (NSArray *) roles + forUser: (NSString *) uid + forObjectAtPath: (NSString *) objectPath +{ + NSMutableDictionary *aclsForObject; + + aclsForObject = [aclCache objectForKey: objectPath]; + if (!aclsForObject) + { + aclsForObject = [NSMutableDictionary dictionary]; + [aclCache setObject: aclsForObject + forKey: objectPath]; + } + if (roles) + [aclsForObject setObject: roles forKey: uid]; + else + [aclsForObject removeObjectForKey: uid]; +} + +- (NSArray *) aclsForUser: (NSString *) uid + forObjectAtPath: (NSArray *) objectPathArray +{ + NSArray *acls; + NSString *objectPath; + NSDictionary *aclsForObject; + + objectPath = [objectPathArray componentsJoinedByString: @"/"]; + aclsForObject = [aclCache objectForKey: objectPath]; + if (aclsForObject) + acls = [aclsForObject objectForKey: uid]; + else + acls = nil; + if (!acls) + { + acls = [self _fetchAclsForUser: uid forObjectAtPath: objectPath]; + [self _cacheRoles: acls forUser: uid forObjectAtPath: objectPath]; + } + + if (!([acls count] || [uid isEqualToString: defaultUser])) + acls = [self aclsForUser: defaultUser forObjectAtPath: objectPathArray]; + + return acls; +} + +- (void) removeAclsForUsers: (NSArray *) users + forObjectAtPath: (NSArray *) objectPathArray +{ + EOQualifier *qualifier; + NSString *uids, *qs, *objectPath; + NSMutableDictionary *aclsForObject; + + if ([users count] > 0) + { + objectPath = [objectPathArray componentsJoinedByString: @"/"]; + aclsForObject = [aclCache objectForKey: objectPath]; + if (aclsForObject) + [aclsForObject removeObjectsForKeys: users]; + uids = [users componentsJoinedByString: @"') OR (c_uid = '"]; + qs = [NSString + stringWithFormat: @"(c_object = '/%@') AND ((c_uid = '%@'))", + objectPath, uids]; + qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; + [[self ocsFolder] deleteAclMatchingQualifier: qualifier]; + } +} + +- (void) setRoles: (NSArray *) roles + forUser: (NSString *) uid + forObjectAtPath: (NSArray *) objectPathArray +{ + EOAdaptorChannel *channel; + GCSFolder *folder; + NSEnumerator *userRoles; + NSString *SQL, *currentRole, *objectPath; + + [self removeAclsForUsers: [NSArray arrayWithObject: uid] + forObjectAtPath: objectPathArray]; + objectPath = [objectPathArray componentsJoinedByString: @"/"]; + [self _cacheRoles: roles forUser: uid forObjectAtPath: objectPath]; + + folder = [self ocsFolder]; + channel = [folder acquireAclChannel]; + userRoles = [roles objectEnumerator]; + currentRole = [userRoles nextObject]; + while (currentRole) + { + if (![currentRole isEqualToString: SOGoRole_AuthorizedSubscriber]) + { + SQL = [NSString stringWithFormat: @"INSERT INTO %@" + @" (c_object, c_uid, c_role)" + @" VALUES ('/%@', '%@', '%@')", + [folder aclTableName], + objectPath, uid, currentRole]; + [channel evaluateExpressionX: SQL]; + } + currentRole = [userRoles nextObject]; + } + + [folder releaseChannel: channel]; +} + +/* acls */ +- (NSArray *) defaultAclRoles +{ +#warning this should be changed to something useful + return nil; +} + +- (NSArray *) acls +{ + return [self aclsForObjectAtPath: [self pathArrayToSoObject]]; +} + +- (NSArray *) aclsForUser: (NSString *) uid +{ + return [self aclsForUser: uid + forObjectAtPath: [self pathArrayToSoObject]]; +} + +- (void) setRoles: (NSArray *) roles + forUser: (NSString *) uid +{ + return [self setRoles: roles + forUser: uid + forObjectAtPath: [self pathArrayToSoObject]]; +} + +- (void) removeAclsForUsers: (NSArray *) users +{ + return [self removeAclsForUsers: users + forObjectAtPath: [self pathArrayToSoObject]]; +} + /* WebDAV */ -- (BOOL)davIsCollection { +- (BOOL) davIsCollection +{ return [self isFolderish]; } diff --git a/SoObjects/SOGo/SOGoObject.h b/SoObjects/SOGo/SOGoObject.h index b09b636c..9d3f7a4f 100644 --- a/SoObjects/SOGo/SOGoObject.h +++ b/SoObjects/SOGo/SOGoObject.h @@ -86,9 +86,18 @@ - (NSException *)matchesRequestConditionInContext:(id)_ctx; +/* acls */ + +- (NSArray *) defaultAclRoles; +- (NSArray *) acls; +- (NSArray *) aclsForUser: (NSString *) uid; +- (void) setRoles: (NSArray *) roles + forUser: (NSString *) uid; +- (void) removeAclsForUsers: (NSArray *) users; + /* description */ -- (void)appendAttributesToDescription:(NSMutableString *)_ms; +- (void) appendAttributesToDescription:(NSMutableString *)_ms; @end diff --git a/SoObjects/SOGo/SOGoObject.m b/SoObjects/SOGo/SOGoObject.m index a0be8285..fff695fc 100644 --- a/SoObjects/SOGo/SOGoObject.m +++ b/SoObjects/SOGo/SOGoObject.m @@ -26,6 +26,7 @@ #import #import #import +#import #import "common.h" @@ -34,7 +35,6 @@ #import "SOGoPermissions.h" #import "SOGoUser.h" -#import "SOGoAclsFolder.h" #import "SOGoAuthenticator.h" #import "SOGoUserFolder.h" @@ -152,19 +152,19 @@ static BOOL kontactGroupDAV = YES; kontactGroupDAV = [ud boolForKey:@"SOGoDisableKontact34GroupDAVHack"] ? NO : YES; - /* SoClass security declarations */ +// SoClass security declarations - /* require View permission to access the root (bound to authenticated ...) */ +// require View permission to access the root (bound to authenticated ...) [[self soClassSecurityInfo] declareObjectProtected: SoPerm_View]; - /* to allow public access to all contained objects (subkeys) */ +// to allow public access to all contained objects (subkeys) [[self soClassSecurityInfo] setDefaultAccess: @"allow"]; - /* require Authenticated role for View and WebDAV */ - [[self soClassSecurityInfo] declareRole: SoRole_Owner - asDefaultForPermission: SoPerm_View]; - [[self soClassSecurityInfo] declareRole: SoRole_Owner - asDefaultForPermission: SoPerm_WebDAVAccess]; +// /* require Authenticated role for View and WebDAV */ +// [[self soClassSecurityInfo] declareRole: SoRole_Owner +// asDefaultForPermission: SoPerm_View]; +// [[self soClassSecurityInfo] declareRole: SoRole_Owner +// asDefaultForPermission: SoPerm_WebDAVAccess]; } + (void) _fillDictionary: (NSMutableDictionary *) dictionary @@ -354,7 +354,7 @@ static BOOL kontactGroupDAV = YES; NSDictionary *currentAcl; SoClassSecurityInfo *sInfo; - acls = [[[SOGoAclsFolder aclsFolder] aclsForObject: self] objectEnumerator]; + acls = [[self acls] objectEnumerator]; aclsDictionary = [NSMutableDictionary dictionary]; sInfo = [[self class] soClassSecurityInfo]; @@ -382,19 +382,28 @@ static BOOL kontactGroupDAV = YES; } - (id)initWithName:(NSString *)_name inContainer:(id)_container { - if ((self = [super init])) { - context = [[WOApplication application] context]; - [context retain]; - nameInContainer = [_name copy]; - container = - [self doesRetainContainer] ? [_container retain] : _container; - customOwner = nil; - } + if ((self = [self init])) + { + context = [[WOApplication application] context]; + [context retain]; + nameInContainer = [_name copy]; + container = + [self doesRetainContainer] ? [_container retain] : _container; + customOwner = nil; + } + return self; } -- (id)init { - return [self initWithName:nil inContainer:nil]; +- (id) init +{ + if ((self = [super init])) + { + nameInContainer = nil; + container = nil; + } + + return self; } - (void)dealloc { @@ -690,6 +699,40 @@ static BOOL kontactGroupDAV = YES; return nil; } +/* acls */ + +- (NSArray *) acls +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + +- (NSArray *) aclsForUser: (NSString *) uid +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + +- (NSArray *) defaultAclRoles +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + +- (void) setRoles: (NSArray *) roles + forUser: (NSString *) uid +{ + [self subclassResponsibility: _cmd]; +} + +- (void) removeAclsForUsers: (NSArray *) users +{ + [self subclassResponsibility: _cmd]; +} + /* description */ - (void)appendAttributesToDescription:(NSMutableString *)_ms { diff --git a/SoObjects/SOGo/SOGoPermissions.h b/SoObjects/SOGo/SOGoPermissions.h index 5f0e51cc..e6825554 100644 --- a/SoObjects/SOGo/SOGoPermissions.h +++ b/SoObjects/SOGo/SOGoPermissions.h @@ -27,16 +27,55 @@ #import -extern NSString *SOGoRole_Assistant; -extern NSString *SOGoRole_Delegate; -extern NSString *SOGoRole_FreeBusyLookup; +extern NSString *SOGoRole_ObjectCreator; +extern NSString *SOGoRole_ObjectEraser; +extern NSString *SOGoRole_ObjectViewer; +extern NSString *SOGoRole_ObjectEditor; +extern NSString *SOGoRole_AuthorizedSubscriber; + extern NSString *SOGoRole_FreeBusy; +extern NSString *SOGoRole_FreeBusyLookup; extern NSString *SOGoPerm_ReadAcls; -extern NSString *SOGoPerm_CreateAndModifyAcls; extern NSString *SOGoPerm_FreeBusyLookup; -extern NSString *SOGoRole_Organizer; -extern NSString *SOGoRole_Participant; +extern NSString *SOGoCalendarRole_Organizer; +extern NSString *SOGoCalendarRole_Participant; + +extern NSString *SOGoCalendarRole_PublicViewer; +extern NSString *SOGoCalendarRole_PublicDAndTViewer; +extern NSString *SOGoCalendarRole_PublicModifier; +extern NSString *SOGoCalendarRole_PublicResponder; +extern NSString *SOGoCalendarRole_PrivateViewer; +extern NSString *SOGoCalendarRole_PrivateDAndTViewer; +extern NSString *SOGoCalendarRole_PrivateModifier; +extern NSString *SOGoCalendarRole_PrivateResponder; +extern NSString *SOGoCalendarRole_ConfidentialViewer; +extern NSString *SOGoCalendarRole_ConfidentialDAndTViewer; +extern NSString *SOGoCalendarRole_ConfidentialModifier; +extern NSString *SOGoCalendarRole_ConfidentialResponder; + +extern NSString *SOGoCalendarRole_ComponentViewer; +extern NSString *SOGoCalendarRole_ComponentDAndTViewer; +extern NSString *SOGoCalendarRole_ComponentModifier; +extern NSString *SOGoCalendarRole_ComponentResponder; + +extern NSString *SOGoCalendarPerm_ViewWholePublicRecords; +extern NSString *SOGoCalendarPerm_ViewDAndTOfPublicRecords; +extern NSString *SOGoCalendarPerm_ModifyPublicRecords; +extern NSString *SOGoCalendarPerm_RespondToPublicRecords; +extern NSString *SOGoCalendarPerm_ViewWholePrivateRecords; +extern NSString *SOGoCalendarPerm_ViewDAndTOfPrivateRecords; +extern NSString *SOGoCalendarPerm_ModifyPrivateRecords; +extern NSString *SOGoCalendarPerm_RespondToPrivateRecords; +extern NSString *SOGoCalendarPerm_ViewWholeConfidentialRecords; +extern NSString *SOGoCalendarPerm_ViewDAndTOfConfidentialRecords; +extern NSString *SOGoCalendarPerm_ModifyConfidentialRecords; +extern NSString *SOGoCalendarPerm_RespondToConfidentialRecords; + +extern NSString *SOGoCalendarPerm_ViewAllComponent; +extern NSString *SOGoCalendarPerm_ViewDAndT; +extern NSString *SOGoCalendarPerm_ModifyComponent; +extern NSString *SOGoCalendarPerm_RespondToComponent; #endif /* SOGOPERMISSIONS_H */ diff --git a/SoObjects/SOGo/SOGoPermissions.m b/SoObjects/SOGo/SOGoPermissions.m index 1b856bb2..a071f019 100644 --- a/SoObjects/SOGo/SOGoPermissions.m +++ b/SoObjects/SOGo/SOGoPermissions.m @@ -22,25 +22,63 @@ #import "SOGoPermissions.h" -NSString *SOGoRole_Assistant = @"Assistant"; /* a colleague */ -NSString *SOGoRole_Delegate = @"Delegate"; /* a colleague or person that I - trust in adding or modifying my - data */ +/* General */ +NSString *SOGoRole_ObjectCreator = @"ObjectCreator"; +NSString *SOGoRole_ObjectEraser = @"ObjectEraser"; +NSString *SOGoRole_ObjectViewer = @"ObjectViewer"; +NSString *SOGoRole_ObjectEditor = @"ObjectEditor"; +NSString *SOGoRole_AuthorizedSubscriber = @"AuthorizedSubscriber"; + +NSString *SOGoRole_FreeBusy = @"FreeBusy"; /* for the "freebusy" special user + */ NSString *SOGoRole_FreeBusyLookup = @"FreeBusyLookup"; /* for users that have access to the freebusy information from a specific calendar */ -NSString *SOGoRole_FreeBusy = @"FreeBusy"; /* for the "freebusy" special user - */ /* Calendar */ -NSString *SOGoRole_Organizer = @"Organizer"; -NSString *SOGoRole_Participant = @"Participant"; +NSString *SOGoCalendarRole_Organizer = @"Organizer"; +NSString *SOGoCalendarRole_Participant = @"Participant"; -#warning ReadAcls still not used... +NSString *SOGoCalendarRole_PublicViewer = @"PublicViewer"; +NSString *SOGoCalendarRole_PublicDAndTViewer = @"PublicDAndTViewer"; +NSString *SOGoCalendarRole_PublicModifier = @"PublicModifier"; +NSString *SOGoCalendarRole_PublicResponder = @"PublicResponder"; +NSString *SOGoCalendarRole_PrivateViewer = @"PrivateViewer"; +NSString *SOGoCalendarRole_PrivateDAndTViewer = @"PrivateDAndTViewer"; +NSString *SOGoCalendarRole_PrivateModifier = @"PrivateModifier"; +NSString *SOGoCalendarRole_PrivateResponder = @"PrivateResponder"; +NSString *SOGoCalendarRole_ConfidentialViewer = @"ConfidentialViewer"; +NSString *SOGoCalendarRole_ConfidentialDAndTViewer = @"ConfidentialDAndTViewer"; +NSString *SOGoCalendarRole_ConfidentialModifier = @"ConfidentialModifier"; +NSString *SOGoCalendarRole_ConfidentialResponder = @"ConfidentialResponder"; + +NSString *SOGoCalendarRole_ComponentViewer = @"ComponentViewer"; +NSString *SOGoCalendarRole_ComponentDAndTViewer = @"ComponentDAndTViewer"; +NSString *SOGoCalendarRole_ComponentModifier = @"ComponentModifier"; +NSString *SOGoCalendarRole_ComponentResponder = @"ComponentResponder"; + +/* permissions */ NSString *SOGoPerm_ReadAcls = @"ReadAcls"; /* the equivalent of "read-acl" in the WebDAV acls spec, which is currently missing from SOPE */ -NSString *SOGoPerm_CreateAndModifyAcls = @"CreateAndModifyAcls"; NSString *SOGoPerm_FreeBusyLookup = @"FreeBusyLookup"; + +NSString *SOGoCalendarPerm_ViewWholePublicRecords = @"ViewWholePublicRecords"; +NSString *SOGoCalendarPerm_ViewDAndTOfPublicRecords = @"ViewDAndTOfPublicRecords"; +NSString *SOGoCalendarPerm_ModifyPublicRecords = @"ModifyPublicRecords"; +NSString *SOGoCalendarPerm_RespondToPublicRecords = @"RespondToPublicRecords"; +NSString *SOGoCalendarPerm_ViewWholePrivateRecords = @"ViewWholePrivateRecords"; +NSString *SOGoCalendarPerm_ViewDAndTOfPrivateRecords = @"ViewDAndTOfPrivateRecords"; +NSString *SOGoCalendarPerm_ModifyPrivateRecords = @"ModifyPrivateRecords"; +NSString *SOGoCalendarPerm_RespondToPrivateRecords = @"RespondToPrivateRecords"; +NSString *SOGoCalendarPerm_ViewWholeConfidentialRecords = @"ViewWholeConfidentialRecords"; +NSString *SOGoCalendarPerm_ViewDAndTOfConfidentialRecords = @"ViewDAndTOfConfidentialRecords"; +NSString *SOGoCalendarPerm_ModifyConfidentialRecords = @"ModifyConfidentialRecords"; +NSString *SOGoCalendarPerm_RespondToConfidentialRecords = @"RespondToConfidentialRecords"; + +NSString *SOGoCalendarPerm_ViewAllComponent = @"ViewAllComponent"; +NSString *SOGoCalendarPerm_ViewDAndT = @"ViewDAndT"; +NSString *SOGoCalendarPerm_ModifyComponent = @"ModifyComponent"; +NSString *SOGoCalendarPerm_RespondToComponent = @"RespondToComponent"; diff --git a/SoObjects/SOGo/SOGoUser.m b/SoObjects/SOGo/SOGoUser.m index d2e9829e..e6c5a498 100644 --- a/SoObjects/SOGo/SOGoUser.m +++ b/SoObjects/SOGo/SOGoUser.m @@ -19,18 +19,23 @@ 02111-1307, USA. */ +#import +#import +#import +#import +#import #import -#import "AgenorUserManager.h" -#import "SOGoAclsFolder.h" -#import "common.h" +#import +#import "AgenorUserManager.h" +#import "SOGoContentObject.h" #import "SOGoUser.h" +#import "SOGoPermissions.h" static NSTimeZone *serverTimeZone = nil; @interface NSObject (SOGoRoles) -- (NSString *) roleOfUser: (NSString *) uid; - (NSArray *) rolesOfUser: (NSString *) uid; @end @@ -180,10 +185,8 @@ static NSTimeZone *serverTimeZone = nil; timeZoneName = [[self userDefaults] stringForKey: @"TimeZone"]; if ([timeZoneName length] > 0) userTimeZone = [NSTimeZone timeZoneWithName: timeZoneName]; - else - userTimeZone = nil; if (!userTimeZone) - userTimeZone = [self serverTimeZone]; + userTimeZone = serverTimeZone; [userTimeZone retain]; } @@ -246,9 +249,7 @@ static NSTimeZone *serverTimeZone = nil; inContext: (WOContext *) context { NSMutableArray *rolesForObject; - SOGoAclsFolder *aclsFolder; NSArray *sogoRoles; - NSString *role; rolesForObject = [NSMutableArray new]; [rolesForObject autorelease]; @@ -261,24 +262,10 @@ static NSTimeZone *serverTimeZone = nil; [rolesForObject addObject: SoRole_Owner]; if ([object isKindOfClass: [SOGoObject class]]) { - aclsFolder = [SOGoAclsFolder aclsFolder]; - sogoRoles = [aclsFolder aclsForObject: (SOGoObject *) object - forUser: login]; - if (sogoRoles) - [rolesForObject addObjectsFromArray: sogoRoles]; - } - if ([object respondsToSelector: @selector (rolesOfUser:)]) - { - sogoRoles = [object rolesOfUser: login]; + sogoRoles = [(SOGoObject *) object aclsForUser: login]; if (sogoRoles) [rolesForObject addObjectsFromArray: sogoRoles]; } - if ([object respondsToSelector: @selector (roleOfUser:)]) - { - role = [object roleOfUser: login]; - if (role) - [rolesForObject addObject: role]; - } return rolesForObject; } diff --git a/UI/Common/English.lproj/Localizable.strings b/UI/Common/English.lproj/Localizable.strings index 3af994ea..119c9c32 100644 --- a/UI/Common/English.lproj/Localizable.strings +++ b/UI/Common/English.lproj/Localizable.strings @@ -20,3 +20,5 @@ "noJavascriptRetry" = "Retry"; "Publish the Free/Busy information" = "Publish the Free/Busy information"; + +"Sorry, the user rights can not be configured for that object." = "Sorry, the user rights can not be configured for that object."; diff --git a/UI/Common/French.lproj/Localizable.strings b/UI/Common/French.lproj/Localizable.strings index 314ae983..dcf84ce1 100644 --- a/UI/Common/French.lproj/Localizable.strings +++ b/UI/Common/French.lproj/Localizable.strings @@ -23,3 +23,5 @@ "Associated Users:" = "Utilisateurs associés :"; "(Unchecked = assistant, checked = delegate)" = "(Coché = assistant, décoché = délégué)"; "Publish the Free/Busy information" = "Publier l'occupation du temps"; + +"Sorry, the user rights can not be configured for that object." = "Sorry, the user rights can not be configured for that object."; diff --git a/UI/Common/GNUmakefile b/UI/Common/GNUmakefile index d80d6bf0..9adbb6dc 100644 --- a/UI/Common/GNUmakefile +++ b/UI/Common/GNUmakefile @@ -16,10 +16,12 @@ CommonUI_OBJC_FILES += \ UIxAppNavView.m \ \ UIxAclEditor.m \ + UIxObjectActions.m \ UIxFolderActions.m \ UIxElemBuilder.m \ UIxTabView.m \ UIxTabItem.m \ + UIxUserRightsEditor.m \ \ UIxSortableTableHeader.m \ \ diff --git a/UI/Common/Toolbars/SOGoAclOwner.toolbar b/UI/Common/Toolbars/SOGoAclOwner.toolbar index 70987eee..e2d8f839 100644 --- a/UI/Common/Toolbars/SOGoAclOwner.toolbar +++ b/UI/Common/Toolbars/SOGoAclOwner.toolbar @@ -8,5 +8,10 @@ isSafe = NO; label = "Close"; onclick = "window.close();"; - image = "tb-mail-stop-flat-24x24.png"; } ) + image = "tb-mail-stop-flat-24x24.png"; } ), + ( { link = "#"; + isSafe = NO; + label = "Edit User Rights"; + onclick = "return openRightsForUser();"; + image = "edit.png"; } ), ) diff --git a/UI/Common/UIxAclEditor.h b/UI/Common/UIxAclEditor.h index d4b047af..e4d0b1d3 100644 --- a/UI/Common/UIxAclEditor.h +++ b/UI/Common/UIxAclEditor.h @@ -1,6 +1,6 @@ /* UIxAclEditor.h - this file is part of SOGo * - * Copyright (C) 2006 Inverse groupe conseil + * Copyright (C) 2006, 2007 Inverse groupe conseil * * Author: Wolfgang Sourdeau * @@ -30,22 +30,17 @@ BOOL prepared; BOOL publishInFreeBusy; NSArray *acls; + NSArray *savedUIDs; NSMutableArray *users; - NSMutableArray *assistants; - NSMutableArray *delegates; NSString *currentUser; - NSString *ownerLogin; } -- (NSArray *) aclsForFolder; -- (NSString *) assistantsValue; -- (NSString *) delegatesValue; +- (NSArray *) aclsForObject; -- (NSArray *) usersForFolder; +- (NSArray *) usersForObject; - (void) setCurrentUser: (NSString *) newCurrentUser; - (NSString *) currentUser; -- (NSString *) ownerLogin; - (NSString *) ownerName; @end diff --git a/UI/Common/UIxAclEditor.m b/UI/Common/UIxAclEditor.m index 79d97b28..8c0e9df9 100644 --- a/UI/Common/UIxAclEditor.m +++ b/UI/Common/UIxAclEditor.m @@ -1,6 +1,6 @@ /* UIxAclEditor.m - this file is part of SOGo * - * Copyright (C) 2006 Inverse groupe conseil + * Copyright (C) 2006, 2007 Inverse groupe conseil * * Author: Wolfgang Sourdeau * @@ -27,7 +27,7 @@ #import #import #import -#import +#import #import #import "UIxAclEditor.h" @@ -42,10 +42,8 @@ prepared = NO; publishInFreeBusy = NO; users = [NSMutableArray new]; - delegates = [NSMutableArray new]; - assistants = [NSMutableArray new]; - ownerLogin = nil; currentUser = nil; + savedUIDs = nil; } return self; @@ -53,38 +51,20 @@ - (void) dealloc { + [savedUIDs release]; [users release]; - [delegates release]; - [assistants release]; - [ownerLogin release]; [currentUser release]; [super dealloc]; } -- (NSArray *) aclsForFolder +- (NSArray *) aclsForObject { - SOGoAclsFolder *folder; - if (!acls) - { - folder = [SOGoAclsFolder aclsFolder]; - acls = [folder aclsForObject: [self clientObject]]; - } + acls = [[self clientObject] acls]; return acls; } -- (NSString *) ownerLogin -{ - if (!ownerLogin) - { - ownerLogin = [[self clientObject] ownerInContext: context]; - [ownerLogin retain]; - } - - return ownerLogin; -} - - (NSString *) _displayNameForUID: (NSString *) uid { AgenorUserManager *um; @@ -98,44 +78,36 @@ - (NSString *) ownerName { - return [self _displayNameForUID: [self ownerLogin]]; + NSString *ownerLogin; + + ownerLogin = [[self clientObject] ownerInContext: context]; + + return [self _displayNameForUID: ownerLogin]; } - (void) _prepareUsers { NSEnumerator *aclsEnum; - AgenorUserManager *um; NSDictionary *currentAcl; - NSString *currentUID; + NSString *currentUID, *ownerLogin; - aclsEnum = [[self aclsForFolder] objectEnumerator]; - um = [AgenorUserManager sharedUserManager]; + ownerLogin = [[self clientObject] ownerInContext: context]; + + aclsEnum = [[self aclsForObject] objectEnumerator]; currentAcl = [aclsEnum nextObject]; while (currentAcl) { currentUID = [currentAcl objectForKey: @"c_uid"]; - if ([currentUID isEqualToString: @"freebusy"]) - publishInFreeBusy = YES; - else - { - if (![[um getCNForUID: currentUID] - isEqualToString: [self ownerLogin]]) - { - if ([[currentAcl objectForKey: @"c_role"] - isEqualToString: SOGoRole_Delegate]) - [delegates addObject: currentUID]; - else - [assistants addObject: currentUID]; - [users addObject: currentUID]; - } - } + if (!([currentUID isEqualToString: ownerLogin] + || [users containsObject: currentUID])) + [users addObject: currentUID]; currentAcl = [aclsEnum nextObject]; prepared = YES; } } -- (NSArray *) usersForFolder +- (NSArray *) usersForObject { if (!prepared) [self _prepareUsers]; @@ -158,84 +130,61 @@ return [self _displayNameForUID: currentUser]; } -- (NSArray *) delegates -{ - if (!prepared) - [self _prepareUsers]; - - return delegates; -} - -- (NSString *) assistantsValue -{ - if (!prepared) - [self _prepareUsers]; - - return [assistants componentsJoinedByString: @","]; -} - -- (NSString *) delegatesValue -{ - if (!prepared) - [self _prepareUsers]; - - return [delegates componentsJoinedByString: @","]; -} - -- (BOOL) publishInFreeBusy -{ - if (!prepared) - [self _prepareUsers]; - - return publishInFreeBusy; -} - - (NSString *) toolbar { - NSString *currentLogin; + NSString *currentLogin, *ownerLogin; currentLogin = [[context activeUser] login]; + ownerLogin = [[self clientObject] ownerInContext: context]; - return (([[self ownerLogin] isEqualToString: currentLogin]) + return (([ownerLogin isEqualToString: currentLogin]) ? @"SOGoAclOwner.toolbar" : @"SOGoAclAssistant.toolbar"); } -- (BOOL) clientIsCalendar +- (void) setUserUIDS: (NSString *) retainedUsers +{ + if ([retainedUsers length] > 0) + savedUIDs = [retainedUsers componentsSeparatedByString: @","]; + else + savedUIDs = [NSArray new]; +} + +- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request + inContext: (WOContext *) context { - return [NSStringFromClass ([[self clientObject] class]) - isEqualToString: @"SOGoAppointmentFolder"]; + return ([[request method] isEqualToString: @"POST"]); } -- (id) saveAclsAction +- (id ) saveAclsAction { - NSString *uids; - NSArray *fbUsers; - WORequest *request; - SOGoAclsFolder *folder; + NSEnumerator *aclsEnum; SOGoObject *clientObject; + NSString *currentUID, *ownerLogin; - folder = [SOGoAclsFolder aclsFolder]; - request = [context request]; clientObject = [self clientObject]; - uids = [request formValueForKey: @"delegates"]; - [folder setRoleForObject: clientObject - forUsers: [uids componentsSeparatedByString: @","] - to: SOGoRole_Delegate]; - uids = [request formValueForKey: @"assistants"]; - [folder setRoleForObject: clientObject - forUsers: [uids componentsSeparatedByString: @","] - to: SOGoRole_Assistant]; - if ([self clientIsCalendar]) { - if ([[request formValueForKey: @"freebusy"] intValue]) - fbUsers = [NSArray arrayWithObject: @"freebusy"]; - else - fbUsers = nil; - [folder setRoleForObject: clientObject - forUsers: fbUsers - to: SOGoRole_FreeBusy]; - } + ownerLogin = [clientObject ownerInContext: context]; + aclsEnum = [[self aclsForObject] objectEnumerator]; + currentUID = [[aclsEnum nextObject] objectForKey: @"c_uid"]; + while (currentUID) + { + if ([currentUID isEqualToString: ownerLogin] + || [savedUIDs containsObject: currentUID]) + [users removeObject: currentUID]; + currentUID = [[aclsEnum nextObject] objectForKey: @"c_uid"]; + } + [clientObject removeAclsForUsers: users]; return [self jsCloseWithRefreshMethod: nil]; } +// - (id ) addUserInAcls +// { +// SOGoObject *clientObject; +// NSString *uid; + +// uid = [self queryParameterForKey: @"uid"]; + +// clientObject = [self clientObject]; +// } + @end diff --git a/UI/Common/UIxFolderActions.m b/UI/Common/UIxFolderActions.m index 473aaaef..4f5ff9e6 100644 --- a/UI/Common/UIxFolderActions.m +++ b/UI/Common/UIxFolderActions.m @@ -27,6 +27,7 @@ #import #import +#import #import #import diff --git a/SoObjects/SOGo/SOGoAclsFolder.h b/UI/Common/UIxObjectActions.h similarity index 54% rename from SoObjects/SOGo/SOGoAclsFolder.h rename to UI/Common/UIxObjectActions.h index 108db62b..30ed1742 100644 --- a/SoObjects/SOGo/SOGoAclsFolder.h +++ b/UI/Common/UIxObjectActions.h @@ -1,6 +1,6 @@ -/* SOGoAclsFolder.h - this file is part of SOGo +/* UIxObjectActions.h - this file is part of SOGo * - * Copyright (C) 2006 Inverse groupe conseil + * Copyright (C) 2007 Inverse groupe conseil * * Author: Wolfgang Sourdeau * @@ -20,30 +20,17 @@ * Boston, MA 02111-1307, USA. */ -#ifndef SOGOACLSFOLDER_H -#define SOGOACLSFOLDER_H +#ifndef UIXOBJECTACTIONS_H +#define UIXOBJECTACTIONS_H -#import +#import -@class NSString; -@class GCSFolder; -@class SOGoObject; +@class WOResponse; -@interface SOGoAclsFolder : NSObject -{ - NSString *ocsPath; - GCSFolder *ocsFolder; -} +@interface UIxObjectActions : WODirectAction -+ (id) aclsFolder; - -- (NSArray *) aclsForObject: (SOGoObject *) object; -- (NSArray *) aclsForObject: (SOGoObject *) object - forUser: (NSString *) uid; -- (void) setRoleForObject: (SOGoObject *) object - forUsers: (NSArray *) uids - to: (NSString *) role; +- (WOResponse *) addUserInAclsAction; @end -#endif /* SOGOACLSOBJECT_H */ +#endif /* UIXOBJECTACTIONS_H */ diff --git a/UI/Common/UIxObjectActions.m b/UI/Common/UIxObjectActions.m new file mode 100644 index 00000000..143f677f --- /dev/null +++ b/UI/Common/UIxObjectActions.m @@ -0,0 +1,66 @@ +/* UIxObjectActions.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 "UIxObjectActions.h" + +@implementation UIxObjectActions + +- (WOResponse *) addUserInAclsAction +{ + WOResponse *response; + WORequest *request; + NSString *uid, *email; + unsigned int code; + AgenorUserManager *um; + SOGoObject *clientObject; + + code = 403; + request = [context request]; + uid = [request formValueForKey: @"uid"]; + if ([uid length] > 0) + { + um = [AgenorUserManager sharedUserManager]; + email = [um getEmailForUID: uid]; + if ([email length] > 0) + { + clientObject = [self clientObject]; + [clientObject setRoles: [clientObject defaultAclRoles] + forUser: uid]; + code = 204; + } + } + + response = [context response]; + [response setStatus: code]; + + return response; +} + +@end diff --git a/UI/Common/UIxUserRightsEditor.h b/UI/Common/UIxUserRightsEditor.h new file mode 100644 index 00000000..35cfe156 --- /dev/null +++ b/UI/Common/UIxUserRightsEditor.h @@ -0,0 +1,53 @@ +/* UIxUserRightsEditor.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 UIXUSERRIGHTSEDITOR_H +#define UIXUSERRIGHTSEDITOR_H + +#import + +@class NSMutableArray; +@class NSString; + +@protocol WOActionResults; + +@interface UIxUserRightsEditor : UIxComponent +{ + NSMutableArray *userRights; + NSString *uid; +} + +- (NSString *) userDisplayName; +- (NSString *) uid; + +- (void) appendRight: (NSString *) newRight; +- (void) appendExclusiveRight: (NSString *) newRight + fromList: (NSArray *) list; +- (void) removeRight: (NSString *) right; +- (void) removeAllRightsFromList: (NSArray *) list; + +- (void) prepareRightsForm; +- (void) updateRights; + +@end + +#endif /* UIXUSERRIGHTSEDITOR_H */ diff --git a/UI/Common/UIxUserRightsEditor.m b/UI/Common/UIxUserRightsEditor.m new file mode 100644 index 00000000..d3792a23 --- /dev/null +++ b/UI/Common/UIxUserRightsEditor.m @@ -0,0 +1,162 @@ +/* UIxUserRightsEditor.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 "UIxUserRightsEditor.h" + +@implementation UIxUserRightsEditor + +- (id) init +{ + if ((self = [super init])) + { + uid = nil; + userRights = [NSMutableArray new]; + } + + return self; +} + +- (void) dealloc +{ + [uid release]; + [userRights release]; + [super dealloc]; +} + +- (NSString *) uid +{ + return uid; +} + +- (NSString *) userDisplayName +{ + AgenorUserManager *um; + + um = [AgenorUserManager sharedUserManager]; + + return [NSString stringWithFormat: @"%@ <%@>", + [um getCNForUID: uid], + [um getEmailForUID: uid]]; +} + +- (BOOL) _initRights +{ + BOOL response; + NSString *newUID, *email; + AgenorUserManager *um; + SOGoObject *clientObject; + + response = NO; + + newUID = [[context request] formValueForKey: @"uid"]; + if ([newUID length] > 0) + { + um = [AgenorUserManager sharedUserManager]; + email = [um getEmailForUID: newUID]; + if ([email length] > 0) + { + ASSIGN (uid, newUID); + clientObject = [self clientObject]; + [userRights addObjectsFromArray: [clientObject aclsForUser: uid]]; + if (![userRights count]) + [userRights addObjectsFromArray: [clientObject defaultAclRoles]]; + + response = YES; + } + } + + return response; +} + +- (id ) defaultAction +{ + id response; + + if (![self _initRights]) + response = [NSException exceptionWithHTTPStatus: 403 + reason: @"No such user."]; + else + { + [self prepareRightsForm]; + response = self; + } + + return response; +} + +- (id ) saveUserRightsAction +{ + id response; + + if (![self _initRights]) + response = [NSException exceptionWithHTTPStatus: 403 + reason: @"No such user."]; + else + { + [self updateRights]; + [[self clientObject] setRoles: userRights + forUser: uid]; + response = [self jsCloseWithRefreshMethod: nil]; + } + + return response; +} + +- (void) appendRight: (NSString *) newRight +{ + if (![userRights containsObject: newRight]) + [userRights addObject: newRight]; +} + +- (void) removeRight: (NSString *) right +{ + if ([userRights containsObject: right]) + [userRights removeObject: right]; +} + +- (void) appendExclusiveRight: (NSString *) newRight + fromList: (NSArray *) list +{ + [userRights removeObjectsInArray: list]; + [self appendRight: newRight]; +} + +- (void) removeAllRightsFromList: (NSArray *) list +{ + [userRights removeObjectsInArray: list]; +} + +- (void) prepareRightsForm +{ +} + +- (void) updateRights +{ + [self subclassResponsibility: _cmd]; +} + +@end diff --git a/UI/Common/product.plist b/UI/Common/product.plist index d0166ea5..0d94f25e 100644 --- a/UI/Common/product.plist +++ b/UI/Common/product.plist @@ -30,42 +30,60 @@ }; categories = { + SOGoObject = { + methods = { + addUserInAcls = { + protectedBy = "SaveAcls"; + actionClass = "UIxObjectActions"; + actionName = "addUserInAcls"; + }; + acls = { + protectedBy = "ReadAcls"; + pageName = "UIxAclEditor"; + }; + saveAcls = { + protectedBy = "SaveAcls"; + pageName = "UIxAclEditor"; + actionName = "saveAcls"; + }; + userRights = { + protectedBy = "ReadAcls"; + pageName = "UIxUserRightsEditor"; + }; + saveUserRights = { + protectedBy = "ReadAcls"; + pageName = "UIxUserRightsEditor"; + actionName = "saveUserRights"; + }; + }; + }; SOGoFolder = { methods = { subscribe = { - protectedBy = "View"; + protectedBy = ""; actionClass = "UIxFolderActions"; actionName = "subscribe"; }; unsubscribe = { - protectedBy = "View"; + protectedBy = ""; actionClass = "UIxFolderActions"; actionName = "unsubscribe"; }; canAccessContent = { - protectedBy = "View"; + protectedBy = ""; actionClass = "UIxFolderActions"; actionName = "canAccessContent"; }; activateFolder = { - protectedBy = "View"; + protectedBy = ""; actionClass = "UIxFolderActions"; actionName = "activateFolder"; }; deactivateFolder = { - protectedBy = "View"; + protectedBy = ""; actionClass = "UIxFolderActions"; - actionName = "deactivateFolder"; + actionName = "deactivateFolder"; }; - acls = { - protectedBy = "ReadAcls"; - pageName = "UIxAclEditor"; - }; - saveAcls = { - protectedBy = "SaveAcls"; - pageName = "UIxAclEditor"; - actionName = "saveAcls"; - }; }; }; }; diff --git a/UI/Contacts/English.lproj/Localizable.strings b/UI/Contacts/English.lproj/Localizable.strings index d94efb27..4233453d 100644 --- a/UI/Contacts/English.lproj/Localizable.strings +++ b/UI/Contacts/English.lproj/Localizable.strings @@ -2,6 +2,7 @@ "Addressbook" = "Addressbook"; "Addresses" = "Addresses"; +"Update" = "Update"; "Cancel" = "Cancel"; "Common" = "Common"; "Contact editor" = "Contact editor"; @@ -100,3 +101,14 @@ = "You cannot subscribe to a folder that you own!"; "Unable to subscribe to that folder!" = "Unable to subscribe to that folder!"; + +"User rights for:" = "User rights for:"; + +"This person can add cards to this addressbook." += "This person can add cards to this addressbook."; +"This person can edit the cards of this addressbook." += "This person can edit the cards of this addressbook."; +"This person can view the cards of this addressbook." += "This person can view the cards of this addressbook."; +"This person can erase cards from this addressbook." += "This person can erase cards from this addressbook."; diff --git a/UI/Contacts/French.lproj/Localizable.strings b/UI/Contacts/French.lproj/Localizable.strings index 940de3a5..46f66571 100644 --- a/UI/Contacts/French.lproj/Localizable.strings +++ b/UI/Contacts/French.lproj/Localizable.strings @@ -12,6 +12,7 @@ "Address Books" = "Carnet d'adresses"; "Addresses" = "Adresses"; +"Update" = "Mettre à jour"; "Cancel" = "Annuler"; "Common" = "Identité"; "Contact editor" = "Éditer le contact"; @@ -113,3 +114,14 @@ = "Vous ne pouvez pas vous inscrire à un dossier qui vous appartient!"; "Unable to subscribe to that folder!" = "Impossible de vous inscrire à ce dossier!"; + +"User rights for:" = "Autorisations pour :"; + +"This person can add cards to this addressbook." += "Cette personne peut ajouter des fiches à ce carnet d'adresses."; +"This person can edit the cards of this addressbook." += "Cette personne peut éditer des fiches de ce carnet d'adresses."; +"This person can view the cards of this addressbook." += "Cette personne peut visionner des fiches de ce carnet d'adresses."; +"This person can erase cards from this addressbook." += "Cette personne peut effacer des fiches de ce carnet d'adresses."; diff --git a/UI/Contacts/GNUmakefile b/UI/Contacts/GNUmakefile index ed831d32..6f7ae7e8 100644 --- a/UI/Contacts/GNUmakefile +++ b/UI/Contacts/GNUmakefile @@ -11,6 +11,7 @@ ContactsUI_LANGUAGES = English French ContactsUI_OBJC_FILES = \ UIxContactsUserFolders.m \ UIxContactsMailerSelection.m \ + UIxContactsUserRightsEditor.m \ \ ContactsUIProduct.m \ UIxContactsFilterPanel.m \ diff --git a/UI/Contacts/UIxContactsUserRightsEditor.h b/UI/Contacts/UIxContactsUserRightsEditor.h new file mode 100644 index 00000000..733bb5e4 --- /dev/null +++ b/UI/Contacts/UIxContactsUserRightsEditor.h @@ -0,0 +1,46 @@ +/* UIxContactsUserRightsEditor.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 UIXCONTACTSUSERRIGHTSEDITOR_H +#define UIXCONTACTSUSERRIGHTSEDITOR_H + +#import + +@interface UIxContactsUserRightsEditor : UIxUserRightsEditor + +- (void) setUserCanCreateObjects: (BOOL) userCanCreateObjects; +- (BOOL) userCanCreateObjects; + +- (void) setUserCanEraseObjects: (BOOL) userCanEraseObjects; +- (BOOL) userCanEraseObjects; + +- (void) setUserCanEditObjects: (BOOL) userCanEditObjects; +- (BOOL) userCanEditObjects; + +- (void) setUserCanViewObjects: (BOOL) userCanViewObjects; +- (BOOL) userCanViewObjects; + +- (void) updateRights; + +@end + +#endif /* UIXCONTACTSUSERRIGHTSEDITOR_H */ diff --git a/UI/Contacts/UIxContactsUserRightsEditor.m b/UI/Contacts/UIxContactsUserRightsEditor.m new file mode 100644 index 00000000..a6d43ee0 --- /dev/null +++ b/UI/Contacts/UIxContactsUserRightsEditor.m @@ -0,0 +1,111 @@ +/* UIxContactsUserRightsEditor.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 "UIxContactsUserRightsEditor.h" + +@implementation UIxContactsUserRightsEditor + +- (void) setUserCanCreateObjects: (BOOL) userCanCreateObjects +{ + if (userCanCreateObjects) + [self appendRight: SOGoRole_ObjectCreator]; + else + [self removeRight: SOGoRole_ObjectCreator]; +} + +- (BOOL) userCanCreateObjects +{ + return [userRights containsObject: SOGoRole_ObjectCreator]; +} + +- (void) setUserCanEraseObjects: (BOOL) userCanEraseObjects +{ + if (userCanEraseObjects) + [self appendRight: SOGoRole_ObjectEraser]; + else + [self removeRight: SOGoRole_ObjectEraser]; +} + +- (BOOL) userCanEraseObjects +{ + return [userRights containsObject: SOGoRole_ObjectEraser]; +} + +- (void) setUserCanEditObjects: (BOOL) userCanEditObjects +{ + if (userCanEditObjects) + [self appendRight: SOGoRole_ObjectEditor]; + else + [self removeRight: SOGoRole_ObjectEditor]; +} + +- (BOOL) userCanEditObjects +{ + return [userRights containsObject: SOGoRole_ObjectEditor]; +} + +- (void) setUserCanViewObjects: (BOOL) userCanViewObjects +{ + if (userCanViewObjects) + [self appendRight: SOGoRole_ObjectViewer]; + else + [self removeRight: SOGoRole_ObjectViewer]; +} + +- (BOOL) userCanViewObjects +{ + return [userRights containsObject: SOGoRole_ObjectViewer]; +} + +- (void) updateRights +{ + WORequest *request; + + request = [context request]; + + if ([[request formValueForKey: @"ObjectCreator"] length] > 0) + [self appendRight: SOGoRole_ObjectCreator]; + else + [self removeRight: SOGoRole_ObjectCreator]; + + if ([[request formValueForKey: @"ObjectEditor"] length] > 0) + [self appendRight: SOGoRole_ObjectEditor]; + else + [self removeRight: SOGoRole_ObjectEditor]; + + if ([[request formValueForKey: @"ObjectViewer"] length] > 0) + [self appendRight: SOGoRole_ObjectViewer]; + else + [self removeRight: SOGoRole_ObjectViewer]; + + if ([[request formValueForKey: @"ObjectEraser"] length] > 0) + [self appendRight: SOGoRole_ObjectEraser]; + else + [self removeRight: SOGoRole_ObjectEraser]; +} + +@end diff --git a/UI/Contacts/product.plist b/UI/Contacts/product.plist index 663ab8d9..b1c47948 100644 --- a/UI/Contacts/product.plist +++ b/UI/Contacts/product.plist @@ -76,7 +76,7 @@ pageName = "UIxContactsListView"; }; new = { - protectedBy = "View"; + protectedBy = "Add Documents, Images, and Files"; pageName = "UIxContactEditor"; actionName = "new"; }; @@ -86,10 +86,19 @@ actionName = "mailerContacts"; }; delete = { - protectedBy = "View"; + protectedBy = "SaveAcls"; /* a hack to force "owner" */ pageName = "UIxContactsListView"; actionName = "delete"; }; + userRights = { + protectedBy = "ReadAcls"; + pageName = "UIxContactsUserRightsEditor"; + }; + saveUserRights = { + protectedBy = "SaveAcls"; + pageName = "UIxContactsUserRightsEditor"; + actionName = "saveUserRights"; + }; }; }; @@ -126,20 +135,20 @@ SOGoContactGCSEntry = { methods = { view = { - protectedBy = "View"; + protectedBy = "Access Contents Information"; pageName = "UIxContactView"; }; delete = { - protectedBy = "View"; + protectedBy = "Delete Objects"; pageName = "UIxContactView"; actionName = "delete"; }; edit = { - protectedBy = "View"; + protectedBy = "Change Images And Files"; pageName = "UIxContactEditor"; }; save = { - protectedBy = "View"; + protectedBy = "Change Images And Files"; pageName = "UIxContactEditor"; actionName = "save"; }; @@ -148,11 +157,6 @@ pageName = "UIxContactEditor"; actionName = "write"; }; - vcard = { - protectedBy = "View"; - pageName = "UIxContactView"; - actionName = "vcard"; - }; }; }; @@ -181,11 +185,6 @@ pageName = "UIxContactEditor"; actionName = "write"; }; - vcard = { - protectedBy = "View"; - pageName = "UIxContactView"; - actionName = "vcard"; - }; }; }; }; diff --git a/UI/MailerUI/product.plist b/UI/MailerUI/product.plist index 6a0803aa..a1934d2f 100644 --- a/UI/MailerUI/product.plist +++ b/UI/MailerUI/product.plist @@ -364,7 +364,6 @@ pageName = "UIxMailEditorAttach"; actionName = "deleteAttachment"; }; - send = { protectedBy = "View"; pageName = "UIxMailEditor"; diff --git a/UI/MainUI/product.plist b/UI/MainUI/product.plist index a189d3c3..44b3503d 100644 --- a/UI/MainUI/product.plist +++ b/UI/MainUI/product.plist @@ -15,40 +15,21 @@ "View" = ( "Authenticated", "FreeBusy" ); }; }; - SOGoUserFolder = { - superclass = "SOGoFolder"; + SOGoFolder = { + superclass = "SOGoObject"; protectedBy = ""; defaultAccess = "allow"; defaultRoles = { - "View" = ( "Owner" ); - }; - /* protectedBy = "HomePage Access"; */ - }; - SOGoFolder = { - superclass = "SOGoObject"; - protectedBy = "Access Contents Information"; - defaultRoles = { - "Add Documents, Images, and Files" = ( "Owner", "Delegate" ); - "View" = ( "Owner", "Delegate", "Assistant" ); - "WebDAV Access" = ( "Owner", "Delegate", "Assistant" ); - "Access Contents Information" = ( "Owner", "Assistant", "Delegate" ); - "ReadAcls" = ( "Owner", "Delegate", "Assistant" ); + "Add Documents, Images, and Files" = ( "Owner", "ObjectCreator" ); + "View" = ( "Owner", "AuthorizedSubscriber" ); + "Access Contents Information" = ( "Owner", "ObjectViewer", "AuthorizedSubscriber" ); + "Change Images And Files" = ( "Owner", "ObjectEditor" ); + "WebDAV Access" = ( "Owner", "AuthorizedSubscriber" ); + "ReadAcls" = ( "Owner", "AuthorizedSubscriber" ); "SaveAcls" = ( "Owner" ); - "Delete Objects" = ( "Owner", "Delegate" ); + "Delete Objects" = ( "Owner", "ObjectEraser" ); }; }; - SOGoGroupsFolder = { - superclass = "SOGoObject"; - protectedBy = "View"; - }; - SOGoGroupFolder = { - superclass = "SOGoObject"; - protectedBy = "View"; - }; - SOGoCustomGroupFolder = { - superclass = "SOGoGroupFolder"; - protectedBy = "View"; - }; }; categories = { diff --git a/UI/Scheduler/English.lproj/Localizable.strings b/UI/Scheduler/English.lproj/Localizable.strings index bf4f1a7f..68edabe8 100644 --- a/UI/Scheduler/English.lproj/Localizable.strings +++ b/UI/Scheduler/English.lproj/Localizable.strings @@ -62,7 +62,6 @@ "this year" = "this year"; - /* Menu */ "Calendars" = "Calendars"; @@ -82,6 +81,20 @@ "OpenGroupware.org" = "OpenGroupware.org"; "Forbidden" = "Forbidden"; +/* acls */ +"User rights for:" = "User rights for:"; +"label_Public" = "Public"; +"label_Private" = "Private"; +"label_Confidential" = "Confidential"; +"View All" = "View All"; +"View the Date & Time" = "View the Date & Time"; +"Modify" = "Modify"; +"Respond To" = "Respond To"; +"None" = "None"; +"This person can create objects in my calendar." += "This person can create objects in my calendar."; +"This person can erase objects from my calendar." += "This person can erase objects from my calendar."; /* Button Titles */ @@ -97,6 +110,7 @@ "Close" = "Close"; "Invite Attendees" = "Invite Attendees"; "Documents" = "Documents"; +"Update" = "Update"; "Cancel" = "Cancel"; "show_rejected_apts" = "Show rejected appointments"; "hide_rejected_apts" = "Hide rejected appointments"; @@ -226,9 +240,12 @@ "prio_9" = "Low"; /* access classes (privacy) */ -"privacy_PUBLIC" = "Public"; -"privacy_CONFIDENTIAL" = "Confidential"; -"privacy_PRIVATE" = "Private"; +"PUBLIC_vevent" = "Public Event"; +"CONFIDENTIAL_vevent" = "Confidential Event"; +"PRIVATE_vevent" = "Private Event"; +"PUBLIC_vtodo" = "Public Task"; +"CONFIDENTIAL_vtodo" = "Confidential Task"; +"PRIVATE_vtodo" = "Private Task"; /* status type */ "status_" = "Not specified"; @@ -374,6 +391,7 @@ validate_endbeforestart = "Enddate is before startdate!"; "Start" = "Start"; "End" = "End"; "Location" = "Location"; +"(Private Event)" = "(Événement privé)"; "closeThisWindowMessage" = "Thank you! You may now close this window."; "Multicolumn Day View" = "Multicolumn Day View"; diff --git a/UI/Scheduler/French.lproj/Localizable.strings b/UI/Scheduler/French.lproj/Localizable.strings index c8b343ac..49515c12 100644 --- a/UI/Scheduler/French.lproj/Localizable.strings +++ b/UI/Scheduler/French.lproj/Localizable.strings @@ -82,6 +82,20 @@ "OpenGroupware.org" = "OpenGroupware.org"; "Forbidden" = "Accès non autorisée"; +/* acls */ +"User rights for:" = "Autorisations pour :"; +"label_Public" = "Public"; +"label_Private" = "Privé"; +"label_Confidential" = "Confidentiel"; +"View All" = "Voir tout"; +"View the Date & Time" = "Voir la date & l'heure"; +"Modify" = "Modifier"; +"Respond To" = "Répondre"; +"None" = "Aucun"; +"This person can create objects in my calendar." += "Cette personne peut ajouter des objets à mon agenda."; +"This person can erase objects from my calendar." += "Cette personne peut effacer des objets de mon agenda."; /* Button Titles */ @@ -97,12 +111,12 @@ "Close" = "Fermer"; "Invite Attendees" = "Participants"; "Documents" = "Documents"; +"Update" = "Mettre à jour"; "Cancel" = "Annuler"; "show_rejected_apts" = "Afficher les rendez-vous refusés"; "hide_rejected_apts" = "Cacher les rendez-vous refusés"; /* Schedule */ - "Schedule" = "Suivi de rendez-vous"; "No appointments found" = "Aucun rendez-vous"; "Meetings proposed by you" = "Rendez-vous que vous proposez"; @@ -115,7 +129,6 @@ "Hide already accepted and rejected appointments" = "Cacher les invitations refusées"; "Show already accepted and rejected appointments" = "Montrer aussi les invitations refusées"; - /* Appointments */ "Appointment viewer" = "Visualisation de rendez-vous"; @@ -225,9 +238,12 @@ "prio_9" = "Basse"; /* access classes (privacy) */ -"privacy_PUBLIC" = "Public"; -"privacy_CONFIDENTIAL" = "Date et heure seulement"; -"privacy_PRIVATE" = "Privé"; +"PUBLIC_vevent" = "Événement public"; +"CONFIDENTIAL_vevent" = "Événement confidentiel"; +"PRIVATE_vevent" = "Événement privé"; +"PUBLIC_vtodo" = "Tâche publique"; +"CONFIDENTIAL_vtodo" = "Tâche confidentielle"; +"PRIVATE_vtodo" = "Tâche privée"; /* status type */ "status_" = "Non-spécifié"; @@ -374,6 +390,7 @@ validate_endbeforestart = "La date de fin est avant la date de début !"; "Start" = "Début"; "End" = "Fin"; "Location" = "Lieu"; +"(Private Event)" = "(Événement privé)"; "closeThisWindowMessage" = "Merci! Vous pouvez maintenant fermer cette fenêtre."; "Multicolumn Day View" = "Multicolonne"; diff --git a/UI/Scheduler/GNUmakefile b/UI/Scheduler/GNUmakefile index 092d61cd..4250113d 100644 --- a/UI/Scheduler/GNUmakefile +++ b/UI/Scheduler/GNUmakefile @@ -15,8 +15,8 @@ SchedulerUI_OBJC_FILES = \ \ UIxCalFilterPanel.m \ UIxCalDayTable.m \ - \ UIxCalDateSelector.m \ + UIxCalUserRightsEditor.m \ \ UIxComponent+Agenor.m \ UIxCalView.m \ diff --git a/UI/Scheduler/UIxCalDayView.h b/UI/Scheduler/UIxCalDayView.h index ee4fbeda..003e8afe 100644 --- a/UI/Scheduler/UIxCalDayView.h +++ b/UI/Scheduler/UIxCalDayView.h @@ -18,8 +18,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ - #ifndef __UIxCalDayView_H_ #define __UIxCalDayView_H_ diff --git a/UI/Scheduler/UIxCalDayView.m b/UI/Scheduler/UIxCalDayView.m index fcca9b5e..18d09bae 100644 --- a/UI/Scheduler/UIxCalDayView.m +++ b/UI/Scheduler/UIxCalDayView.m @@ -18,7 +18,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ #import #import diff --git a/UI/Scheduler/UIxCalInlineAptView.m b/UI/Scheduler/UIxCalInlineAptView.m index 5f3c3243..a0bc0d82 100644 --- a/UI/Scheduler/UIxCalInlineAptView.m +++ b/UI/Scheduler/UIxCalInlineAptView.m @@ -284,23 +284,4 @@ return userIsInTheCard; } -- (BOOL) titleShouldBeHidden -{ - BOOL shouldBeHidden; - SOGoUser *user; - SOGoAuthenticator *sAuth; - - sAuth = [SOGoAuthenticator sharedSOGoAuthenticator]; - user = [sAuth userInContext: context]; - - if ([[appointment objectForKey: @"owner"] isEqualToString: [user login]] - || ([[appointment objectForKey: @"classification"] intValue] - != iCalAccessConfidential)) - shouldBeHidden = NO; - else - shouldBeHidden = ![self _userIsInTheCard: [user email]]; - - return shouldBeHidden; -} - @end diff --git a/UI/Scheduler/UIxCalUserRightsEditor.h b/UI/Scheduler/UIxCalUserRightsEditor.h new file mode 100644 index 00000000..d20c5aed --- /dev/null +++ b/UI/Scheduler/UIxCalUserRightsEditor.h @@ -0,0 +1,58 @@ +/* UIxCalUserRightsEditor.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 UIXCALUSERRIGHTSEDITOR_H +#define UIXCALUSERRIGHTSEDITOR_H + +#import + +@class NSArray; +@class NSString; +@class NSMutableDictionary; + +@interface UIxCalUserRightsEditor : UIxUserRightsEditor +{ + NSString *currentRight; + NSString *currentRightType; + NSMutableDictionary *rights; +} + +- (NSArray *) objectRights; +- (void) setCurrentRight: (NSString *) newCurrentRight; +- (NSString *) currentRight; + +- (NSArray *) rightTypes; +- (void) setCurrentRightType: (NSString *) newCurrentRightType; +- (NSString *) currentRightType; +- (NSString *) currentRightTypeLabel; +- (NSString *) currentRightTypeName; +- (NSString *) currentRightSelection; + +- (void) setUserCanCreateObjects: (BOOL) userCanCreateObjects; +- (BOOL) userCanCreateObjects; + +- (void) setUserCanEraseObjects: (BOOL) userCanEraseObjects; +- (BOOL) userCanEraseObjects; + +@end + +#endif /* UIXCALUSERRIGHTSEDITOR_H */ diff --git a/UI/Scheduler/UIxCalUserRightsEditor.m b/UI/Scheduler/UIxCalUserRightsEditor.m new file mode 100644 index 00000000..4f6b5f14 --- /dev/null +++ b/UI/Scheduler/UIxCalUserRightsEditor.m @@ -0,0 +1,206 @@ +/* UIxCalUserRightsEditor.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 "UIxCalUserRightsEditor.h" + +@implementation UIxCalUserRightsEditor + +- (id) init +{ + if ((self = [super init])) + { + currentRight = nil; + currentRightType = nil; + rights = [NSMutableDictionary new]; + [rights setObject: @"None" forKey: @"Public"]; + [rights setObject: @"None" forKey: @"Private"]; + [rights setObject: @"None" forKey: @"Confidential"]; + } + + return self; +} + +- (void) dealloc +{ + [currentRight release]; + [currentRightType release]; + [rights release]; + [super dealloc]; +} + +- (void) prepareRightsForm +{ + NSEnumerator *roles, *types; + NSString *role, *type; + unsigned int length; + + roles = [userRights objectEnumerator]; + role = [roles nextObject]; + while (role) + { + types = [[self rightTypes] objectEnumerator]; + type = [types nextObject]; + while (type) + { + if ([role hasPrefix: type]) + { + length = [type length]; + [rights setObject: [role substringFromIndex: length] + forKey: type]; + } + type = [types nextObject]; + } + role = [roles nextObject]; + } +} + +- (NSArray *) _rightsForType: (NSString *) type +{ + NSMutableArray *rightsForType; + NSEnumerator *commonRights; + NSString *currentCommonRight; + + rightsForType = [NSMutableArray new]; + [rightsForType autorelease]; + commonRights = [[self objectRights] objectEnumerator]; + currentCommonRight = [commonRights nextObject]; + while (currentCommonRight) + { + [rightsForType addObject: [NSString stringWithFormat: @"%@%@", + type, currentCommonRight]]; + currentCommonRight = [commonRights nextObject]; + } + + return rightsForType; +} + +- (void) updateRights +{ + NSEnumerator *types; + NSString *currentType, *currentValue; + NSArray *rightsForType; + WORequest *request; + + request = [context request]; + types = [[self rightTypes] objectEnumerator]; + currentType = [types nextObject]; + while (currentType) + { + rightsForType = [self _rightsForType: currentType]; + currentValue + = [request formValueForKey: + [NSString stringWithFormat: @"%@Right", currentType]]; + if ([currentValue isEqualToString: @"None"]) + [self removeAllRightsFromList: rightsForType]; + else + [self appendExclusiveRight: [NSString stringWithFormat: @"%@%@", + currentType, currentValue] + fromList: rightsForType]; + currentType = [types nextObject]; + } + + if ([[request formValueForKey: @"ObjectCreator"] length] > 0) + [self appendRight: SOGoRole_ObjectCreator]; + else + [self removeRight: SOGoRole_ObjectCreator]; + + if ([[request formValueForKey: @"ObjectEraser"] length] > 0) + [self appendRight: SOGoRole_ObjectEraser]; + else + [self removeRight: SOGoRole_ObjectEraser]; +} + +- (NSArray *) objectRights +{ + return + [NSArray arrayWithObjects: + @"Viewer", @"DAndTViewer", @"Modifier", @"Responder", @"None", nil]; +} + +- (void) setCurrentRight: (NSString *) newCurrentRight +{ + ASSIGN (currentRight, newCurrentRight); +} + +- (NSString *) currentRight +{ + return currentRight; +} + +- (NSArray *) rightTypes +{ + return + [NSArray arrayWithObjects: @"Public", @"Confidential", @"Private", nil]; +} + +- (void) setCurrentRightType: (NSString *) newCurrentRightType +{ + ASSIGN (currentRightType, newCurrentRightType); +} + +- (NSString *) currentRightType +{ + return currentRightType; +} + +- (NSString *) currentRightTypeLabel +{ + return [self labelForKey: + [NSString stringWithFormat: @"label_%@", currentRightType]]; +} + +- (NSString *) currentRightTypeName +{ + return [NSString stringWithFormat: @"%@Right", currentRightType]; +} + +- (NSString *) currentRightSelection +{ + return [rights objectForKey: currentRightType]; +} + +- (void) setUserCanCreateObjects: (BOOL) userCanCreateObjects +{ + [self appendRight: SOGoRole_ObjectCreator]; +} + +- (BOOL) userCanCreateObjects +{ + return [userRights containsObject: SOGoRole_ObjectCreator]; +} + +- (void) setUserCanEraseObjects: (BOOL) userCanEraseObjects +{ + [self appendRight: SOGoRole_ObjectEraser]; +} + +- (BOOL) userCanEraseObjects +{ + return [userRights containsObject: SOGoRole_ObjectEraser]; +} + +@end diff --git a/UI/Scheduler/UIxCalView.m b/UI/Scheduler/UIxCalView.m index 0d1c9426..037a99f4 100644 --- a/UI/Scheduler/UIxCalView.m +++ b/UI/Scheduler/UIxCalView.m @@ -161,45 +161,39 @@ static BOOL shouldDisplayWeekend = NO; - (void) setAppointment:(id) _apt { - NSString *mailtoChunk; - NSString *myEmail; - - ASSIGN(appointment, _apt); - - /* cache some info about apt for faster access */ - - mailtoChunk = [_apt valueForKey: @"orgmail"]; - myEmail = [self emailForUser]; - if ([mailtoChunk rangeOfString: myEmail].length > 0) - { - aptFlags.isMyApt = YES; - aptFlags.canAccessApt = YES; - } - else - { - NSString *partmails; - - aptFlags.isMyApt = NO; - - partmails = [_apt valueForKey: @"partmails"]; - if ([partmails rangeOfString: myEmail].length) - aptFlags.canAccessApt = YES; - else - aptFlags.canAccessApt - = ([[_apt valueForKey: @"classification"] intValue] - == iCalAccessPublic); - } + ASSIGN (appointment, _apt); } -- (void) setTasks: (NSArray *) _tasks -{ - ASSIGN(tasks, _tasks); -} +// - (void) setAppointment:(id) _apt +// { +// NSString *mailtoChunk; +// NSString *myEmail; +// NSString *partmails; -- (NSArray *) tasks -{ - return tasks; -} +// ASSIGN(appointment, _apt); + +// /* cache some info about apt for faster access */ + +// mailtoChunk = [_apt valueForKey: @"orgmail"]; +// myEmail = [self emailForUser]; +// if ([mailtoChunk rangeOfString: myEmail].length > 0) +// { +// aptFlags.isMyApt = YES; +// aptFlags.canAccessApt = YES; +// } +// else +// { +// aptFlags.isMyApt = NO; + +// partmails = [_apt valueForKey: @"partmails"]; +// if ([partmails rangeOfString: myEmail].length) +// aptFlags.canAccessApt = YES; +// else +// aptFlags.canAccessApt +// = ([[_apt valueForKey: @"classification"] intValue] +// == iCalAccessPublic); +// } +// } - (id) appointment { @@ -248,6 +242,16 @@ static BOOL shouldDisplayWeekend = NO; return privateAptTooltipFormatter; } +- (void) setTasks: (NSArray *) _tasks +{ + ASSIGN(tasks, _tasks); +} + +- (NSArray *) tasks +{ + return tasks; +} + /* TODO: remove this */ - (NSString *) shortTextForApt { @@ -496,6 +500,38 @@ static BOOL shouldDisplayWeekend = NO; return activeFolders; } +- (void) _updatePrivacyInObjects: (NSArray *) objectInfos + fromFolder: (SOGoAppointmentFolder *) folder +{ + int hideDetails[] = {-1, -1, -1}; + NSMutableDictionary *currentRecord; + int privacyFlag; + NSString *roleString, *userLogin; + NSEnumerator *infos; + + userLogin = [[context activeUser] login]; + infos = [objectInfos objectEnumerator]; + currentRecord = [infos nextObject]; + while (currentRecord) + { + privacyFlag = [[currentRecord objectForKey: @"classification"] intValue]; + if (hideDetails[privacyFlag] == -1) + { + roleString = [folder roleForComponentsWithAccessClass: privacyFlag + forUser: userLogin]; + hideDetails[privacyFlag] = ([roleString isEqualToString: @"ComponentDAndTViewer"] + ? 1 : 0); + } + if (hideDetails[privacyFlag]) + { + [currentRecord setObject: [self labelForKey: @"(Private Event)"] + forKey: @"title"]; + [currentRecord setObject: @"" forKey: @"location"]; + } + currentRecord = [infos nextObject]; + } +} + - (NSArray *) _fetchCoreInfosForComponent: (NSString *) component { NSArray *currentInfos; @@ -517,6 +553,8 @@ static BOOL shouldDisplayWeekend = NO; [currentInfos makeObjectsPerform: @selector (setObject:forKey:) withObject: [currentFolder ownerInContext: nil] withObject: @"owner"]; + [self _updatePrivacyInObjects: currentInfos + fromFolder: currentFolder]; [infos addObjectsFromArray: currentInfos]; currentFolder = [folders nextObject]; } diff --git a/UI/Scheduler/UIxComponentEditor.h b/UI/Scheduler/UIxComponentEditor.h index e7c53351..72bf704b 100644 --- a/UI/Scheduler/UIxComponentEditor.h +++ b/UI/Scheduler/UIxComponentEditor.h @@ -136,13 +136,6 @@ - (BOOL) isWriteableClientObject; - (NSException *) validateObjectForStatusChange; -- (NSString *) iCalParticipantsAndResourcesStringFromQueryParameters; -- (NSString *) iCalParticipantsStringFromQueryParameters; -- (NSString *) iCalResourcesStringFromQueryParameters; -- (NSString *) iCalStringFromQueryParameter: (NSString *) _qp - format: (NSString *) _format; -- (NSString *) iCalOrganizerString; - @end #endif /* UIXCOMPONENTEDITOR_H */ diff --git a/UI/Scheduler/UIxComponentEditor.m b/UI/Scheduler/UIxComponentEditor.m index 7ddb35d5..9684e36b 100644 --- a/UI/Scheduler/UIxComponentEditor.m +++ b/UI/Scheduler/UIxComponentEditor.m @@ -184,7 +184,11 @@ - (NSString *) itemPrivacyText { - return [self labelForKey: [NSString stringWithFormat: @"privacy_%@", item]]; + NSString *tag; + + tag = [[self clientObject] componentTag]; + + return [self labelForKey: [NSString stringWithFormat: @"%@_%@", item, tag]]; } - (NSString *) itemStatusText @@ -325,11 +329,6 @@ return calendarList; } -- (NSString *) itemCalendarText -{ - return item; -} - - (NSString *) calendarsFoldersList { NSArray *calendars; @@ -678,74 +677,65 @@ : @"visibility: hidden;"); } -- (NSString *) iCalParticipantsAndResourcesStringFromQueryParameters -{ - NSString *s; +// - (NSString *) iCalParticipantsAndResourcesStringFromQueryParameters +// { +// NSString *s; - s = [self iCalParticipantsStringFromQueryParameters]; - return [s stringByAppendingString: - [self iCalResourcesStringFromQueryParameters]]; -} - -- (NSString *) iCalParticipantsStringFromQueryParameters -{ - static NSString *iCalParticipantString = \ - @"ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;CN=\"%@\":MAILTO:%@\r\n"; +// s = [self iCalParticipantsStringFromQueryParameters]; +// return [s stringByAppendingString: +// [self iCalResourcesStringFromQueryParameters]]; +// } + +// - (NSString *) iCalParticipantsStringFromQueryParameters +// { +// static NSString *iCalParticipantString = @"ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;CN=\"%@\":MAILTO:%@\r\n"; - return [self iCalStringFromQueryParameter: @"ps" - format: iCalParticipantString]; -} - -- (NSString *) iCalResourcesStringFromQueryParameters -{ - static NSString *iCalResourceString = \ - @"ATTENDEE;ROLE=NON-PARTICIPANT;CN=\"%@\":MAILTO:%@\r\n"; - - return [self iCalStringFromQueryParameter: @"rs" - format: iCalResourceString]; -} - -- (NSString *) iCalStringFromQueryParameter: (NSString *) _qp - format: (NSString *) _format -{ - AgenorUserManager *um; - NSMutableString *iCalRep; - NSString *s; - - um = [AgenorUserManager sharedUserManager]; - iCalRep = (NSMutableString *)[NSMutableString string]; - s = [self queryParameterForKey:_qp]; - if(s && [s length] > 0) { - NSArray *es; - unsigned i, count; +// return [self iCalStringFromQueryParameter: @"ps" +// format: iCalParticipantString]; +// } + +// - (NSString *) iCalResourcesStringFromQueryParameters +// { +// static NSString *iCalResourceString = @"ATTENDEE;ROLE=NON-PARTICIPANT;CN=\"%@\":MAILTO:%@\r\n"; + +// return [self iCalStringFromQueryParameter: @"rs" +// format: iCalResourceString]; +// } + +// - (NSString *) iCalStringFromQueryParameter: (NSString *) _qp +// format: (NSString *) _format +// { +// AgenorUserManager *um; +// NSMutableString *iCalRep; +// NSString *s; + +// um = [AgenorUserManager sharedUserManager]; +// iCalRep = (NSMutableString *)[NSMutableString string]; +// s = [self queryParameterForKey:_qp]; +// if(s && [s length] > 0) { +// NSArray *es; +// unsigned i, count; - es = [s componentsSeparatedByString: @","]; - count = [es count]; - for(i = 0; i < count; i++) { - NSString *email, *cn; +// es = [s componentsSeparatedByString: @","]; +// count = [es count]; +// for(i = 0; i < count; i++) { +// NSString *email, *cn; - email = [es objectAtIndex:i]; - cn = [um getCNForUID:[um getUIDForEmail:email]]; - [iCalRep appendFormat:_format, cn, email]; - } - } - return iCalRep; -} - -- (NSString *) iCalOrganizerString -{ - return [NSString stringWithFormat: @"ORGANIZER;CN=\"%@\":MAILTO:%@\r\n", - [self cnForUser], [self emailForUser]]; -} +// email = [es objectAtIndex:i]; +// cn = [um getCNForUID:[um getUIDForEmail:email]]; +// [iCalRep appendFormat:_format, cn, email]; +// } +// } +// return iCalRep; +// } - (NSException *) validateObjectForStatusChange { id co; co = [self clientObject]; - if (![co - respondsToSelector: @selector(changeParticipationStatus:)]) - return [NSException exceptionWithHTTPStatus:400 /* Bad Request */ + if (![co respondsToSelector: @selector(changeParticipationStatus:)]) + return [NSException exceptionWithHTTPStatus: 400 /* Bad Request */ reason: @"method cannot be invoked on the specified object"]; @@ -839,6 +829,7 @@ [component setLocation: location]; [component setComment: comment]; [component setUrl: url]; + [component setAccessClass: privacy]; [self _handleAttendeesEdition]; [self _handleOrganizer]; clientObject = [self clientObject]; diff --git a/UI/Scheduler/product.plist b/UI/Scheduler/product.plist index c561228b..1a4a61d3 100644 --- a/UI/Scheduler/product.plist +++ b/UI/Scheduler/product.plist @@ -105,9 +105,20 @@ editAttendees = { protectedBy = "View"; pageName = "UIxAttendeesEditor"; - }; + }; + userRights = { + protectedBy = "ReadAcls"; + pageName = "UIxCalUserRightsEditor"; + }; + saveUserRights = { + protectedBy = "SaveAcls"; + pageName = "UIxCalUserRightsEditor"; + actionName = "saveUserRights"; + }; }; }; + SOGoCalendarComponent = { + }; SOGoAppointmentObject = { slots = { @@ -118,47 +129,42 @@ }; methods = { view = { - protectedBy = "View"; + protectedBy = "ViewAllComponent"; pageName = "UIxAppointmentView"; }; delete = { - protectedBy = "View"; + protectedBy = "Delete Objects"; pageName = "UIxAppointmentView"; actionName = "delete"; }; edit = { - protectedBy = "View"; + protectedBy = "ViewAllComponent"; pageName = "UIxAppointmentEditor"; }; editAsAppointment = { - protectedBy = "View"; + protectedBy = "ViewAllComponent"; pageName = "UIxAppointmentEditor"; }; save = { - protectedBy = "View"; + protectedBy = "ModifyComponent"; pageName = "UIxAppointmentEditor"; actionName = "save"; }; saveAsAppointment = { - protectedBy = "View"; + protectedBy = "ModifyComponent"; pageName = "UIxAppointmentEditor"; actionName = "save"; }; accept = { - protectedBy = "View"; + protectedBy = "RespondToComponent"; pageName = "UIxAppointmentEditor"; actionName = "accept"; }; decline = { - protectedBy = "View"; + protectedBy = "RespondToComponent"; pageName = "UIxAppointmentEditor"; actionName = "decline"; }; - test = { - protectedBy = "View"; - pageName = "UIxAppointmentEditor"; - actionName = "test"; - }; }; }; @@ -171,52 +177,47 @@ }; methods = { view = { - protectedBy = "View"; + protectedBy = "ViewAllComponent"; pageName = "UIxTaskView"; }; delete = { - protectedBy = "View"; + protectedBy = "Delete Objects"; pageName = "UIxTaskView"; actionName = "delete"; }; edit = { - protectedBy = "View"; + protectedBy = "ViewAllComponent"; pageName = "UIxTaskEditor"; }; editAsTask = { - protectedBy = "View"; + protectedBy = "ViewAllComponent"; pageName = "UIxTaskEditor"; }; save = { - protectedBy = "Change Images and Files"; + protectedBy = "ModifyComponent"; pageName = "UIxTaskEditor"; actionName = "save"; }; saveAsTask = { - protectedBy = "Change Images and Files"; + protectedBy = "ModifyComponent"; pageName = "UIxTaskEditor"; actionName = "save"; }; changeStatus = { - protectedBy = "Change Images and Files"; + protectedBy = "ModifyComponent"; pageName = "UIxTaskEditor"; actionName = "changeStatus"; }; accept = { - protectedBy = "Change Images and Files"; + protectedBy = "RespondToComponent"; pageName = "UIxTaskEditor"; actionName = "accept"; }; decline = { - protectedBy = "Change Images and Files"; + protectedBy = "RespondToComponent"; pageName = "UIxTaskEditor"; actionName = "decline"; }; - test = { - protectedBy = "View"; - pageName = "UIxTaskEditor"; - actionName = "test"; - }; }; }; }; diff --git a/UI/Templates/ContactsUI/UIxContactsUserRightsEditor.wox b/UI/Templates/ContactsUI/UIxContactsUserRightsEditor.wox new file mode 100644 index 00000000..e14ea785 --- /dev/null +++ b/UI/Templates/ContactsUI/UIxContactsUserRightsEditor.wox @@ -0,0 +1,47 @@ + + + +
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+ + +
+
+
diff --git a/UI/Templates/SchedulerUI/UIxCalInlineAptView.wox b/UI/Templates/SchedulerUI/UIxCalInlineAptView.wox index 929a66ca..7d769af3 100644 --- a/UI/Templates/SchedulerUI/UIxCalInlineAptView.wox +++ b/UI/Templates/SchedulerUI/UIxCalInlineAptView.wox @@ -26,10 +26,7 @@ >
+ >
+ diff --git a/UI/Templates/SchedulerUI/UIxCalUserRightsEditor.wox b/UI/Templates/SchedulerUI/UIxCalUserRightsEditor.wox new file mode 100644 index 00000000..14ba7d5b --- /dev/null +++ b/UI/Templates/SchedulerUI/UIxCalUserRightsEditor.wox @@ -0,0 +1,60 @@ + + + +
+ +
+ +
+
+ + + + + + + + + + + + + +
+
+
+ +
+ +
+
+ + +
+
+
diff --git a/UI/Templates/SchedulerUI/UIxComponentEditor.wox b/UI/Templates/SchedulerUI/UIxComponentEditor.wox index 48cb8e08..2cee81ff 100644 --- a/UI/Templates/SchedulerUI/UIxComponentEditor.wox +++ b/UI/Templates/SchedulerUI/UIxComponentEditor.wox @@ -15,13 +15,11 @@ diff --git a/UI/Templates/UIxAclEditor.wox b/UI/Templates/UIxAclEditor.wox index d0d6d55f..842726b0 100644 --- a/UI/Templates/UIxAclEditor.wox +++ b/UI/Templates/UIxAclEditor.wox @@ -14,17 +14,11 @@
- - +
- -
-
    -
- -
-
diff --git a/UI/Templates/UIxUserRightsEditor.wox b/UI/Templates/UIxUserRightsEditor.wox new file mode 100644 index 00000000..d535c486 --- /dev/null +++ b/UI/Templates/UIxUserRightsEditor.wox @@ -0,0 +1,14 @@ + + + +
+
diff --git a/UI/WebServerResources/ContactsUI.js b/UI/WebServerResources/ContactsUI.js index f63a3d6a..99d1d0fe 100644 --- a/UI/WebServerResources/ContactsUI.js +++ b/UI/WebServerResources/ContactsUI.js @@ -3,6 +3,9 @@ var cachedContacts = new Array(); var currentContactFolder = '/personal'; +var usersRightsWindowHeight = 180; +var usersRightsWindowWidth = 450; + function openContactWindow(sender, url) { var msgWin = window.open(url, null, "width=450,height=600,resizable=0"); msgWin.focus(); diff --git a/UI/WebServerResources/MailerUI.js b/UI/WebServerResources/MailerUI.js index 831cef80..4c28bcea 100644 --- a/UI/WebServerResources/MailerUI.js +++ b/UI/WebServerResources/MailerUI.js @@ -760,7 +760,7 @@ function expandUpperTree(node) { function initMailboxSelection(mailboxName) { currentMailbox = mailboxName; - log("initMailboxSelection: " + mailboxName); +// log("initMailboxSelection: " + mailboxName); var tree = $("d"); var treeNodes = document.getElementsByClassName("dTreeNode", tree); var i = 0; @@ -768,7 +768,7 @@ function initMailboxSelection(mailboxName) { && treeNodes[i].getAttribute("dataname") != currentMailbox) i++; if (i < treeNodes.length) { - log ("found mailbox"); +// log ("found mailbox"); var links = document.getElementsByClassName("node", treeNodes[i]); if (tree.selectedEntry) tree.selectedEntry.deselect(); @@ -944,7 +944,7 @@ function initDnd() { document.DNDManager.registerDestination(images[i]); } } - var nodes = document.getElementsByClassName("leaf", tree); + var nodes = document.getElementsByClassName("nodeName", tree); for (var i = 0; i < nodes.length; i++) { nodes[i].dndAcceptType = mailboxSpanAcceptType; nodes[i].dndEnter = mailboxSpanEnter; diff --git a/UI/WebServerResources/SchedulerUI.css b/UI/WebServerResources/SchedulerUI.css index f495cdf1..e11c28c7 100644 --- a/UI/WebServerResources/SchedulerUI.css +++ b/UI/WebServerResources/SchedulerUI.css @@ -4,7 +4,7 @@ DIV#leftPanel position: absolute; top: 5.5em; left: 0px; - width: 17em; + width: 18.5em; bottom: 0px; overflow: hidden; } @@ -15,13 +15,13 @@ DIV#schedulerTabs top: 0.5em; left: .2em; right: .2em; - height: 16em; + height: 17em; } DIV#tasksListView { position: absolute; - top: 18.5em; + top: 20em; bottom: 0px; left: .2em; right: .7em; @@ -128,7 +128,7 @@ DIV#rightPanel { position: absolute; top: 5.5em; - left: 17em; + left: 18.5em; right: 0px; bottom: 0px; margin: 0px; @@ -172,7 +172,7 @@ DIV#calendarView A { cursor: e-resize; top: 7.5em; - left: 17em; + left: 18.5em; width: 5px; bottom: 0px; } diff --git a/UI/WebServerResources/SchedulerUI.js b/UI/WebServerResources/SchedulerUI.js index fec8322a..ffc2880b 100644 --- a/UI/WebServerResources/SchedulerUI.js +++ b/UI/WebServerResources/SchedulerUI.js @@ -19,6 +19,9 @@ var contactSelectorAction = 'calendars-contacts'; var eventsToDelete = new Array(); var ownersOfEventsToDelete = new Array(); +var usersRightsWindowHeight = 250; +var usersRightsWindowWidth = 502; + function newEvent(sender, type) { var day = sender.getAttribute("day"); if (!day) @@ -1054,6 +1057,7 @@ function appendCalendar(folderName, folder) { checkBox.type = "checkbox"; checkBox.addEventListener("change", updateCalendarStatus, false); li.appendChild(checkBox); + li.appendChild(document.createTextNode(" ")); var colorBox = document.createElement("div"); colorBox.appendChild(document.createTextNode("OO")); colorBox.addClassName("colorBox"); @@ -1068,6 +1072,10 @@ function appendCalendar(folderName, folder) { var contactId = folder.split(":")[0]; var styles = document.getElementsByTagName("style"); + + var url = URLForFolderID(folder) + "/canAccessContent"; + triggerAjaxRequest(url, calendarEntryCallback, folder); + styles[0].innerHTML += ('.ownerIs' + contactId + ' {' + ' background-color: ' + color diff --git a/UI/WebServerResources/UIxAclEditor.js b/UI/WebServerResources/UIxAclEditor.js index f8cd0b95..18eaab99 100644 --- a/UI/WebServerResources/UIxAclEditor.js +++ b/UI/WebServerResources/UIxAclEditor.js @@ -6,17 +6,17 @@ function addUser(userName, userID) { if (!$(userID)) { var ul = $("userList"); ul.appendChild(nodeForUser(userName, userID)); - var roleList = $("assistants"); - if (roleList.value.length > 0) { - var uids = roleList.value.split(","); - uids.push(userID); - roleList.value = uids.join(","); - } - else - roleList.value = userID; + var url = window.location.href; + var elements = url.split("/"); + elements[elements.length-1] = ("addUserInAcls?uid=" + + userID); + triggerAjaxRequest(elements.join("/"), addUserCallback); } } +function addUserCallback(http) { +} + function nodeForUser(userName, userId) { var node = document.createElement("li"); node.setAttribute("id", userId); @@ -34,64 +34,14 @@ function nodeForUser(userName, userId) { } function saveAcls() { - $("aclForm").submit(); - - return false; -} - -function updateSelectedRole(list) { - var select = $("userRoleDropDown"); - var selection = list.getSelectedRows(); - if (selection.length > 0) { - select.style.visibility = "visible;"; - var selected = selection[0]; - var assistantsValue = $("assistants"); - var uid = selected.getAttribute("id"); - var regexp = new RegExp("(^|,)" + uid + "(,|$)","i"); - if (regexp.test(assistantsValue.value)) - select.selectedIndex = 0; - else - select.selectedIndex = 1; - } - else - select.style.visibility = "hidden;"; -} - -function onAclSelectionChange() { - log("selectionchange"); - updateSelectedRole(this); -} - -function onUserRoleDropDownChange() { - var oldList; - var newList; - - if (this.selectedIndex == 0) { - oldList = $("delegates"); - newList = $("assistants"); - } else { - oldList = $("assistants"); - newList = $("delegates"); - } - - var uid = $("userList").getSelectedRows()[0].getAttribute("id"); - var newListArray; - if (newList.value.length > 0) { - newListArray = newList.value.split(","); - newListArray.push(uid); - } - else - newListArray = new Array(uid); - newList.value = newListArray.join(","); - - var oldListArray = oldList.value.split(",").without(uid); - if (oldListArray.length > 0) - oldList.value = oldListArray.join(","); - else - oldList.value = ""; - - log("assistants: " + $("assistants").value); - log("delegates: " + $("delegates").value); + var uidList = new Array(); + var users = $("userList").childNodesWithTag("li"); + for (var i = 0; i < users.length; i++) + uidList.push(users[i].getAttribute("id")); + $("userUIDS").value = uidList.join(","); + $("aclForm").submit(); + + return false; } function onUserAdd(event) { @@ -101,24 +51,10 @@ function onUserAdd(event) { } function onUserRemove(event) { - var userlist = $("userList"); - var node = userlist.getSelectedRows()[0]; - var uid = node.getAttribute("id"); - var regexp = new RegExp("(^|,)" + uid + "($|,)"); - var uids = $("assistants"); - if (!regexp.test(uids.value)) - uids = $("delegates"); - if (regexp.test(uids.value)) { - var list = uids.value.split(","); - var newList = new Array(); - for (var i = 0; i < list.length; i++) { - if (list[i] != uid) - newList.push(list[i]); - } - uids.value = newList.join(","); - node.parentNode.removeChild(node); - } - updateSelectedRole(userlist); + var userList = $("userList"); + var nodes = userList.getSelectedRows(); + for (var i = 0; i < nodes.length; i++) + userList.removeChild(nodes[i]); event.preventDefault(); } @@ -127,22 +63,44 @@ function subscribeToFolder(refreshCallback, refreshCallbackData) { refreshCallbackData["folder"]); } +function openRightsForUser(button) { + var nodes = $("userList").getSelectedRows(); + if (nodes.length > 0) { + var url = window.location.href; + var elements = url.split("/"); + elements[elements.length-1] = ("userRights?uid=" + + nodes[0].getAttribute("id")); + + window.open(elements.join("/"), "", + "width=" + this.userRightsWidth + + ",height=" + this.userRightsHeight + + ",resizable=0,scrollbars=0,toolbar=0," + + "location=0,directories=0,status=0,menubar=0,copyhistory=0"); + } + + return false; +} + +function onOpenUserRights(event) { + openRightsForUser(); + event.preventDefault(); +} + function onAclLoadHandler() { var ul = $("userList"); - ul.addEventListener("selectionchange", - onAclSelectionChange, false); var lis = ul.childNodesWithTag("li"); for (var i = 0; i < lis.length; i++) { lis[i].addEventListener("mousedown", listRowMouseDownHandler, false); + lis[i].addEventListener("dblclick", onOpenUserRights, false); lis[i].addEventListener("click", onRowClick, false); } - var select = $("userRoleDropDown"); - select.addEventListener("change", onUserRoleDropDownChange, false); - var buttons = $("userSelectorButtons").childNodesWithTag("a"); buttons[0].addEventListener("click", onUserAdd, false); buttons[1].addEventListener("click", onUserRemove, false); + + this.userRightsHeight = window.opener.getUsersRightsWindowHeight(); + this.userRightsWidth = window.opener.getUsersRightsWindowWidth(); } window.addEventListener("load", onAclLoadHandler, false); diff --git a/UI/WebServerResources/UIxCalUserRightsEditor.css b/UI/WebServerResources/UIxCalUserRightsEditor.css new file mode 100644 index 00000000..783e47a6 --- /dev/null +++ b/UI/WebServerResources/UIxCalUserRightsEditor.css @@ -0,0 +1,49 @@ +DIV.title +{ color: #000; + vertical-align: bottom; + padding-top: 15px; + padding-left: 1em; + height: 33px; + background-color: #fff; + border-bottom: 1px solid #555; } + +DIV.title SPAN.value +{ margin-left: 1em; + font-size: 18px; + font-weight: bold; } + +DIV.calendarUserRights +{ margin: 1em;} + +DIV.calendarUserRights > TABLE +{ background-color: #fff; + width: 45em; + color: #999; + border-collapse: collapse; + border-bottom: 1px solid #fff; + border-right: 1px solid #fff; + border-top: 2px solid #222; + border-left: 2px solid #222; + -moz-border-top-colors: ThreeDShadow ThreeDDarkShadow transparent; + -moz-border-left-colors: ThreeDShadow ThreeDDarkShadow transparent; } + +DIV.calendarUserRights > TABLE TR.permissions TH +{ color: #00f; +/* background-color: #ddd; + */ border-bottom: 1px solid #999; } + +DIV.calendarUserRights > TABLE TH +{ width: 15em; } + +DIV.calendarUserRights > TABLE TD.eventType +{ width: 5em; + text-align: right; + border-right: 1px solid #999; } + +DIV.calendarUserRights > TABLE TD +{ text-align: center; + border-top: 1px solid #cecbff; } + +DIV.buttons +{ text-align: right; + margin: 1em; } diff --git a/UI/WebServerResources/UIxCalUserRightsEditor.js b/UI/WebServerResources/UIxCalUserRightsEditor.js new file mode 100644 index 00000000..71fe311f --- /dev/null +++ b/UI/WebServerResources/UIxCalUserRightsEditor.js @@ -0,0 +1,9 @@ +function onCancelClick(event) { + window.close(); +} + +function initACLButtons() { + $("cancelButton").addEventListener("click", onCancelClick, false); +} + +window.addEventListener("load", initACLButtons, false); diff --git a/UI/WebServerResources/UIxComponentEditor.js b/UI/WebServerResources/UIxComponentEditor.js index 525a9b1c..632d1f86 100644 --- a/UI/WebServerResources/UIxComponentEditor.js +++ b/UI/WebServerResources/UIxComponentEditor.js @@ -1,5 +1,3 @@ -window.addEventListener("load", onComponentEditorLoad, false); - function onPopupAttendeesWindow(event) { if (event) event.preventDefault(); @@ -51,16 +49,14 @@ function onPopupDocumentWindow(event) { return false; } -function onMenuSetClassification(event, classification) { +function onMenuSetClassification(event) { event.cancelBubble = true; - var node = event.target; - if (node.tagName != "LI") - node = node.getParentWithTagName("li"); - if (node.parentNode.chosenNode) - node.parentNode.chosenNode.removeClassName("_chosen"); - node.addClassName("_chosen"); - node.parentNode.chosenNode = node; + var classification = this.getAttribute("classification"); + if (this.parentNode.chosenNode) + this.parentNode.chosenNode.removeClassName("_chosen"); + this.addClassName("_chosen"); + this.parentNode.chosenNode = this; log("classification: " + classification); var privacyInput = document.getElementById("privacy"); @@ -78,9 +74,8 @@ function onChangeCalendar(event) { else ownerLogin = UserLogin; urlElems[urlElems.length-4] = ownerLogin; - + form.setAttribute("action", urlElems.join("/")); - log ("after: " + form.getAttribute("action")); } function refreshAttendees() { @@ -153,5 +148,15 @@ function onComponentEditorLoad(event) { initializeAttendeesHref(); initializeDocumentHref(); initializePrivacyMenu(); - $("calendarList").addEventListener("change", onChangeCalendar, false); + var list = $("calendarList"); + list.addEventListener("change", onChangeCalendar, false); + var onSelectionChangeEvent = document.createEvent("Event"); + onSelectionChangeEvent.initEvent("change", false, false); + list.dispatchEvent(onSelectionChangeEvent); + + var menuItems = $("itemPrivacyList").childNodesWithTag("li"); + for (var i = 0; i < menuItems.length; i++) + menuItems[i].addEventListener("mouseup", onMenuSetClassification, false); } + +window.addEventListener("load", onComponentEditorLoad, false); diff --git a/UI/WebServerResources/UIxContactsUserRightsEditor.css b/UI/WebServerResources/UIxContactsUserRightsEditor.css new file mode 100644 index 00000000..783e47a6 --- /dev/null +++ b/UI/WebServerResources/UIxContactsUserRightsEditor.css @@ -0,0 +1,49 @@ +DIV.title +{ color: #000; + vertical-align: bottom; + padding-top: 15px; + padding-left: 1em; + height: 33px; + background-color: #fff; + border-bottom: 1px solid #555; } + +DIV.title SPAN.value +{ margin-left: 1em; + font-size: 18px; + font-weight: bold; } + +DIV.calendarUserRights +{ margin: 1em;} + +DIV.calendarUserRights > TABLE +{ background-color: #fff; + width: 45em; + color: #999; + border-collapse: collapse; + border-bottom: 1px solid #fff; + border-right: 1px solid #fff; + border-top: 2px solid #222; + border-left: 2px solid #222; + -moz-border-top-colors: ThreeDShadow ThreeDDarkShadow transparent; + -moz-border-left-colors: ThreeDShadow ThreeDDarkShadow transparent; } + +DIV.calendarUserRights > TABLE TR.permissions TH +{ color: #00f; +/* background-color: #ddd; + */ border-bottom: 1px solid #999; } + +DIV.calendarUserRights > TABLE TH +{ width: 15em; } + +DIV.calendarUserRights > TABLE TD.eventType +{ width: 5em; + text-align: right; + border-right: 1px solid #999; } + +DIV.calendarUserRights > TABLE TD +{ text-align: center; + border-top: 1px solid #cecbff; } + +DIV.buttons +{ text-align: right; + margin: 1em; } diff --git a/UI/WebServerResources/UIxContactsUserRightsEditor.js b/UI/WebServerResources/UIxContactsUserRightsEditor.js new file mode 100644 index 00000000..71fe311f --- /dev/null +++ b/UI/WebServerResources/UIxContactsUserRightsEditor.js @@ -0,0 +1,9 @@ +function onCancelClick(event) { + window.close(); +} + +function initACLButtons() { + $("cancelButton").addEventListener("click", onCancelClick, false); +} + +window.addEventListener("load", initACLButtons, false); diff --git a/UI/WebServerResources/generic.css b/UI/WebServerResources/generic.css index b40cf6c5..1af01b02 100644 --- a/UI/WebServerResources/generic.css +++ b/UI/WebServerResources/generic.css @@ -35,7 +35,7 @@ IMG#progressIndicator DIV.pageContent { /* position: absolute; - background: #ffa; + background-color: #ffa; top: 3em; left: 0px; right: 0px; @@ -136,8 +136,7 @@ table.skytextdocktable table-layout: auto; } DIV.linkbanner -{ - background: #222; +{ background-color: #222; width: 100%; top: 0px; left: 0px; @@ -145,8 +144,7 @@ DIV.linkbanner color: #aaa; } DIV.linkbanner A -{ - top: 0px; +{ top: 0px; left: 0px; color: #ddd; text-decoration: none; @@ -186,7 +184,7 @@ DIV.contactSelector DIV.contactList height: 3em; overflow: auto; border: 1px solid #444; - background: #eee; + background-color: #eee; text-align: left; } TEXTAREA @@ -324,7 +322,7 @@ SPAN.toolbarButton:active vertical-align: middle; } .menu LI:hover, .menu LI.submenu-selected -{ background: #4b6983; +{ background-color: #4b6983; color: #fff; } .menu LI.separator, .menu LI.separator:hover @@ -359,7 +357,7 @@ DIV#logConsole -moz-border-left-colors: ThreeDDarkShadow ThreeDShadow transparent; font-family: monospace; font-weight: bold; - background: #000; + background-color: #000; color: #ddd; top: 1em; left: 0px; @@ -453,10 +451,10 @@ td.tbtv_subject_headercell DIV.dragHandle { position: absolute; z-index: 1; - background: #d4d0c8; } + background-color: #d4d0c8; } DIV.dragHandle:active -{ background: #99a; } +{ background-color: #99a; } /* search fields */ DIV#filterPanel @@ -477,7 +475,7 @@ INPUT#searchValue DIV.javascriptPopupBackground { position: absolute; - background: #999; + background-color: #999; -moz-opacity: 0.6; z-index: 2; top: 0px; @@ -501,7 +499,7 @@ DIV.javascriptMessagePseudoWindow margin: 0px auto; -moz-opacity: 1.0; color: #000; - background: #dedede; } + background-color: #dedede; } DIV.noJavascriptErrorMessage { top: 10em; @@ -561,13 +559,13 @@ DIV.dTreeNode A SPAN.nodeName DIV.dTreeNode A._selected SPAN.nodeName { - background: #4b6983; + background-color: #4b6983; color: #fff; } DIV.dTreeNode SPAN._dragOver { - background: #4b6983; + background-color: #4b6983; color: #fff; } @@ -576,7 +574,7 @@ DIV.tabsContainer { position: relative; color: #000; - background: #d4d0c8; + background-color: #d4d0c8; margin-top: 1.5em; border-top: 2px solid #fff; border-left: 2px solid #fff; @@ -619,7 +617,7 @@ DIV.tabsContainer > UL LI.active DIV.tabsContainer > UL LI.active { z-index: 5; - background: #d4d0c8; + background-color: #d4d0c8; border-bottom: 1px none #fff; padding-top: 2px; padding-bottom: 3px; diff --git a/UI/WebServerResources/generic.js b/UI/WebServerResources/generic.js index cd7923d2..976cad50 100644 --- a/UI/WebServerResources/generic.js +++ b/UI/WebServerResources/generic.js @@ -825,7 +825,7 @@ function subscribeToFolder(refreshCallback, refreshCallbackData) { var folderPath = folderData[1]; if (username != UserLogin) { var url = (UserFolderURL + "../" + username - + "/" + folderPath + "/subscribe"); + + folderPath + "/subscribe"); if (document.subscriptionAjaxRequest) { document.subscriptionAjaxRequest.aborted = true; document.subscriptionAjaxRequest.abort(); @@ -836,7 +836,8 @@ function subscribeToFolder(refreshCallback, refreshCallbackData) { rfCbData); } else - window.alert(labels["You cannot subscribe to a folder that you own!"].decodeEntities()); + window.alert(labels["You cannot subscribe to a folder that you own!"] + .decodeEntities()); } function folderUnsubscriptionCallback(http) { @@ -853,7 +854,8 @@ function folderUnsubscriptionCallback(http) { function unsubscribeFromFolder(folder, refreshCallback, refreshCallbackData) { if (document.body.hasClassName("popup")) { - window.opener.unsubscribeFromFolder(folder, refreshCallback, refreshCallbackData); + window.opener.unsubscribeFromFolder(folder, refreshCallback, + refreshCallbackData); } else { var folderData = folder.split(":"); @@ -867,9 +869,9 @@ function unsubscribeFromFolder(folder, refreshCallback, refreshCallbackData) { document.unsubscriptionAjaxRequest.abort(); } var rfCbData = { method: refreshCallback, data: refreshCallbackData }; - document.unsubscriptionAjaxRequest = triggerAjaxRequest(url, - folderUnsubscriptionCallback, - rfCbData); + document.unsubscriptionAjaxRequest + = triggerAjaxRequest(url, folderUnsubscriptionCallback, + rfCbData); } else window.alert(labels["You cannot unsubscribe from a folder that you own!"].decodeEntities()); @@ -946,6 +948,14 @@ function openAclWindow(url) { return w; } +function getUsersRightsWindowHeight() { + return usersRightsWindowHeight; +} + +function getUsersRightsWindowWidth() { + return usersRightsWindowWidth; +} + function onTabClick(event) { var node = event.target; @@ -1023,15 +1033,14 @@ function indexColor(number) { var currentValue = number; var index = 0; - while (currentValue) - { - if (currentValue & 1) + while (currentValue) { + if (currentValue & 1) colorTable[index]++; - if (index == 3) - index = 0; - currentValue >>= 1; - index++; - } + if (index == 3) + index = 0; + currentValue >>= 1; + index++; + } color = ("#" + d2h((256 / colorTable[2]) - 1) -- 2.39.5