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
22 #import <NGObjWeb/SoObject.h>
23 #import <GDLAccess/EOAdaptorChannel.h>
24 #import <GDLContentStore/GCSFolderManager.h>
25 #import <GDLContentStore/GCSFolder.h>
26 #import <GDLContentStore/GCSFolderType.h>
27 #import <SaxObjC/XMLNamespaces.h>
29 #import "SOGoPermissions.h"
30 #import "SOGoFolder.h"
35 static NSString *defaultUserID = @"<default>";
37 @implementation SOGoFolder
41 return [super version] + 0 /* v0 */;
46 NSAssert2([super version] == 0,
47 @"invalid superclass (%@) version %i !",
48 NSStringFromClass([self superclass]), [super version]);
51 + (NSString *) globallyUniqueObjectId
54 4C08AE1A-A808-11D8-AC5A-000393BBAFF6
55 SOGo-Web-28273-18283-288182
56 printf( "%x", *(int *) &f);
59 static int sequence = 0;
60 static float rndm = 0;
64 { /* break if we fork ;-) */
69 f = [[NSDate date] timeIntervalSince1970];
70 return [NSString stringWithFormat:@"%0X-%0X-%0X-%0X",
71 pid, *(int *)&f, sequence++, random];
76 if ((self = [super init]))
80 aclCache = [NSMutableDictionary new];
101 - (void) setOCSPath: (NSString *) _path
103 if ([ocsPath isEqualToString:_path])
107 [self warnWithFormat:@"GCS path is already set! '%@'", _path];
109 ASSIGNCOPY(ocsPath, _path);
112 - (NSString *) ocsPath
117 - (GCSFolderManager *) folderManager
119 static GCSFolderManager *folderManager = nil;
123 folderManager = [GCSFolderManager defaultFolderManager];
124 [folderManager setFolderNamePrefix: @"SOGo_"];
127 return folderManager;
130 - (GCSFolder *) ocsFolderForPath: (NSString *) _path
132 return [[self folderManager] folderAtPath:_path];
135 - (GCSFolder *) ocsFolder
140 ocsFolder = [[self ocsFolderForPath:[self ocsPath]] retain];
142 if ([ocsFolder isNotNull])
150 - (NSString *) folderType
159 result = [[self folderManager] createFolderOfType: [self folderType]
162 return (result == nil);
165 - (NSException *) delete
167 return [[self folderManager] deleteFolderAtPath: ocsPath];
170 - (NSArray *)fetchContentObjectNames {
171 NSArray *fields, *records;
173 fields = [NSArray arrayWithObject:@"c_name"];
174 records = [[self ocsFolder] fetchFields:fields matchingQualifier:nil];
175 if (![records isNotNull]) {
176 [self errorWithFormat:@"(%s): fetch failed!", __PRETTY_FUNCTION__];
179 if ([records isKindOfClass:[NSException class]])
181 return [records valueForKey:@"c_name"];
184 - (BOOL) nameExistsInFolder: (NSString *) objectName
186 NSArray *fields, *records;
187 EOQualifier *qualifier;
190 = [EOQualifier qualifierWithQualifierFormat:
191 [NSString stringWithFormat: @"c_name='%@'", objectName]];
193 fields = [NSArray arrayWithObject: @"c_name"];
194 records = [[self ocsFolder] fetchFields: fields
195 matchingQualifier: qualifier];
197 && ![records isKindOfClass:[NSException class]]
198 && [records count] > 0);
201 - (NSDictionary *)fetchContentStringsAndNamesOfAllObjects {
204 files = [[self ocsFolder] fetchContentsOfAllFiles];
205 if (![files isNotNull]) {
206 [self errorWithFormat:@"(%s): fetch failed!", __PRETTY_FUNCTION__];
209 if ([files isKindOfClass:[NSException class]])
216 - (NSString *)defaultFilenameExtension {
218 Override to add an extension to a filename
220 Note: be careful with that, needs to be consistent with object lookup!
225 - (NSArray *) davResourceType
227 NSArray *rType, *groupDavCollection;
229 if ([self respondsToSelector: @selector (groupDavResourceType)])
231 groupDavCollection = [NSArray arrayWithObjects: [self groupDavResourceType],
232 XMLNS_GROUPDAV, nil];
233 rType = [NSArray arrayWithObjects: @"collection", groupDavCollection, nil];
236 rType = [NSArray arrayWithObject: @"collection"];
241 - (NSString *) davContentType
243 return @"httpd/unix-directory";
246 - (NSArray *) toOneRelationshipKeys {
247 /* toOneRelationshipKeys are the 'files' contained in a folder */
250 NSString *name, *ext;
254 names = [self fetchContentObjectNames];
255 count = [names count];
256 ext = [self defaultFilenameExtension];
257 if (count && [ext length] > 0)
259 ma = [NSMutableArray arrayWithCapacity: count];
260 for (i = 0; i < count; i++)
262 name = [names objectAtIndex: i];
263 r = [name rangeOfString: @"."];
265 name = [[name stringByAppendingString:@"."] stringByAppendingString: ext];
275 /* acls as a container */
277 - (NSArray *) aclUsersForObjectAtPath: (NSArray *) objectPathArray;
279 EOQualifier *qualifier;
283 qs = [NSString stringWithFormat: @"c_object = '/%@'",
284 [objectPathArray componentsJoinedByString: @"/"]];
285 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
286 records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier];
288 return [records valueForKey: @"c_uid"];
291 - (NSArray *) _fetchAclsForUser: (NSString *) uid
292 forObjectAtPath: (NSString *) objectPath
294 EOQualifier *qualifier;
296 NSMutableArray *acls;
299 qs = [NSString stringWithFormat: @"(c_object = '/%@') AND (c_uid = '%@')",
301 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
302 records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier];
304 acls = [NSMutableArray array];
305 if ([records count] > 0)
307 [acls addObject: SOGoRole_AuthorizedSubscriber];
308 [acls addObjectsFromArray: [records valueForKey: @"c_role"]];
314 - (void) _cacheRoles: (NSArray *) roles
315 forUser: (NSString *) uid
316 forObjectAtPath: (NSString *) objectPath
318 NSMutableDictionary *aclsForObject;
320 aclsForObject = [aclCache objectForKey: objectPath];
323 aclsForObject = [NSMutableDictionary dictionary];
324 [aclCache setObject: aclsForObject
328 [aclsForObject setObject: roles forKey: uid];
330 [aclsForObject removeObjectForKey: uid];
333 - (NSArray *) aclsForUser: (NSString *) uid
334 forObjectAtPath: (NSArray *) objectPathArray
337 NSString *objectPath;
338 NSDictionary *aclsForObject;
340 objectPath = [objectPathArray componentsJoinedByString: @"/"];
341 aclsForObject = [aclCache objectForKey: objectPath];
343 acls = [aclsForObject objectForKey: uid];
348 acls = [self _fetchAclsForUser: uid forObjectAtPath: objectPath];
349 [self _cacheRoles: acls forUser: uid forObjectAtPath: objectPath];
352 if (!([acls count] || [uid isEqualToString: defaultUserID]))
353 acls = [self aclsForUser: defaultUserID
354 forObjectAtPath: objectPathArray];
359 - (void) removeAclsForUsers: (NSArray *) users
360 forObjectAtPath: (NSArray *) objectPathArray
362 EOQualifier *qualifier;
363 NSString *uids, *qs, *objectPath;
364 NSMutableDictionary *aclsForObject;
366 if ([users count] > 0)
368 objectPath = [objectPathArray componentsJoinedByString: @"/"];
369 aclsForObject = [aclCache objectForKey: objectPath];
371 [aclsForObject removeObjectsForKeys: users];
372 uids = [users componentsJoinedByString: @"') OR (c_uid = '"];
374 stringWithFormat: @"(c_object = '/%@') AND ((c_uid = '%@'))",
376 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
377 [[self ocsFolder] deleteAclMatchingQualifier: qualifier];
381 - (void) _commitRoles: (NSArray *) roles
382 forUID: (NSString *) uid
383 forObject: (NSString *) objectPath
385 EOAdaptorChannel *channel;
387 NSEnumerator *userRoles;
388 NSString *SQL, *currentRole;
390 folder = [self ocsFolder];
391 channel = [folder acquireAclChannel];
392 userRoles = [roles objectEnumerator];
393 currentRole = [userRoles nextObject];
396 SQL = [NSString stringWithFormat: @"INSERT INTO %@"
397 @" (c_object, c_uid, c_role)"
398 @" VALUES ('/%@', '%@', '%@')",
399 [folder aclTableName],
400 objectPath, uid, currentRole];
401 [channel evaluateExpressionX: SQL];
402 currentRole = [userRoles nextObject];
405 [folder releaseChannel: channel];
408 - (void) setRoles: (NSArray *) roles
409 forUser: (NSString *) uid
410 forObjectAtPath: (NSArray *) objectPathArray
412 NSString *objectPath;
413 NSMutableArray *newRoles;
415 [self removeAclsForUsers: [NSArray arrayWithObject: uid]
416 forObjectAtPath: objectPathArray];
418 newRoles = [NSMutableArray arrayWithArray: roles];
419 [newRoles removeObject: SOGoRole_AuthorizedSubscriber];
420 [newRoles removeObject: SOGoRole_None];
421 objectPath = [objectPathArray componentsJoinedByString: @"/"];
422 [self _cacheRoles: newRoles forUser: uid
423 forObjectAtPath: objectPath];
424 if (![newRoles count])
425 [newRoles addObject: SOGoRole_None];
427 [self _commitRoles: newRoles forUID: uid forObject: objectPath];
431 - (NSArray *) aclUsers
433 return [self aclUsersForObjectAtPath: [self pathArrayToSoObject]];
436 - (NSArray *) aclsForUser: (NSString *) uid
438 NSMutableArray *acls;
439 NSArray *ownAcls, *containerAcls;
441 acls = [NSMutableArray array];
442 ownAcls = [self aclsForUser: uid
443 forObjectAtPath: [self pathArrayToSoObject]];
444 [acls addObjectsFromArray: ownAcls];
445 if ([container respondsToSelector: @selector (aclsForUser:)])
447 containerAcls = [container aclsForUser: uid];
448 if ([containerAcls count] > 0)
450 if ([containerAcls containsObject: SOGoRole_ObjectReader])
451 [acls addObject: SOGoRole_ObjectViewer];
452 #warning this should be checked
453 if ([containerAcls containsObject: SOGoRole_ObjectEraser])
454 [acls addObject: SOGoRole_ObjectEraser];
461 - (void) setRoles: (NSArray *) roles
462 forUser: (NSString *) uid
464 return [self setRoles: roles
466 forObjectAtPath: [self pathArrayToSoObject]];
469 - (void) removeAclsForUsers: (NSArray *) users
471 return [self removeAclsForUsers: users
472 forObjectAtPath: [self pathArrayToSoObject]];
475 - (NSString *) defaultUserID
477 return defaultUserID;
480 - (NSString *) httpURLForAdvisoryToUser: (NSString *) uid
482 return [[self soURL] absoluteString];
485 - (NSString *) resourceURLForAdvisoryToUser: (NSString *) uid
487 return [[self davURL] absoluteString];
492 - (BOOL) davIsCollection
494 return [self isFolderish];
499 - (NSString *)outlookFolderClass {
505 - (void)appendAttributesToDescription:(NSMutableString *)_ms {
506 [super appendAttributesToDescription:_ms];
508 [_ms appendFormat:@" ocs=%@", [self ocsPath]];
511 - (NSString *)loggingPrefix {
512 return [NSString stringWithFormat:@"<0x%08X[%@]:%@>",
513 self, NSStringFromClass([self class]),
514 [self nameInContainer]];
517 @end /* SOGoFolder */