From 51408bbde04fb8e77a4446c4a6a07fabcf650d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Wed, 10 Feb 2016 09:48:09 +0100 Subject: [PATCH] oc-tasks: Add edit/delete own and Folder Contact/Owner sharing perm By storing these custom MAPI roles in the ACL. Take into account that a task folder is shared with a calendar folder with the same name, therefore permissions are shared and overwritten from different Outlook sections. The extension 'X-SOGO-COMPONENT-CREATED-BY' is used to store the task creator in both Outlook and SOGo Webmail. The PidLidTaskOwner is not yet properly managed and we are always returning the folder owner but to effects of sharing that extension is used by now which matches a little more with what the user expects until we fix the task ownership defined in [MS-OXOTASK]. --- OpenChange/MAPIStoreTasksFolder.m | 66 +++++++++++++++++++++++++++++- OpenChange/MAPIStoreTasksMessage.m | 38 +++++++++++++++++ 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/OpenChange/MAPIStoreTasksFolder.m b/OpenChange/MAPIStoreTasksFolder.m index f4f6ac160..4b198d2d1 100644 --- a/OpenChange/MAPIStoreTasksFolder.m +++ b/OpenChange/MAPIStoreTasksFolder.m @@ -75,6 +75,10 @@ return newMessage; } +// -------------------------------------------- +// Permissions and sharing +// -------------------------------------------- + - (NSArray *) rolesForExchangeRights: (uint32_t) rights { NSMutableArray *roles; @@ -82,21 +86,34 @@ roles = [NSMutableArray arrayWithCapacity: 6]; if (rights & RightsCreateItems) [roles addObject: SOGoRole_ObjectCreator]; + if (rights & RightsDeleteAll) [roles addObject: SOGoRole_ObjectEraser]; + if (rights & RightsDeleteOwn) + [roles addObject: MAPIStoreRightDeleteOwn]; + if (rights & RightsEditAll) { [roles addObject: SOGoCalendarRole_PublicModifier]; [roles addObject: SOGoCalendarRole_PrivateModifier]; [roles addObject: SOGoCalendarRole_ConfidentialModifier]; } - else if (rights & RightsReadItems) + if (rights & RightsEditOwn) + [roles addObject: MAPIStoreRightEditOwn]; + + if (rights & RightsReadItems) { [roles addObject: SOGoCalendarRole_PublicViewer]; [roles addObject: SOGoCalendarRole_PrivateViewer]; [roles addObject: SOGoCalendarRole_ConfidentialViewer]; } + if (rights & RightsFolderOwner) + [roles addObject: MAPIStoreRightFolderOwner]; + + if (rights & RightsFolderContact) + [roles addObject: MAPIStoreRightFolderContact]; + return roles; } @@ -116,20 +133,65 @@ && [roles containsObject: SOGoCalendarRole_PrivateViewer] && [roles containsObject: SOGoCalendarRole_ConfidentialViewer]) rights |= RightsReadItems; + + if ([roles containsObject: MAPIStoreRightEditOwn]) + rights |= RightsEditOwn; + if ([roles containsObject: MAPIStoreRightDeleteOwn]) + rights |= RightsDeleteOwn; + if (rights != 0) rights |= RoleNone; /* actually "folder visible" */ + if ([roles containsObject: MAPIStoreRightFolderOwner]) + rights |= RightsFolderOwner | RoleNone; + + if ([roles containsObject: MAPIStoreRightFolderContact]) + rights |= RightsFolderContact; + return rights; } +- (BOOL) subscriberCanModifyMessages +{ + static NSArray *modifierRoles = nil; + + if (!modifierRoles) + modifierRoles = [[NSArray alloc] initWithObjects: + SOGoCalendarRole_PublicModifier, + SOGoCalendarRole_PrivateModifier, + SOGoCalendarRole_ConfidentialModifier, + nil]; + + return ([[self activeUserRoles] firstObjectCommonWithArray: modifierRoles] + != nil); +} + +- (BOOL) subscriberCanReadMessages +{ + static NSArray *viewerRoles = nil; + + if (!viewerRoles) + viewerRoles = [[NSArray alloc] initWithObjects: + SOGoCalendarRole_PublicViewer, + SOGoCalendarRole_PrivateViewer, + SOGoCalendarRole_ConfidentialViewer, + nil]; + + return ([[self activeUserRoles] firstObjectCommonWithArray: viewerRoles] + != nil); +} + - (EOQualifier *) aclQualifier { return [EOQualifier qualifierWithQualifierFormat: [(SOGoAppointmentFolder *) sogoObject aclSQLListingFilter]]; } +// -------------------------------------------- +// Property getters +// -------------------------------------------- - (enum mapistore_error) getPidTagDefaultPostMessageClass: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { *data = [@"IPM.Task" asUnicodeInMemCtx: memCtx]; diff --git a/OpenChange/MAPIStoreTasksMessage.m b/OpenChange/MAPIStoreTasksMessage.m index 728fdb909..382c61fa0 100644 --- a/OpenChange/MAPIStoreTasksMessage.m +++ b/OpenChange/MAPIStoreTasksMessage.m @@ -154,6 +154,9 @@ return MAPISTORE_SUCCESS; } +//------------------------------------ +// Specific task related properties +//------------------------------------ - (enum mapistore_error) getPidLidTaskComplete: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -323,6 +326,7 @@ { NSString *owner; + /* FIXME: This is wrong when setting task's request */ owner = [sogoObject ownerInContext: nil]; *data = [owner asUnicodeInMemCtx: memCtx]; @@ -336,6 +340,25 @@ return [self getLongZero: data inMemCtx: memCtx]; } +// ---------------------------------- +// Sharing +// ---------------------------------- +- (NSString *) creator +{ + iCalToDo *task; + + task = [sogoObject component: NO secure: YES]; + return [[task uniqueChildWithTag: @"x-sogo-component-created-by"] + flattenedValuesForKey: @""]; +} + +- (NSString *) owner +{ + /* This is not true but to allow a user edit its own tasks is required. + FIXME: When PidLidTaskOwner getter is properly implemented for Task Requests */ + return [self creator]; +} + - (BOOL) subscriberCanReadMessage { return ([[self activeUserRoles] @@ -354,6 +377,15 @@ rc = ([roles containsObject: SOGoCalendarRole_ComponentModifier] || [roles containsObject: SOGoCalendarRole_ComponentResponder]); + /* Check if the message is owned and it has permission to edit it */ + if (!rc && [roles containsObject: MAPIStoreRightEditOwn]) + { + NSString *currentUser; + + currentUser = [[container context] activeUser]; + rc = [currentUser isEqual: [self ownerUser]]; + } + return rc; } @@ -524,10 +556,16 @@ [vToDo setAccessClass: @"PUBLIC"]; } + /* Creation */ now = [NSCalendarDate date]; if ([sogoObject isNew]) { [vToDo setCreated: now]; + /* Creator is used for sharing purposes */ + value = [properties objectForKey: MAPIPropertyKey (PidTagLastModifierName)]; + if (value) + [[vToDo uniqueChildWithTag: @"x-sogo-component-created-by"] setSingleValue: value + forKey: @""]; } [vToDo setTimeStampAsDate: now];