diff --git a/ChangeLog b/ChangeLog index 8f361f562..de528af86 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,56 @@ +2011-11-30 Wolfgang Sourdeau + + * SoObjects/SOGo/SOGoFolder.m + (_expandPropertyResponse:forObject:): set the element in the 404 + bag only if the value is nil to avoid iCal complaining about lack + of support for sharing. + + * SoObjects/Appointments/SOGoCalendarProxy.m (+webdavAclManager): + overriden method. + (-davGroupMemberSet, -setDavGroupMemberSet:): instantiate the + "Calendar" object from the result of -[self lookupUserFolder] + instead of "container", since we might attach proxy objects to + other containers. + + * Main/SOGo+DAV.m (-davPrincipalURL): new DAV getter. + (-davPrincipalSearchPropertySet): added "calendar-user-type", even + though it's a lie. + (-davComplianceClassesInContext:): declare + "calendar-query-extended", "extended-mkcol", + "calendarserver-principal-property-search" as additional classes, + even though it's a lie. + + * SoObjects/Appointments/SOGoUserFolder+Appointments.m + (-davCalendarUserAddressSet): make sure each email address is + reported only once, we also return the user principal in the list + (for iCal). + + * SoObjects/SOGo/SOGoObject.m (-davComplianceClassesInContext:): + declare "calendar-query-extended", "extended-mkcol", + "calendarserver-principal-property-search" as additional calendar + classes, even though it's a lie. + (-davCurrentUserPrincipal): new method. + + * SoObjects/Appointments/SOGoAppointmentFolder.m (-davResourceId): + new DAV getter. + + * SoObjects/SOGo/SOGoUserFolder.m (-davResourceId): new DAV getter. + + * SoObjects/SOGo/SOGoFolder.m (-davPrincipalURL): moved from + SOGoUserFolder. + + * SoObjects/SOGo/WORequest+SOGo.m (-isICal, -isICal4): updated for + iCal 5. + + * SoObjects/Appointments/SOGoAppointmentInboxFolder.m + (-davScheduleDefaultCalendarURL): fixed method to return a + properly formatted XML chunk. + (-displayName): returns nameInContainer. + + * SoObjects/Appointments/SOGoAppointmentFolder.m + (-davCalendarTimeZone): fixed by embedding the VTIMEZONE element + in a VCALENDAR. + 2011-11-29 Wolfgang Sourdeau * OpenChange/MAPIStoreTypes.m (NSObjectFromSPropValue): set the diff --git a/Main/SOGo+DAV.m b/Main/SOGo+DAV.m index 41d4b64b5..66f7f0461 100644 --- a/Main/SOGo+DAV.m +++ b/Main/SOGo+DAV.m @@ -48,6 +48,26 @@ @implementation SOGo (SOGoWebDAVExtensions) +- (NSArray *) davPrincipalURL +{ + NSArray *principalURL; + NSString *classes; + WOContext *context; + + context = [self context]; + if ([[context request] isICal4]) + { + classes = [[self davComplianceClassesInContext: context] + componentsJoinedByString: @", "]; + [[context response] setHeader: classes forKey: @"DAV"]; + } + + principalURL = [NSArray arrayWithObjects: @"href", @"DAV:", @"D", + [self davURLAsString], nil]; + + return [NSArray arrayWithObject: principalURL]; +} + - (WOResponse *) davPrincipalSearchPropertySet: (WOContext *) localContext { static NSDictionary *davResponse = nil; @@ -62,6 +82,7 @@ properties = [NSArray arrayWithObjects: @"calendar-user-type", @"calendar-user-address-set", + @"calendar-user-type", @"displayname", @"first-name", @"last-name", @@ -72,6 +93,7 @@ namespaces = [NSArray arrayWithObjects: XMLNS_CALDAV, XMLNS_CALDAV, + XMLNS_CALDAV, XMLNS_WEBDAV, XMLNS_CalendarServerOrg, XMLNS_CalendarServerOrg, @@ -549,9 +571,15 @@ { newClasses = [[super davComplianceClassesInContext: localContext] mutableCopy]; - selfClasses = [NSArray arrayWithObjects: @"access-control", @"addressbook", - @"calendar-access", @"calendar-auto-schedule", - @"calendar-schedule", @"calendar-proxy", nil]; + selfClasses = [NSArray arrayWithObjects: @"access-control", + @"addressbook", @"calendar-access", + @"calendar-schedule", @"calendar-auto-schedule", + @"calendar-proxy", + + @"calendar-query-extended", + @"extended-mkcol", + @"calendarserver-principal-property-search", + nil]; [newClasses addObjectsFromArray: selfClasses]; } diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 9b250a2ba..4ebcbe489 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -59,6 +59,7 @@ #import #import #import +#import #import #import #import @@ -1542,11 +1543,22 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir { SOGoUser *ownerUser; NSString *ownerTimeZone; + iCalCalendar *tzCal; + iCalTimeZone *tz; + NSString *prodID; ownerUser = [SOGoUser userWithLogin: [self ownerInContext: context]]; ownerTimeZone = [[ownerUser userDefaults] timeZoneName]; - - return [[iCalTimeZone timeZoneForName: ownerTimeZone] versitString]; + tz = [iCalTimeZone timeZoneForName: ownerTimeZone]; + + tzCal = [iCalCalendar groupWithTag: @"vcalendar"]; + [tzCal setVersion: @"2.0"]; + prodID = [NSString stringWithFormat: + @"-//Inverse inc./SOGo %@//EN", SOGoVersion]; + [tzCal setProdID: prodID]; + [tzCal addChild: tz]; + + return [tzCal versitString]; } - (NSException *) setDavCalendarTimeZone: (NSString *) newTimeZone @@ -2037,6 +2049,12 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir return @""; } +- (NSString *) davResourceId +{ + return [NSString stringWithFormat: @"urn:uuid:%@:calendars:%@", + [self ownerInContext: context], [self nameInContainer]]; +} + - (NSArray *) davScheduleCalendarTransparency { const NSString *opacity; diff --git a/SoObjects/Appointments/SOGoAppointmentInboxFolder.m b/SoObjects/Appointments/SOGoAppointmentInboxFolder.m index 33a9cde73..a30242fcf 100644 --- a/SoObjects/Appointments/SOGoAppointmentInboxFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentInboxFolder.m @@ -76,17 +76,17 @@ return nil; } -- (NSArray *) davScheduleDefaultCalendarURL +- (SOGoWebDAVValue *) davScheduleDefaultCalendarURL { - NSArray *response; NSString *personalURL; + NSDictionary *href; personalURL = [NSString stringWithFormat: @"%@personal/", [container davURLAsString]]; - response = [NSArray arrayWithObjects: @"href", XMLNS_WEBDAV, @"D", - personalURL, nil]; + href = davElementWithContent (@"href", XMLNS_WEBDAV, personalURL); - return response; + return [davElementWithContent (@"schedule-default-calendar-URL", XMLNS_CALDAV, href) + asWebDAVValue]; } - (NSArray *) aclsForUser: (NSString *) userID @@ -109,4 +109,9 @@ return acls; } +- (NSString *) displayName +{ + return nameInContainer; +} + @end diff --git a/SoObjects/Appointments/SOGoCalendarProxy.m b/SoObjects/Appointments/SOGoCalendarProxy.m index be6f2c9b8..9d2b22446 100644 --- a/SoObjects/Appointments/SOGoCalendarProxy.m +++ b/SoObjects/Appointments/SOGoCalendarProxy.m @@ -30,12 +30,74 @@ #import #import +#import +#import +#import + #import "SOGoAppointmentFolders.h" #import "SOGoCalendarProxy.h" @implementation SOGoCalendarProxy ++ (SOGoWebDAVAclManager *) webdavAclManager +{ + static SOGoWebDAVAclManager *aclManager = nil; + NSString *nsI; + + if (!aclManager) + { + nsI = @"urn:inverse:params:xml:ns:inverse-dav"; + + aclManager = [SOGoWebDAVAclManager new]; + [aclManager registerDAVPermission: davElement (@"read", XMLNS_WEBDAV) + abstract: YES + withEquivalent: SoPerm_WebDAVAccess + asChildOf: davElement (@"all", XMLNS_WEBDAV)]; + [aclManager + registerDAVPermission: davElement (@"read-current-user-privilege-set", XMLNS_WEBDAV) + abstract: YES + withEquivalent: SoPerm_WebDAVAccess + asChildOf: davElement (@"read", XMLNS_WEBDAV)]; + [aclManager registerDAVPermission: davElement (@"write", XMLNS_WEBDAV) + abstract: YES + withEquivalent: nil + asChildOf: davElement (@"all", XMLNS_WEBDAV)]; + [aclManager registerDAVPermission: davElement (@"bind", XMLNS_WEBDAV) + abstract: NO + withEquivalent: SoPerm_AddDocumentsImagesAndFiles + asChildOf: davElement (@"write", XMLNS_WEBDAV)]; + [aclManager registerDAVPermission: davElement (@"unbind", XMLNS_WEBDAV) + abstract: NO + withEquivalent: SoPerm_DeleteObjects + asChildOf: davElement (@"write", XMLNS_WEBDAV)]; + [aclManager + registerDAVPermission: davElement (@"write-properties", XMLNS_WEBDAV) + abstract: NO + withEquivalent: SoPerm_ChangePermissions /* hackish */ + asChildOf: davElement (@"write", XMLNS_WEBDAV)]; + [aclManager + registerDAVPermission: davElement (@"write-content", XMLNS_WEBDAV) + abstract: NO + withEquivalent: SoPerm_AddDocumentsImagesAndFiles + asChildOf: davElement (@"write", XMLNS_WEBDAV)]; + [aclManager registerDAVPermission: davElement (@"admin", nsI) + abstract: YES + withEquivalent: nil + asChildOf: davElement (@"all", XMLNS_WEBDAV)]; + [aclManager registerDAVPermission: davElement (@"read-acl", XMLNS_WEBDAV) + abstract: YES + withEquivalent: SOGoPerm_ReadAcls + asChildOf: davElement (@"admin", nsI)]; + [aclManager registerDAVPermission: davElement (@"write-acl", XMLNS_WEBDAV) + abstract: YES + withEquivalent: SoPerm_ChangePermissions + asChildOf: davElement (@"admin", nsI)]; + } + + return aclManager; +} + - (id) init { if ((self = [super init])) @@ -78,7 +140,9 @@ appName = [[context request] applicationName]; proxySubscribers - = [[container lookupName: @"Calendar" inContext: context acquire: NO] + = [[[self lookupUserFolder] lookupName: @"Calendar" + inContext: context + acquire: NO] proxySubscribersWithWriteAccess: hasWriteAccess]; max = [proxySubscribers count]; members = [NSMutableArray arrayWithCapacity: max]; @@ -138,18 +202,13 @@ - (NSException *) setDavGroupMemberSet: (NSString *) memberSet { - SOGoUser *ownerUser; - SOGoUserSettings *us; NSMutableArray *addedSubscribers, *removedSubscribers; NSArray *oldProxySubscribers, *newProxySubscribers; - NSString *login; SOGoAppointmentFolders *folders; - login = [self ownerInContext: context]; - ownerUser = [SOGoUser userWithLogin: login roles: nil]; - us = [ownerUser userSettings]; - folders = [container lookupName: @"Calendar" - inContext: context acquire: NO]; + folders = [[self lookupUserFolder] lookupName: @"Calendar" + inContext: context + acquire: NO]; oldProxySubscribers = [folders proxySubscribersWithWriteAccess: hasWriteAccess]; if (!oldProxySubscribers) diff --git a/SoObjects/Appointments/SOGoUserFolder+Appointments.m b/SoObjects/Appointments/SOGoUserFolder+Appointments.m index a7feb2caf..1a32b73cb 100644 --- a/SoObjects/Appointments/SOGoUserFolder+Appointments.m +++ b/SoObjects/Appointments/SOGoUserFolder+Appointments.m @@ -59,21 +59,32 @@ NSArray *tag; NSMutableArray *addresses; NSEnumerator *emails; + NSMutableDictionary *doneEmails; NSString *currentEmail; SOGoUser *ownerUser; addresses = [NSMutableArray array]; + doneEmails = [NSMutableDictionary dictionary]; ownerUser = [SOGoUser userWithLogin: owner]; emails = [[ownerUser allEmails] objectEnumerator]; while ((currentEmail = [emails nextObject])) { - tag = [NSArray arrayWithObjects: @"href", XMLNS_WEBDAV, @"D", - [NSString stringWithFormat: @"mailto:%@", currentEmail], - nil]; - [addresses addObject: tag]; + if (![doneEmails objectForKey: currentEmail]) + { + tag = [NSArray arrayWithObjects: @"href", XMLNS_WEBDAV, @"D", + [NSString stringWithFormat: @"mailto:%@", currentEmail], + nil]; + [addresses addObject: tag]; + [doneEmails setObject: [NSNull null] forKey: currentEmail]; + } } + tag = [NSArray arrayWithObjects: @"href", XMLNS_WEBDAV, @"D", + [NSString stringWithFormat: @"/SOGo/dav/%@/", nameInContainer], + nil]; + [addresses addObjectUniquely: tag]; + return addresses; } diff --git a/SoObjects/SOGo/SOGoFolder.m b/SoObjects/SOGo/SOGoFolder.m index 62b01002f..5587f18b8 100644 --- a/SoObjects/SOGo/SOGoFolder.m +++ b/SoObjects/SOGo/SOGoFolder.m @@ -44,6 +44,7 @@ #import "NSString+Utilities.h" #import "SOGoPermissions.h" #import "SOGoWebDAVAclManager.h" +#import "WORequest+SOGo.h" #import "WOResponse+SOGo.h" #import "SOGoFolder.h" @@ -232,14 +233,16 @@ { comparison = [self _compareByNameInContainer: otherFolder]; if (comparison == NSOrderedSame) - if ([self displayName] == nil) - comparison = NSOrderedAscending; - else if ([otherFolder displayName] == nil) - comparison = NSOrderedDescending; - else - comparison - = [[self displayName] - localizedCaseInsensitiveCompare: [otherFolder displayName]]; + { + if ([self displayName] == nil) + comparison = NSOrderedAscending; + else if ([otherFolder displayName] == nil) + comparison = NSOrderedDescending; + else + comparison + = [[self displayName] + localizedCaseInsensitiveCompare: [otherFolder displayName]]; + } } return comparison; @@ -442,7 +445,7 @@ if (!tagNS) tagNS = XMLNS_WEBDAV; tagName = [childProperty attribute: @"name"]; - if ([childValue count]) + if (childValue) [properties200 addObject: davElementWithContent (tagName, tagNS, childValue)]; @@ -562,4 +565,22 @@ return nil; } +- (NSArray *) davPrincipalURL +{ + NSArray *principalURL; + NSString *classes; + + if ([[context request] isICal4]) + { + classes = [[self davComplianceClassesInContext: context] + componentsJoinedByString: @", "]; + [[context response] setHeader: classes forKey: @"DAV"]; + } + + principalURL = [NSArray arrayWithObjects: @"href", @"DAV:", @"D", + [self davURLAsString], nil]; + + return [NSArray arrayWithObject: principalURL]; +} + @end diff --git a/SoObjects/SOGo/SOGoObject.m b/SoObjects/SOGo/SOGoObject.m index 1e237bc5c..8736cf050 100644 --- a/SoObjects/SOGo/SOGoObject.m +++ b/SoObjects/SOGo/SOGoObject.m @@ -1211,14 +1211,48 @@ /* CalDAV */ if (needCalDAVClasses) { - caldavClasses = [NSArray arrayWithObjects: @"calendar-access", @"calendar-schedule", - @"calendar-auto-schedule", @"calendar-proxy", nil]; + caldavClasses = [NSArray arrayWithObjects: @"calendar-access", + @"calendar-schedule", + @"calendar-auto-schedule", + @"calendar-proxy", + // @"calendarserver-private-events", + // @"calendarserver-private-comments", + // @"calendarserver-sharing", + // @"calendarserver-sharing-no-scheduling", + @"calendar-query-extended", + @"extended-mkcol", + @"calendarserver-principal-property-search", + nil]; [classes addObjectsFromArray: caldavClasses]; } return classes; } +- (SOGoWebDAVValue *) davCurrentUserPrincipal +{ + NSDictionary *userHREF; + NSString *login; + SOGoUser *activeUser; + SOGoWebDAVValue *davCurrentUserPrincipal; + + activeUser = [[self context] activeUser]; + login = [activeUser login]; + if ([login isEqualToString: @"anonymous"]) + davCurrentUserPrincipal = nil; + else + { + userHREF = davElementWithContent (@"href", XMLNS_WEBDAV, [self davURLAsString]); + davCurrentUserPrincipal + = [davElementWithContent (@"current-user-principal", + XMLNS_WEBDAV, + userHREF) + asWebDAVValue]; + } + + return davCurrentUserPrincipal; +} + /* dav acls */ - (NSString *) davRecordForUser: (NSString *) user parameters: (NSArray *) params diff --git a/SoObjects/SOGo/SOGoUserFolder.h b/SoObjects/SOGo/SOGoUserFolder.h index 83b7bbd3b..a51c326f7 100644 --- a/SoObjects/SOGo/SOGoUserFolder.h +++ b/SoObjects/SOGo/SOGoUserFolder.h @@ -55,8 +55,6 @@ - (id) mailAccountsFolder: (NSString *) _key inContext: (WOContext *) _ctx; -- (NSArray *) davPrincipalURL; - - (BOOL) collectionDavKey: (NSString *) key matches: (NSString *) value; diff --git a/SoObjects/SOGo/SOGoUserFolder.m b/SoObjects/SOGo/SOGoUserFolder.m index 1584ef8bb..862525153 100644 --- a/SoObjects/SOGo/SOGoUserFolder.m +++ b/SoObjects/SOGo/SOGoUserFolder.m @@ -635,14 +635,9 @@ getCNForUID: nameInContainer]; } -- (NSArray *) davPrincipalURL +- (NSString *) davResourceId { - NSArray *principalURL; - - principalURL = [NSArray arrayWithObjects: @"href", @"DAV:", @"D", - [self davURLAsString], nil]; - - return [NSArray arrayWithObject: principalURL]; + return [NSString stringWithFormat: @"urn:uuid:%@", nameInContainer]; } - (NSException *) setDavSignature: (NSString *) newSignature @@ -665,5 +660,4 @@ return YES; } - @end /* SOGoUserFolder */ diff --git a/SoObjects/SOGo/WORequest+SOGo.m b/SoObjects/SOGo/WORequest+SOGo.m index 31671a019..c7b6b6f83 100644 --- a/SoObjects/SOGo/WORequest+SOGo.m +++ b/SoObjects/SOGo/WORequest+SOGo.m @@ -131,7 +131,8 @@ - (BOOL) isICal { - return [self isAppleDAVWithSubstring: @"Mac OS X/10."]; + return ([self isAppleDAVWithSubstring: @"Mac OS X/10."] + || [self isAppleDAVWithSubstring: @"CoreDAV/"]); } // @@ -140,8 +141,9 @@ // - (BOOL) isICal4 { - return ([self isAppleDAVWithSubstring: @"iCal/4."] || - [self isAppleDAVWithSubstring: @"iCal/5."]); + return ([self isAppleDAVWithSubstring: @"iCal/4."] + || [self isAppleDAVWithSubstring: @"iCal/5."] + || [self isAppleDAVWithSubstring: @"CoreDAV/"]); } diff --git a/Version b/Version index 09503ebca..9a650549e 100644 --- a/Version +++ b/Version @@ -2,6 +2,6 @@ # This file is included by library makefiles to set the version information # of the executable. -MAJOR_VERSION=2 -MINOR_VERSION=0 -SUBMINOR_VERSION=0 +MAJOR_VERSION=1 +MINOR_VERSION=3 +SUBMINOR_VERSION=10