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 <NGExtensions/NSNull+misc.h>
32 #import <NGExtensions/NSObject+Logs.h>
33 #import <EOControl/EOQualifier.h>
34 #import <GDLAccess/EOAdaptorChannel.h>
35 #import <GDLContentStore/GCSFolderManager.h>
36 #import <GDLContentStore/GCSFolder.h>
37 #import <GDLContentStore/GCSFolderType.h>
38 #import <SaxObjC/XMLNamespaces.h>
40 #import "SOGoPermissions.h"
42 #import "SOGoFolder.h"
44 static NSString *defaultUserID = @"<default>";
46 @implementation SOGoFolder
50 return [super version] + 0 /* v0 */;
55 NSAssert2([super version] == 0,
56 @"invalid superclass (%@) version %i !",
57 NSStringFromClass([self superclass]), [super version]);
60 + (NSString *) globallyUniqueObjectId
63 4C08AE1A-A808-11D8-AC5A-000393BBAFF6
64 SOGo-Web-28273-18283-288182
65 printf( "%x", *(int *) &f);
68 static int sequence = 0;
69 static float rndm = 0;
73 { /* break if we fork ;-) */
78 f = [[NSDate date] timeIntervalSince1970];
79 return [NSString stringWithFormat:@"%0X-%0X-%0X-%0X",
80 pid, *(int *)&f, sequence++, random];
85 if ((self = [super init]))
89 aclCache = [NSMutableDictionary new];
110 - (void) setOCSPath: (NSString *) _path
112 if ([ocsPath isEqualToString:_path])
116 [self warnWithFormat:@"GCS path is already set! '%@'", _path];
118 ASSIGNCOPY(ocsPath, _path);
121 - (NSString *) ocsPath
126 - (GCSFolderManager *) folderManager
128 static GCSFolderManager *folderManager = nil;
132 folderManager = [GCSFolderManager defaultFolderManager];
133 [folderManager setFolderNamePrefix: @"SOGo"];
136 return folderManager;
139 - (GCSFolder *) ocsFolderForPath: (NSString *) _path
141 return [[self folderManager] folderAtPath: _path];
144 - (BOOL) folderIsMandatory
146 [self subclassResponsibility: _cmd];
151 - (GCSFolder *) ocsFolder
157 ocsFolder = [self ocsFolderForPath: [self ocsPath]];
159 && [self folderIsMandatory]
161 ocsFolder = [self ocsFolderForPath: [self ocsPath]];
165 if ([ocsFolder isNotNull])
173 - (NSString *) folderType
182 result = [[self folderManager] createFolderOfType: [self folderType]
185 return (result == nil);
188 - (NSException *) delete
190 return [[self folderManager] deleteFolderAtPath: ocsPath];
193 - (NSArray *) fetchContentObjectNames
195 NSArray *fields, *records;
197 fields = [NSArray arrayWithObject: @"c_name"];
198 records = [[self ocsFolder] fetchFields:fields matchingQualifier:nil];
199 if (![records isNotNull])
201 [self errorWithFormat: @"(%s): fetch failed!", __PRETTY_FUNCTION__];
204 if ([records isKindOfClass: [NSException class]])
206 return [records valueForKey: @"c_name"];
209 - (BOOL) nameExistsInFolder: (NSString *) objectName
211 NSArray *fields, *records;
212 EOQualifier *qualifier;
215 = [EOQualifier qualifierWithQualifierFormat:
216 [NSString stringWithFormat: @"c_name='%@'", objectName]];
218 fields = [NSArray arrayWithObject: @"c_name"];
219 records = [[self ocsFolder] fetchFields: fields
220 matchingQualifier: qualifier];
222 && ![records isKindOfClass:[NSException class]]
223 && [records count] > 0);
226 - (NSDictionary *) fetchContentStringsAndNamesOfAllObjects
230 files = [[self ocsFolder] fetchContentsOfAllFiles];
231 if (![files isNotNull])
233 [self errorWithFormat:@"(%s): fetch failed!", __PRETTY_FUNCTION__];
236 if ([files isKindOfClass:[NSException class]])
243 - (NSString *) defaultFilenameExtension
246 Override to add an extension to a filename
248 Note: be careful with that, needs to be consistent with object lookup!
253 - (NSArray *) davResourceType
255 NSArray *rType, *groupDavCollection;
257 if ([self respondsToSelector: @selector (groupDavResourceType)])
259 groupDavCollection = [NSArray arrayWithObjects: [self groupDavResourceType],
260 XMLNS_GROUPDAV, nil];
261 rType = [NSArray arrayWithObjects: @"collection", groupDavCollection, nil];
264 rType = [NSArray arrayWithObject: @"collection"];
269 - (NSString *) davContentType
271 return @"httpd/unix-directory";
274 - (NSArray *) toOneRelationshipKeys
276 /* toOneRelationshipKeys are the 'files' contained in a folder */
279 NSString *name, *ext;
283 names = [self fetchContentObjectNames];
284 count = [names count];
285 ext = [self defaultFilenameExtension];
286 if (count && [ext length] > 0)
288 ma = [NSMutableArray arrayWithCapacity: count];
289 for (i = 0; i < count; i++)
291 name = [names objectAtIndex: i];
292 r = [name rangeOfString: @"."];
294 name = [[name stringByAppendingString:@"."] stringByAppendingString: ext];
304 /* acls as a container */
306 - (NSArray *) aclUsersForObjectAtPath: (NSArray *) objectPathArray;
308 EOQualifier *qualifier;
312 qs = [NSString stringWithFormat: @"c_object = '/%@'",
313 [objectPathArray componentsJoinedByString: @"/"]];
314 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
315 records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier];
317 return [records valueForKey: @"c_uid"];
320 - (NSArray *) _fetchAclsForUser: (NSString *) uid
321 forObjectAtPath: (NSString *) objectPath
323 EOQualifier *qualifier;
325 NSMutableArray *acls;
328 qs = [NSString stringWithFormat: @"(c_object = '/%@') AND (c_uid = '%@')",
330 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
331 records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier];
333 acls = [NSMutableArray array];
334 if ([records count] > 0)
336 [acls addObject: SOGoRole_AuthorizedSubscriber];
337 [acls addObjectsFromArray: [records valueForKey: @"c_role"]];
343 - (void) _cacheRoles: (NSArray *) roles
344 forUser: (NSString *) uid
345 forObjectAtPath: (NSString *) objectPath
347 NSMutableDictionary *aclsForObject;
349 aclsForObject = [aclCache objectForKey: objectPath];
352 aclsForObject = [NSMutableDictionary dictionary];
353 [aclCache setObject: aclsForObject
357 [aclsForObject setObject: roles forKey: uid];
359 [aclsForObject removeObjectForKey: uid];
362 - (NSArray *) aclsForUser: (NSString *) uid
363 forObjectAtPath: (NSArray *) objectPathArray
366 NSString *objectPath;
367 NSDictionary *aclsForObject;
369 objectPath = [objectPathArray componentsJoinedByString: @"/"];
370 aclsForObject = [aclCache objectForKey: objectPath];
372 acls = [aclsForObject objectForKey: uid];
377 acls = [self _fetchAclsForUser: uid forObjectAtPath: objectPath];
378 [self _cacheRoles: acls forUser: uid forObjectAtPath: objectPath];
381 if (!([acls count] || [uid isEqualToString: defaultUserID]))
382 acls = [self aclsForUser: defaultUserID
383 forObjectAtPath: objectPathArray];
388 - (void) removeAclsForUsers: (NSArray *) users
389 forObjectAtPath: (NSArray *) objectPathArray
391 EOQualifier *qualifier;
392 NSString *uids, *qs, *objectPath;
393 NSMutableDictionary *aclsForObject;
395 if ([users count] > 0)
397 objectPath = [objectPathArray componentsJoinedByString: @"/"];
398 aclsForObject = [aclCache objectForKey: objectPath];
400 [aclsForObject removeObjectsForKeys: users];
401 uids = [users componentsJoinedByString: @"') OR (c_uid = '"];
403 stringWithFormat: @"(c_object = '/%@') AND ((c_uid = '%@'))",
405 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
406 [[self ocsFolder] deleteAclMatchingQualifier: qualifier];
410 - (void) _commitRoles: (NSArray *) roles
411 forUID: (NSString *) uid
412 forObject: (NSString *) objectPath
414 EOAdaptorChannel *channel;
416 NSEnumerator *userRoles;
417 NSString *SQL, *currentRole;
419 folder = [self ocsFolder];
420 channel = [folder acquireAclChannel];
421 userRoles = [roles objectEnumerator];
422 currentRole = [userRoles nextObject];
425 SQL = [NSString stringWithFormat: @"INSERT INTO %@"
426 @" (c_object, c_uid, c_role)"
427 @" VALUES ('/%@', '%@', '%@')",
428 [folder aclTableName],
429 objectPath, uid, currentRole];
430 [channel evaluateExpressionX: SQL];
431 currentRole = [userRoles nextObject];
434 [folder releaseChannel: channel];
437 - (void) setRoles: (NSArray *) roles
438 forUser: (NSString *) uid
439 forObjectAtPath: (NSArray *) objectPathArray
441 NSString *objectPath;
442 NSMutableArray *newRoles;
444 [self removeAclsForUsers: [NSArray arrayWithObject: uid]
445 forObjectAtPath: objectPathArray];
447 newRoles = [NSMutableArray arrayWithArray: roles];
448 [newRoles removeObject: SOGoRole_AuthorizedSubscriber];
449 [newRoles removeObject: SOGoRole_None];
450 objectPath = [objectPathArray componentsJoinedByString: @"/"];
451 [self _cacheRoles: newRoles forUser: uid
452 forObjectAtPath: objectPath];
453 if (![newRoles count])
454 [newRoles addObject: SOGoRole_None];
456 [self _commitRoles: newRoles forUID: uid forObject: objectPath];
460 - (NSArray *) aclUsers
462 return [self aclUsersForObjectAtPath: [self pathArrayToSoObject]];
465 - (NSArray *) aclsForUser: (NSString *) uid
467 NSMutableArray *acls;
468 NSArray *ownAcls, *containerAcls;
470 acls = [NSMutableArray array];
471 ownAcls = [self aclsForUser: uid
472 forObjectAtPath: [self pathArrayToSoObject]];
473 [acls addObjectsFromArray: ownAcls];
474 if ([container respondsToSelector: @selector (aclsForUser:)])
476 containerAcls = [container aclsForUser: uid];
477 if ([containerAcls count] > 0)
479 if ([containerAcls containsObject: SOGoRole_ObjectReader])
480 [acls addObject: SOGoRole_ObjectViewer];
481 #warning this should be checked
482 if ([containerAcls containsObject: SOGoRole_ObjectEraser])
483 [acls addObject: SOGoRole_ObjectEraser];
490 - (void) setRoles: (NSArray *) roles
491 forUser: (NSString *) uid
493 return [self setRoles: roles
495 forObjectAtPath: [self pathArrayToSoObject]];
498 - (void) removeAclsForUsers: (NSArray *) users
500 return [self removeAclsForUsers: users
501 forObjectAtPath: [self pathArrayToSoObject]];
504 - (NSString *) defaultUserID
506 return defaultUserID;
509 - (NSString *) httpURLForAdvisoryToUser: (NSString *) uid
511 return [[self soURL] absoluteString];
514 - (NSString *) resourceURLForAdvisoryToUser: (NSString *) uid
516 return [[self davURL] absoluteString];
521 - (BOOL) davIsCollection
523 return [self isFolderish];
528 - (NSString *)outlookFolderClass {
534 - (void)appendAttributesToDescription:(NSMutableString *)_ms {
535 [super appendAttributesToDescription:_ms];
537 [_ms appendFormat:@" ocs=%@", [self ocsPath]];
540 - (NSString *)loggingPrefix {
541 return [NSString stringWithFormat:@"<0x%08X[%@]:%@>",
542 self, NSStringFromClass([self class]),
543 [self nameInContainer]];
546 @end /* SOGoFolder */