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 - (GCSFolder *) ocsFolder
149 ocsFolder = [[self ocsFolderForPath:[self ocsPath]] retain];
151 if ([ocsFolder isNotNull])
159 - (NSString *) folderType
168 result = [[self folderManager] createFolderOfType: [self folderType]
171 return (result == nil);
174 - (NSException *) delete
176 return [[self folderManager] deleteFolderAtPath: ocsPath];
179 - (NSArray *)fetchContentObjectNames {
180 NSArray *fields, *records;
182 fields = [NSArray arrayWithObject:@"c_name"];
183 records = [[self ocsFolder] fetchFields:fields matchingQualifier:nil];
184 if (![records isNotNull]) {
185 [self errorWithFormat:@"(%s): fetch failed!", __PRETTY_FUNCTION__];
188 if ([records isKindOfClass:[NSException class]])
190 return [records valueForKey:@"c_name"];
193 - (BOOL) nameExistsInFolder: (NSString *) objectName
195 NSArray *fields, *records;
196 EOQualifier *qualifier;
199 = [EOQualifier qualifierWithQualifierFormat:
200 [NSString stringWithFormat: @"c_name='%@'", objectName]];
202 fields = [NSArray arrayWithObject: @"c_name"];
203 records = [[self ocsFolder] fetchFields: fields
204 matchingQualifier: qualifier];
206 && ![records isKindOfClass:[NSException class]]
207 && [records count] > 0);
210 - (NSDictionary *)fetchContentStringsAndNamesOfAllObjects {
213 files = [[self ocsFolder] fetchContentsOfAllFiles];
214 if (![files isNotNull]) {
215 [self errorWithFormat:@"(%s): fetch failed!", __PRETTY_FUNCTION__];
218 if ([files isKindOfClass:[NSException class]])
225 - (NSString *)defaultFilenameExtension {
227 Override to add an extension to a filename
229 Note: be careful with that, needs to be consistent with object lookup!
234 - (NSArray *) davResourceType
236 NSArray *rType, *groupDavCollection;
238 if ([self respondsToSelector: @selector (groupDavResourceType)])
240 groupDavCollection = [NSArray arrayWithObjects: [self groupDavResourceType],
241 XMLNS_GROUPDAV, nil];
242 rType = [NSArray arrayWithObjects: @"collection", groupDavCollection, nil];
245 rType = [NSArray arrayWithObject: @"collection"];
250 - (NSString *) davContentType
252 return @"httpd/unix-directory";
255 - (NSArray *) toOneRelationshipKeys {
256 /* toOneRelationshipKeys are the 'files' contained in a folder */
259 NSString *name, *ext;
263 names = [self fetchContentObjectNames];
264 count = [names count];
265 ext = [self defaultFilenameExtension];
266 if (count && [ext length] > 0)
268 ma = [NSMutableArray arrayWithCapacity: count];
269 for (i = 0; i < count; i++)
271 name = [names objectAtIndex: i];
272 r = [name rangeOfString: @"."];
274 name = [[name stringByAppendingString:@"."] stringByAppendingString: ext];
284 /* acls as a container */
286 - (NSArray *) aclUsersForObjectAtPath: (NSArray *) objectPathArray;
288 EOQualifier *qualifier;
292 qs = [NSString stringWithFormat: @"c_object = '/%@'",
293 [objectPathArray componentsJoinedByString: @"/"]];
294 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
295 records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier];
297 return [records valueForKey: @"c_uid"];
300 - (NSArray *) _fetchAclsForUser: (NSString *) uid
301 forObjectAtPath: (NSString *) objectPath
303 EOQualifier *qualifier;
305 NSMutableArray *acls;
308 qs = [NSString stringWithFormat: @"(c_object = '/%@') AND (c_uid = '%@')",
310 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
311 records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier];
313 acls = [NSMutableArray array];
314 if ([records count] > 0)
316 [acls addObject: SOGoRole_AuthorizedSubscriber];
317 [acls addObjectsFromArray: [records valueForKey: @"c_role"]];
323 - (void) _cacheRoles: (NSArray *) roles
324 forUser: (NSString *) uid
325 forObjectAtPath: (NSString *) objectPath
327 NSMutableDictionary *aclsForObject;
329 aclsForObject = [aclCache objectForKey: objectPath];
332 aclsForObject = [NSMutableDictionary dictionary];
333 [aclCache setObject: aclsForObject
337 [aclsForObject setObject: roles forKey: uid];
339 [aclsForObject removeObjectForKey: uid];
342 - (NSArray *) aclsForUser: (NSString *) uid
343 forObjectAtPath: (NSArray *) objectPathArray
346 NSString *objectPath;
347 NSDictionary *aclsForObject;
349 objectPath = [objectPathArray componentsJoinedByString: @"/"];
350 aclsForObject = [aclCache objectForKey: objectPath];
352 acls = [aclsForObject objectForKey: uid];
357 acls = [self _fetchAclsForUser: uid forObjectAtPath: objectPath];
358 [self _cacheRoles: acls forUser: uid forObjectAtPath: objectPath];
361 if (!([acls count] || [uid isEqualToString: defaultUserID]))
362 acls = [self aclsForUser: defaultUserID
363 forObjectAtPath: objectPathArray];
368 - (void) removeAclsForUsers: (NSArray *) users
369 forObjectAtPath: (NSArray *) objectPathArray
371 EOQualifier *qualifier;
372 NSString *uids, *qs, *objectPath;
373 NSMutableDictionary *aclsForObject;
375 if ([users count] > 0)
377 objectPath = [objectPathArray componentsJoinedByString: @"/"];
378 aclsForObject = [aclCache objectForKey: objectPath];
380 [aclsForObject removeObjectsForKeys: users];
381 uids = [users componentsJoinedByString: @"') OR (c_uid = '"];
383 stringWithFormat: @"(c_object = '/%@') AND ((c_uid = '%@'))",
385 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
386 [[self ocsFolder] deleteAclMatchingQualifier: qualifier];
390 - (void) _commitRoles: (NSArray *) roles
391 forUID: (NSString *) uid
392 forObject: (NSString *) objectPath
394 EOAdaptorChannel *channel;
396 NSEnumerator *userRoles;
397 NSString *SQL, *currentRole;
399 folder = [self ocsFolder];
400 channel = [folder acquireAclChannel];
401 userRoles = [roles objectEnumerator];
402 currentRole = [userRoles nextObject];
405 SQL = [NSString stringWithFormat: @"INSERT INTO %@"
406 @" (c_object, c_uid, c_role)"
407 @" VALUES ('/%@', '%@', '%@')",
408 [folder aclTableName],
409 objectPath, uid, currentRole];
410 [channel evaluateExpressionX: SQL];
411 currentRole = [userRoles nextObject];
414 [folder releaseChannel: channel];
417 - (void) setRoles: (NSArray *) roles
418 forUser: (NSString *) uid
419 forObjectAtPath: (NSArray *) objectPathArray
421 NSString *objectPath;
422 NSMutableArray *newRoles;
424 [self removeAclsForUsers: [NSArray arrayWithObject: uid]
425 forObjectAtPath: objectPathArray];
427 newRoles = [NSMutableArray arrayWithArray: roles];
428 [newRoles removeObject: SOGoRole_AuthorizedSubscriber];
429 [newRoles removeObject: SOGoRole_None];
430 objectPath = [objectPathArray componentsJoinedByString: @"/"];
431 [self _cacheRoles: newRoles forUser: uid
432 forObjectAtPath: objectPath];
433 if (![newRoles count])
434 [newRoles addObject: SOGoRole_None];
436 [self _commitRoles: newRoles forUID: uid forObject: objectPath];
440 - (NSArray *) aclUsers
442 return [self aclUsersForObjectAtPath: [self pathArrayToSoObject]];
445 - (NSArray *) aclsForUser: (NSString *) uid
447 NSMutableArray *acls;
448 NSArray *ownAcls, *containerAcls;
450 acls = [NSMutableArray array];
451 ownAcls = [self aclsForUser: uid
452 forObjectAtPath: [self pathArrayToSoObject]];
453 [acls addObjectsFromArray: ownAcls];
454 if ([container respondsToSelector: @selector (aclsForUser:)])
456 containerAcls = [container aclsForUser: uid];
457 if ([containerAcls count] > 0)
459 if ([containerAcls containsObject: SOGoRole_ObjectReader])
460 [acls addObject: SOGoRole_ObjectViewer];
461 #warning this should be checked
462 if ([containerAcls containsObject: SOGoRole_ObjectEraser])
463 [acls addObject: SOGoRole_ObjectEraser];
470 - (void) setRoles: (NSArray *) roles
471 forUser: (NSString *) uid
473 return [self setRoles: roles
475 forObjectAtPath: [self pathArrayToSoObject]];
478 - (void) removeAclsForUsers: (NSArray *) users
480 return [self removeAclsForUsers: users
481 forObjectAtPath: [self pathArrayToSoObject]];
484 - (NSString *) defaultUserID
486 return defaultUserID;
489 - (NSString *) httpURLForAdvisoryToUser: (NSString *) uid
491 return [[self soURL] absoluteString];
494 - (NSString *) resourceURLForAdvisoryToUser: (NSString *) uid
496 return [[self davURL] absoluteString];
501 - (BOOL) davIsCollection
503 return [self isFolderish];
508 - (NSString *)outlookFolderClass {
514 - (void)appendAttributesToDescription:(NSMutableString *)_ms {
515 [super appendAttributesToDescription:_ms];
517 [_ms appendFormat:@" ocs=%@", [self ocsPath]];
520 - (NSString *)loggingPrefix {
521 return [NSString stringWithFormat:@"<0x%08X[%@]:%@>",
522 self, NSStringFromClass([self class]),
523 [self nameInContainer]];
526 @end /* SOGoFolder */