2 Copyright (C) 2002-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "SoObject+SoDAV.h"
24 #include "NSException+HTTP.h"
25 #include "SoDAVLockManager.h"
26 #include <NGObjWeb/WOApplication.h>
29 /* informal interface for methods tried by the DAV key implementation */
31 @interface NSObject(SoResourceObject)
34 - (NSString *)displayName;
37 - (unsigned int)contentLength;
38 - (EOGlobalID *)globalID;
41 - (id)baseURLInContext:(id)_ctx;
45 @implementation NSObject(SoObjectSoDAVImp)
47 - (NSArray *)defaultWebDAVPropertyNamesInContext:(id)_ctx {
48 // TODO: check for set in SoClass slots
49 static NSArray *defNames = nil;
50 if (defNames == nil) {
51 defNames = [[[NSUserDefaults standardUserDefaults]
52 arrayForKey:@"SoDefaultWebDAVPropertyNames"]
55 #if 0 /* TODO: check whether this would be better ... */
56 keys = [[self soClassDescription] attributeKeys];
57 [self debugWithFormat:@"using keys from description: %@", keys];
62 - (NSArray *)davComplianceClassesInContext:(id)_ctx {
64 Class 1 is everything in WebDAV which is a MUST.
66 Class 2 adds the LOCK method, the supportedlock property, the lockdiscovery
67 property, the time-out response header and the lock-token request header.
69 In this method we check that by querying the lock manager. If the object
70 has one, it will return class 2, otherwise just class 1.
72 static NSArray *class1 = nil, *class2 = nil;
75 class1 = [[NSArray alloc] initWithObjects:@"1", nil];
77 class2 = [[NSArray alloc] initWithObjects:@"1", @"2", nil];
79 return ([self davLockManagerInContext:_ctx] != nil)
83 - (NSArray *)davAllowedMethodsInContext:(id)_ctx {
84 static NSArray *defMethods = nil;
85 NSMutableArray *allow;
87 if (defMethods == nil) {
88 defMethods = [[[NSUserDefaults standardUserDefaults]
89 arrayForKey:@"SoWebDAVDefaultAllowMethods"]
93 allow = [NSMutableArray arrayWithCapacity:16];
94 if (defMethods) [allow addObjectsFromArray:defMethods];
96 if ([self respondsToSelector:@selector(performWebDAVQuery:inContext:)]) {
97 [allow addObject:@"PROPFIND"];
98 [allow addObject:@"SEARCH"];
100 if ([self respondsToSelector:
101 @selector(davSetProperties:removePropertiesNamed:)])
102 [allow addObject:@"PROPPATCH"];
109 - (BOOL)davIsCollection {
112 if ([self respondsToSelector:@selector(isCollection)])
113 return [self isCollection];
114 if ([(v = [self valueForKey:@"NSFileType"]) isNotNull]) {
115 if ([v isEqualToString:NSFileTypeDirectory])
120 if ([[self toManyRelationshipKeys] count] > 0)
122 if ([[self toOneRelationshipKeys] count] > 0)
127 - (BOOL)davIsFolder {
128 return [self davIsCollection];
131 - (BOOL)davHasSubFolders {
136 if (![self davIsCollection]) return NO;
137 ctx = [[WOApplication application] context];
139 e = [self davChildKeysInContext:ctx];
140 while ((childName = [e nextObject])) {
141 if ([[self lookupName:childName inContext:ctx acquire:NO] davIsFolder])
147 - (BOOL)davDenySubFolders {
148 return [self davIsCollection] ? NO : YES;
151 - (unsigned int)davChildCount {
155 if (![self davIsCollection]) return 0;
156 e = [self davChildKeysInContext:[[WOApplication application] context]];
157 for (i = 0; [e nextObject]; i++)
161 - (unsigned int)davObjectCount {
167 if (![self davIsCollection]) return 0;
169 ctx = [[WOApplication application] context];
171 e = [self davChildKeysInContext:ctx];
172 while ((childName = [e nextObject]) != nil) {
173 if (![[self lookupName:childName inContext:ctx acquire:NO]davIsCollection])
178 - (unsigned int)davVisibleCount {
179 return [self davObjectCount];
182 - (BOOL)davIsHidden {
187 if ([self respondsToSelector:@selector(globalID)])
188 return [self globalID];
189 return [self davURL];
195 - (BOOL)davIsStructuredDocument {
202 if ([self respondsToSelector:@selector(baseURLInContext:)]) {
203 url = [self baseURLInContext:[[WOApplication application] context]];
205 else if ([self respondsToSelector:@selector(baseURL)]) {
206 [self logWithFormat:@"object does not respond to baseURLInContext:?"];
207 url = [self baseURL];
210 [self warnWithFormat:@"unable to calculate davURL for this object !"];
214 [self warnWithFormat:@"got no davURL for this object !"];
219 - (NSDate *)davLastModified {
221 if ((v = [self valueForKey:NSFileModificationDate])) return v;
222 return [NSDate date];
225 - (NSDate *)davCreationDate {
227 if ((v = [self valueForKey:@"NSFileCreationDate"])) return v;
228 if ((v = [self valueForKey:NSFileModificationDate])) return v;
232 - (NSString *)davContentType {
233 if ([self davIsFolder]) {
234 //return @"x-directory/webdav"; /* this is taken from Nautilus */
235 return @"httpd/unix-directory"; /* this is returned by Apache */
238 return @"application/octet-stream";
241 - (id)davContentLength {
243 if ((v = [self valueForKey:NSFileSize])) return v;
244 if ([self respondsToSelector:@selector(contentLength)])
245 return [NSNumber numberWithUnsignedInt:[self contentLength]];
248 - (NSString *)davDisplayName {
251 if ([self respondsToSelector:@selector(displayName)])
252 return [self displayName];
253 #if COCOA_Foundation_LIBRARY
254 NS_DURING /* handle query for unbound key is easily triggered ... */
255 if ((v = [self valueForKey:@"NSFileSubject"])) ;
256 else if ((v = [self valueForKey:@"NSFileName"])) ;
257 else if ((v = [self valueForKey:@"NSFilePath"])) ;
262 if ((v = [self valueForKey:@"NSFileSubject"])) return v;
263 if ((v = [self valueForKey:@"NSFileName"])) return v;
264 if ((v = [self valueForKey:@"NSFilePath"])) return [v lastPathComponent];
266 if ([self respondsToSelector:@selector(path)])
267 return [[self path] lastPathComponent];
271 - (NSString *)davResourceType {
272 if ([self davIsCollection])
273 return @"collection";
277 - (NSString *)davContentClass {
278 /* this doesn't return something really useful, override if necessary ! */
279 return ([self davIsFolder])
280 ? @"urn:content-classes:folder"
281 : @"urn:content-classes:item";
284 - (BOOL)davIsExecutable {
290 - (SoDAVLockManager *)davLockManagerInContext:(id)_ctx {
291 return [SoDAVLockManager sharedLockManager];
294 @end /* NSObject(SoObjectSoDAV) */
296 @interface WOCoreApplication(Resources)
297 + (NSString *)findNGObjWebResource:(NSString *)_name ofType:(NSString *)_ext;
300 @implementation NSObject(SoObjectDAVMaps)
302 + (id)defaultWebDAVAttributeMap {
303 static NSDictionary *defMap = nil;
307 path = [WOApplication findNGObjWebResource:@"DAVPropMap" ofType:@"plist"];
309 defMap = [[NSDictionary alloc] initWithContentsOfFile:path];
314 - (id)davAttributeMapInContext:(id)_ctx {
315 /* default is: do map some DAV properties, pass through anything else */
316 return [[self class] defaultWebDAVAttributeMap];
319 @end /* NSObject(SoObjectDAVMaps) */
321 #include <NGObjWeb/WOApplication.h>
322 #include <NGObjWeb/WORequestHandler.h>
324 @implementation WOCoreApplication(WebDAV)
326 - (BOOL)davIsCollection {
329 - (BOOL)davHasSubFolders {
333 return [self davURL];
336 return [self baseURL];
338 - (NSDate *)davLastModified {
339 return [NSDate date];
341 - (NSDate *)davCreationDate {
344 - (NSString *)davContentType {
347 - (id)davContentLength {
350 - (NSString *)davDisplayName {
354 @end /* WOCoreApplication(WebDAV) */
356 @implementation WOApplication(WebDAV)
358 - (NSString *)davDisplayName {
362 @end /* WOApplication(WebDAV) */
364 @implementation WORequestHandler(WebDAV)
366 - (BOOL)davIsCollection {
369 - (BOOL)davHasSubFolders {
374 return [self davURL];
377 - (NSDate *)davLastModified {
378 return [NSDate date];
380 - (NSDate *)davCreationDate {
384 - (NSString *)davContentType {
388 - (id)davContentLength {
392 @end /* WORequestHandler(WebDAV) */
394 #include "SoControlPanel.h"
396 @implementation SoControlPanel(WebDAV)
398 - (BOOL)davIsCollection {
401 - (BOOL)davHasSubFolders {
406 return [self davURL];
409 - (NSDate *)davLastModified {
410 return [NSDate date];
412 - (NSDate *)davCreationDate {
416 - (id)davContentLength {
420 @end /* SoControlPanel(WebDAV) */
422 @implementation NSObject(DavOperations)
424 - (NSException *)davSetProperties:(NSDictionary *)_setProps
425 removePropertiesNamed:(NSArray *)_delProps
428 return [NSException exceptionWithHTTPStatus:405 /* not allowed */
429 reason:@"this object cannot edit object properties "
433 - (id)davCreateObject:(NSString *)_name
434 properties:(NSDictionary *)_props
437 return [NSException exceptionWithHTTPStatus:405 /* not allowed */
438 reason:@"this object cannot create child objects "
442 - (NSException *)davCreateCollection:(NSString *)_name inContext:(id)_ctx {
443 return [NSException exceptionWithHTTPStatus:405 /* not allowed */
444 reason:@"this object cannot create subcollections "
448 - (NSException *)davMoveToTargetObject:(id)_target newName:(NSString *)_name
451 return [NSException exceptionWithHTTPStatus:405 /* not allowed */
452 reason:@"this object cannot be moved via WebDAV"];
455 - (NSException *)davCopyToTargetObject:(id)_target newName:(NSString *)_name
458 return [NSException exceptionWithHTTPStatus:405 /* not allowed */
459 reason:@"this object cannot be copied via WebDAV"];
462 @end /* NSObject(DavOperations) */