2 Copyright (C) 2004-2005 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo 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 OGo 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 OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 #import <Foundation/NSArray.h>
26 #import <Foundation/NSDate.h>
27 #import <Foundation/NSDictionary.h>
28 #import <Foundation/NSException.h>
29 #import <Foundation/NSKeyValueCoding.h>
30 #import <Foundation/NSURL.h>
32 #import <NGObjWeb/SoObject.h>
33 #import <NGObjWeb/SoObject+SoDAV.h>
34 #import <NGObjWeb/SoSelectorInvocation.h>
35 #import <NGObjWeb/WOContext+SoObjects.h>
36 #import <NGExtensions/NSNull+misc.h>
37 #import <NGExtensions/NSObject+Logs.h>
38 #import <EOControl/EOQualifier.h>
39 #import <GDLAccess/EOAdaptorChannel.h>
40 #import <GDLContentStore/GCSFolderManager.h>
41 #import <GDLContentStore/GCSFolder.h>
42 #import <GDLContentStore/GCSFolderType.h>
43 #import <SaxObjC/XMLNamespaces.h>
45 #import "NSArray+Utilities.h"
46 #import "NSString+Utilities.h"
48 #import "SOGoPermissions.h"
51 #import "SOGoFolder.h"
53 static NSString *defaultUserID = @"<default>";
55 @implementation SOGoFolder
59 return [super version] + 0 /* v0 */;
64 NSAssert2([super version] == 0,
65 @"invalid superclass (%@) version %i !",
66 NSStringFromClass([self superclass]), [super version]);
69 + (NSString *) globallyUniqueObjectId
72 4C08AE1A-A808-11D8-AC5A-000393BBAFF6
73 SOGo-Web-28273-18283-288182
74 printf( "%x", *(int *) &f);
77 static int sequence = 0;
78 static float rndm = 0;
82 { /* break if we fork ;-) */
87 f = [[NSDate date] timeIntervalSince1970];
88 return [NSString stringWithFormat:@"%0X-%0X-%0X-%0X",
89 pid, *(int *)&f, sequence++, random];
94 if ((self = [super init]))
98 aclCache = [NSMutableDictionary new];
119 - (void) setOCSPath: (NSString *) _path
121 if ([ocsPath isEqualToString:_path])
125 [self warnWithFormat:@"GCS path is already set! '%@'", _path];
127 ASSIGNCOPY(ocsPath, _path);
130 - (NSString *) ocsPath
135 - (GCSFolderManager *) folderManager
137 static GCSFolderManager *folderManager = nil;
140 folderManager = [GCSFolderManager defaultFolderManager];
142 return folderManager;
145 - (GCSFolder *) ocsFolderForPath: (NSString *) _path
147 return [[self folderManager] folderAtPath: _path];
150 - (BOOL) folderIsMandatory
152 [self subclassResponsibility: _cmd];
157 - (GCSFolder *) ocsFolder
164 ocsFolder = [self ocsFolderForPath: [self ocsPath]];
165 userLogin = [[context activeUser] login];
167 && [userLogin isEqualToString: [self ownerInContext: context]]
168 && [self folderIsMandatory]
170 ocsFolder = [self ocsFolderForPath: [self ocsPath]];
174 if ([ocsFolder isNotNull])
182 - (NSString *) folderType
191 result = [[self folderManager] createFolderOfType: [self folderType]
194 return (result == nil);
197 - (NSException *) delete
199 return [[self folderManager] deleteFolderAtPath: ocsPath];
202 - (NSArray *) fetchContentObjectNames
204 NSArray *fields, *records;
206 fields = [NSArray arrayWithObject: @"c_name"];
207 records = [[self ocsFolder] fetchFields:fields matchingQualifier:nil];
208 if (![records isNotNull])
210 [self errorWithFormat: @"(%s): fetch failed!", __PRETTY_FUNCTION__];
213 if ([records isKindOfClass: [NSException class]])
215 return [records objectsForKey: @"c_name"];
218 - (BOOL) nameExistsInFolder: (NSString *) objectName
220 NSArray *fields, *records;
221 EOQualifier *qualifier;
224 = [EOQualifier qualifierWithQualifierFormat:
225 [NSString stringWithFormat: @"c_name='%@'", objectName]];
227 fields = [NSArray arrayWithObject: @"c_name"];
228 records = [[self ocsFolder] fetchFields: fields
229 matchingQualifier: qualifier];
231 && ![records isKindOfClass:[NSException class]]
232 && [records count] > 0);
235 - (NSDictionary *) fetchContentStringsAndNamesOfAllObjects
239 files = [[self ocsFolder] fetchContentsOfAllFiles];
240 if (![files isNotNull])
242 [self errorWithFormat:@"(%s): fetch failed!", __PRETTY_FUNCTION__];
245 if ([files isKindOfClass:[NSException class]])
252 - (NSString *) defaultFilenameExtension
255 Override to add an extension to a filename
257 Note: be careful with that, needs to be consistent with object lookup!
262 - (NSArray *) davResourceType
264 NSArray *rType, *groupDavCollection;
266 if ([self respondsToSelector: @selector (groupDavResourceType)])
269 = [NSArray arrayWithObjects: [self groupDavResourceType],
270 XMLNS_GROUPDAV, nil];
271 rType = [NSArray arrayWithObjects: @"collection", groupDavCollection,
275 rType = [NSArray arrayWithObject: @"collection"];
280 - (NSString *) davContentType
282 return @"httpd/unix-directory";
285 - (NSArray *) toOneRelationshipKeys
287 /* toOneRelationshipKeys are the 'files' contained in a folder */
290 NSString *name, *ext;
294 names = [self fetchContentObjectNames];
295 count = [names count];
296 ext = [self defaultFilenameExtension];
297 if (count && [ext length] > 0)
299 ma = [NSMutableArray arrayWithCapacity: count];
300 for (i = 0; i < count; i++)
302 name = [names objectAtIndex: i];
303 r = [name rangeOfString: @"."];
305 name = [NSMutableString stringWithFormat: @"%@.%@", name, ext];
306 [ma addObject: name];
315 /* acls as a container */
317 - (NSArray *) aclUsersForObjectAtPath: (NSArray *) objectPathArray;
319 EOQualifier *qualifier;
323 qs = [NSString stringWithFormat: @"c_object = '/%@'",
324 [objectPathArray componentsJoinedByString: @"/"]];
325 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
326 records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier];
328 return [records valueForKey: @"c_uid"];
331 - (NSArray *) _fetchAclsForUser: (NSString *) uid
332 forObjectAtPath: (NSString *) objectPath
334 EOQualifier *qualifier;
336 NSMutableArray *acls;
339 qs = [NSString stringWithFormat: @"(c_object = '/%@') AND (c_uid = '%@')",
341 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
342 records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier];
344 acls = [NSMutableArray array];
345 if ([records count] > 0)
347 [acls addObject: SOGoRole_AuthorizedSubscriber];
348 [acls addObjectsFromArray: [records valueForKey: @"c_role"]];
354 - (void) _cacheRoles: (NSArray *) roles
355 forUser: (NSString *) uid
356 forObjectAtPath: (NSString *) objectPath
358 NSMutableDictionary *aclsForObject;
360 aclsForObject = [aclCache objectForKey: objectPath];
363 aclsForObject = [NSMutableDictionary dictionary];
364 [aclCache setObject: aclsForObject
368 [aclsForObject setObject: roles forKey: uid];
370 [aclsForObject removeObjectForKey: uid];
373 - (NSArray *) aclsForUser: (NSString *) uid
374 forObjectAtPath: (NSArray *) objectPathArray
377 NSString *objectPath;
378 NSDictionary *aclsForObject;
380 objectPath = [objectPathArray componentsJoinedByString: @"/"];
381 aclsForObject = [aclCache objectForKey: objectPath];
383 acls = [aclsForObject objectForKey: uid];
388 acls = [self _fetchAclsForUser: uid forObjectAtPath: objectPath];
389 [self _cacheRoles: acls forUser: uid forObjectAtPath: objectPath];
392 if (!([acls count] || [uid isEqualToString: defaultUserID]))
393 acls = [self aclsForUser: defaultUserID
394 forObjectAtPath: objectPathArray];
399 - (void) removeAclsForUsers: (NSArray *) users
400 forObjectAtPath: (NSArray *) objectPathArray
402 EOQualifier *qualifier;
403 NSString *uids, *qs, *objectPath;
404 NSMutableDictionary *aclsForObject;
406 if ([users count] > 0)
408 objectPath = [objectPathArray componentsJoinedByString: @"/"];
409 aclsForObject = [aclCache objectForKey: objectPath];
411 [aclsForObject removeObjectsForKeys: users];
412 uids = [users componentsJoinedByString: @"') OR (c_uid = '"];
414 stringWithFormat: @"(c_object = '/%@') AND ((c_uid = '%@'))",
416 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
417 [[self ocsFolder] deleteAclMatchingQualifier: qualifier];
421 - (void) _commitRoles: (NSArray *) roles
422 forUID: (NSString *) uid
423 forObject: (NSString *) objectPath
425 EOAdaptorChannel *channel;
427 NSEnumerator *userRoles;
428 NSString *SQL, *currentRole;
430 folder = [self ocsFolder];
431 channel = [folder acquireAclChannel];
432 userRoles = [roles objectEnumerator];
433 currentRole = [userRoles nextObject];
436 SQL = [NSString stringWithFormat: @"INSERT INTO %@"
437 @" (c_object, c_uid, c_role)"
438 @" VALUES ('/%@', '%@', '%@')",
439 [folder aclTableName],
440 objectPath, uid, currentRole];
441 [channel evaluateExpressionX: SQL];
442 currentRole = [userRoles nextObject];
445 [folder releaseChannel: channel];
448 - (void) setRoles: (NSArray *) roles
449 forUser: (NSString *) uid
450 forObjectAtPath: (NSArray *) objectPathArray
452 NSString *objectPath;
453 NSMutableArray *newRoles;
455 [self removeAclsForUsers: [NSArray arrayWithObject: uid]
456 forObjectAtPath: objectPathArray];
458 newRoles = [NSMutableArray arrayWithArray: roles];
459 [newRoles removeObject: SOGoRole_AuthorizedSubscriber];
460 [newRoles removeObject: SOGoRole_None];
461 objectPath = [objectPathArray componentsJoinedByString: @"/"];
462 [self _cacheRoles: newRoles forUser: uid
463 forObjectAtPath: objectPath];
464 if (![newRoles count])
465 [newRoles addObject: SOGoRole_None];
467 [self _commitRoles: newRoles forUID: uid forObject: objectPath];
471 - (NSArray *) aclUsers
473 return [self aclUsersForObjectAtPath: [self pathArrayToSoObject]];
476 - (NSArray *) aclsForUser: (NSString *) uid
478 NSMutableArray *acls;
479 NSArray *ownAcls, *containerAcls;
481 acls = [NSMutableArray array];
482 ownAcls = [self aclsForUser: uid
483 forObjectAtPath: [self pathArrayToSoObject]];
484 [acls addObjectsFromArray: ownAcls];
485 if ([container respondsToSelector: @selector (aclsForUser:)])
487 containerAcls = [container aclsForUser: uid];
488 if ([containerAcls count] > 0)
490 if ([containerAcls containsObject: SOGoRole_ObjectReader])
491 [acls addObject: SOGoRole_ObjectViewer];
492 #warning this should be checked
493 if ([containerAcls containsObject: SOGoRole_ObjectEraser])
494 [acls addObject: SOGoRole_ObjectEraser];
501 - (void) setRoles: (NSArray *) roles
502 forUser: (NSString *) uid
504 return [self setRoles: roles
506 forObjectAtPath: [self pathArrayToSoObject]];
509 - (void) removeAclsForUsers: (NSArray *) users
511 return [self removeAclsForUsers: users
512 forObjectAtPath: [self pathArrayToSoObject]];
515 - (NSString *) defaultUserID
517 return defaultUserID;
520 - (NSString *) httpURLForAdvisoryToUser: (NSString *) uid
522 return [[self soURL] absoluteString];
525 - (NSString *) resourceURLForAdvisoryToUser: (NSString *) uid
527 return [[self davURL] absoluteString];
530 - (id) lookupName: (NSString *) lookupName
531 inContext: (id) localContext
532 acquire: (BOOL) acquire
535 NSArray *davNamespaces;
536 NSDictionary *davInvocation;
537 NSString *objcMethod;
539 obj = [super lookupName: lookupName inContext: localContext
543 davNamespaces = [self davNamespaces];
544 if ([davNamespaces count] > 0)
546 davInvocation = [lookupName asDavInvocation];
549 containsObject: [davInvocation objectForKey: @"ns"]])
551 objcMethod = [[davInvocation objectForKey: @"method"]
553 obj = [[SoSelectorInvocation alloc]
554 initWithSelectorNamed:
555 [NSString stringWithFormat: @"%@:", objcMethod]
556 addContextParameter: YES];
567 - (NSArray *) davNamespaces
572 - (BOOL) davIsCollection
574 return [self isFolderish];
579 - (NSString *) outlookFolderClass
581 [self subclassResponsibility: _cmd];
588 - (void) appendAttributesToDescription: (NSMutableString *) _ms
590 [super appendAttributesToDescription:_ms];
592 [_ms appendFormat:@" ocs=%@", [self ocsPath]];
595 - (NSString *) loggingPrefix
597 return [NSString stringWithFormat:@"<0x%08X[%@]:%@>",
598 self, NSStringFromClass([self class]),
599 [self nameInContainer]];
602 @end /* SOGoFolder */