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/NSDictionary.h>
27 #import <Foundation/NSException.h>
28 #import <Foundation/NSURL.h>
30 #import <NGObjWeb/SoObject.h>
31 #import <NGObjWeb/WOContext+SoObjects.h>
32 #import <NGExtensions/NSNull+misc.h>
33 #import <NGExtensions/NSObject+Logs.h>
34 #import <EOControl/EOQualifier.h>
35 #import <GDLAccess/EOAdaptorChannel.h>
36 #import <GDLContentStore/GCSFolderManager.h>
37 #import <GDLContentStore/GCSFolder.h>
38 #import <GDLContentStore/GCSFolderType.h>
39 #import <SaxObjC/XMLNamespaces.h>
41 #import "SOGoPermissions.h"
44 #import "SOGoFolder.h"
46 static NSString *defaultUserID = @"<default>";
48 @implementation SOGoFolder
52 return [super version] + 0 /* v0 */;
57 NSAssert2([super version] == 0,
58 @"invalid superclass (%@) version %i !",
59 NSStringFromClass([self superclass]), [super version]);
62 + (NSString *) globallyUniqueObjectId
65 4C08AE1A-A808-11D8-AC5A-000393BBAFF6
66 SOGo-Web-28273-18283-288182
67 printf( "%x", *(int *) &f);
70 static int sequence = 0;
71 static float rndm = 0;
75 { /* break if we fork ;-) */
80 f = [[NSDate date] timeIntervalSince1970];
81 return [NSString stringWithFormat:@"%0X-%0X-%0X-%0X",
82 pid, *(int *)&f, sequence++, random];
87 if ((self = [super init]))
91 aclCache = [NSMutableDictionary new];
112 - (void) setOCSPath: (NSString *) _path
114 if ([ocsPath isEqualToString:_path])
118 [self warnWithFormat:@"GCS path is already set! '%@'", _path];
120 ASSIGNCOPY(ocsPath, _path);
123 - (NSString *) ocsPath
128 - (GCSFolderManager *) folderManager
130 static GCSFolderManager *folderManager = nil;
134 folderManager = [GCSFolderManager defaultFolderManager];
135 [folderManager setFolderNamePrefix: @"SOGo"];
138 return folderManager;
141 - (GCSFolder *) ocsFolderForPath: (NSString *) _path
143 return [[self folderManager] folderAtPath: _path];
146 - (BOOL) folderIsMandatory
148 [self subclassResponsibility: _cmd];
153 - (GCSFolder *) ocsFolder
160 ocsFolder = [self ocsFolderForPath: [self ocsPath]];
161 userLogin = [[context activeUser] login];
163 && [userLogin isEqualToString: [self ownerInContext: context]]
164 && [self folderIsMandatory]
166 ocsFolder = [self ocsFolderForPath: [self ocsPath]];
170 if ([ocsFolder isNotNull])
178 - (NSString *) folderType
187 result = [[self folderManager] createFolderOfType: [self folderType]
190 return (result == nil);
193 - (NSException *) delete
195 return [[self folderManager] deleteFolderAtPath: ocsPath];
198 - (NSArray *) fetchContentObjectNames
200 NSArray *fields, *records;
202 fields = [NSArray arrayWithObject: @"c_name"];
203 records = [[self ocsFolder] fetchFields:fields matchingQualifier:nil];
204 if (![records isNotNull])
206 [self errorWithFormat: @"(%s): fetch failed!", __PRETTY_FUNCTION__];
209 if ([records isKindOfClass: [NSException class]])
211 return [records valueForKey: @"c_name"];
214 - (BOOL) nameExistsInFolder: (NSString *) objectName
216 NSArray *fields, *records;
217 EOQualifier *qualifier;
220 = [EOQualifier qualifierWithQualifierFormat:
221 [NSString stringWithFormat: @"c_name='%@'", objectName]];
223 fields = [NSArray arrayWithObject: @"c_name"];
224 records = [[self ocsFolder] fetchFields: fields
225 matchingQualifier: qualifier];
227 && ![records isKindOfClass:[NSException class]]
228 && [records count] > 0);
231 - (NSDictionary *) fetchContentStringsAndNamesOfAllObjects
235 files = [[self ocsFolder] fetchContentsOfAllFiles];
236 if (![files isNotNull])
238 [self errorWithFormat:@"(%s): fetch failed!", __PRETTY_FUNCTION__];
241 if ([files isKindOfClass:[NSException class]])
248 - (NSString *) defaultFilenameExtension
251 Override to add an extension to a filename
253 Note: be careful with that, needs to be consistent with object lookup!
258 - (NSArray *) davResourceType
260 NSArray *rType, *groupDavCollection;
262 if ([self respondsToSelector: @selector (groupDavResourceType)])
264 groupDavCollection = [NSArray arrayWithObjects: [self groupDavResourceType],
265 XMLNS_GROUPDAV, nil];
266 rType = [NSArray arrayWithObjects: @"collection", groupDavCollection, nil];
269 rType = [NSArray arrayWithObject: @"collection"];
274 - (NSString *) davContentType
276 return @"httpd/unix-directory";
279 - (NSArray *) toOneRelationshipKeys
281 /* toOneRelationshipKeys are the 'files' contained in a folder */
284 NSString *name, *ext;
288 names = [self fetchContentObjectNames];
289 count = [names count];
290 ext = [self defaultFilenameExtension];
291 if (count && [ext length] > 0)
293 ma = [NSMutableArray arrayWithCapacity: count];
294 for (i = 0; i < count; i++)
296 name = [names objectAtIndex: i];
297 r = [name rangeOfString: @"."];
299 name = [[name stringByAppendingString:@"."] stringByAppendingString: ext];
309 /* acls as a container */
311 - (NSArray *) aclUsersForObjectAtPath: (NSArray *) objectPathArray;
313 EOQualifier *qualifier;
317 qs = [NSString stringWithFormat: @"c_object = '/%@'",
318 [objectPathArray componentsJoinedByString: @"/"]];
319 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
320 records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier];
322 return [records valueForKey: @"c_uid"];
325 - (NSArray *) _fetchAclsForUser: (NSString *) uid
326 forObjectAtPath: (NSString *) objectPath
328 EOQualifier *qualifier;
330 NSMutableArray *acls;
333 qs = [NSString stringWithFormat: @"(c_object = '/%@') AND (c_uid = '%@')",
335 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
336 records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier];
338 acls = [NSMutableArray array];
339 if ([records count] > 0)
341 [acls addObject: SOGoRole_AuthorizedSubscriber];
342 [acls addObjectsFromArray: [records valueForKey: @"c_role"]];
348 - (void) _cacheRoles: (NSArray *) roles
349 forUser: (NSString *) uid
350 forObjectAtPath: (NSString *) objectPath
352 NSMutableDictionary *aclsForObject;
354 aclsForObject = [aclCache objectForKey: objectPath];
357 aclsForObject = [NSMutableDictionary dictionary];
358 [aclCache setObject: aclsForObject
362 [aclsForObject setObject: roles forKey: uid];
364 [aclsForObject removeObjectForKey: uid];
367 - (NSArray *) aclsForUser: (NSString *) uid
368 forObjectAtPath: (NSArray *) objectPathArray
371 NSString *objectPath;
372 NSDictionary *aclsForObject;
374 objectPath = [objectPathArray componentsJoinedByString: @"/"];
375 aclsForObject = [aclCache objectForKey: objectPath];
377 acls = [aclsForObject objectForKey: uid];
382 acls = [self _fetchAclsForUser: uid forObjectAtPath: objectPath];
383 [self _cacheRoles: acls forUser: uid forObjectAtPath: objectPath];
386 if (!([acls count] || [uid isEqualToString: defaultUserID]))
387 acls = [self aclsForUser: defaultUserID
388 forObjectAtPath: objectPathArray];
393 - (void) removeAclsForUsers: (NSArray *) users
394 forObjectAtPath: (NSArray *) objectPathArray
396 EOQualifier *qualifier;
397 NSString *uids, *qs, *objectPath;
398 NSMutableDictionary *aclsForObject;
400 if ([users count] > 0)
402 objectPath = [objectPathArray componentsJoinedByString: @"/"];
403 aclsForObject = [aclCache objectForKey: objectPath];
405 [aclsForObject removeObjectsForKeys: users];
406 uids = [users componentsJoinedByString: @"') OR (c_uid = '"];
408 stringWithFormat: @"(c_object = '/%@') AND ((c_uid = '%@'))",
410 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
411 [[self ocsFolder] deleteAclMatchingQualifier: qualifier];
415 - (void) _commitRoles: (NSArray *) roles
416 forUID: (NSString *) uid
417 forObject: (NSString *) objectPath
419 EOAdaptorChannel *channel;
421 NSEnumerator *userRoles;
422 NSString *SQL, *currentRole;
424 folder = [self ocsFolder];
425 channel = [folder acquireAclChannel];
426 userRoles = [roles objectEnumerator];
427 currentRole = [userRoles nextObject];
430 SQL = [NSString stringWithFormat: @"INSERT INTO %@"
431 @" (c_object, c_uid, c_role)"
432 @" VALUES ('/%@', '%@', '%@')",
433 [folder aclTableName],
434 objectPath, uid, currentRole];
435 [channel evaluateExpressionX: SQL];
436 currentRole = [userRoles nextObject];
439 [folder releaseChannel: channel];
442 - (void) setRoles: (NSArray *) roles
443 forUser: (NSString *) uid
444 forObjectAtPath: (NSArray *) objectPathArray
446 NSString *objectPath;
447 NSMutableArray *newRoles;
449 [self removeAclsForUsers: [NSArray arrayWithObject: uid]
450 forObjectAtPath: objectPathArray];
452 newRoles = [NSMutableArray arrayWithArray: roles];
453 [newRoles removeObject: SOGoRole_AuthorizedSubscriber];
454 [newRoles removeObject: SOGoRole_None];
455 objectPath = [objectPathArray componentsJoinedByString: @"/"];
456 [self _cacheRoles: newRoles forUser: uid
457 forObjectAtPath: objectPath];
458 if (![newRoles count])
459 [newRoles addObject: SOGoRole_None];
461 [self _commitRoles: newRoles forUID: uid forObject: objectPath];
465 - (NSArray *) aclUsers
467 return [self aclUsersForObjectAtPath: [self pathArrayToSoObject]];
470 - (NSArray *) aclsForUser: (NSString *) uid
472 NSMutableArray *acls;
473 NSArray *ownAcls, *containerAcls;
475 acls = [NSMutableArray array];
476 ownAcls = [self aclsForUser: uid
477 forObjectAtPath: [self pathArrayToSoObject]];
478 [acls addObjectsFromArray: ownAcls];
479 if ([container respondsToSelector: @selector (aclsForUser:)])
481 containerAcls = [container aclsForUser: uid];
482 if ([containerAcls count] > 0)
484 if ([containerAcls containsObject: SOGoRole_ObjectReader])
485 [acls addObject: SOGoRole_ObjectViewer];
486 #warning this should be checked
487 if ([containerAcls containsObject: SOGoRole_ObjectEraser])
488 [acls addObject: SOGoRole_ObjectEraser];
495 - (void) setRoles: (NSArray *) roles
496 forUser: (NSString *) uid
498 return [self setRoles: roles
500 forObjectAtPath: [self pathArrayToSoObject]];
503 - (void) removeAclsForUsers: (NSArray *) users
505 return [self removeAclsForUsers: users
506 forObjectAtPath: [self pathArrayToSoObject]];
509 - (NSString *) defaultUserID
511 return defaultUserID;
514 - (NSString *) httpURLForAdvisoryToUser: (NSString *) uid
516 return [[self soURL] absoluteString];
519 - (NSString *) resourceURLForAdvisoryToUser: (NSString *) uid
521 return [[self davURL] absoluteString];
526 - (BOOL) davIsCollection
528 return [self isFolderish];
533 - (NSString *)outlookFolderClass {
539 - (void)appendAttributesToDescription:(NSMutableString *)_ms {
540 [super appendAttributesToDescription:_ms];
542 [_ms appendFormat:@" ocs=%@", [self ocsPath]];
545 - (NSString *)loggingPrefix {
546 return [NSString stringWithFormat:@"<0x%08X[%@]:%@>",
547 self, NSStringFromClass([self class]),
548 [self nameInContainer]];
551 @end /* SOGoFolder */