]> err.no Git - sope/blob - sope-appserver/NGObjWeb/WebDAV/SoObject+SoDAV.m
synced with latest gstep-make process
[sope] / sope-appserver / NGObjWeb / WebDAV / SoObject+SoDAV.m
1 /*
2   Copyright (C) 2002-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21
22 #include "SoObject+SoDAV.h"
23 #include "SoObject.h"
24 #include "NSException+HTTP.h"
25 #include "SoDAVLockManager.h"
26 #include <NGObjWeb/WOApplication.h>
27 #include "common.h"
28
29 /* informal interface for methods tried by the DAV key implementation */
30
31 @interface NSObject(SoResourceObject)
32
33 - (BOOL)isCollection;
34 - (NSString *)displayName;
35 - (NSString *)path;
36
37 - (unsigned int)contentLength;
38 - (EOGlobalID *)globalID;
39
40 - (id)baseURL;
41 - (id)baseURLInContext:(id)_ctx;
42
43 @end
44
45 @implementation NSObject(SoObjectSoDAVImp)
46
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"]
53                                  copy];
54   }
55 #if 0 /* TODO: check whether this would be better ... */
56   keys = [[self soClassDescription] attributeKeys];
57   [self debugWithFormat:@"using keys from description: %@", keys];
58 #endif
59   return defNames;
60 }
61
62 - (NSArray *)davComplianceClassesInContext:(id)_ctx {
63   /*
64     Class 1 is everything in WebDAV which is a MUST.
65     
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.
68     
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.
71   */
72   static NSArray *class1 = nil, *class2 = nil;
73   
74   if (class1 == nil)
75     class1 = [[NSArray alloc] initWithObjects:@"1", nil];
76   if (class2 == nil)
77     class2 = [[NSArray alloc] initWithObjects:@"1", @"2", nil];
78   
79   return ([self davLockManagerInContext:_ctx] != nil)
80     ? class2 : class1;
81 }
82
83 - (NSArray *)davAllowedMethodsInContext:(id)_ctx {
84   static NSArray *defMethods = nil;
85   NSMutableArray *allow;
86   
87   if (defMethods == nil) {
88     defMethods = [[[NSUserDefaults standardUserDefaults] 
89                                    arrayForKey:@"SoWebDAVDefaultAllowMethods"] 
90                                    copy];
91   }
92   
93   allow = [NSMutableArray arrayWithCapacity:16];
94   if (defMethods) [allow addObjectsFromArray:defMethods];
95   
96   if ([self respondsToSelector:@selector(performWebDAVQuery:inContext:)]) {
97     [allow addObject:@"PROPFIND"];
98     [allow addObject:@"SEARCH"];
99   }
100   if ([self respondsToSelector:
101               @selector(davSetProperties:removePropertiesNamed:)])
102     [allow addObject:@"PROPPATCH"];
103   
104   return allow;
105 }
106
107 /* attributes */
108
109 - (BOOL)davIsCollection {
110   id v;
111   
112   if ([self respondsToSelector:@selector(isCollection)])
113     return [self isCollection];
114   if ([(v = [self valueForKey:@"NSFileType"]) isNotNull]) {
115     if ([v isEqualToString:NSFileTypeDirectory])
116       return YES;
117     else
118       return NO;
119   }
120   if ([[self toManyRelationshipKeys] count] > 0)
121     return YES;
122   if ([[self toOneRelationshipKeys] count] > 0)
123     return YES;
124   return NO;
125 }
126
127 - (BOOL)davIsFolder {
128   return [self davIsCollection];
129 }
130
131 - (BOOL)davHasSubFolders {
132   NSEnumerator *e;
133   NSString *childName;
134   id       ctx;
135   
136   if (![self davIsCollection]) return NO;
137   ctx = [[WOApplication application] context];
138   
139   e = [self davChildKeysInContext:ctx];
140   while ((childName = [e nextObject])) {
141     if ([[self lookupName:childName inContext:ctx acquire:NO] davIsFolder])
142       return YES;
143   }
144   return NO;
145 }
146
147 - (BOOL)davDenySubFolders {
148   return [self davIsCollection] ? NO : YES;
149 }
150
151 - (unsigned int)davChildCount {
152   NSEnumerator *e;
153   unsigned int i;
154   
155   if (![self davIsCollection]) return 0;
156   e = [self davChildKeysInContext:[[WOApplication application] context]];
157   for (i = 0; [e nextObject]; i++)
158     ;
159   return i;
160 }
161 - (unsigned int)davObjectCount {
162   NSEnumerator *e;
163   unsigned int i;
164   NSString     *childName;
165   WOContext    *ctx;
166   
167   if (![self davIsCollection]) return 0;
168   
169   ctx = [[WOApplication application] context];
170   i = 0;
171   e = [self davChildKeysInContext:ctx];
172   while ((childName = [e nextObject]) != nil) {
173     if (![[self lookupName:childName inContext:ctx acquire:NO]davIsCollection])
174       i++;
175   }
176   return i;
177 }
178 - (unsigned int)davVisibleCount {
179   return [self davObjectCount];
180 }
181
182 - (BOOL)davIsHidden {
183   return NO;
184 }
185
186 - (id)davUid {
187   if ([self respondsToSelector:@selector(globalID)])
188     return [self globalID];
189   return [self davURL];
190 }
191 - (id)davEntityTag {
192   return nil;
193 }
194
195 - (BOOL)davIsStructuredDocument {
196   return NO;
197 }
198
199 - (id)davURL {
200   id url;
201   
202   if ([self respondsToSelector:@selector(baseURLInContext:)]) {
203     url = [self baseURLInContext:[[WOApplication application] context]];
204   }
205   else if ([self respondsToSelector:@selector(baseURL)]) {
206     [self logWithFormat:@"object does not respond to baseURLInContext:?"];
207     url = [self baseURL];
208   }
209   else {
210     [self warnWithFormat:@"unable to calculate davURL for this object !"];
211     url = nil;
212   }
213   if (url == nil)
214     [self warnWithFormat:@"got no davURL for this object !"];
215   
216   return url;
217 }
218
219 - (NSDate *)davLastModified {
220   id v;
221   if ((v = [self valueForKey:NSFileModificationDate])) return v;
222   return [NSDate date];
223 }
224
225 - (NSDate *)davCreationDate {
226   id v;
227   if ((v = [self valueForKey:@"NSFileCreationDate"]))  return v;
228   if ((v = [self valueForKey:NSFileModificationDate])) return v;
229   return nil;
230 }
231
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 */
236   }
237   
238   return @"application/octet-stream";
239 }
240
241 - (id)davContentLength {
242   id v;
243   if ((v = [self valueForKey:NSFileSize])) return v;
244   if ([self respondsToSelector:@selector(contentLength)])
245     return [NSNumber numberWithUnsignedInt:[self contentLength]];
246   return 0;
247 }
248 - (NSString *)davDisplayName {
249   id v = nil;
250   
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"])) ;
258   NS_HANDLER
259     v = nil;
260   NS_ENDHANDLER;
261 #else
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];
265 #endif
266   if ([self respondsToSelector:@selector(path)])
267     return [[self path] lastPathComponent];
268   return nil;
269 }
270
271 - (NSString *)davResourceType {
272   if ([self davIsCollection])
273     return @"collection";
274   return nil;
275 }
276
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";
282 }
283
284 - (BOOL)davIsExecutable {
285   return NO;
286 }
287
288 /* lock manager */
289
290 - (SoDAVLockManager *)davLockManagerInContext:(id)_ctx {
291   return [SoDAVLockManager sharedLockManager];
292 }
293
294 @end /* NSObject(SoObjectSoDAV) */
295
296 @interface WOCoreApplication(Resources)
297 + (NSString *)findNGObjWebResource:(NSString *)_name ofType:(NSString *)_ext;
298 @end
299
300 @implementation NSObject(SoObjectDAVMaps)
301
302 + (id)defaultWebDAVAttributeMap {
303   static NSDictionary *defMap = nil;
304   if (defMap == nil) {
305     NSString *path;
306     
307     path = [WOApplication findNGObjWebResource:@"DAVPropMap" ofType:@"plist"];
308     if (path != nil)
309       defMap = [[NSDictionary alloc] initWithContentsOfFile:path];
310   }
311   return defMap;
312 }
313
314 - (id)davAttributeMapInContext:(id)_ctx {
315   /* default is: do map some DAV properties, pass through anything else */
316   return [[self class] defaultWebDAVAttributeMap];
317 }
318
319 @end /* NSObject(SoObjectDAVMaps) */
320
321 #include <NGObjWeb/WOApplication.h>
322 #include <NGObjWeb/WORequestHandler.h>
323
324 @implementation WOCoreApplication(WebDAV)
325
326 - (BOOL)davIsCollection {
327   return YES;
328 }
329 - (BOOL)davHasSubFolders {
330   return YES;
331 }
332 - (id)davUid {
333   return [self davURL];
334 }
335 - (id)davURL {
336   return [self baseURL];
337 }
338 - (NSDate *)davLastModified {
339   return [NSDate date];
340 }
341 - (NSDate *)davCreationDate {
342   return nil;
343 }
344 - (NSString *)davContentType {
345   return @"text/html";
346 }
347 - (id)davContentLength {
348   return 0;
349 }
350 - (NSString *)davDisplayName {
351   return @"ROOT";
352 }
353
354 @end /* WOCoreApplication(WebDAV) */
355
356 @implementation WOApplication(WebDAV)
357
358 - (NSString *)davDisplayName {
359   return [self name];
360 }
361
362 @end /* WOApplication(WebDAV) */
363
364 @implementation WORequestHandler(WebDAV)
365
366 - (BOOL)davIsCollection {
367   return YES;
368 }
369 - (BOOL)davHasSubFolders {
370   return YES;
371 }
372
373 - (id)davUid {
374   return [self davURL];
375 }
376
377 - (NSDate *)davLastModified {
378   return [NSDate date];
379 }
380 - (NSDate *)davCreationDate {
381   return nil;
382 }
383
384 - (NSString *)davContentType {
385   return @"text/html";
386 }
387
388 - (id)davContentLength {
389   return 0;
390 }
391
392 @end /* WORequestHandler(WebDAV) */
393
394 #include "SoControlPanel.h"
395
396 @implementation SoControlPanel(WebDAV)
397
398 - (BOOL)davIsCollection {
399   return YES;
400 }
401 - (BOOL)davHasSubFolders {
402   return YES;
403 }
404
405 - (id)davUid {
406   return [self davURL];
407 }
408
409 - (NSDate *)davLastModified {
410   return [NSDate date];
411 }
412 - (NSDate *)davCreationDate {
413   return nil;
414 }
415
416 - (id)davContentLength {
417   return 0;
418 }
419
420 @end /* SoControlPanel(WebDAV) */
421
422 @implementation NSObject(DavOperations)
423
424 - (NSException *)davSetProperties:(NSDictionary *)_setProps
425   removePropertiesNamed:(NSArray *)_delProps
426   inContext:(id)_ctx
427 {
428   return [NSException exceptionWithHTTPStatus:405 /* not allowed */
429                       reason:@"this object cannot edit object properties "
430                       @"via WebDAV"];
431 }
432
433 - (id)davCreateObject:(NSString *)_name
434   properties:(NSDictionary *)_props
435   inContext:(id)_ctx
436 {
437   return [NSException exceptionWithHTTPStatus:405 /* not allowed */
438                       reason:@"this object cannot create child objects "
439                       @"via WebDAV"];
440 }
441
442 - (NSException *)davCreateCollection:(NSString *)_name inContext:(id)_ctx {
443   return [NSException exceptionWithHTTPStatus:405 /* not allowed */
444                       reason:@"this object cannot create subcollections "
445                       @"via WebDAV"];
446 }
447
448 - (NSException *)davMoveToTargetObject:(id)_target newName:(NSString *)_name
449   inContext:(id)_ctx
450 {
451   return [NSException exceptionWithHTTPStatus:405 /* not allowed */
452                       reason:@"this object cannot be moved via WebDAV"];
453 }
454
455 - (NSException *)davCopyToTargetObject:(id)_target newName:(NSString *)_name
456   inContext:(id)_ctx
457 {
458   return [NSException exceptionWithHTTPStatus:405 /* not allowed */
459                       reason:@"this object cannot be copied via WebDAV"];
460 }
461
462 @end /* NSObject(DavOperations) */