diff --git a/ChangeLog b/ChangeLog index 346874bf2..b93da339b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,19 @@ 2009-06-18 Wolfgang Sourdeau - * SoObjects/SOGo/DOMNode+SOGo.h: new category module that + * SoObjects/SOGo/DOMNode+SOGo.m + (-flatPropertyNameOfSubElements): new method that returns + flattened ({namespace}tag) names of the first direct child + elements. + + * SoObjects/SOGo/SOGoGCSFolder.m (-davSQLFieldsTable): new method + that returns a correspondance table between requested dav + properties and SQL fields required to answer them. + (-parseDAVRequestedProperties:): new method derived from a similar + one in SOGoAppointmentFolder which will return a dictionary of DAV + properties that are requested as well as their corresponding SQL + fields. + + * SoObjects/SOGo/DOMNode+SOGo.[hm]: new category module that implement helper methods for DOM processing. * SoObjects/Appointments/SOGoAppointmentFolder.m diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 2b6ce722d..e1c43ba12 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -37,7 +37,7 @@ #import #import #import -#import +#import #import #import #import @@ -52,6 +52,7 @@ #import #import +#import #import #import #import @@ -1358,7 +1359,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir [filter setObject: textMatch forKey: propName]; } -- (NSDictionary *) _parseCalendarFilter: (id ) filterElement +- (NSDictionary *) _parseCalendarFilter: (DOMElement *) filterElement { NSMutableDictionary *filterData; id parentNode; @@ -1397,65 +1398,6 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir return filterData; } -/* TODO: This method should be generalized to all SOGoGCSFolder-based - classes. */ -- (NSDictionary *) _parseRequestedProperties: (id ) parentNode -{ - NSMutableDictionary *properties; - NSObject *propList, *children; - NSObject *currentChild; - unsigned int count, max, count2, max2; - NSString *flatProperty; - NSString *sqlField; - static NSMutableDictionary *davPropsToSQLFields = nil; - - if (!davPropsToSQLFields) - { - /* This table is meant to match SQL fields to the properties that - requires them. The fields may NOT be processed directly. This list - is not complete but is at least sufficient for processing requests - from Lightning. */ - davPropsToSQLFields = [NSMutableDictionary new]; - [davPropsToSQLFields setObject: @"c_content" - forKey: @"{urn:ietf:params:xml:ns:caldav}calendar-data"]; - [davPropsToSQLFields setObject: @"c_version" - forKey: @"{DAV:}getetag"]; - } - -// NSLog (@"parseRequestProperties: %@", [NSDate date]); - properties = [NSMutableDictionary dictionary]; - - propList = [parentNode getElementsByTagName: @"prop"]; - max = [propList length]; - for (count = 0; count < max; count++) - { - children = [[propList objectAtIndex: count] childNodes]; - max2 = [children length]; - for (count2 = 0; count2 < max2; count2++) - { - currentChild = [children objectAtIndex: count2]; - if ([currentChild conformsToProtocol: @protocol (DOMElement)]) - { - flatProperty = [NSString stringWithFormat: @"{%@}%@", - [currentChild namespaceURI], - [currentChild nodeName]]; - sqlField = [davPropsToSQLFields objectForKey: flatProperty]; - if (sqlField) - [properties setObject: sqlField forKey: flatProperty]; - else - [self errorWithFormat: @"DAV property '%@' not yet supported," - @" response will be incomplete", flatProperty]; - } - } - - // while ([children hasChildNodes]) - // [properties addObject: [children next]]; - } - // NSLog (@"/parseRequestProperties: %@", [NSDate date]); - - return properties; -} - - (NSDictionary *) _makeCyclicFilterFrom: (NSDictionary *) filter { NSMutableDictionary *rc; @@ -1472,10 +1414,10 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir return rc; } -- (NSArray *) _parseCalendarFilters: (id ) parentNode +- (NSArray *) _parseCalendarFilters: (DOMElement *) parentNode { id children; - id node; + DOMElement *element; NSMutableArray *filters; NSDictionary *filter; unsigned int count, max; @@ -1487,8 +1429,8 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir max = [children length]; for (count = 0; count < max; count++) { - node = [children objectAtIndex: count]; - filter = [self _parseCalendarFilter: node]; + element = [children objectAtIndex: count]; + filter = [self _parseCalendarFilter: element]; if (filter) { [filters addObject: filter]; @@ -1667,7 +1609,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir propertiesArray = [[properties allKeys] asPointersOfObjects]; propertiesCount = [properties count]; - NSLog (@"start"); +// NSLog (@"start"); filterList = [filters objectEnumerator]; while ((currentFilter = [filterList nextObject])) { @@ -1681,7 +1623,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir title: [currentFilter objectForKey: @"title"] component: [currentFilter objectForKey: @"name"] additionalFilters: additionalFilters]; - NSLog(@"adding properties"); +// NSLog(@"adding properties"); max = [apts count]; buffer = [NSMutableString stringWithCapacity: max * 512]; for (count = 0; count < max; count++) @@ -1690,20 +1632,37 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir count: propertiesCount withBaseURL: baseURL toBuffer: buffer]; - NSLog(@"done 1"); +// NSLog(@"done 1"); [response appendContentString: buffer]; - NSLog(@"done 2"); +// NSLog(@"done 2"); } - NSLog (@"stop"); +// NSLog (@"stop"); NSZoneFree (NULL, propertiesArray); } +/* This table is meant to match SQL fields to the properties that requires + them. The fields may NOT be processed directly. This list is not complete + but is at least sufficient for processing requests from Lightning. */ +- (NSDictionary *) davSQLFieldsTable +{ + static NSMutableDictionary *davSQLFieldsTable = nil; + + if (!davSQLFieldsTable) + { + davSQLFieldsTable = [[super davSQLFieldsTable] mutableCopy]; + [davSQLFieldsTable setObject: @"c_content" + forKey: @"{" XMLNS_CALDAV @"}calendar-data"]; + } + + return davSQLFieldsTable; +} + - (id) davCalendarQuery: (id) queryContext { WOResponse *r; id document; - id documentElement; + DOMElement *documentElement, *propElement; r = [context response]; [r setStatus: 207]; @@ -1713,11 +1672,14 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir [r setHeader: @"no-cache" forKey: @"cache-control"]; [r appendContentString:@""]; [r appendContentString: @""]; + @" xmlns:C=\"urn:ietf:params:xml:ns:caldav\">"]; document = [[context request] contentAsDOMDocument]; - documentElement = [document documentElement]; - [self _appendComponentProperties: [self _parseRequestedProperties: documentElement] + documentElement = (DOMElement *) [document documentElement]; + propElement = [documentElement firstElementWithTag: @"prop" + inNamespace: XMLNS_WEBDAV]; + + [self _appendComponentProperties: [self parseDAVRequestedProperties: propElement] matchingFilters: [self _parseCalendarFilters: documentElement] toResponse: r]; [r appendContentString:@""]; @@ -1905,7 +1867,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir { WOResponse *r; id document; - id documentElement; + DOMElement *documentElement, *propElement; r = [context response]; [r setStatus: 207]; @@ -1918,8 +1880,11 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir @" xmlns:C=\"urn:ietf:params:xml:ns:caldav\">"]; document = [[context request] contentAsDOMDocument]; - documentElement = [document documentElement]; - [self _appendComponentProperties: [self _parseRequestedProperties: documentElement] + documentElement = (DOMElement *) [document documentElement]; + propElement = [documentElement firstElementWithTag: @"prop" + inNamespace: @"DAV:"]; + + [self _appendComponentProperties: [self parseDAVRequestedProperties: propElement] matchingURLs: [documentElement getElementsByTagName: @"href"] toResponse: r]; [r appendContentString:@""]; diff --git a/SoObjects/SOGo/DAVReportMap.plist b/SoObjects/SOGo/DAVReportMap.plist index acffb2ec4..a3413d406 100644 --- a/SoObjects/SOGo/DAVReportMap.plist +++ b/SoObjects/SOGo/DAVReportMap.plist @@ -14,6 +14,8 @@ "{DAV:}principal-match" = davPrincipalMatch; "{DAV:}principal-property-search" = davPrincipalPropertySearch; "{DAV:}principal-search-property-set" = davPrincipalSearchPropertySet; + "{DAV:}principal-search-property-set" = davPrincipalSearchPropertySet; + "{DAV:}sync-collection" = davSyncCollection; /* Inverse DAV */ "{urn:inverse:params:xml:ns:inverse-dav}collection-query" diff --git a/SoObjects/SOGo/DOMNode+SOGo.h b/SoObjects/SOGo/DOMNode+SOGo.h index a4dee9222..8ba80188c 100644 --- a/SoObjects/SOGo/DOMNode+SOGo.h +++ b/SoObjects/SOGo/DOMNode+SOGo.h @@ -25,15 +25,19 @@ #import -@interface NGDOMNodeWithChildren (SOGoDOMExtensions) < DOMNode > +@class DOMElement; + +@interface NGDOMNodeWithChildren (SOGoDOMExtensions) - (id ) childElementsWithTag: (NSString *) tagName; - (id ) childElementsWithTag: (NSString *) tagName inNamespace: (NSString *) namespace; -- (id ) firstElementWithTag: (NSString *) tagName; -- (id ) firstElementWithTag: (NSString *) tagName - inNamespace: (NSString *) namespace; +- (DOMElement *) firstElementWithTag: (NSString *) tagName; +- (DOMElement *) firstElementWithTag: (NSString *) tagName + inNamespace: (NSString *) namespace; + +- (NSArray *) flatPropertyNameOfSubElements; @end diff --git a/SoObjects/SOGo/DOMNode+SOGo.m b/SoObjects/SOGo/DOMNode+SOGo.m index f959a3945..6fa3514c1 100644 --- a/SoObjects/SOGo/DOMNode+SOGo.m +++ b/SoObjects/SOGo/DOMNode+SOGo.m @@ -59,11 +59,11 @@ return [self childElementsWithTag: tagName inNamespace: nil]; } -- (id ) firstElementWithTag: (NSString *) tagName - inNamespace: (NSString *) namespace +- (DOMElement *) firstElementWithTag: (NSString *) tagName + inNamespace: (NSString *) namespace { id nodes; - id node, currentElement; + DOMElement *node, *currentElement; unsigned int count, max; node = nil; @@ -83,9 +83,36 @@ return node; } -- (id ) firstElementWithTag: (NSString *) tagName +- (DOMElement *) firstElementWithTag: (NSString *) tagName { return [self firstElementWithTag: tagName inNamespace: nil]; } +- (NSArray *) flatPropertyNameOfSubElements +{ + NSMutableArray *propertyNames; + id children; + DOMElement *currentElement; + NSString *property; + unsigned int count, max; + + propertyNames = [NSMutableArray array]; + + children = [self childNodes]; + max = [children length]; + for (count = 0; count < max; count++) + { + currentElement = [children objectAtIndex: count]; + if ([currentElement nodeType] == DOM_ELEMENT_NODE) + { + property = [NSString stringWithFormat: @"{%@}%@", + [currentElement namespaceURI], + [currentElement tagName]]; + [propertyNames addObject: property]; + } + } + + return propertyNames; +} + @end diff --git a/SoObjects/SOGo/GNUmakefile b/SoObjects/SOGo/GNUmakefile index e5e431515..7871ea16b 100644 --- a/SoObjects/SOGo/GNUmakefile +++ b/SoObjects/SOGo/GNUmakefile @@ -55,6 +55,8 @@ SOGo_HEADER_FILES = \ NSDictionary+BSJSONAdditions.h \ NSScanner+BSJSONAdditions.h \ \ + DOMNode+SOGo.h \ + \ WORequest+SOGo.h \ WOContext+SOGo.h @@ -101,6 +103,8 @@ SOGo_OBJC_FILES = \ NSDictionary+BSJSONAdditions.m \ NSScanner+BSJSONAdditions.m \ \ + DOMNode+SOGo.m \ + \ WORequest+SOGo.m \ WOContext+SOGo.m diff --git a/SoObjects/SOGo/SOGoGCSFolder.h b/SoObjects/SOGo/SOGoGCSFolder.h index fb4f7fbc9..425447dcf 100644 --- a/SoObjects/SOGo/SOGoGCSFolder.h +++ b/SoObjects/SOGo/SOGoGCSFolder.h @@ -33,6 +33,8 @@ @class WOContext; @class WOResponse; +@class DOMElement; + /* SOGoGCSFolder @@ -105,6 +107,10 @@ /* advisories */ - (void) sendFolderAdvisoryTemplate: (NSString *) template; +/* DAV */ +- (NSDictionary *) davSQLFieldsTable; +- (NSDictionary *) parseDAVRequestedProperties: (DOMElement *) propElement; + @end #endif /* __SOGo_SOGoGCSFolder_H__ */ diff --git a/SoObjects/SOGo/SOGoGCSFolder.m b/SoObjects/SOGo/SOGoGCSFolder.m index e5f219abf..527509da8 100644 --- a/SoObjects/SOGo/SOGoGCSFolder.m +++ b/SoObjects/SOGo/SOGoGCSFolder.m @@ -40,6 +40,7 @@ #import #import #import +#import #import #import #import @@ -58,6 +59,7 @@ #import "NSObject+DAV.h" #import "NSString+Utilities.h" +#import "DOMNode+SOGo.h" #import "SOGoContentObject.h" #import "SOGoGroup.h" #import "SOGoParentFolder.h" @@ -791,6 +793,55 @@ static NSArray *childRecordFields = nil; inContext: queryContext]; } +- (NSDictionary *) davSQLFieldsTable +{ + static NSMutableDictionary *davSQLFieldsTable = nil; + + if (!davSQLFieldsTable) + { + davSQLFieldsTable = [NSMutableDictionary new]; + [davSQLFieldsTable setObject: @"c_version" forKey: @"{DAV:}getetag"]; + } + + return davSQLFieldsTable; +} + +- (NSDictionary *) _davSQLFieldsForProperties: (NSArray *) properties +{ + NSMutableDictionary *davSQLFields; + NSDictionary *davSQLFieldsTable; + NSString *sqlField, *property; + unsigned int count, max; + + davSQLFieldsTable = [self davSQLFieldsTable]; + + max = [properties count]; + davSQLFields = [NSMutableDictionary dictionaryWithCapacity: max]; + for (count = 0; count < max; count++) + { + property = [properties objectAtIndex: count]; + sqlField = [davSQLFieldsTable objectForKey: property]; + if (sqlField) + [davSQLFields setObject: sqlField forKey: property]; + else + [self errorWithFormat: @"DAV property '%@' has no matching SQL field," + @" response will be incomplete", property]; + } + + return davSQLFields; +} + +- (NSDictionary *) parseDAVRequestedProperties: (DOMElement *) propElement +{ + NSArray *properties; + NSDictionary *sqlFieldsTable; + + properties = [propElement flatPropertyNameOfSubElements]; + sqlFieldsTable = [self _davSQLFieldsForProperties: properties]; + + return sqlFieldsTable; +} + /* handling acls from quick tables */ - (void) initializeQuickTablesAclsInContext: (WOContext *) localContext {