diff --git a/ChangeLog b/ChangeLog index 2ac26fa38..58e8c7bf2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,51 @@ 2008-05-02 Wolfgang Sourdeau + * SoObjects/Contacts/SOGoContactLDAPFolder.m ([-davNamespaces]): + removed method. + + * SoObjects/Contacts/SOGoContactGCSFolder.m ([-davNamespaces]): + removed method. + + * SoObjects/SOGo/SOGoGCSFolder.m ([SOGoGCSFolder + +webdavAclManager]): new overriden method. + + * SoObjects/SOGo/SOGoFolder.m ([SOGoFolder +webdavAclManager]): + new overriden method. + + * SoObjects/Appointments/SOGoAppointmentObject.m + ([SOGoAppointmentObject +webdavAclManager]): new overriden method. + + * SoObjects/Appointments/SOGoAppointmentFolder.m + ([SOGoAppointmentFolder +webdavAclManager]): new overriden method. + ([-davNamespaces]): removed method. + ([-lookupGroupFolderForUIDs:_uidsinContext:]) + ([-lookupGroupCalendarFolderForUIDs:_uidsinContext:_ctx]): + disabled methods. + + * SoObjects/SOGo/SOGoWebDAVAclManager.[hm]: new class module that + implements the rendering of DAV acl trees as well as their mapping + from SOGo permissions. + + * SoObjects/SOGo/SOGoObject.m ([SOGoObject +initialize]): libSOGo + is now a framework, so we can simplify the loading of the DAVReportMap. + ([-lookupGroupsFolder]): disabled method. + ([SOGoObject -davOwner], [SOGoObject -davAclRestrictions]) + ([SOGoObject -davPrincipalCollectionSet]) + ([SOGoObject -davCurrentUserPrivilegeSet]) + ([SOGoObject -davSupportedPrivilegeSet], [SOGoObject -davAcl]) + ([SOGoObject -davPrincipalMatch:localContext]) + ([SOGoObject -davSupportedReportSet]): (re-)implemented dav + methods with our new dav rendering paradigm. + ([-davNamespaces]): removed method. + ([SOGoObject -domNode:nodegetChildNodesByType:type]): new helper + method to help subclass with parsing dav requests, especially wrt + REPORT ones. + ([SOGoObject +webdavAclManager]): new overridable method that + returns a properly configured DAV acl manager (see above). + + * SoObjects/Appointments/SOGoUserFolder+Appointments.[hm]: new + category module that implements DAV methods required by CalDAV. + * UI/SOGoUI/UIxComponent.m ([UIxComponent -applicationPath]): disabled all mentions of "SOGoGroupFolder*". diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index bf618a8bf..889e3390e 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -49,13 +49,15 @@ #import // #import +#import +#import +#import #import -#import +// #import #import #import -#import -#import #import +#import #import "SOGoAppointmentObject.h" #import "SOGoAppointmentFolders.h" @@ -110,6 +112,139 @@ static NSNumber *sharedYes = nil; sharedYes = [[NSNumber numberWithBool: YES] retain]; } ++ (SOGoWebDAVAclManager *) webdavAclManager +{ + SOGoWebDAVAclManager *webdavAclManager = nil; + NSString *nsCD, *nsD, *nsI; + + if (!webdavAclManager) + { + nsD = @"DAV:"; + nsCD = @"urn:ietf:params:xml:ns:caldav"; + nsI = @"urn:inverse:params:xml:ns:inverse-dav"; + + webdavAclManager = [SOGoWebDAVAclManager new]; + [webdavAclManager registerDAVPermission: davElement (@"read", nsD) + abstract: YES + withEquivalent: SoPerm_WebDAVAccess + asChildOf: davElement (@"all", nsD)]; + [webdavAclManager registerDAVPermission: davElement (@"read-current-user-privilege-set", nsD) + abstract: YES + withEquivalent: SoPerm_WebDAVAccess + asChildOf: davElement (@"read", nsD)]; + [webdavAclManager registerDAVPermission: davElement (@"read-free-busy", nsD) + abstract: NO + withEquivalent: SoPerm_AccessContentsInformation + asChildOf: davElement (@"read", nsD)]; + [webdavAclManager registerDAVPermission: davElement (@"write", nsD) + abstract: YES + withEquivalent: nil + asChildOf: davElement (@"all", nsD)]; + [webdavAclManager registerDAVPermission: davElement (@"bind", nsD) + abstract: NO + withEquivalent: SoPerm_AddDocumentsImagesAndFiles + asChildOf: davElement (@"write", nsD)]; + [webdavAclManager registerDAVPermission: davElement (@"schedule", + nsCD) + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"bind", nsD)]; + [webdavAclManager registerDAVPermission: davElement (@"schedule-post", + nsCD) + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule", nsCD)]; + [webdavAclManager registerDAVPermission: + davElement (@"schedule-post-vevent", nsCD) + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-post", nsCD)]; + [webdavAclManager registerDAVPermission: + davElement (@"schedule-post-vtodo", nsCD) + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-post", nsCD)]; + [webdavAclManager registerDAVPermission: + davElement (@"schedule-post-vjournal", nsCD) + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-post", nsCD)]; + [webdavAclManager registerDAVPermission: + davElement (@"schedule-post-vfreebusy", nsCD) + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-post", nsCD)]; + [webdavAclManager registerDAVPermission: davElement (@"schedule-deliver", + nsCD) + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule", nsCD)]; + [webdavAclManager registerDAVPermission: + davElement (@"schedule-deliver-vevent", nsCD) + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-deliver", nsCD)]; + [webdavAclManager registerDAVPermission: + davElement (@"schedule-deliver-vtodo", nsCD) + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-deliver", nsCD)]; + [webdavAclManager registerDAVPermission: + davElement (@"schedule-deliver-vjournal", nsCD) + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-deliver", nsCD)]; + [webdavAclManager registerDAVPermission: + davElement (@"schedule-deliver-vfreebusy", nsCD) + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-deliver", nsCD)]; + [webdavAclManager registerDAVPermission: davElement (@"schedule-respond", + nsCD) + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule", nsCD)]; + [webdavAclManager registerDAVPermission: + davElement (@"schedule-respond-vevent", nsCD) + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-respond", nsCD)]; + [webdavAclManager registerDAVPermission: + davElement (@"schedule-respond-vtodo", nsCD) + abstract: NO + withEquivalent: nil + asChildOf: davElement (@"schedule-respond", nsCD)]; + [webdavAclManager registerDAVPermission: davElement (@"unbind", nsD) + abstract: NO + withEquivalent: SoPerm_DeleteObjects + asChildOf: davElement (@"write", nsD)]; + [webdavAclManager + registerDAVPermission: davElement (@"write-properties", nsD) + abstract: YES + withEquivalent: SoPerm_ChangePermissions /* hackish */ + asChildOf: davElement (@"write", nsD)]; + [webdavAclManager + registerDAVPermission: davElement (@"write-content", nsD) + abstract: YES + withEquivalent: nil + asChildOf: davElement (@"write", nsD)]; + [webdavAclManager registerDAVPermission: davElement (@"admin", nsI) + abstract: YES + withEquivalent: nil + asChildOf: davElement (@"all", nsD)]; + [webdavAclManager registerDAVPermission: davElement (@"read-acl", nsD) + abstract: YES + withEquivalent: SOGoPerm_ReadAcls + asChildOf: davElement (@"admin", nsI)]; + [webdavAclManager registerDAVPermission: davElement (@"write-acl", nsD) + abstract: YES + withEquivalent: SoPerm_ChangePermissions + asChildOf: davElement (@"admin", nsI)]; + } + + return webdavAclManager; +} + - (id) initWithName: (NSString *) name inContainer: (id) newContainer { @@ -593,16 +728,6 @@ static NSNumber *sharedYes = nil; } } -- (NSArray *) davNamespaces -{ - NSMutableArray *ns; - - ns = [NSMutableArray arrayWithArray: [super davNamespaces]]; - [ns addObjectUniquely: @"urn:ietf:params:xml:ns:caldav"]; - - return ns; -} - - (NSString *) davCalendarColor { NSString *color; @@ -1649,37 +1774,37 @@ static NSNumber *sharedYes = nil; return [self lookupCalendarFoldersForUIDs:uids inContext:_ctx]; } -- (id) lookupGroupFolderForUIDs: (NSArray *) _uids - inContext: (id)_ctx -{ - SOGoCustomGroupFolder *folder; +// - (id) lookupGroupFolderForUIDs: (NSArray *) _uids +// inContext: (id)_ctx +// { +// SOGoCustomGroupFolder *folder; - if (_uids == nil) - return nil; +// if (_uids == nil) +// return nil; - folder = [[SOGoCustomGroupFolder alloc] initWithUIDs:_uids inContainer:self]; - return [folder autorelease]; -} +// folder = [[SOGoCustomGroupFolder alloc] initWithUIDs:_uids inContainer:self]; +// return [folder autorelease]; +// } -- (id) lookupGroupCalendarFolderForUIDs: (NSArray *) _uids - inContext: (id) _ctx -{ - SOGoCustomGroupFolder *folder; +// - (id) lookupGroupCalendarFolderForUIDs: (NSArray *) _uids +// inContext: (id) _ctx +// { +// SOGoCustomGroupFolder *folder; - if ((folder = [self lookupGroupFolderForUIDs:_uids inContext:_ctx]) == nil) - return nil; +// if ((folder = [self lookupGroupFolderForUIDs:_uids inContext:_ctx]) == nil) +// return nil; - folder = [folder lookupName:@"Calendar" inContext:_ctx acquire:NO]; - if (![folder isNotNull]) - return nil; - if ([folder isKindOfClass:[NSException class]]) { - [self debugWithFormat:@"Note: could not lookup 'Calendar' in folder: %@", - folder]; - return nil; - } +// folder = [folder lookupName:@"Calendar" inContext:_ctx acquire:NO]; +// if (![folder isNotNull]) +// return nil; +// if ([folder isKindOfClass:[NSException class]]) { +// [self debugWithFormat:@"Note: could not lookup 'Calendar' in folder: %@", +// folder]; +// return nil; +// } - return folder; -} +// return folder; +// } /* bulk fetches */ diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index c3f283713..71863150c 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -33,9 +33,12 @@ #import #import #import +#import #import #import #import +#import +#import #import #import "NSArray+Appointments.h" @@ -48,6 +51,76 @@ @implementation SOGoAppointmentObject ++ (SOGoWebDAVAclManager *) webdavAclManager +{ + SOGoWebDAVAclManager *webdavAclManager = nil; + NSString *nsD, *nsI; + + if (!webdavAclManager) + { + nsD = @"DAV:"; + nsI = @"urn:inverse:params:xml:ns:inverse-dav"; + +// extern NSString *SOGoCalendarPerm_ViewAllComponent; +// extern NSString *SOGoCalendarPerm_ViewDAndT; +// extern NSString *SOGoCalendarPerm_ModifyComponent; +// extern NSString *SOGoCalendarPerm_RespondToComponent; + + webdavAclManager = [SOGoWebDAVAclManager new]; + [webdavAclManager registerDAVPermission: davElement (@"read", nsD) + abstract: YES + withEquivalent: nil + asChildOf: davElement (@"all", nsD)]; + [webdavAclManager registerDAVPermission: davElement (@"read-current-user-privilege-set", nsD) + abstract: YES + withEquivalent: SoPerm_WebDAVAccess + asChildOf: davElement (@"read", nsD)]; + [webdavAclManager registerDAVPermission: davElement (@"view-whole-component", nsI) + abstract: NO + withEquivalent: SOGoCalendarPerm_ViewAllComponent + asChildOf: davElement (@"read", nsD)]; + [webdavAclManager registerDAVPermission: davElement (@"view-date-and-time", nsI) + abstract: NO + withEquivalent: SOGoCalendarPerm_ViewDAndT + asChildOf: davElement (@"view-whole-component", nsI)]; + [webdavAclManager registerDAVPermission: davElement (@"write", nsD) + abstract: YES + withEquivalent: nil + asChildOf: davElement (@"all", nsD)]; + [webdavAclManager + registerDAVPermission: davElement (@"write-properties", nsD) + abstract: YES + withEquivalent: SoPerm_ChangePermissions /* hackish */ + asChildOf: davElement (@"write", nsD)]; + [webdavAclManager + registerDAVPermission: davElement (@"write-content", nsD) + abstract: YES + withEquivalent: SOGoCalendarPerm_ModifyComponent + asChildOf: davElement (@"write", nsD)]; + [webdavAclManager + registerDAVPermission: davElement (@"respond-to-component", nsI) + abstract: YES + withEquivalent: SOGoCalendarPerm_RespondToComponent + asChildOf: davElement (@"write-content", nsD)]; + [webdavAclManager registerDAVPermission: davElement (@"admin", nsI) + abstract: YES + withEquivalent: nil + asChildOf: davElement (@"all", nsD)]; + [webdavAclManager + registerDAVPermission: davElement (@"read-acl", nsD) + abstract: YES + withEquivalent: SOGoPerm_ReadAcls + asChildOf: davElement (@"admin", nsI)]; + [webdavAclManager + registerDAVPermission: davElement (@"write-acl", nsD) + abstract: YES + withEquivalent: nil + asChildOf: davElement (@"admin", nsI)]; + } + + return webdavAclManager; +} + - (NSString *) componentTag { return @"vevent"; diff --git a/SoObjects/Appointments/SOGoUserFolder+Appointments.h b/SoObjects/Appointments/SOGoUserFolder+Appointments.h new file mode 100644 index 000000000..d1edfa284 --- /dev/null +++ b/SoObjects/Appointments/SOGoUserFolder+Appointments.h @@ -0,0 +1,42 @@ +/* SOGoUserFolder+Appointments.h - this file is part of SOGo + * + * Copyright (C) 2008 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 SOGOUSERFOLDER_APPOINTMENTS_H +#define SOGOUSERFOLDER_APPOINTMENTS_H + +@class NSArray; + +#import + +@interface SOGoUserFolder (SOGoCalDAVSupport) + +- (NSArray *) davCalendarUserAddressSet; + +// - (NSArray *) davCalendarHomeSet +// - (NSArray *) davCalendarScheduleInboxURL +// - (NSString *) davCalendarScheduleOutboxURL +// - (NSString *) davDropboxHomeURL +// - (NSString *) davNotificationsURL + +@end + +#endif /* SOGOUSERFOLDER_APPOINTMENTS_H */ diff --git a/SoObjects/Appointments/SOGoUserFolder+Appointments.m b/SoObjects/Appointments/SOGoUserFolder+Appointments.m new file mode 100644 index 000000000..fa890c750 --- /dev/null +++ b/SoObjects/Appointments/SOGoUserFolder+Appointments.m @@ -0,0 +1,130 @@ +/* SOGoUserFolder+Appointments.m - this file is part of SOGo + * + * Copyright (C) 2008 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 "SOGoUserFolder+Appointments.h" + +@implementation SOGoUserFolder (SOGoCalDAVSupport) + +- (NSArray *) davCalendarUserAddressSet +{ + NSArray *tag, *allEmails; + NSMutableArray *addresses; + NSEnumerator *emails; + NSString *currentEmail; + + addresses = [NSMutableArray array]; + + allEmails = [[context activeUser] allEmails]; + emails = [allEmails objectEnumerator]; + while ((currentEmail = [emails nextObject])) + { + tag = [NSArray arrayWithObjects: @"href", @"DAV:", @"D", + [NSString stringWithFormat: @"MAILTO:%@", currentEmail], + nil]; + [addresses addObject: tag]; + } + + return addresses; +} + + +// /* CalDAV support */ +// - (NSArray *) davCalendarHomeSet +// { +// /* +// +// http://cal.example.com/home/bernard/calendars/ +// + +// Note: this is the *container* for calendar collections, not the +// collections itself. So for use its the home folder, the +// public folder and the groups folder. +// */ +// NSArray *tag; +// SOGoAppointmentFolders *parent; + +// parent = [self privateCalendars: @"Calendar" inContext: context]; +// tag = [NSArray arrayWithObjects: @"href", @"DAV:", @"D", +// [parent davURL], nil]; + +// return [NSArray arrayWithObject: tag]; +// } + +// - (NSArray *) davCalendarScheduleInboxURL +// { +// NSArray *tag; +// SOGoAppointmentFolders *parent; + +// parent = [self privateCalendars: @"Calendar" inContext: context]; +// tag = [NSArray arrayWithObjects: @"href", @"DAV:", @"D", +// [NSString stringWithFormat: @"%@personal/", [parent davURL]], +// nil]; + +// return [NSArray arrayWithObject: tag]; +// } + +// - (NSString *) davCalendarScheduleOutboxURL +// { +// NSArray *tag; +// SOGoAppointmentFolders *parent; + +// parent = [self privateCalendars: @"Calendar" inContext: context]; +// tag = [NSArray arrayWithObjects: @"href", @"DAV:", @"D", +// [NSString stringWithFormat: @"%@personal/", [parent davURL]], +// nil]; + +// return [NSArray arrayWithObject: tag]; +// } + +// - (NSString *) davDropboxHomeURL +// { +// NSArray *tag; +// SOGoAppointmentFolders *parent; + +// parent = [self privateCalendars: @"Calendar" inContext: context]; +// tag = [NSArray arrayWithObjects: @"href", @"DAV:", @"D", +// [NSString stringWithFormat: @"%@personal/", [parent davURL]], +// nil]; + +// return [NSArray arrayWithObject: tag]; +// } + +// - (NSString *) davNotificationsURL +// { +// NSArray *tag; +// SOGoAppointmentFolders *parent; + +// parent = [self privateCalendars: @"Calendar" inContext: context]; +// tag = [NSArray arrayWithObjects: @"href", @"DAV:", @"D", +// [NSString stringWithFormat: @"%@personal/", [parent davURL]], +// nil]; + +// return [NSArray arrayWithObject: tag]; +// } + +@end diff --git a/SoObjects/Contacts/SOGoContactGCSFolder.m b/SoObjects/Contacts/SOGoContactGCSFolder.m index 0c285bae3..2fbe19638 100644 --- a/SoObjects/Contacts/SOGoContactGCSFolder.m +++ b/SoObjects/Contacts/SOGoContactGCSFolder.m @@ -384,16 +384,6 @@ return classes; } -- (NSArray *) davNamespaces -{ - NSMutableArray *ns; - - ns = [NSMutableArray arrayWithArray: [super davNamespaces]]; - [ns addObjectUniquely: @"urn:ietf:params:xml:ns:carddav"]; - - return ns; -} - - (NSString *) groupDavResourceType { return @"vcard-collection"; diff --git a/SoObjects/Contacts/SOGoContactLDAPFolder.m b/SoObjects/Contacts/SOGoContactLDAPFolder.m index f3d173283..ce1253360 100644 --- a/SoObjects/Contacts/SOGoContactLDAPFolder.m +++ b/SoObjects/Contacts/SOGoContactLDAPFolder.m @@ -130,11 +130,6 @@ ASSIGN (ldapSource, newLDAPSource); } -- (NSArray *) davNamespaces -{ - return [NSArray arrayWithObject: @"urn:ietf:params:xml:ns:carddav"]; -} - - (NSString *) groupDavResourceType { return @"vcard-collection"; diff --git a/SoObjects/SOGo/SOGoFolder.m b/SoObjects/SOGo/SOGoFolder.m index 1d821ae31..f931cc496 100644 --- a/SoObjects/SOGo/SOGoFolder.m +++ b/SoObjects/SOGo/SOGoFolder.m @@ -26,13 +26,42 @@ #import +#import "NSObject+DAV.h" #import "NSString+Utilities.h" #import "SOGoPermissions.h" +#import "SOGoWebDAVAclManager.h" + #import "SOGoFolder.h" +@interface SOGoObject (SOGoDAVHelpers) + +- (void) _fillArrayWithPrincipalsOwnedBySelf: (NSMutableArray *) hrefs; + +@end + @implementation SOGoFolder ++ (SOGoWebDAVAclManager *) webdavAclManager +{ + SOGoWebDAVAclManager *webdavAclManager = nil; + + if (!webdavAclManager) + { + webdavAclManager = [SOGoWebDAVAclManager new]; + [webdavAclManager registerDAVPermission: davElement (@"read", @"DAV:") + abstract: YES + withEquivalent: SoPerm_WebDAVAccess + asChildOf: davElement (@"all", @"DAV:")]; + [webdavAclManager registerDAVPermission: davElement (@"read-current-user-privilege-set", @"DAV:") + abstract: YES + withEquivalent: nil + asChildOf: davElement (@"read", @"DAV:")]; + } + + return webdavAclManager; +} + - (id) init { if ((self = [super init])) @@ -75,6 +104,11 @@ return [NSArray array]; } +- (NSArray *) toManyRelationshipKeys +{ + return nil; +} + - (BOOL) isValidContentName: (NSString *) name { return ([name length] > 0); @@ -192,6 +226,24 @@ return rType; } +/* web dav acl helper */ +- (void) _fillArrayWithPrincipalsOwnedBySelf: (NSMutableArray *) hrefs +{ + NSEnumerator *children; + NSString *currentKey; + + [super _fillArrayWithPrincipalsOwnedBySelf: hrefs]; + children = [[self toOneRelationshipKeys] objectEnumerator]; + while ((currentKey = [children nextObject])) + [[self lookupName: currentKey inContext: context + acquire: NO] _fillArrayWithPrincipalsOwnedBySelf: hrefs]; + + children = [[self toManyRelationshipKeys] objectEnumerator]; + while ((currentKey = [children nextObject])) + [[self lookupName: currentKey inContext: context + acquire: NO] _fillArrayWithPrincipalsOwnedBySelf: hrefs]; +} + /* folder type */ - (BOOL) isEqual: (id) otherFolder @@ -211,6 +263,11 @@ /* acls */ +- (NSString *) defaultUserID +{ + return nil; +} + - (NSArray *) subscriptionRoles { return [NSArray arrayWithObjects: SoRole_Owner, SOGoRole_ObjectViewer, @@ -223,4 +280,9 @@ return nil; } +- (NSArray *) aclUsers +{ + return nil; +} + @end diff --git a/SoObjects/SOGo/SOGoObject.h b/SoObjects/SOGo/SOGoObject.h index 5c8f87b1e..eb1736f2f 100644 --- a/SoObjects/SOGo/SOGoObject.h +++ b/SoObjects/SOGo/SOGoObject.h @@ -24,6 +24,14 @@ #import +#import + +#if LIB_FOUNDATION_LIBRARY +#error SOGo will not work properly with libFoundation. +#error Please use gnustep-base instead. +#endif + + /* SOGoObject @@ -48,8 +56,8 @@ @class GCSFolder; @class SOGoUserFolder; -@class SOGoGroupsFolder; -@class SOGoDAVSet; +@class SOGoWebDAVValue; +@class SOGoWebDAVAclManager; #define $(class) NSClassFromString(class) @@ -58,6 +66,7 @@ WOContext *context; NSString *nameInContainer; NSString *owner; + SOGoWebDAVAclManager *webdavAclManager; id container; } @@ -90,7 +99,6 @@ /* looking up shared objects */ - (SOGoUserFolder *) lookupUserFolder; -- (SOGoGroupsFolder *) lookupGroupsFolder; - (void) sleep; @@ -103,8 +111,6 @@ - (NSException *)delete; - (id)GETAction:(id)_ctx; -- (SOGoDAVSet *) davCurrentUserPrivilegeSet; - /* etag support */ - (NSException *) matchesRequestConditionInContext:(id)_ctx; @@ -129,8 +135,10 @@ - (NSString *) httpURLForAdvisoryToUser: (NSString *) uid; - (NSString *) resourceURLForAdvisoryToUser: (NSString *) uid; -/* dav */ -- (NSArray *) davNamespaces; +/* dav acls */ +- (SOGoWebDAVValue *) davCurrentUserPrivilegeSet; + +/* inverse dav extensions for acls */ - (NSString *) davRecordForUser: (NSString *) user; /* description */ @@ -139,4 +147,17 @@ @end +@interface SOGoObject (SOGo) + +- (NSString *) contentAsString; + +@end + +@interface SOGoObject (SOGoDomHelpers) + +- (NSArray *) domNode: (id ) node + getChildNodesByType: (DOMNodeType) type; + +@end + #endif /* __SoObjects_SOGoObject_H__ */ diff --git a/SoObjects/SOGo/SOGoObject.m b/SoObjects/SOGo/SOGoObject.m index eada235b9..9f99e009c 100644 --- a/SoObjects/SOGo/SOGoObject.m +++ b/SoObjects/SOGo/SOGoObject.m @@ -1,28 +1,25 @@ -/* - Copyright (C) 2004-2005 SKYRIX Software AG - - This file is part of OpenGroupware.org. - - OGo is free software; you can redistribute it and/or modify it under - the terms of the GNU Lesser General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - OGo is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with OGo; see the file COPYING. If not, write to the - Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. -*/ - -#if LIB_FOUNDATION_LIBRARY -#error SOGo will not work properly with libFoundation. -#error Please use gnustep-base instead. -#endif +/* SOGoGCSFolder.m - this file is part of SOGo + * + * Copyright (C) 2004-2005 SKYRIX Software AG + * Copyright (C) 2006-2008 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 @@ -36,10 +33,8 @@ #import #import -#import #import #import -#import #import #import #import @@ -60,14 +55,15 @@ #import "NSArray+Utilities.h" #import "NSCalendarDate+SOGo.h" #import "NSDictionary+Utilities.h" +#import "NSObject+DAV.h" #import "NSObject+Utilities.h" #import "NSString+Utilities.h" #import "SOGoCache.h" -#import "SOGoDAVAuthenticator.h" -#import "SOGoDAVRendererTypes.h" #import "SOGoPermissions.h" #import "SOGoUser.h" #import "SOGoUserFolder.h" +#import "SOGoWebDAVAclManager.h" +#import "SOGoWebDAVValue.h" #import "SOGoObject.h" @@ -76,136 +72,62 @@ static BOOL sendACLAdvisories = NO; static NSDictionary *reportMap = nil; -@interface SOGoObject(Content) -- (NSString *) contentAsString; -@end - -@interface SoClassSecurityInfo (SOGoAcls) - -+ (id) defaultWebDAVPermissionsMap; - -- (NSArray *) allPermissions; -- (NSArray *) allDAVPermissions; -- (NSArray *) DAVPermissionsForRole: (NSString *) role; -- (NSArray *) DAVPermissionsForRoles: (NSArray *) roles; - -@end - -@implementation SoClassSecurityInfo (SOGoAcls) - -+ (id) defaultWebDAVPermissionsMap -{ - return [NSDictionary dictionaryWithObjectsAndKeys: - @"read", SoPerm_AccessContentsInformation, - @"bind", SoPerm_AddDocumentsImagesAndFiles, - @"unbind", SoPerm_DeleteObjects, - @"write-acl", SoPerm_ChangePermissions, - @"write-content", SoPerm_ChangeImagesAndFiles, - @"read-free-busy", SOGoPerm_FreeBusyLookup, - NULL]; -} - -- (NSArray *) allPermissions -{ - return [defRoles allKeys]; -} - -- (NSArray *) allDAVPermissions -{ - NSEnumerator *allPermissions; - NSMutableArray *davPermissions; - NSDictionary *davPermissionsMap; - NSString *sopePermission, *davPermission; - - davPermissions = [NSMutableArray array]; - - davPermissionsMap = [[self class] defaultWebDAVPermissionsMap]; - allPermissions = [[self allPermissions] objectEnumerator]; - sopePermission = [allPermissions nextObject]; - while (sopePermission) - { - davPermission = [davPermissionsMap objectForCaseInsensitiveKey: sopePermission]; - if (davPermission && ![davPermissions containsObject: davPermission]) - [davPermissions addObject: davPermission]; - sopePermission = [allPermissions nextObject]; - } - - return davPermissions; -} - -- (NSArray *) DAVPermissionsForRole: (NSString *) role -{ - return [self DAVPermissionsForRoles: [NSArray arrayWithObject: role]]; -} - -- (NSArray *) DAVPermissionsForRoles: (NSArray *) roles -{ - NSEnumerator *allPermissions; - NSMutableArray *davPermissions; - NSDictionary *davPermissionsMap; - NSString *sopePermission, *davPermission; - - davPermissions = [NSMutableArray array]; - - davPermissionsMap = [[self class] defaultWebDAVPermissionsMap]; - allPermissions = [[self allPermissions] objectEnumerator]; - sopePermission = [allPermissions nextObject]; - while (sopePermission) - { - if ([[defRoles objectForCaseInsensitiveKey: sopePermission] - firstObjectCommonWithArray: roles]) - { - davPermission - = [davPermissionsMap objectForCaseInsensitiveKey: sopePermission]; - if (davPermission - && ![davPermissions containsObject: davPermission]) - [davPermissions addObject: davPermission]; - } - sopePermission = [allPermissions nextObject]; - } - - return davPermissions; -} - -@end - @implementation SOGoObject -+ (void) _loadReportMap ++ (SOGoWebDAVAclManager *) webdavAclManager { - NSFileManager *fm; - NSEnumerator *paths; - NSString *currentPath, *filename; + SOGoWebDAVAclManager *webdavAclManager = nil; - [self logWithFormat: @"Loading DAV REPORT map:"]; + if (!webdavAclManager) + webdavAclManager = [SOGoWebDAVAclManager new]; - fm = [NSFileManager defaultManager]; - paths = [NSStandardLibraryPaths() objectEnumerator]; - while (!reportMap && (currentPath = [paths nextObject])) - { - filename = [NSString stringWithFormat: @"%@/SOGo-%s.%s/SOGo.framework" - @"/Resources/DAVReportMap.plist", - currentPath, - SOGO_MAJOR_VERSION, SOGO_MINOR_VERSION]; - [self logWithFormat: @" %@", filename]; - if ([fm fileExistsAtPath: filename]) - { - reportMap = [[NSDictionary alloc] initWithContentsOfFile: filename]; - [self logWithFormat: @"found!"]; - } - } + return webdavAclManager; } +/* ++ (id) WebDAVPermissionsMap +{ + static NSDictionary *permissions = nil; + + if (!permissions) + { + permissions = [NSDictionary dictionaryWithObjectsAndKeys: + davElement (@"read", @"DAV:"), + SoPerm_AccessContentsInformation, + davElement (@"bind", @"DAV:"), + SoPerm_AddDocumentsImagesAndFiles, + davElement (@"unbind", @"DAV:"), + SoPerm_DeleteObjects, + davElement (@"write-acl", @"DAV:"), + SoPerm_ChangePermissions, + davElement (@"write-content", @"DAV:"), + SoPerm_ChangeImagesAndFiles, NULL]; + [permissions retain]; + } + + return permissions; + } */ + + (void) initialize { NSUserDefaults *ud; + NSString *filename; + NSBundle *bundle; ud = [NSUserDefaults standardUserDefaults]; kontactGroupDAV = ![ud boolForKey:@"SOGoDisableKontact34GroupDAVHack"]; sendACLAdvisories = [ud boolForKey: @"SOGoACLsSendEMailNotifications"]; if (!reportMap) - [self _loadReportMap]; + { + bundle = [NSBundle bundleForClass: self]; + filename = [bundle pathForResource: @"DAVReportMap" ofType: @"plist"]; + if (filename + && [[NSFileManager defaultManager] fileExistsAtPath: filename]) + reportMap = [[NSDictionary alloc] initWithContentsOfFile: filename]; + else + [self logWithFormat: @"DAV REPORT map not found!"]; + } // SoClass security declarations // require View permission to access the root (bound to authenticated ...) @@ -250,51 +172,6 @@ static NSDictionary *reportMap = nil; return [[self class] globallyUniqueObjectId]; } -+ (void) _fillDictionary: (NSMutableDictionary *) dictionary - withDAVMethods: (NSString *) firstMethod, ... -{ - va_list ap; - NSString *aclMethodName; - NSString *methodName; - SEL methodSel; - - va_start (ap, firstMethod); - aclMethodName = firstMethod; - while (aclMethodName) - { - methodName = [aclMethodName davMethodToObjC]; - methodSel = NSSelectorFromString (methodName); - if (methodSel && [self instancesRespondToSelector: methodSel]) - [dictionary setObject: methodName - forKey: [NSString stringWithFormat: @"{DAV:}%@", - aclMethodName]]; - else - NSLog(@"************ method '%@' is still unimplemented!", - methodName); - aclMethodName = va_arg (ap, NSString *); - } - - va_end (ap); -} - -+ (NSDictionary *) defaultWebDAVAttributeMap -{ - static NSMutableDictionary *map = nil; - - if (!map) - { - map = [NSMutableDictionary - dictionaryWithDictionary: [super defaultWebDAVAttributeMap]]; - [map retain]; - [self _fillDictionary: map - withDAVMethods: @"owner", @"group", @"supported-privilege-set", - @"current-user-privilege-set", @"acl", @"acl-restrictions", - @"inherited-acl-set", @"principal-collection-set", nil]; - } - - return map; -} - /* containment */ + (id) objectWithName: (NSString *)_name inContainer:(id)_container @@ -307,156 +184,6 @@ static NSDictionary *reportMap = nil; return object; } -/* DAV ACL properties */ -- (NSString *) davOwner -{ - return [NSString stringWithFormat: @"%@%@", - [WOApplication davURL], - [self ownerInContext: nil]]; -} - -- (NSString *) davAclRestrictions -{ - NSMutableString *restrictions; - - restrictions = [NSMutableString string]; - [restrictions appendString: @""]; - [restrictions appendString: @""]; - - return restrictions; -} - -- (SOGoDAVSet *) davPrincipalCollectionSet -{ - NSString *usersUrl; - - usersUrl = [NSString stringWithFormat: @"%@users", - [self rootURLInContext: context]]; - - return [SOGoDAVSet davSetWithArray: [NSArray arrayWithObject: usersUrl] - ofValuesTaggedAs: @"D:href"]; -} - -- (SOGoDAVSet *) davCurrentUserPrivilegeSet -{ - SOGoDAVAuthenticator *sAuth; - SoUser *user; - NSArray *roles; - SoClassSecurityInfo *sInfo; - NSArray *davPermissions; - - sAuth = [SOGoDAVAuthenticator sharedSOGoDAVAuthenticator]; - user = [sAuth userInContext: context]; - roles = [user rolesForObject: self inContext: context]; - sInfo = [[self class] soClassSecurityInfo]; - - davPermissions - = [[sInfo DAVPermissionsForRoles: roles] stringsWithFormat: @""]; - - return [SOGoDAVSet davSetWithArray: davPermissions - ofValuesTaggedAs: @"D:privilege"]; -} - -- (SOGoDAVSet *) davSupportedPrivilegeSet -{ - SoClassSecurityInfo *sInfo; - NSArray *allPermissions; - - sInfo = [[self class] soClassSecurityInfo]; - - allPermissions = [[sInfo allDAVPermissions] stringsWithFormat: @""]; - - return [SOGoDAVSet davSetWithArray: allPermissions - ofValuesTaggedAs: @"D:privilege"]; -} - -- (NSArray *) _davAcesFromAclsDictionary: (NSDictionary *) aclsDictionary -{ - NSEnumerator *keys; - NSArray *privileges; - NSMutableString *currentAce; - NSMutableArray *davAces; - NSString *currentKey, *principal; - SOGoDAVSet *privilegesDS; - - davAces = [NSMutableArray array]; - keys = [[aclsDictionary allKeys] objectEnumerator]; - currentKey = [keys nextObject]; - while (currentKey) - { - currentAce = [NSMutableString string]; - if ([currentKey hasPrefix: @":"]) - [currentAce - appendFormat: @"", - [currentKey substringFromIndex: 1]]; - else - { - principal = [NSString stringWithFormat: @"%@users/%@", - [self rootURLInContext: context], - currentKey]; - [currentAce - appendFormat: @"%@", - principal]; - } - - privileges = [[aclsDictionary objectForKey: currentKey] - stringsWithFormat: @""]; - privilegesDS = [SOGoDAVSet davSetWithArray: privileges - ofValuesTaggedAs: @"privilege"]; - [currentAce appendString: [privilegesDS stringForTag: @"{DAV:}grant" - rawName: @"grant" - inContext: nil prefixes: nil]]; - [davAces addObject: currentAce]; - currentKey = [keys nextObject]; - } - - return davAces; -} - -- (void) _appendRolesForPseudoPrincipals: (NSMutableDictionary *) aclsDictionary - withClassSecurityInfo: (SoClassSecurityInfo *) sInfo -{ - NSArray *perms; - - perms = [sInfo DAVPermissionsForRole: SoRole_Owner]; - if ([perms count]) - [aclsDictionary setObject: perms forKey: @":owner"]; - perms = [sInfo DAVPermissionsForRole: SoRole_Authenticated]; - if ([perms count]) - [aclsDictionary setObject: perms forKey: @":authenticated"]; - perms = [sInfo DAVPermissionsForRole: SoRole_Anonymous]; - if ([perms count]) - [aclsDictionary setObject: perms forKey: @":unauthenticated"]; -} - -- (SOGoDAVSet *) davAcl -{ - NSArray *roles; - NSEnumerator *uids; - NSMutableDictionary *aclsDictionary; - NSString *currentUID; - SoClassSecurityInfo *sInfo; - - aclsDictionary = [NSMutableDictionary dictionary]; - uids = [[self aclUsers] objectEnumerator]; - sInfo = [[self class] soClassSecurityInfo]; - - currentUID = [uids nextObject]; - while (currentUID) - { - roles = [self aclsForUser: currentUID]; - [aclsDictionary setObject: [sInfo DAVPermissionsForRoles: roles] - forKey: currentUID]; - currentUID = [uids nextObject]; - } - [self _appendRolesForPseudoPrincipals: aclsDictionary - withClassSecurityInfo: sInfo]; - - return [SOGoDAVSet davSetWithArray: - [self _davAcesFromAclsDictionary: aclsDictionary] - ofValuesTaggedAs: @"D:ace"]; -} - /* end of properties */ - (BOOL) doesRetainContainer @@ -472,6 +199,7 @@ static NSDictionary *reportMap = nil; nameInContainer = nil; container = nil; owner = nil; + webdavAclManager = [[self class] webdavAclManager]; } return self; @@ -614,16 +342,14 @@ static NSDictionary *reportMap = nil; { id obj; SOGoCache *cache; - NSString *objcMethod; + NSString *objcMethod, *httpMethod; cache = [SOGoCache sharedCache]; obj = [cache objectNamed: lookupName inContainer: self]; if (!obj) { - obj = [[self soClass] lookupKey: lookupName inContext: localContext]; - if (obj) - [obj bindToObject: self inContext: localContext]; - else + httpMethod = [[localContext request] method]; + if ([httpMethod isEqualToString: @"REPORT"]) { objcMethod = [self _reportSelector: lookupName]; if (objcMethod) @@ -634,6 +360,12 @@ static NSDictionary *reportMap = nil; [obj autorelease]; } } + else + { + obj = [[self soClass] lookupKey: lookupName inContext: localContext]; + if (obj) + [obj bindToObject: self inContext: localContext]; + } if (obj) [cache registerObject: obj withName: lookupName inContainer: self]; @@ -652,10 +384,10 @@ static NSDictionary *reportMap = nil; return [container lookupUserFolder]; } -- (SOGoGroupsFolder *) lookupGroupsFolder -{ - return [[self lookupUserFolder] lookupGroupsFolder]; -} +// - (SOGoGroupsFolder *) lookupGroupsFolder +// { +// return [[self lookupUserFolder] lookupGroupsFolder]; +// } - (void) sleep { @@ -686,6 +418,316 @@ static NSDictionary *reportMap = nil; return [self nameInContainer]; } +/* DAV ACL properties */ +- (SOGoWebDAVValue *) davOwner +{ + NSDictionary *ownerHREF; + NSString *usersUrl; + + usersUrl = [NSString stringWithFormat: @"%@%@/", + [[WOApplication application] davURL], owner]; + ownerHREF = davElementWithContent (@"href", @"DAV:", usersUrl); + + return [davElementWithContent (@"owner", @"DAV:", ownerHREF) + asWebDAVValue]; +} + +- (SOGoWebDAVValue *) davAclRestrictions +{ + NSArray *restrictions; + + restrictions = [NSArray arrayWithObjects: + davElement (@"grant-only", @"DAV:"), + davElement (@"no-invert", @"DAV:"), + nil]; + + return [davElementWithContent (@"acl-restrictions", @"DAV:", restrictions) + asWebDAVValue]; +} + +- (SOGoWebDAVValue *) davPrincipalCollectionSet +{ + NSString *usersUrl; + NSDictionary *collectionHREF; + + /* WOApplication has no support for the DAV methods we define here so we + use the user's principal object as a reference */ + usersUrl = [NSString stringWithFormat: @"%@%@/", + [[WOApplication application] davURL], owner]; + collectionHREF = davElementWithContent (@"href", @"DAV:", usersUrl); + + return [davElementWithContent (@"principal-collection-set", + @"DAV:", + [NSArray arrayWithObject: collectionHREF]) + asWebDAVValue]; +} + +- (NSArray *) _davPrivilegesFromRoles: (NSArray *) roles +{ + NSEnumerator *privileges; + NSDictionary *privilege; + NSMutableArray *davPrivileges; + + davPrivileges = [NSMutableArray array]; + + privileges = [[webdavAclManager davPermissionsForRoles: roles + onObject: self] objectEnumerator]; + while ((privilege = [privileges nextObject])) + [davPrivileges addObject: davElementWithContent (@"privilege", @"DAV:", + privilege)]; + + return davPrivileges; +} + +- (SOGoWebDAVValue *) davCurrentUserPrivilegeSet +{ + NSArray *userRoles; + + userRoles = [[context activeUser] rolesForObject: self inContext: context]; + + return [davElementWithContent (@"current-user-privilege-set", + @"DAV:", + [self _davPrivilegesFromRoles: userRoles]) + asWebDAVValue]; +} + +- (SOGoWebDAVValue *) davSupportedPrivilegeSet +{ + return [davElementWithContent (@"supported-privilege-set", + @"DAV:", + [webdavAclManager treeAsWebDAVValue]) + asWebDAVValue]; +} + +#warning this method has probably some code shared with its pseudo principal equivalent +- (void) _fillAces: (NSMutableArray *) aces + withRolesForUID: (NSString *) currentUID +{ + NSMutableArray *currentAce; + NSArray *roles; + NSDictionary *currentGrant, *userHREF; + NSString *principalURL; + + currentAce = [NSMutableArray new]; + roles = [[SOGoUser userWithLogin: currentUID roles: nil] + rolesForObject: self + inContext: context]; + if ([roles count]) + { + principalURL = [NSString stringWithFormat: @"%@%@/", + [[WOApplication application] davURL], + currentUID]; + userHREF = davElementWithContent (@"href", @"DAV:", principalURL); + [currentAce addObject: davElementWithContent (@"principal", @"DAV:", + userHREF)]; + currentGrant + = davElementWithContent (@"grant", @"DAV:", + [self _davPrivilegesFromRoles: roles]); + [currentAce addObject: currentGrant]; + [aces addObject: davElementWithContent (@"ace", @"DAV:", currentAce)]; + [currentAce release]; + } +} + +- (void) _fillAcesWithRolesForPseudoPrincipals: (NSMutableArray *) aces +{ + NSArray *roles, *currentAce; + NSDictionary *principal, *currentGrant; + SOGoUser *user; + +// DAV:self, DAV:property(owner), DAV:authenticated + user = [context activeUser]; + roles = [user rolesForObject: self inContext: context]; + if ([roles count]) + { + principal = davElement (@"self", @"DAV:"); + currentGrant + = davElementWithContent (@"grant", @"DAV:", + [self _davPrivilegesFromRoles: roles]); + currentAce = [NSArray arrayWithObjects: + davElementWithContent (@"principal", @"DAV:", + principal), + currentGrant, nil]; + [aces addObject: davElementWithContent (@"ace", @"DAV:", currentAce)]; + } + + user = [SOGoUser userWithLogin: [self ownerInContext: context] roles: nil]; + roles = [user rolesForObject: self inContext: context]; + if ([roles count]) + { + principal = davElementWithContent (@"property", @"DAV:", + davElement (@"owner", @"DAV:")); + currentGrant + = davElementWithContent (@"grant", @"DAV:", + [self _davPrivilegesFromRoles: roles]); + currentAce = [NSArray arrayWithObjects: + davElementWithContent (@"principal", @"DAV:", + principal), + currentGrant, nil]; + [aces addObject: davElementWithContent (@"ace", @"DAV:", currentAce)]; + } + + roles = [self aclsForUser: [self defaultUserID]]; + if ([roles count]) + { + principal = davElement (@"authenticated", @"DAV:"); + currentGrant + = davElementWithContent (@"grant", @"DAV:", + [self _davPrivilegesFromRoles: roles]); + currentAce = [NSArray arrayWithObjects: + davElementWithContent (@"principal", @"DAV:", + principal), + currentGrant, nil]; + [aces addObject: davElementWithContent (@"ace", @"DAV:", currentAce)]; + } +} + +- (SOGoWebDAVValue *) davAcl +{ + NSEnumerator *uids; + NSMutableArray *aces; + NSString *currentUID; + + aces = [NSMutableArray array]; + + [self _fillAcesWithRolesForPseudoPrincipals: aces]; + uids = [[self aclUsers] objectEnumerator]; + while ((currentUID = [uids nextObject])) + [self _fillAces: aces withRolesForUID: currentUID]; + + return [davElementWithContent (@"acl", @"DAV:", aces) + asWebDAVValue]; +} + +#warning all REPORT method should be standardized... +- (NSDictionary *) _formalizePrincipalMatchResponse: (NSArray *) hrefs +{ + NSDictionary *multiStatus; + NSEnumerator *hrefList; + NSString *currentHref; + NSMutableArray *responses; + NSArray *responseElements; + + responses = [NSMutableArray new]; + + hrefList = [hrefs objectEnumerator]; + while ((currentHref = [hrefList nextObject])) + { + responseElements + = [NSArray arrayWithObjects: davElementWithContent (@"href", @"DAV:", + currentHref), + davElementWithContent (@"status", @"DAV:", + @"HTTP/1.1 200 OK"), + nil]; + [responses addObject: davElementWithContent (@"response", @"DAV:", + responseElements)]; + } + + multiStatus = davElementWithContent (@"multistatus", @"DAV:", responses); + [responses release]; + + return multiStatus; +} + +- (NSDictionary *) _handlePrincipalMatchSelf +{ + NSString *davURL, *userLogin; + NSArray *principalURL; + + davURL = [[WOApplication application] davURL]; + userLogin = [[context activeUser] login]; + principalURL + = [NSArray arrayWithObject: [NSString stringWithFormat: @"%@%@/", davURL, + userLogin]]; + return [self _formalizePrincipalMatchResponse: principalURL]; +} + +- (void) _fillArrayWithPrincipalsOwnedBySelf: (NSMutableArray *) hrefs +{ + NSString *url; + NSArray *roles; + + roles = [[context activeUser] rolesForObject: self inContext: context]; + if ([roles containsObject: SoRole_Owner]) + { + url = [[self davURL] absoluteString]; + [hrefs addObject: url]; + } +} + +- (NSDictionary *) + _handlePrincipalMatchPrincipalProperty: (id ) child +{ + NSMutableArray *hrefs; + NSDictionary *response; + + hrefs = [NSMutableArray new]; + [self _fillArrayWithPrincipalsOwnedBySelf: hrefs]; + + response = [self _formalizePrincipalMatchResponse: hrefs]; + [hrefs release]; + + return response; +} + +- (NSDictionary *) _handlePrincipalMatchReport: (id ) document +{ + NSDictionary *response; + id documentElement, queryChild; + NSArray *children; + NSString *queryTag; + + documentElement = [document documentElement]; + children = [self domNode: documentElement + getChildNodesByType: DOM_ELEMENT_NODE]; + if ([children count] == 1) + { + queryChild = [children objectAtIndex: 0]; + queryTag = [queryChild tagName]; + if ([queryTag isEqualToString: @"self"]) + response = [self _handlePrincipalMatchSelf]; + else if ([queryTag isEqualToString: @"principal-property"]) + response = [self _handlePrincipalMatchPrincipalProperty: queryChild]; + else + response = [NSException exceptionWithHTTPStatus: 400 + reason: @"Query element must be either " + @" '{DAV:}principal-property' or '{DAV:}self'"]; + } + else + response = [NSException exceptionWithHTTPStatus: 400 + reason: @"Query must have one element:" + @" '{DAV:}principal-property' or '{DAV:}self'"]; + + return response; +} + +- (WOResponse *) davPrincipalMatch: (WOContext *) localContext +{ + WOResponse *r; + id document; + NSDictionary *xmlResponse; + + r = [context response]; + + document = [[context request] contentAsDOMDocument]; + xmlResponse = [self _handlePrincipalMatchReport: document]; + if ([xmlResponse isKindOfClass: [NSException class]]) + r = (WOResponse *) xmlResponse; + else + { + [r setStatus: 207]; + [r setContentEncoding: NSUTF8StringEncoding]; + [r setHeader: @"text/xml; charset=\"utf-8\"" forKey: @"content-type"]; + [r setHeader: @"no-cache" forKey: @"pragma"]; + [r setHeader: @"no-cache" forKey: @"cache-control"]; + [r appendContentString: + @"\r\n"]; + [r appendContentString: [xmlResponse asWebDavStringWithNamespaces: nil]]; + } + + return r; +} + /* actions */ - (id) DELETEAction: (id) _ctx @@ -763,7 +805,8 @@ static NSDictionary *reportMap = nil; if ([rq isSoWebDAVRequest]) { cType = [rq headerForKey: @"content-type"]; - if ([cType isEqualToString: @"application/xml"]) + if ([cType hasPrefix: @"application/xml"] + || [cType hasPrefix: @"text/xml"]) { document = [rq contentAsDOMDocument]; command = [[self _parseXMLCommand: document] davMethodToObjC]; @@ -1188,7 +1231,8 @@ static NSDictionary *reportMap = nil; /* description */ -- (void)appendAttributesToDescription:(NSMutableString *)_ms { +- (void) appendAttributesToDescription: (NSMutableString *) _ms +{ if (nameInContainer) [_ms appendFormat:@" name=%@", nameInContainer]; if (container) @@ -1196,7 +1240,8 @@ static NSDictionary *reportMap = nil; container, [container valueForKey:@"nameInContainer"]]; } -- (NSString *)description { +- (NSString *) description +{ NSMutableString *ms; ms = [NSMutableString stringWithCapacity:64]; @@ -1227,12 +1272,6 @@ static NSDictionary *reportMap = nil; } /* dav acls */ -- (NSArray *) davNamespaces -{ - return [NSArray arrayWithObject: - @"urn:inverse:params:xml:ns:inverse-dav"]; -} - - (NSString *) davRecordForUser: (NSString *) user { NSMutableString *userRecord; @@ -1443,11 +1482,12 @@ static NSDictionary *reportMap = nil; return exception; } -- (NSArray *) davSupportedReportSet +- (SOGoWebDAVValue *) davSupportedReportSet { + NSDictionary *currentValue; NSEnumerator *reportKeys; NSMutableArray *reportSet; - NSString *currentKey, *currentValue; + NSString *currentKey; reportSet = [NSMutableArray array]; @@ -1455,13 +1495,37 @@ static NSDictionary *reportMap = nil; while ((currentKey = [reportKeys nextObject])) if ([self _reportSelector: currentKey]) { - currentValue = [[currentKey asDavInvocation] - keysWithFormat: @"<%{method} xmlns=\"%{ns}\"/>"]; - [reportSet addObject: [SoWebDAVValue valueForObject: currentValue - attributes: nil]]; + currentValue = [currentKey asDavInvocation]; + [reportSet addObject: davElementWithContent(@"report", + @"DAV:", + currentValue)]; } - return [SOGoDAVSet davSetWithArray: reportSet ofValuesTaggedAs: @"report"]; + return [davElementWithContent (@"supported-report-set", @"DAV:", reportSet) + asWebDAVValue]; } @end /* SOGoObject */ + +@implementation SOGoObject (SOGoDomHelpers) + +- (NSArray *) domNode: (id ) node + getChildNodesByType: (DOMNodeType ) type +{ + NSMutableArray *nodes; + id currentChild; + + nodes = [NSMutableArray array]; + + currentChild = [node firstChild]; + while (currentChild) + { + if ([currentChild nodeType] == type) + [nodes addObject: currentChild]; + currentChild = [currentChild nextSibling]; + } + + return nodes; +} + +@end diff --git a/SoObjects/SOGo/SOGoWebDAVAclManager.h b/SoObjects/SOGo/SOGoWebDAVAclManager.h new file mode 100644 index 000000000..18c4c49de --- /dev/null +++ b/SoObjects/SOGo/SOGoWebDAVAclManager.h @@ -0,0 +1,53 @@ +/* SOGoWebDAVAclManager.h - this file is part of SOGo + * + * Copyright (C) 2008 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 SOGOWEBDAVACLMANAGER_H +#define SOGOWEBDAVACLMANAGER_H + +#import + +@class NSDictionary; +@class NSMutableDictionary; +@class NSString; + +@class SOGoObject; +@class SOGoUser; +@class SOGoWebDAVValue; + +@interface SOGoWebDAVAclManager : NSObject +{ + NSMutableDictionary *aclTree; +} + +- (void) registerDAVPermission: (NSDictionary *) davPermission + abstract: (BOOL) abstract + withEquivalent: (NSString *) sogoPermission + asChildOf: (NSDictionary *) otherDAVPermission; + +- (NSArray *) davPermissionsForRoles: (NSArray *) roles + onObject: (SOGoObject *) object; + +- (SOGoWebDAVValue *) treeAsWebDAVValue; + +@end + +#endif /* SOGOWEBDAVACLMANAGER_H */ diff --git a/SoObjects/SOGo/SOGoWebDAVAclManager.m b/SoObjects/SOGo/SOGoWebDAVAclManager.m new file mode 100644 index 000000000..ad576d710 --- /dev/null +++ b/SoObjects/SOGo/SOGoWebDAVAclManager.m @@ -0,0 +1,262 @@ +/* SOGoWebDAVAclManager.m - this file is part of SOGo + * + * Copyright (C) 2008 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 "NSDictionary+Utilities.h" +#import "NSObject+DAV.h" +#import "SOGoObject.h" +#import "SOGoUser.h" +#import "SOGoWebDAVValue.h" + +#import "SOGoWebDAVAclManager.h" + +static NSNumber *yesObject = nil; + +@interface SoClass (SOGoDAVPermissions) + +- (BOOL) userRoles: (NSArray *) userRoles + havePermission: (NSString *) permission; + +@end + +@implementation SoClass (SOGoDAVPermissions) + +- (BOOL) userRoles: (NSArray *) userRoles + havePermission: (NSString *) permission +{ + BOOL result; + SoClass *currentClass; + NSArray *roles; + + result = NO; + + currentClass = self; + while (!result && currentClass) + { + roles = [[currentClass soClassSecurityInfo] + defaultRolesForPermission: permission]; + if ([roles firstObjectCommonWithArray: userRoles]) + { + NSLog (@"matched '%@': %@", permission, roles); + result = YES; + } + else + currentClass = [currentClass soSuperClass]; + } + + return result; +} + +@end + +@implementation SOGoWebDAVAclManager + ++ (void) initialize +{ + if (!yesObject) + { + yesObject = [NSNumber numberWithBool: YES]; + [yesObject retain]; + } +} + +- (id) init +{ + if ((self = [super init])) + { + aclTree = [NSMutableDictionary new]; + [self registerDAVPermission: davElement (@"all", @"DAV:") + abstract: YES + withEquivalent: nil + asChildOf: nil]; + } + + return self; +} + +- (void) dealloc +{ + [aclTree release]; + [super dealloc]; +} + +- (void) _registerChild: (NSMutableDictionary *) newEntry + of: (NSDictionary *) parentPermission +{ + NSString *identifier; + NSMutableDictionary *parentEntry; + NSMutableArray *children; + + identifier = [parentPermission keysWithFormat: @"{%{ns}}%{method}"]; + parentEntry = [aclTree objectForKey: identifier]; + if (!parentEntry) + [self warnWithFormat: @"parent entry '%@' does not exist in DAV" + @" permissions table", identifier]; + children = [parentEntry objectForKey: @"children"]; + if (!children) + { + children = [NSMutableArray new]; + [parentEntry setObject: children forKey: @"children"]; + [children release]; + } + [children addObject: newEntry]; + [newEntry setObject: parentEntry forKey: @"parent"]; +} + +- (void) registerDAVPermission: (NSDictionary *) davPermission + abstract: (BOOL) abstract + withEquivalent: (NSString *) sogoPermission + asChildOf: (NSDictionary *) otherDAVPermission +{ + NSMutableDictionary *newEntry; + NSString *identifier; + + newEntry = [NSMutableDictionary new]; + identifier = [davPermission keysWithFormat: @"{%{ns}}%{method}"]; + if ([aclTree objectForKey: identifier]) + [self warnWithFormat: + @"entry '%@' already exists in DAV permissions table", + identifier]; + [aclTree setObject: newEntry forKey: identifier]; + [newEntry setObject: davPermission forKey: @"permission"]; + if (abstract) + [newEntry setObject: yesObject forKey: @"abstract"]; + if (sogoPermission) + [newEntry setObject: sogoPermission forKey: @"equivalent"]; + + if (otherDAVPermission) + [self _registerChild: newEntry of: otherDAVPermission]; + + [newEntry release]; +} + +#warning this method should be simplified! +/* We add the permissions that fill those conditions: + - should match the sogo permissions implied by the user roles + If all the child permissions of a permission are included, then this + permission will be included too. Conversely, if a permission is included, + all the child permissions will be included too. */ + +- (BOOL) _fillArray: (NSMutableArray *) davPermissions + withPermission: (NSDictionary *) permission + forUserRoles: (NSArray *) userRoles + withSoClass: (SoClass *) soClass + matchSOGoPerms: (BOOL) matchSOGoPerms +{ + NSString *sogoPermission; + NSDictionary *childPermission; + NSEnumerator *children; + BOOL appended, childrenAppended; + + appended = YES; + if (matchSOGoPerms) + { + sogoPermission = [permission objectForKey: @"equivalent"]; + if (sogoPermission + && [soClass userRoles: userRoles havePermission: sogoPermission]) + { + [davPermissions + addObject: [permission objectForKey: @"permission"]]; + } + else + appended = NO; + } + else + [davPermissions + addObject: [permission objectForKey: @"permission"]]; + + children = [[permission objectForKey: @"children"] objectEnumerator]; + if (children) + { + childrenAppended = YES; + while ((childPermission = [children nextObject])) + childrenAppended = (childrenAppended + && [self _fillArray: davPermissions + withPermission: childPermission + forUserRoles: userRoles + withSoClass: soClass + matchSOGoPerms: (matchSOGoPerms && !appended)]); + if (childrenAppended && !appended) + { + [davPermissions + addObject: [permission objectForKey: @"permission"]]; + appended = YES; + } + } + + return appended; +} + +- (NSArray *) davPermissionsForRoles: (NSArray *) roles + onObject: (SOGoObject *) object +{ + NSMutableArray *davPermissions; + SoClass *soClass; + + davPermissions = [NSMutableArray array]; + soClass = [[object class] soClass]; + [self _fillArray: davPermissions + withPermission: [aclTree objectForKey: @"{DAV:}all"] + forUserRoles: roles + withSoClass: soClass + matchSOGoPerms: YES]; + + return davPermissions; +} + +- (SOGoWebDAVValue *) + _supportedPrivilegeSetFromPermission: (NSDictionary *) perm +{ + NSMutableArray *privilege; + NSEnumerator *children; + NSDictionary *currentPerm; + + privilege = [NSMutableArray array]; + [privilege addObject: + davElementWithContent (@"privilege", + @"DAV:", + [perm objectForKey: @"permission"])]; + if ([[perm objectForKey: @"abstract"] boolValue]) + [privilege addObject: davElement (@"abstract", @"DAV:")]; + children = [[perm objectForKey: @"children"] objectEnumerator]; + while ((currentPerm = [children nextObject])) + [privilege addObject: + [self _supportedPrivilegeSetFromPermission: currentPerm]]; + + return davElementWithContent (@"supported-privilege", + @"DAV:", privilege); +} + +- (SOGoWebDAVValue *) treeAsWebDAVValue +{ + return [self _supportedPrivilegeSetFromPermission: + [aclTree objectForKey: @"{DAV:}all"]]; +} + +@end