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 "NSString+Utilities.h"
47 #import "SOGoPermissions.h"
50 #import "SOGoFolder.h"
52 static NSString *defaultUserID = @"<default>";
54 @implementation SOGoFolder
58 return [super version] + 0 /* v0 */;
63 NSAssert2([super version] == 0,
64 @"invalid superclass (%@) version %i !",
65 NSStringFromClass([self superclass]), [super version]);
68 + (NSString *) globallyUniqueObjectId
71 4C08AE1A-A808-11D8-AC5A-000393BBAFF6
72 SOGo-Web-28273-18283-288182
73 printf( "%x", *(int *) &f);
76 static int sequence = 0;
77 static float rndm = 0;
81 { /* break if we fork ;-) */
86 f = [[NSDate date] timeIntervalSince1970];
87 return [NSString stringWithFormat:@"%0X-%0X-%0X-%0X",
88 pid, *(int *)&f, sequence++, random];
93 if ((self = [super init]))
97 aclCache = [NSMutableDictionary new];
118 - (void) setOCSPath: (NSString *) _path
120 if ([ocsPath isEqualToString:_path])
124 [self warnWithFormat:@"GCS path is already set! '%@'", _path];
126 ASSIGNCOPY(ocsPath, _path);
129 - (NSString *) ocsPath
134 - (GCSFolderManager *) folderManager
136 static GCSFolderManager *folderManager = nil;
139 folderManager = [GCSFolderManager defaultFolderManager];
141 return folderManager;
144 - (GCSFolder *) ocsFolderForPath: (NSString *) _path
146 return [[self folderManager] folderAtPath: _path];
149 - (BOOL) folderIsMandatory
151 [self subclassResponsibility: _cmd];
156 - (GCSFolder *) ocsFolder
163 ocsFolder = [self ocsFolderForPath: [self ocsPath]];
164 userLogin = [[context activeUser] login];
166 && [userLogin isEqualToString: [self ownerInContext: context]]
167 && [self folderIsMandatory]
169 ocsFolder = [self ocsFolderForPath: [self ocsPath]];
173 if ([ocsFolder isNotNull])
181 - (NSString *) folderType
190 result = [[self folderManager] createFolderOfType: [self folderType]
193 return (result == nil);
196 - (NSException *) delete
198 return [[self folderManager] deleteFolderAtPath: ocsPath];
201 - (NSArray *) fetchContentObjectNames
203 NSArray *fields, *records;
205 fields = [NSArray arrayWithObject: @"c_name"];
206 records = [[self ocsFolder] fetchFields:fields matchingQualifier:nil];
207 if (![records isNotNull])
209 [self errorWithFormat: @"(%s): fetch failed!", __PRETTY_FUNCTION__];
212 if ([records isKindOfClass: [NSException class]])
214 return [records valueForKey: @"c_name"];
217 - (BOOL) nameExistsInFolder: (NSString *) objectName
219 NSArray *fields, *records;
220 EOQualifier *qualifier;
223 = [EOQualifier qualifierWithQualifierFormat:
224 [NSString stringWithFormat: @"c_name='%@'", objectName]];
226 fields = [NSArray arrayWithObject: @"c_name"];
227 records = [[self ocsFolder] fetchFields: fields
228 matchingQualifier: qualifier];
230 && ![records isKindOfClass:[NSException class]]
231 && [records count] > 0);
234 - (NSDictionary *) fetchContentStringsAndNamesOfAllObjects
238 files = [[self ocsFolder] fetchContentsOfAllFiles];
239 if (![files isNotNull])
241 [self errorWithFormat:@"(%s): fetch failed!", __PRETTY_FUNCTION__];
244 if ([files isKindOfClass:[NSException class]])
251 - (NSString *) defaultFilenameExtension
254 Override to add an extension to a filename
256 Note: be careful with that, needs to be consistent with object lookup!
261 - (NSArray *) davResourceType
263 NSArray *rType, *groupDavCollection;
265 if ([self respondsToSelector: @selector (groupDavResourceType)])
268 = [NSArray arrayWithObjects: [self groupDavResourceType],
269 XMLNS_GROUPDAV, nil];
270 rType = [NSArray arrayWithObjects: @"collection", groupDavCollection,
274 rType = [NSArray arrayWithObject: @"collection"];
279 - (NSString *) davContentType
281 return @"httpd/unix-directory";
284 - (NSArray *) toOneRelationshipKeys
286 /* toOneRelationshipKeys are the 'files' contained in a folder */
289 NSString *name, *ext;
293 names = [self fetchContentObjectNames];
294 count = [names count];
295 ext = [self defaultFilenameExtension];
296 if (count && [ext length] > 0)
298 ma = [NSMutableArray arrayWithCapacity: count];
299 for (i = 0; i < count; i++)
301 name = [names objectAtIndex: i];
302 r = [name rangeOfString: @"."];
304 name = [NSMutableString stringWithFormat: @"%@.%@", name, ext];
305 [ma addObject: name];
314 /* acls as a container */
316 - (NSArray *) aclUsersForObjectAtPath: (NSArray *) objectPathArray;
318 EOQualifier *qualifier;
322 qs = [NSString stringWithFormat: @"c_object = '/%@'",
323 [objectPathArray componentsJoinedByString: @"/"]];
324 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
325 records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier];
327 return [records valueForKey: @"c_uid"];
330 - (NSArray *) _fetchAclsForUser: (NSString *) uid
331 forObjectAtPath: (NSString *) objectPath
333 EOQualifier *qualifier;
335 NSMutableArray *acls;
338 qs = [NSString stringWithFormat: @"(c_object = '/%@') AND (c_uid = '%@')",
340 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
341 records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier];
343 acls = [NSMutableArray array];
344 if ([records count] > 0)
346 [acls addObject: SOGoRole_AuthorizedSubscriber];
347 [acls addObjectsFromArray: [records valueForKey: @"c_role"]];
353 - (void) _cacheRoles: (NSArray *) roles
354 forUser: (NSString *) uid
355 forObjectAtPath: (NSString *) objectPath
357 NSMutableDictionary *aclsForObject;
359 aclsForObject = [aclCache objectForKey: objectPath];
362 aclsForObject = [NSMutableDictionary dictionary];
363 [aclCache setObject: aclsForObject
367 [aclsForObject setObject: roles forKey: uid];
369 [aclsForObject removeObjectForKey: uid];
372 - (NSArray *) aclsForUser: (NSString *) uid
373 forObjectAtPath: (NSArray *) objectPathArray
376 NSString *objectPath;
377 NSDictionary *aclsForObject;
379 objectPath = [objectPathArray componentsJoinedByString: @"/"];
380 aclsForObject = [aclCache objectForKey: objectPath];
382 acls = [aclsForObject objectForKey: uid];
387 acls = [self _fetchAclsForUser: uid forObjectAtPath: objectPath];
388 [self _cacheRoles: acls forUser: uid forObjectAtPath: objectPath];
391 if (!([acls count] || [uid isEqualToString: defaultUserID]))
392 acls = [self aclsForUser: defaultUserID
393 forObjectAtPath: objectPathArray];
398 - (void) removeAclsForUsers: (NSArray *) users
399 forObjectAtPath: (NSArray *) objectPathArray
401 EOQualifier *qualifier;
402 NSString *uids, *qs, *objectPath;
403 NSMutableDictionary *aclsForObject;
405 if ([users count] > 0)
407 objectPath = [objectPathArray componentsJoinedByString: @"/"];
408 aclsForObject = [aclCache objectForKey: objectPath];
410 [aclsForObject removeObjectsForKeys: users];
411 uids = [users componentsJoinedByString: @"') OR (c_uid = '"];
413 stringWithFormat: @"(c_object = '/%@') AND ((c_uid = '%@'))",
415 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
416 [[self ocsFolder] deleteAclMatchingQualifier: qualifier];
420 - (void) _commitRoles: (NSArray *) roles
421 forUID: (NSString *) uid
422 forObject: (NSString *) objectPath
424 EOAdaptorChannel *channel;
426 NSEnumerator *userRoles;
427 NSString *SQL, *currentRole;
429 folder = [self ocsFolder];
430 channel = [folder acquireAclChannel];
431 userRoles = [roles objectEnumerator];
432 currentRole = [userRoles nextObject];
435 SQL = [NSString stringWithFormat: @"INSERT INTO %@"
436 @" (c_object, c_uid, c_role)"
437 @" VALUES ('/%@', '%@', '%@')",
438 [folder aclTableName],
439 objectPath, uid, currentRole];
440 [channel evaluateExpressionX: SQL];
441 currentRole = [userRoles nextObject];
444 [folder releaseChannel: channel];
447 - (void) setRoles: (NSArray *) roles
448 forUser: (NSString *) uid
449 forObjectAtPath: (NSArray *) objectPathArray
451 NSString *objectPath;
452 NSMutableArray *newRoles;
454 [self removeAclsForUsers: [NSArray arrayWithObject: uid]
455 forObjectAtPath: objectPathArray];
457 newRoles = [NSMutableArray arrayWithArray: roles];
458 [newRoles removeObject: SOGoRole_AuthorizedSubscriber];
459 [newRoles removeObject: SOGoRole_None];
460 objectPath = [objectPathArray componentsJoinedByString: @"/"];
461 [self _cacheRoles: newRoles forUser: uid
462 forObjectAtPath: objectPath];
463 if (![newRoles count])
464 [newRoles addObject: SOGoRole_None];
466 [self _commitRoles: newRoles forUID: uid forObject: objectPath];
470 - (NSArray *) aclUsers
472 return [self aclUsersForObjectAtPath: [self pathArrayToSoObject]];
475 - (NSArray *) aclsForUser: (NSString *) uid
477 NSMutableArray *acls;
478 NSArray *ownAcls, *containerAcls;
480 acls = [NSMutableArray array];
481 ownAcls = [self aclsForUser: uid
482 forObjectAtPath: [self pathArrayToSoObject]];
483 [acls addObjectsFromArray: ownAcls];
484 if ([container respondsToSelector: @selector (aclsForUser:)])
486 containerAcls = [container aclsForUser: uid];
487 if ([containerAcls count] > 0)
489 if ([containerAcls containsObject: SOGoRole_ObjectReader])
490 [acls addObject: SOGoRole_ObjectViewer];
491 #warning this should be checked
492 if ([containerAcls containsObject: SOGoRole_ObjectEraser])
493 [acls addObject: SOGoRole_ObjectEraser];
500 - (void) setRoles: (NSArray *) roles
501 forUser: (NSString *) uid
503 return [self setRoles: roles
505 forObjectAtPath: [self pathArrayToSoObject]];
508 - (void) removeAclsForUsers: (NSArray *) users
510 return [self removeAclsForUsers: users
511 forObjectAtPath: [self pathArrayToSoObject]];
514 - (NSString *) defaultUserID
516 return defaultUserID;
519 - (NSString *) httpURLForAdvisoryToUser: (NSString *) uid
521 return [[self soURL] absoluteString];
524 - (NSString *) resourceURLForAdvisoryToUser: (NSString *) uid
526 return [[self davURL] absoluteString];
529 - (id) lookupName: (NSString *) lookupName
530 inContext: (id) localContext
531 acquire: (BOOL) acquire
534 NSArray *davNamespaces;
535 NSDictionary *davInvocation;
536 NSString *objcMethod;
538 obj = [super lookupName: lookupName inContext: localContext
542 davNamespaces = [self davNamespaces];
543 if ([davNamespaces count] > 0)
545 davInvocation = [lookupName asDavInvocation];
548 containsObject: [davInvocation objectForKey: @"ns"]])
550 objcMethod = [[davInvocation objectForKey: @"method"]
552 obj = [[SoSelectorInvocation alloc]
553 initWithSelectorNamed:
554 [NSString stringWithFormat: @"%@:", objcMethod]
555 addContextParameter: YES];
566 - (NSArray *) davNamespaces
571 - (BOOL) davIsCollection
573 return [self isFolderish];
578 - (NSString *) outlookFolderClass
580 [self subclassResponsibility: _cmd];
587 - (void) appendAttributesToDescription: (NSMutableString *) _ms
589 [super appendAttributesToDescription:_ms];
591 [_ms appendFormat:@" ocs=%@", [self ocsPath]];
594 - (NSString *) loggingPrefix
596 return [NSString stringWithFormat:@"<0x%08X[%@]:%@>",
597 self, NSStringFromClass([self class]),
598 [self nameInContainer]];
601 @end /* SOGoFolder */