/*
- Copyright (C) 2000-2005 SKYRIX Software AG
+ Copyright (C) 2000-2006 SKYRIX Software AG
+ Copyright (C) 2006 Helge Hess
This file is part of SOPE.
return stat;
}
+- (void)renderNullProperty:(NSString *)_key
+ toResponse:(WOResponse *)r inContext:(WOContext *)_ctx
+ namesOnly:(BOOL)_namesOnly isBrief:(BOOL)isBrief
+ tagToPrefix:(NSDictionary *)extNameCache
+ nsToPrefix:(NSDictionary *)nsToPrefix
+{
+ NSString *extName;
+
+ extName = [extNameCache objectForKey:_key];
+
+ [r appendContentCharacter:'<'];
+ [r appendContentString:extName];
+ [r appendContentString:@"/>"];
+ if (formatOutput) [r appendContentCharacter:'\n'];
+}
+
+- (void)renderProperty:(NSString *)_key value:(id)value
+ toResponse:(WOResponse *)r inContext:(WOContext *)_ctx
+ namesOnly:(BOOL)_namesOnly
+ tagToPrefix:(NSDictionary *)extNameCache
+ nsToPrefix:(NSDictionary *)nsToPrefix
+{
+ NSString *extName;
+ NSString *s;
+
+ extName = [extNameCache objectForKey:_key];
+
+ if (_namesOnly) {
+ [r appendContentCharacter:'<'];
+ [r appendContentString:extName];
+ [r appendContentString:@"/>"];
+ if (formatOutput) [r appendContentCharacter:'\n'];
+ return;
+ }
+
+ if ([value isKindOfClass:[SoWebDAVValue class]]) {
+ s = [value stringForTag:_key rawName:extName
+ inContext:_ctx prefixes:nsToPrefix];
+ [r appendContentString:s];
+ }
+ else {
+ [r appendContentCharacter:'<'];
+ [r appendContentString:extName];
+ [r appendContentCharacter:'>'];
+
+ s = [self stringForValue:value ofProperty:_key prefixes:nsToPrefix];
+ [r appendContentString:s];
+
+ [r appendContentString:@"</"];
+ [r appendContentString:extName];
+ [r appendContentString:@">"];
+ if (formatOutput) [r appendContentCharacter:'\n'];
+ }
+}
+
- (void)renderSearchResultEntry:(id)entry inContext:(WOContext *)_ctx
namesOnly:(BOOL)_namesOnly
attributes:(NSArray *)_attrs
{
/* Note: the entry is an NSArray in case _namesOnly is requested! */
// TODO: use -valueForKey: to improve NSNull handling ?
+ NSMutableArray *missingProps;
WOResponse *r;
NSEnumerator *keys;
NSString *key;
[self warnWithFormat:@"no key for {DAV:}href in property map !"];
}
}
+ /*
+ TODO: where is this used? It doesn't make a lot of sense since one
+ response can have multiple status values?! One for each
+ property.
+ So: do we actually use this special key anywhere?
+ */
if ((stat = [entry valueForKey:@"{DAV:}status"]) == nil) {
if ((key = [_propMap objectForKey:@"{DAV:}status"]))
stat = [entry valueForKey:key];
[self debugWithFormat:@" href: %@", href];
}
- /* generate */
+ /* start the response */
+
[r appendContentString:@"<D:response>"];
if (formatOutput) [r appendContentCharacter:'\n'];
+
+ /* write the href the response is for */
- if ([href isNotNull]) {
+ if ([href isNotEmpty]) {
[r appendContentString:@"<D:href>"];
/*
TODO: need to find out what is appropriate! While Cadaver and ZideLook
}
[r appendContentString:@"<D:propstat>"];
+
+ if (stat != nil) {
+ [r appendContentString:@"<D:status>"];
+ [r appendContentXMLString:[stat stringValue]];
+ [r appendContentString:@"</D:status>"];
+ }
+
[r appendContentString:@"<D:prop>"];
if (formatOutput) [r appendContentCharacter:'\n'];
- /* now the properties */
-
+ /* first the available properties */
+
+ missingProps = nil;
keys = [_attrs objectEnumerator] ;
- while ((key = [keys nextObject])) {
- NSString *extName;
+ while ((key = [keys nextObject]) != nil) {
NSString *okey;
id value;
+
+ /* determine value */
-#if 0 /* this filter probably doesn't make sense ? */
- /* filter out predefined props */
- if ([key isEqualToString:@"{DAV:}href"]) continue;
- if ([key isEqualToString:@"{DAV:}status"]) continue;
-#endif
-
- extName = [extNameCache objectForKey:key];
-
- if (_namesOnly) {
- [r appendContentCharacter:'<'];
- [r appendContentString:extName];
- [r appendContentString:@"/>"];
- if (formatOutput) [r appendContentCharacter:'\n'];
- continue;
- }
-
- // TODO: we should support property status (eg encode 404 on NSNull)
-
if ((okey = [_propMap objectForKey:key]) == nil)
okey = key;
-
- if ([key isEqualToString:@"{DAV:}href"])
- value = href;
- else
- value = [entry valueForKey:okey];
- if ([value isNotNull]) {
- NSString *s;
-
- if ([value isKindOfClass:[SoWebDAVValue class]]) {
- s = [value stringForTag:key rawName:extName
- inContext:_ctx prefixes:nsToPrefix];
- [r appendContentString:s];
- }
- else {
- [r appendContentCharacter:'<'];
- [r appendContentString:extName];
- [r appendContentCharacter:'>'];
-
- s = [self stringForValue:value ofProperty:key prefixes:nsToPrefix];
- [r appendContentString:s];
-
- [r appendContentString:@"</"];
- [r appendContentString:extName];
- [r appendContentString:@">"];
- if (formatOutput) [r appendContentCharacter:'\n'];
- }
+ value = [key isEqualToString:@"{DAV:}href"]
+ ? href
+ : [entry valueForKey:okey];
+
+ if (![value isNotNull]) {
+ if (missingProps == nil)
+ missingProps = [[NSMutableArray alloc] initWithCapacity:8];
+ [missingProps addObject:key];
continue;
}
- if (!isBrief) {
- /*
- Not sure whether this is correct, do we need to encode null attrs?
- Seems like Evo gets confused on that.
- TODO: probably add a 404 property status for that!
- */
- [r appendContentCharacter:'<'];
- [r appendContentString:extName];
- [r appendContentString:@"/>"];
- if (formatOutput) [r appendContentCharacter:'\n'];
+ /* render */
+
+ [self renderProperty:key value:value
+ toResponse:r inContext:_ctx
+ namesOnly:_namesOnly
+ tagToPrefix:extNameCache nsToPrefix:nsToPrefix];
+ }
+
+ /* next the missing properties unless we are brief */
+
+ if (!isBrief && [missingProps isNotEmpty]) {
+ /* close previous propstat and open a new one */
+ [r appendContentString:@"</D:prop></D:propstat>"];
+ if (formatOutput) [r appendContentCharacter:'\n'];
+
+ [r appendContentString:@"<D:propstat>"];
+ [r appendContentString:
+ @"<D:status>HTTP/1.1 404 Resource Not Found</D:status>"];
+ [r appendContentString:@"<D:prop>"];
+ if (formatOutput) [r appendContentCharacter:'\n'];
+
+ keys = [missingProps objectEnumerator] ;
+ while ((key = [keys nextObject]) != nil) {
+ [self renderNullProperty:key
+ toResponse:r inContext:_ctx
+ namesOnly:_namesOnly isBrief:isBrief
+ tagToPrefix:extNameCache nsToPrefix:nsToPrefix];
}
}
-
+
+ [missingProps release]; missingProps = nil;
+
[r appendContentString:@"</D:prop>"];
if (formatOutput) [r appendContentCharacter:'\n'];
- if (stat != nil) {
- [r appendContentString:@"<D:status>"];
- [r appendContentXMLString:[stat stringValue]];
- [r appendContentString:@"</D:status>"];
- }
+ [r appendContentString:@"</D:propstat>"];
- [r appendContentString:@"</D:propstat></D:response>"];
+
+ /* finish response */
+
+ [r appendContentString:@"</D:response>"];
if (formatOutput) [r appendContentCharacter:'\n'];
}
[self debugWithFormat:@" baseURL: %@", baseURL];
entryCount = 0; /* Note: this will clash with streamed output later */
- while ((entry = [_entries nextObject])) {
+ while ((entry = [_entries nextObject]) != nil) {
[self renderSearchResultEntry:entry inContext:_ctx
namesOnly:_namesOnly attributes:_attrs propertyMap:_propMap
baseURL:baseURL tagToPrefix:extNameCache nsToPrefix:nsToPrefix];