]> err.no Git - sope/commitdiff
Improved WebDAV support.
authorhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Thu, 4 May 2006 22:19:42 +0000 (22:19 +0000)
committerhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Thu, 4 May 2006 22:19:42 +0000 (22:19 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@1261 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

sope-appserver/NGObjWeb/ChangeLog
sope-appserver/NGObjWeb/SoObjects/SoObjectRequestHandler.m
sope-appserver/NGObjWeb/Version
sope-appserver/NGObjWeb/WEClientCapabilities.m
sope-appserver/NGObjWeb/WebDAV/SoWebDAVRenderer.m

index 4a5399fc14afe35f0531a416f766ab32d867cef6..131e0d7295c7855ab42f492f853c89875283c303 100644 (file)
@@ -1,3 +1,15 @@
+2006-05-05  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.5.231
+       
+       * WebDAV/SoWebDAVRenderer.m: major change: WebDAV properties which got
+         NSNull as their value are now rendered in a 404-propstat element. So
+         if you want to have empty properties delivered, return empty strings.
+       
+       * SoObjects/SoObjectRequestHandler.m: minor code cleanups
+
+       * WEClientCapabilities.m: added support for Office 2003
+
 2006-05-04  Helge Hess  <helge.hess@opengroupware.org>
 
        * v4.5.230
index 38a4d35c9954facbed8c7b3e7ec287b997ccb214..6aa2d0006fe020e92a6d81b9404e210c00d8a4b5 100644 (file)
@@ -227,10 +227,12 @@ static NSString *redirectURISafetySuffix = nil;
   unsigned i, count;
   NSString *m;
   NSArray  *a;
-
+  
   if (rqKeys == nil)
     /* cache set of registered request handlers */
     rqKeys = [[[WOApplication application] registeredRequestHandlerKeys] copy];
+
+  /* check request handler keys */
   
   m = [_rq requestHandlerKey];
   if ([rqKeys containsObject:m]) {
@@ -285,7 +287,7 @@ static NSString *redirectURISafetySuffix = nil;
     if ([self enableZideLookHack])
       p = [self hackZideLookName:p];
     
-    if ([p length] > 0)
+    if ([p isNotEmpty])
       [traversalPath addObject:p];
   }
   
@@ -332,7 +334,7 @@ static NSString *redirectURISafetySuffix = nil;
     /* build traversal path */
     
     traversalPath = [self traversalPathFromRequest:_rq];
-    if (traversalPath)
+    if (traversalPath != nil)
       [_ctx setSoRequestTraversalPath:traversalPath];
     
     /* setup root object */
@@ -496,8 +498,8 @@ static NSString *redirectURISafetySuffix = nil;
 {
   /* split up this big method */
   WOResponse *r;
-  id object;
-  id authenticator;
+  id   object;
+  id   authenticator;
   BOOL doDispatch;
   
   if (debugLogger) {
index 65af81b9f96276327a52ca246af07cbe3b821fba..704a3bc2fc9888d19cc97bab3593e834f481a055 100644 (file)
@@ -1,6 +1,6 @@
 # version file
 
-SUBMINOR_VERSION:=230
+SUBMINOR_VERSION:=231
 
 # v4.5.214 requires libNGExtensions v4.5.179
 # v4.5.122 requires libNGExtensions v4.5.153
index ccf2b97c89df2ace704131c9ed60814d12eb317e..99a50878b5666d13650d399884a823457a836f02 100644 (file)
     /* WebFolder */
     self->browser = WEUA_WebFolder;
   }
+  else if (strstr(ua, "Microsoft Office Protocol Discovery")) {
+    /* Word 2003, treat as WebFolder */
+    self->browser = WEUA_WebFolder;
+  }
   else if (strstr(ua, "curl")) {
     /* curl program */
     self->browser = WEUA_CURL;
@@ -960,6 +964,9 @@ static NSString *WEClientDetectorFormName = @"WEClientDetect";
   
   MacOSX 10.2.1 DAV FS
     WebDAVFS/1.2.1 (01218000) Darwin/6.1 (Power Macintosh)
+
+  MacOSX 10.4.2 DAV FS
+    WebDAVFS/1.4.1 (01418000) Darwin/8.6.0 (Power Macintosh)
   
   Cadaver 0.17.0
     'cadaver/0.17.0 neon/0.12.0-dev'
@@ -1064,4 +1071,7 @@ static NSString *WEClientDetectorFormName = @"WEClientDetect";
 
   WebFolders Win XP SP2
     'Microsoft-WebDAV-MiniRedir/5.1.2600'
+  
+  Word 2003
+    'Microsoft Office Protocol Discovery'
 */
index c4490572486ffd27ab9eaaffae574d803ed80db2..9c5c5c135c620bba8ce4277de202630567247fb7 100644 (file)
@@ -1,5 +1,6 @@
 /*
-  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.
 
@@ -497,6 +498,61 @@ static BOOL         formatOutput = NO;
   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
@@ -507,6 +563,7 @@ static BOOL         formatOutput = NO;
 {
   /* 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;
@@ -539,6 +596,12 @@ static BOOL         formatOutput = NO;
         [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];
@@ -560,11 +623,14 @@ static BOOL         formatOutput = NO;
     [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
@@ -587,90 +653,81 @@ static BOOL         formatOutput = NO;
   }
   
   [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'];
 }
 
@@ -796,7 +853,7 @@ static BOOL         formatOutput = NO;
     [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];