diff --git a/ChangeLog b/ChangeLog index 22e580b7e..ec36a0173 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,40 @@ 2011-11-18 Wolfgang Sourdeau + * OpenChange/MAPIStoreFolder.m (-permissionEntries): new public + method. + (-modifyPermissions:withCount:andFlags:): new backend op public + method. + (-aclFolder, -rolesForExchangeRights:, -exchangeRightsForRoles:): + new mandatory methods. + + * OpenChange/SOGoMAPIFSFolder.m (-defaultUserID, -addUserInAcls:) + (-removeAclsForUsers:, -aclUsers, -aclsForUser:) + (-setRoles:forUser:): implemented standard ACL methods. + + * OpenChange/MAPIStorePermissionsTable.m + (+[MAPIStorePermissionEntry + entryWithUserId:andMemberId:forFolder:]): constructor now takes a + memberId and the container folder as parameters. + (-[MAPIStorePermissionEntry getPrMemberId:inMemCtx:]): now based + on the new memberId ivar. + (-[MAPIStorePermissionEntry getPrEntryId:inMemCtx:]): now make use + of MAPIStoreInternalEntryId for regular member ids and return an + empty blob for special ones, as specified in oxcperm. + (-[MAPIStorePermissionEntry getPrMemberName:inMemCtx:]): now + returns the real CN of the user for regular member ids and return + @"" or @"Anonymous" for special ones, as specified in oxcperm. + (-[MAPIStorePermissionEntry getPrMemberName:inMemCtx:]): now + returns the real member rights, based on the aclFolder of the + container, using standard SOGo methods. + + * OpenChange/MAPIStorePermissionsTable.h + (MAPIStorePermissionsEntry): made class public. + + * OpenChange/MAPIStoreSOGo.m (sogo_folder_modify_permissions): new + backend op. + (sogo_backend_init): invoke "disableLocalCache" to avoid the + caching of ACL. + * SoObjects/SOGo/SOGoCache.m (-disableLocalCache): new method to disable the local cache altogether (helper for non-WO access). diff --git a/OpenChange/MAPIStoreCalendarFolder.m b/OpenChange/MAPIStoreCalendarFolder.m index 29ad5f16b..34c5dea6b 100644 --- a/OpenChange/MAPIStoreCalendarFolder.m +++ b/OpenChange/MAPIStoreCalendarFolder.m @@ -25,6 +25,7 @@ #import #import #import +#import #import #import #import @@ -36,6 +37,9 @@ #import "MAPIStoreCalendarFolder.h" +#include +#include + @implementation MAPIStoreCalendarFolder - (id) initWithURL: (NSURL *) newURL @@ -106,4 +110,51 @@ return newMessage; } +- (NSArray *) rolesForExchangeRights: (uint32_t) rights +{ + NSMutableArray *roles; + + roles = [NSMutableArray arrayWithCapacity: 6]; + if (rights & RightsCreateItems) + [roles addObject: SOGoRole_ObjectCreator]; + if (rights & RightsDeleteAll) + [roles addObject: SOGoRole_ObjectEraser]; + if (rights & RightsEditAll) + { + [roles addObject: SOGoCalendarRole_PublicModifier]; + [roles addObject: SOGoCalendarRole_PrivateModifier]; + [roles addObject: SOGoCalendarRole_ConfidentialModifier]; + } + else if (rights & RightsReadItems) + { + [roles addObject: SOGoCalendarRole_PublicViewer]; + [roles addObject: SOGoCalendarRole_PrivateViewer]; + [roles addObject: SOGoCalendarRole_ConfidentialViewer]; + } + + return roles; +} + +- (uint32_t) exchangeRightsForRoles: (NSArray *) roles +{ + uint32_t rights = 0; + + if ([roles containsObject: SOGoRole_ObjectCreator]) + rights |= RightsCreateItems; + if ([roles containsObject: SOGoRole_ObjectEraser]) + rights |= RightsDeleteAll; + if ([roles containsObject: SOGoCalendarRole_PublicModifier] + && [roles containsObject: SOGoCalendarRole_PrivateModifier] + && [roles containsObject: SOGoCalendarRole_ConfidentialModifier]) + rights |= RightsReadItems | RightsEditAll; + else if ([roles containsObject: SOGoCalendarRole_PublicViewer] + && [roles containsObject: SOGoCalendarRole_PrivateViewer] + && [roles containsObject: SOGoCalendarRole_ConfidentialViewer]) + rights |= RightsReadItems; + if (rights != 0) + rights |= RoleNone; /* actually "folder visible" */ + + return rights; +} + @end diff --git a/OpenChange/MAPIStoreContactsFolder.m b/OpenChange/MAPIStoreContactsFolder.m index 65801e5c1..0b7354d9e 100644 --- a/OpenChange/MAPIStoreContactsFolder.m +++ b/OpenChange/MAPIStoreContactsFolder.m @@ -23,6 +23,7 @@ #import #import #import +#import #import #import @@ -33,6 +34,9 @@ #import "MAPIStoreContactsFolder.h" +#include +#include + @implementation MAPIStoreContactsFolder - (id) initWithURL: (NSURL *) newURL @@ -103,4 +107,39 @@ return newMessage; } +- (NSArray *) rolesForExchangeRights: (uint32_t) rights +{ + NSMutableArray *roles; + + roles = [NSMutableArray arrayWithCapacity: 6]; + if (rights & RightsCreateItems) + [roles addObject: SOGoRole_ObjectCreator]; + if (rights & RightsDeleteAll) + [roles addObject: SOGoRole_ObjectEraser]; + if (rights & RightsEditAll) + [roles addObject: SOGoRole_ObjectEditor]; + if (rights & RightsReadItems) + [roles addObject: SOGoRole_ObjectViewer]; + + return roles; +} + +- (uint32_t) exchangeRightsForRoles: (NSArray *) roles +{ + uint32_t rights = 0; + + if ([roles containsObject: SOGoRole_ObjectCreator]) + rights |= RightsCreateItems; + if ([roles containsObject: SOGoRole_ObjectEraser]) + rights |= RightsDeleteAll; + if ([roles containsObject: SOGoRole_ObjectEditor]) + rights |= RightsEditAll; + if ([roles containsObject: SOGoRole_ObjectViewer]) + rights |= RightsReadItems; + if (rights != 0) + rights |= RoleNone; /* actually "folder visible" */ + + return rights; +} + @end diff --git a/OpenChange/MAPIStoreFSFolder.m b/OpenChange/MAPIStoreFSFolder.m index 5c9478d74..d2ec82d86 100644 --- a/OpenChange/MAPIStoreFSFolder.m +++ b/OpenChange/MAPIStoreFSFolder.m @@ -193,4 +193,64 @@ static Class EOKeyValueQualifierK; return date; } +- (SOGoFolder *) aclFolder +{ + return propsFolder; +} + +- (NSArray *) rolesForExchangeRights: (uint32_t) rights +{ + NSMutableArray *roles; + + roles = [NSMutableArray arrayWithCapacity: 9]; + if (rights & RightsReadItems) + [roles addObject: @"RightsReadItems"]; + if (rights & RightsCreateItems) + [roles addObject: @"RightsCreateItems"]; + if (rights & RightsEditOwn) + [roles addObject: @"RightsEditOwn"]; + if (rights & RightsDeleteOwn) + [roles addObject: @"RightsDeleteOwn"]; + if (rights & RightsEditAll) + [roles addObject: @"RightsEditAll"]; + if (rights & RightsDeleteAll) + [roles addObject: @"RightsDeleteAll"]; + if (rights & RightsCreateSubfolders) + [roles addObject: @"RightsCreateSubfolders"]; + if (rights & RightsFolderOwner) + [roles addObject: @"RightsFolderOwner"]; + if (rights & RightsFolderContact) + [roles addObject: @"RightsFolderContact"]; + + return roles; +} + +- (uint32_t) exchangeRightsForRoles: (NSArray *) roles +{ + uint32_t rights = 0; + + if ([roles containsObject: @"RightsReadItems"]) + rights |= RightsReadItems; + if ([roles containsObject: @"RightsCreateItems"]) + rights |= RightsCreateItems; + if ([roles containsObject: @"RightsEditOwn"]) + rights |= RightsEditOwn; + if ([roles containsObject: @"RightsDeleteOwn"]) + rights |= RightsDeleteOwn; + if ([roles containsObject: @"RightsEditAll"]) + rights |= RightsEditAll; + if ([roles containsObject: @"RightsDeleteAll"]) + rights |= RightsDeleteAll; + if ([roles containsObject: @"RightsCreateSubfolders"]) + rights |= RightsCreateSubfolders; + if ([roles containsObject: @"RightsFolderOwner"]) + rights |= RightsFolderOwner; + if ([roles containsObject: @"RightsFolderContact"]) + rights |= RightsFolderContact; + if (rights != 0) + rights |= RoleNone; /* actually "folder visible" */ + + return rights; +} + @end diff --git a/OpenChange/MAPIStoreFolder.h b/OpenChange/MAPIStoreFolder.h index 57a63b499..085795de2 100644 --- a/OpenChange/MAPIStoreFolder.h +++ b/OpenChange/MAPIStoreFolder.h @@ -40,10 +40,10 @@ @class MAPIStoreFolderTable; @class MAPIStoreMessageTable; @class MAPIStorePermissionsTable; +@class SOGoFolder; @class SOGoMAPIFSFolder; @class SOGoMAPIFSMessage; - #import "MAPIStoreObject.h" @interface MAPIStoreFolder : MAPIStoreObject @@ -74,6 +74,7 @@ /* permissions */ - (MAPIStorePermissionsTable *) permissionsTable; +- (NSArray *) permissionEntries; /* message objects and tables */ - (id) lookupMessage: (NSString *) messageKey; @@ -135,6 +136,10 @@ tableType: (uint8_t) tableType andHandleId: (uint32_t) handleId; +- (int) modifyPermissions: (struct PermissionData *) permissions + withCount: (uint16_t) pcount + andFlags: (int8_t) flags; + /* helpers */ - (uint64_t) idForObjectWithKey: (NSString *) childKey; @@ -152,6 +157,10 @@ - (NSCalendarDate *) lastMessageModificationTime; +- (SOGoFolder *) aclFolder; +- (NSArray *) rolesForExchangeRights: (uint32_t) rights; +- (uint32_t) exchangeRightsForRoles: (NSArray *) roles; + /* subclass helpers */ - (void) postNotificationsForMoveCopyMessagesWithMIDs: (uint64_t *) srcMids andMessageURLs: (NSArray *) oldMessageURLs diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 4630f7246..2e81d9a82 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -41,6 +41,7 @@ #import "MAPIStoreMapping.h" #import "MAPIStoreMessage.h" #import "MAPIStorePermissionsTable.h" +#import "MAPIStoreSamDBUtils.h" #import "MAPIStoreTypes.h" #import "NSDate+MAPIStore.h" #import "NSString+MAPIStore.h" @@ -700,6 +701,23 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe return rc; } +- (SOGoFolder *) aclFolder +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + +- (void) _modifyPermissionEntryForUser: (NSString *) user + withRoles: (NSArray *) roles + isAddition: (BOOL) isAddition + withACLFolder: (SOGoFolder *) aclFolder +{ + if (isAddition) + [aclFolder addUserInAcls: user]; + [aclFolder setRoles: roles forUser: user]; +} + - (void) postNotificationsForMoveCopyMessagesWithMIDs: (uint64_t *) srcMids andMessageURLs: (NSArray *) oldMessageURLs andCount: (uint32_t) midCount @@ -1247,6 +1265,196 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe return [MAPIStorePermissionsTable tableForContainer: self]; } +- (NSArray *) permissionEntries +{ + NSMutableArray *permissionEntries; + MAPIStorePermissionEntry *entry; + NSArray *aclUsers; + uint64_t memberId, regularMemberId = 1; + NSUInteger count, max; + NSString *username, *defaultUserId; + SOGoFolder *aclFolder; + + aclFolder = [self aclFolder]; + + defaultUserId = [aclFolder defaultUserID]; + aclUsers = [aclFolder aclUsers]; + max = [aclUsers count]; + permissionEntries = [NSMutableArray arrayWithCapacity: max]; + for (count = 0; count < max; count++) + { + username = [aclUsers objectAtIndex: count]; + if (![username hasPrefix: @"@"]) + { + if ([username isEqualToString: defaultUserId]) + memberId = 0; + else if ([username isEqualToString: @"anonymous"]) + memberId = ULLONG_MAX; + else + { + memberId = regularMemberId; + regularMemberId++; + } + entry = [MAPIStorePermissionEntry entryWithUserId: username + andMemberId: memberId + forFolder: self]; + [permissionEntries addObject: entry]; + } + } + + return permissionEntries; +} + +- (NSArray *) rolesForExchangeRights: (uint32_t) rights +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (uint32_t) exchangeRightsForRoles: (NSArray *) roles +{ + [self subclassResponsibility: _cmd]; + return 0; +} + +- (NSString *) _usernameFromEntryId: (struct SBinary_short *) bin +{ + struct Binary_r bin32; + struct AddressBookEntryId *entryId; + NSString *username; + struct ldb_context *samCtx; + + bin32.cb = bin->cb; + bin32.lpb = bin->lpb; + + entryId = get_AddressBookEntryId (NULL, &bin32); + if (entryId) + { + samCtx = [[self context] connectionInfo]->sam_ctx; + username = MAPIStoreSamDBUserAttribute (samCtx, @"legacyExchangeDN", + [NSString stringWithUTF8String: entryId->X500DN], + @"sAMAccountName"); + } + else + username = nil; + talloc_free (entryId); + + return username; +} + +- (NSString *) _usernameFromMemberId: (uint64_t) memberId + inEntries: (NSArray *) entries +{ + NSString *username = nil; + NSUInteger count, max; + MAPIStorePermissionEntry *entry; + + max = [entries count]; + for (count = 0; !username && count < max; count++) + { + entry = [entries objectAtIndex: count]; + if ([entry memberId] == memberId) + username = [entry userId]; + } + + return username; +} + +- (void) _emptyACL +{ + NSUInteger count, max; + NSArray *users; + SOGoFolder *aclFolder; + + aclFolder = [self aclFolder]; + + users = [aclFolder aclUsers]; + max = [users count]; + for (count = 0; count < max; count++) + [aclFolder removeUserFromAcls: [users objectAtIndex: count]]; +} + +- (int) modifyPermissions: (struct PermissionData *) permissions + withCount: (uint16_t) pcount + andFlags: (int8_t) flags +{ + NSUInteger count, propCount; + struct PermissionData *currentPermission; + struct mapi_SPropValue *mapiValue; + NSString *permissionUser; + NSArray *entries; + NSArray *permissionRoles; + BOOL reset, isAdd; + SOGoFolder *aclFolder; + + aclFolder = [self aclFolder]; + + reset = ((flags & ModifyPerms_ReplaceRows) != 0); + if (reset) + [self _emptyACL]; + + entries = [self permissionEntries]; + + for (count = 0; count < pcount; count++) + { + currentPermission = permissions + count; + + permissionUser = nil; + permissionRoles = nil; + + isAdd = (currentPermission->PermissionDataFlags == ROW_ADD); + for (propCount = 0; + propCount < currentPermission->lpProps.cValues; + propCount++) + { + mapiValue = currentPermission->lpProps.lpProps + propCount; + switch (mapiValue->ulPropTag) + { + case PR_ENTRYID: + permissionUser + = [self _usernameFromEntryId: &mapiValue->value.bin]; + break; + case PR_MEMBER_ID: + permissionUser = [self _usernameFromMemberId: mapiValue->value.d + inEntries: entries]; + break; + case PR_MEMBER_RIGHTS: + permissionRoles = [self + rolesForExchangeRights: mapiValue->value.l]; + break; + default: + if (mapiValue->ulPropTag != PR_MEMBER_NAME) + [self warnWithFormat: @"unhandled permission property: %.8x", + mapiValue->ulPropTag]; + } + } + + if (reset) + { + if (isAdd) + [self _modifyPermissionEntryForUser: permissionUser + withRoles: permissionRoles + isAddition: YES + withACLFolder: aclFolder]; + } + else + { + if (isAdd || currentPermission->PermissionDataFlags == ROW_MODIFY) + [self _modifyPermissionEntryForUser: permissionUser + withRoles: permissionRoles + isAddition: isAdd + withACLFolder: aclFolder]; + else if (currentPermission->PermissionDataFlags == ROW_REMOVE) + [aclFolder removeUserFromAcls: permissionUser]; + else + [self errorWithFormat: @"unhandled permission action flag: %d", + currentPermission->PermissionDataFlags]; + } + } + + return MAPISTORE_SUCCESS; +} + - (uint64_t) objectId { uint64_t objectId; diff --git a/OpenChange/MAPIStoreGCSFolder.m b/OpenChange/MAPIStoreGCSFolder.m index b4c7844d9..6fe81e303 100644 --- a/OpenChange/MAPIStoreGCSFolder.m +++ b/OpenChange/MAPIStoreGCSFolder.m @@ -133,6 +133,11 @@ return value; } +- (SOGoFolder *) aclFolder +{ + return (SOGoFolder *) sogoObject; +} + /* synchronisation */ /* Tree diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index e99ec2059..f15142d1f 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -43,11 +43,11 @@ #import #import #import +#import #import "MAPIApplication.h" #import "MAPIStoreAppointmentWrapper.h" #import "MAPIStoreContext.h" -// #import "MAPIStoreDraftsMessage.h" #import "MAPIStoreFAIMessage.h" #import "MAPIStoreMailMessageTable.h" #import "MAPIStoreMapping.h" @@ -391,6 +391,11 @@ static Class SOGoMailFolderK; return value; } +- (SOGoFolder *) aclFolder +{ + return (SOGoFolder *) sogoObject; +} + /* synchronisation */ /* Tree: @@ -1008,6 +1013,65 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) return newMessage; } + +- (NSArray *) rolesForExchangeRights: (uint32_t) rights +{ + NSMutableArray *roles; + + roles = [NSMutableArray arrayWithCapacity: 6]; + if (rights & RoleOwner) + [roles addObject: SOGoMailRole_Administrator]; + if (rights & RightsCreateItems) + { + [roles addObject: SOGoRole_ObjectCreator]; + [roles addObject: SOGoMailRole_Writer]; + [roles addObject: SOGoMailRole_Poster]; + } + if (rights & RightsDeleteAll) + { + [roles addObject: SOGoRole_ObjectEraser]; + [roles addObject: SOGoRole_FolderEraser]; + [roles addObject: SOGoMailRole_Expunger]; + } + if (rights & RightsEditAll) + [roles addObject: SOGoRole_ObjectEditor]; + if (rights & RightsReadItems) + [roles addObject: SOGoRole_ObjectViewer]; + if (rights & RightsCreateSubfolders) + [roles addObject: SOGoRole_FolderCreator]; + if (rights & RightsCreateSubfolders) + [roles addObject: SOGoRole_FolderCreator]; + + return roles; +} + +- (uint32_t) exchangeRightsForRoles: (NSArray *) roles +{ + uint32_t rights = 0; + + if ([roles containsObject: SOGoMailRole_Administrator]) + rights |= (RoleOwner ^ RightsAll); + if ([roles containsObject: SOGoRole_ObjectCreator]) + rights |= RightsCreateItems; + if ([roles containsObject: SOGoRole_ObjectEraser] + && [roles containsObject: SOGoRole_FolderEraser]) + rights |= RightsDeleteAll; + + if ([roles containsObject: SOGoRole_ObjectEditor]) + rights |= RightsEditAll; + if ([roles containsObject: SOGoRole_ObjectViewer]) + rights |= RightsReadItems; + if ([roles containsObject: SOGoRole_FolderCreator]) + rights |= RightsCreateSubfolders; + if ([roles containsObject: SOGoRole_FolderCreator]) + rights |= RightsCreateSubfolders; + + if (rights != 0) + rights |= RoleNone; /* actually "folder visible" */ + + return rights; +} + @end @implementation MAPIStoreInboxFolder : MAPIStoreMailFolder diff --git a/OpenChange/MAPIStorePermissionsTable.h b/OpenChange/MAPIStorePermissionsTable.h index 20a98e37d..ef490d8b3 100644 --- a/OpenChange/MAPIStorePermissionsTable.h +++ b/OpenChange/MAPIStorePermissionsTable.h @@ -25,7 +25,31 @@ #import "MAPIStoreTable.h" +struct ldb_context; + +@interface MAPIStorePermissionEntry : MAPIStoreObject +{ + NSString *userId; + uint64_t memberId; +} + ++ (id) entryWithUserId: (NSString *) newUserId + andMemberId: (uint64_t) newMemberId + forFolder: (MAPIStoreFolder *) newFolder; +- (id) initWithUserId: (NSString *) newUserId + andMemberId: (uint64_t) newMemberId + forFolder: (MAPIStoreFolder *) newFolder; + +- (NSString *) userId; +- (uint64_t) memberId; + +@end + @interface MAPIStorePermissionsTable : MAPIStoreTable +{ + NSMutableDictionary *entries; +} + @end #endif /* MAPISTOREPERMISSIONSTABLE_H */ diff --git a/OpenChange/MAPIStorePermissionsTable.m b/OpenChange/MAPIStorePermissionsTable.m index 04b2b3327..6247d8694 100644 --- a/OpenChange/MAPIStorePermissionsTable.m +++ b/OpenChange/MAPIStorePermissionsTable.m @@ -21,44 +21,48 @@ */ #import +#import #import -#import "MAPIStoreObject.h" +#import +#import + +#import "MAPIStoreContext.h" +#import "MAPIStoreFolder.h" #import "MAPIStoreTypes.h" +#import "MAPIStoreSamDBUtils.h" #import "NSData+MAPIStore.h" #import "NSString+MAPIStore.h" #import "MAPIStorePermissionsTable.h" +#undef DEBUG +#include #include -@interface MAPIStorePermissionEntry : MAPIStoreObject -{ - NSString *userId; -} - -+ (id) entryWithUserId: (NSString *) newUserId; -- (id) initWithUserId: (NSString *) newUserId; - -@end - @implementation MAPIStorePermissionEntry + (id) entryWithUserId: (NSString *) newUserId + andMemberId: (uint64_t) newMemberId + forFolder: (MAPIStoreFolder *) newFolder { MAPIStorePermissionEntry *newEntry; - newEntry = [[self alloc] initWithUserId: newUserId]; + newEntry = [[self alloc] initWithUserId: newUserId andMemberId: newMemberId + forFolder: newFolder]; [newEntry autorelease]; return newEntry; } - (id) initWithUserId: (NSString *) newUserId + andMemberId: (uint64_t) newMemberId + forFolder: (MAPIStoreFolder *) newFolder { - if ((self = [self init])) + if ((self = [self initWithSOGoObject: nil inContainer: newFolder])) { ASSIGN (userId, newUserId); + memberId = newMemberId; } return self; @@ -70,15 +74,20 @@ [super dealloc]; } +- (NSString *) userId +{ + return userId; +} + +- (uint64_t) memberId +{ + return memberId; +} + - (int) getPrMemberId: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - uint64_t value = 0; - - if ([userId isEqualToString: @"anonymous"]) - value = ULLONG_MAX; - - *data = MAPILongLongValue (memCtx, value); + *data = MAPILongLongValue (memCtx, memberId); return MAPISTORE_SUCCESS; } @@ -86,7 +95,17 @@ - (int) getPrEntryid: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = [[NSData data] asBinaryInMemCtx: memCtx]; + NSData *entryId; + struct mapistore_connection_info *connInfo; + + if (memberId == 0 || memberId == ULLONG_MAX) + entryId = [NSData data]; + else + { + connInfo = [[container context] connectionInfo]; + entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, userId); + } + *data = [entryId asBinaryInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } @@ -94,7 +113,16 @@ - (int) getPrMemberName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = [userId asUnicodeInMemCtx: memCtx]; + NSString *displayName; + + if (memberId == 0) + displayName = @""; + else if (memberId == ULLONG_MAX) + displayName = @"Anonymous"; + else + displayName = [[SOGoUser userWithLogin: userId] cn]; + + *data = [displayName asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } @@ -102,7 +130,13 @@ - (int) getPrMemberRights: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = MAPILongValue (memCtx, 0); + uint32_t rights; + NSArray *roles; + + roles = [[(MAPIStoreFolder *) container aclFolder] aclsForUser: userId]; + rights = [(MAPIStoreFolder *) container exchangeRightsForRoles: roles]; + + *data = MAPILongValue (memCtx, rights); return MAPISTORE_SUCCESS; } @@ -111,9 +145,37 @@ @implementation MAPIStorePermissionsTable +- (void) dealloc +{ + [entries release]; + [super dealloc]; +} + +- (void) _fetchEntries +{ + NSArray *permEntries; + NSUInteger count, max; + MAPIStorePermissionEntry *entry; + + entries = [NSMutableDictionary new]; + permEntries = [(MAPIStoreFolder *) container permissionEntries]; + max = [permEntries count]; + for (count = 0; count < max; count++) + { + entry = [permEntries objectAtIndex: count]; + [entries setObject: entry forKey: [entry userId]]; + } + + childKeys = [entries allKeys]; + [childKeys retain]; +} + - (NSArray *) childKeys { - return [NSArray arrayWithObjects: @"default", @"anonymous", nil]; + if (!entries) + [self _fetchEntries]; + + return childKeys; } - (NSArray *) restrictedChildKeys @@ -123,7 +185,10 @@ - (id) lookupChild: (NSString *) childKey { - return [MAPIStorePermissionEntry entryWithUserId: childKey]; + if (!entries) + [self _fetchEntries]; + + return [entries objectForKey: childKey]; } @end diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index e060855c8..3deda51e7 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -1,6 +1,6 @@ /* MAPIStoreSOGo.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010, 2011 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -100,6 +100,7 @@ sogo_backend_init (void) [[MAPIApplicationK new] activateApplication]; [[SOGoCache sharedCache] disableRequestsCache]; + [[SOGoCache sharedCache] disableLocalCache]; [pool release]; @@ -554,6 +555,36 @@ sogo_folder_open_table(void *folder_object, TALLOC_CTX *mem_ctx, return rc; } +static int +sogo_folder_modify_permissions(void *folder_object, uint8_t flags, + uint16_t pcount, + struct PermissionData *permissions) +{ + struct MAPIStoreTallocWrapper *wrapper; + NSAutoreleasePool *pool; + MAPIStoreFolder *folder; + int rc; + + DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + + if (folder_object) + { + wrapper = folder_object; + folder = wrapper->MAPIStoreSOGoObject; + pool = [NSAutoreleasePool new]; + rc = [folder modifyPermissions: permissions + withCount: pcount + andFlags: flags]; + [pool release]; + } + else + { + rc = sogo_backend_unexpected_error(); + } + + return rc; +} + static int sogo_message_get_message_data(void *message_object, TALLOC_CTX *mem_ctx, @@ -1189,6 +1220,7 @@ int mapistore_init_backend(void) backend.folder.get_deleted_fmids = sogo_folder_get_deleted_fmids; backend.folder.get_child_count = sogo_folder_get_child_count; backend.folder.open_table = sogo_folder_open_table; + backend.folder.modify_permissions = sogo_folder_modify_permissions; backend.message.create_attachment = sogo_message_create_attachment; backend.message.get_attachment_table = sogo_message_get_attachment_table; backend.message.open_attachment = sogo_message_open_attachment; diff --git a/OpenChange/MAPIStoreTasksFolder.m b/OpenChange/MAPIStoreTasksFolder.m index deb02477d..83eaea02a 100644 --- a/OpenChange/MAPIStoreTasksFolder.m +++ b/OpenChange/MAPIStoreTasksFolder.m @@ -25,6 +25,7 @@ #import #import #import +#import #import #import #import @@ -36,6 +37,9 @@ #import "MAPIStoreTasksFolder.h" +#include +#include + @implementation MAPIStoreTasksFolder - (id) initWithURL: (NSURL *) newURL @@ -106,4 +110,51 @@ return newMessage; } +- (NSArray *) rolesForExchangeRights: (uint32_t) rights +{ + NSMutableArray *roles; + + roles = [NSMutableArray arrayWithCapacity: 6]; + if (rights & RightsCreateItems) + [roles addObject: SOGoRole_ObjectCreator]; + if (rights & RightsDeleteAll) + [roles addObject: SOGoRole_ObjectEraser]; + if (rights & RightsEditAll) + { + [roles addObject: SOGoCalendarRole_PublicModifier]; + [roles addObject: SOGoCalendarRole_PrivateModifier]; + [roles addObject: SOGoCalendarRole_ConfidentialModifier]; + } + else if (rights & RightsReadItems) + { + [roles addObject: SOGoCalendarRole_PublicViewer]; + [roles addObject: SOGoCalendarRole_PrivateViewer]; + [roles addObject: SOGoCalendarRole_ConfidentialViewer]; + } + + return roles; +} + +- (uint32_t) exchangeRightsForRoles: (NSArray *) roles +{ + uint32_t rights = 0; + + if ([roles containsObject: SOGoRole_ObjectCreator]) + rights |= RightsCreateItems; + if ([roles containsObject: SOGoRole_ObjectEraser]) + rights |= RightsDeleteAll; + if ([roles containsObject: SOGoCalendarRole_PublicModifier] + && [roles containsObject: SOGoCalendarRole_PrivateModifier] + && [roles containsObject: SOGoCalendarRole_ConfidentialModifier]) + rights |= RightsReadItems | RightsEditAll; + else if ([roles containsObject: SOGoCalendarRole_PublicViewer] + && [roles containsObject: SOGoCalendarRole_PrivateViewer] + && [roles containsObject: SOGoCalendarRole_ConfidentialViewer]) + rights |= RightsReadItems; + if (rights != 0) + rights |= RoleNone; /* actually "folder visible" */ + + return rights; +} + @end diff --git a/OpenChange/SOGoMAPIFSFolder.m b/OpenChange/SOGoMAPIFSFolder.m index 67c592543..b2cf7cbe5 100644 --- a/OpenChange/SOGoMAPIFSFolder.m +++ b/OpenChange/SOGoMAPIFSFolder.m @@ -21,13 +21,17 @@ */ #import +#import +#import #import #import +#import #import #import #import #import +#import #import "EOQualifier+MAPI.h" #import "SOGoMAPIFSMessage.h" @@ -200,11 +204,14 @@ static NSString *privateDir = nil; for (count = 0; count < max; count++) { file = [contents objectAtIndex: count]; - fullName = [directory stringByAppendingPathComponent: file]; - if ([fm fileExistsAtPath: fullName - isDirectory: &isDir] - && dirs == isDir) - [files addObject: file]; + if (![file isEqualToString: @"permissions.plist"]) + { + fullName = [directory stringByAppendingPathComponent: file]; + if ([fm fileExistsAtPath: fullName + isDirectory: &isDir] + && dirs == isDir) + [files addObject: file]; + } } return files; @@ -305,4 +312,108 @@ static NSString *privateDir = nil; return [self _fileAttributeForKey: NSFileModificationDate]; } +/* acl */ +- (NSString *) defaultUserID +{ + return @"default"; +} + +- (NSMutableDictionary *) _aclEntries +{ + NSMutableDictionary *aclEntries; + NSData *content; + NSString *error, *filename; + NSPropertyListFormat format; + + filename = [directory stringByAppendingPathComponent: @"permissions.plist"]; + content = [NSData dataWithContentsOfFile: filename]; + if (content) + aclEntries = [NSPropertyListSerialization propertyListFromData: content + mutabilityOption: NSPropertyListMutableContainers + format: &format + errorDescription: &error]; + else + aclEntries = nil; + if (!aclEntries) + { + aclEntries = [NSMutableDictionary dictionary]; + [aclEntries setObject: [NSMutableArray array] forKey: @"users"]; + [aclEntries setObject: [NSMutableDictionary dictionary] + forKey: @"entries"]; + } + + return aclEntries; +} + +- (void) _saveAcl: (NSDictionary *) acl +{ + NSString *filename; + NSData *content; + + filename = [directory stringByAppendingPathComponent: @"permissions.plist"]; + [self ensureDirectory]; + + if (acl) + content = [NSPropertyListSerialization + dataFromPropertyList: acl + format: NSPropertyListBinaryFormat_v1_0 + errorDescription: NULL]; + else + content = [NSData data]; + if (![content writeToFile: filename atomically: NO]) + [NSException raise: @"MAPIStoreIOException" + format: @"could not save acl"]; +} + +- (void) addUserInAcls: (NSString *) user +{ + NSMutableDictionary *acl; + NSMutableArray *users; + + acl = [self _aclEntries]; + users = [acl objectForKey: @"users"]; + [users addObjectUniquely: user]; + [self _saveAcl: acl]; +} + +- (void) removeAclsForUsers: (NSArray *) oldUsers +{ + NSDictionary *acl; + NSMutableDictionary *entries; + NSMutableArray *users; + + acl = [self _aclEntries]; + entries = [acl objectForKey: @"entries"]; + [entries removeObjectsForKeys: oldUsers]; + users = [acl objectForKey: @"users"]; + [users removeObjectsInArray: oldUsers]; + [self _saveAcl: acl]; +} + +- (NSArray *) aclUsers +{ + return [[self _aclEntries] objectForKey: @"users"]; +} + +- (NSArray *) aclsForUser: (NSString *) uid +{ + NSDictionary *entries; + + entries = [[self _aclEntries] objectForKey: @"entries"]; + + return [entries objectForKey: uid]; +} + +- (void) setRoles: (NSArray *) roles + forUser: (NSString *) uid +{ + NSMutableDictionary *acl; + NSMutableDictionary *entries; + + acl = [self _aclEntries]; + entries = [acl objectForKey: @"entries"]; + [entries setObject: roles forKey: uid]; + [self _saveAcl: acl]; +} + @end