X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=SoObjects%2FSOGo%2FSOGoFolder.m;h=7d914d396780f425236abec414f435bfeb7318db;hb=4a618da690a9beadcefd0ea89a921900e3897ce8;hp=ee96bf3b8e9e8eaf6778a050308bdfdf9611b53d;hpb=9cd1ac40314d3684f7b716eca2212b4a6360ebd6;p=scalable-opengroupware.org diff --git a/SoObjects/SOGo/SOGoFolder.m b/SoObjects/SOGo/SOGoFolder.m index ee96bf3b..7d914d39 100644 --- a/SoObjects/SOGo/SOGoFolder.m +++ b/SoObjects/SOGo/SOGoFolder.m @@ -19,82 +19,161 @@ 02111-1307, USA. */ -#include "SOGoFolder.h" -#include "common.h" -#include -#include -#include -#include +#import +#import + +#import +#import +#import +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import "SOGoPermissions.h" + +#import "SOGoFolder.h" + +static NSString *defaultUserID = @""; @implementation SOGoFolder -+ (int)version { ++ (int) version +{ return [super version] + 0 /* v0 */; } -+ (void)initialize { + ++ (void) initialize +{ NSAssert2([super version] == 0, @"invalid superclass (%@) version %i !", NSStringFromClass([self superclass]), [super version]); } -+ (NSString *)globallyUniqueObjectId { ++ (NSString *) globallyUniqueObjectId +{ /* 4C08AE1A-A808-11D8-AC5A-000393BBAFF6 SOGo-Web-28273-18283-288182 printf( "%x", *(int *) &f); */ - static int pid = 0; - static int sequence = 0; + static int pid = 0; + static int sequence = 0; static float rndm = 0; float f; - if (pid == 0) { /* break if we fork ;-) */ - pid = getpid(); - rndm = random(); - } + if (pid == 0) + { /* break if we fork ;-) */ + pid = getpid(); + rndm = random(); + } sequence++; f = [[NSDate date] timeIntervalSince1970]; return [NSString stringWithFormat:@"%0X-%0X-%0X-%0X", pid, *(int *)&f, sequence++, random]; } -- (void)dealloc { - [self->ocsFolder release]; - [self->ocsPath release]; +- (id) init +{ + if ((self = [super init])) + { + ocsPath = nil; + ocsFolder = nil; + aclCache = [NSMutableDictionary new]; + } + + return self; +} + +- (void) dealloc +{ + [ocsFolder release]; + [ocsPath release]; + [aclCache release]; [super dealloc]; } /* accessors */ -- (BOOL)isFolderish { +- (BOOL) isFolderish +{ return YES; } -- (void)setOCSPath:(NSString *)_path { - if ([self->ocsPath isEqualToString:_path]) +- (void) setOCSPath: (NSString *) _path +{ + if ([ocsPath isEqualToString:_path]) return; - if (self->ocsPath) + if (ocsPath) [self warnWithFormat:@"GCS path is already set! '%@'", _path]; - ASSIGNCOPY(self->ocsPath, _path); + ASSIGNCOPY(ocsPath, _path); } -- (NSString *)ocsPath { - return self->ocsPath; + +- (NSString *) ocsPath +{ + return ocsPath; } -- (GCSFolderManager *)folderManager { - return [GCSFolderManager defaultFolderManager]; +- (GCSFolderManager *) folderManager +{ + static GCSFolderManager *folderManager = nil; + + if (!folderManager) + { + folderManager = [GCSFolderManager defaultFolderManager]; + [folderManager setFolderNamePrefix: @"SOGo_"]; + } + + return folderManager; } -- (GCSFolder *)ocsFolderForPath:(NSString *)_path { + +- (GCSFolder *) ocsFolderForPath: (NSString *) _path +{ return [[self folderManager] folderAtPath:_path]; } -- (GCSFolder *)ocsFolder { - if (self->ocsFolder != nil) - return [self->ocsFolder isNotNull] ? self->ocsFolder : nil; - - self->ocsFolder = [[self ocsFolderForPath:[self ocsPath]] retain]; - return self->ocsFolder; + +- (GCSFolder *) ocsFolder +{ + GCSFolder *folder; + + if (!ocsFolder) + ocsFolder = [[self ocsFolderForPath:[self ocsPath]] retain]; + + if ([ocsFolder isNotNull]) + folder = ocsFolder; + else + folder = nil; + + return folder; +} + +- (NSString *) folderType +{ + return @""; +} + +- (BOOL) create +{ + NSException *result; + + result = [[self folderManager] createFolderOfType: [self folderType] + atPath: ocsPath]; + + return (result == nil); +} + +- (NSException *) delete +{ + return [[self folderManager] deleteFolderAtPath: ocsPath]; } - (NSArray *)fetchContentObjectNames { @@ -110,6 +189,24 @@ return records; return [records valueForKey:@"c_name"]; } + +- (BOOL) nameExistsInFolder: (NSString *) objectName +{ + NSArray *fields, *records; + EOQualifier *qualifier; + + qualifier + = [EOQualifier qualifierWithQualifierFormat: + [NSString stringWithFormat: @"c_name='%@'", objectName]]; + + fields = [NSArray arrayWithObject: @"c_name"]; + records = [[self ocsFolder] fetchFields: fields + matchingQualifier: qualifier]; + return (records + && ![records isKindOfClass:[NSException class]] + && [records count] > 0); +} + - (NSDictionary *)fetchContentStringsAndNamesOfAllObjects { NSDictionary *files; @@ -134,40 +231,275 @@ return nil; } -- (NSArray *)toOneRelationshipKeys { +- (NSArray *) davResourceType +{ + NSArray *rType, *groupDavCollection; + + if ([self respondsToSelector: @selector (groupDavResourceType)]) + { + groupDavCollection = [NSArray arrayWithObjects: [self groupDavResourceType], + XMLNS_GROUPDAV, nil]; + rType = [NSArray arrayWithObjects: @"collection", groupDavCollection, nil]; + } + else + rType = [NSArray arrayWithObject: @"collection"]; + + return rType; +} + +- (NSString *) davContentType +{ + return @"httpd/unix-directory"; +} + +- (NSArray *) toOneRelationshipKeys { /* toOneRelationshipKeys are the 'files' contained in a folder */ NSMutableArray *ma; NSArray *names; - NSString *ext; + NSString *name, *ext; unsigned i, count; + NSRange r; - if ((names = [self fetchContentObjectNames]) == nil) - return names; - - if ((count = [names count]) == 0) - return names; - - if ((ext = [self defaultFilenameExtension]) == nil) - return names; - - ma = [NSMutableArray arrayWithCapacity:count]; - for (i = 0; i < count; i++) { - NSRange r; - NSString *name; - - name = [names objectAtIndex:i]; - r = [name rangeOfString:@"."]; - if (r.length == 0) - name = [[name stringByAppendingString:@"."] stringByAppendingString:ext]; - - [ma addObject:name]; - } - return ma; + names = [self fetchContentObjectNames]; + count = [names count]; + ext = [self defaultFilenameExtension]; + if (count && [ext length] > 0) + { + ma = [NSMutableArray arrayWithCapacity: count]; + for (i = 0; i < count; i++) + { + name = [names objectAtIndex: i]; + r = [name rangeOfString: @"."]; + if (r.length == 0) + name = [[name stringByAppendingString:@"."] stringByAppendingString: ext]; + [ma addObject:name]; + } + + names = ma; + } + + return names; +} + +/* acls as a container */ + +- (NSArray *) aclUsersForObjectAtPath: (NSArray *) objectPathArray; +{ + EOQualifier *qualifier; + NSString *qs; + NSArray *records; + + qs = [NSString stringWithFormat: @"c_object = '/%@'", + [objectPathArray componentsJoinedByString: @"/"]]; + qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; + records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier]; + + return [records valueForKey: @"c_uid"]; +} + +- (NSArray *) _fetchAclsForUser: (NSString *) uid + forObjectAtPath: (NSString *) objectPath +{ + EOQualifier *qualifier; + NSArray *records; + NSMutableArray *acls; + NSString *qs; + + qs = [NSString stringWithFormat: @"(c_object = '/%@') AND (c_uid = '%@')", + objectPath, uid]; + qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; + records = [[self ocsFolder] fetchAclMatchingQualifier: qualifier]; + + acls = [NSMutableArray array]; + if ([records count] > 0) + { + [acls addObject: SOGoRole_AuthorizedSubscriber]; + [acls addObjectsFromArray: [records valueForKey: @"c_role"]]; + } + + return acls; +} + +- (void) _cacheRoles: (NSArray *) roles + forUser: (NSString *) uid + forObjectAtPath: (NSString *) objectPath +{ + NSMutableDictionary *aclsForObject; + + aclsForObject = [aclCache objectForKey: objectPath]; + if (!aclsForObject) + { + aclsForObject = [NSMutableDictionary dictionary]; + [aclCache setObject: aclsForObject + forKey: objectPath]; + } + if (roles) + [aclsForObject setObject: roles forKey: uid]; + else + [aclsForObject removeObjectForKey: uid]; +} + +- (NSArray *) aclsForUser: (NSString *) uid + forObjectAtPath: (NSArray *) objectPathArray +{ + NSArray *acls; + NSString *objectPath; + NSDictionary *aclsForObject; + + objectPath = [objectPathArray componentsJoinedByString: @"/"]; + aclsForObject = [aclCache objectForKey: objectPath]; + if (aclsForObject) + acls = [aclsForObject objectForKey: uid]; + else + acls = nil; + if (!acls) + { + acls = [self _fetchAclsForUser: uid forObjectAtPath: objectPath]; + [self _cacheRoles: acls forUser: uid forObjectAtPath: objectPath]; + } + + if (!([acls count] || [uid isEqualToString: defaultUserID])) + acls = [self aclsForUser: defaultUserID + forObjectAtPath: objectPathArray]; + + return acls; +} + +- (void) removeAclsForUsers: (NSArray *) users + forObjectAtPath: (NSArray *) objectPathArray +{ + EOQualifier *qualifier; + NSString *uids, *qs, *objectPath; + NSMutableDictionary *aclsForObject; + + if ([users count] > 0) + { + objectPath = [objectPathArray componentsJoinedByString: @"/"]; + aclsForObject = [aclCache objectForKey: objectPath]; + if (aclsForObject) + [aclsForObject removeObjectsForKeys: users]; + uids = [users componentsJoinedByString: @"') OR (c_uid = '"]; + qs = [NSString + stringWithFormat: @"(c_object = '/%@') AND ((c_uid = '%@'))", + objectPath, uids]; + qualifier = [EOQualifier qualifierWithQualifierFormat: qs]; + [[self ocsFolder] deleteAclMatchingQualifier: qualifier]; + } +} + +- (void) _commitRoles: (NSArray *) roles + forUID: (NSString *) uid + forObject: (NSString *) objectPath +{ + EOAdaptorChannel *channel; + GCSFolder *folder; + NSEnumerator *userRoles; + NSString *SQL, *currentRole; + + folder = [self ocsFolder]; + channel = [folder acquireAclChannel]; + userRoles = [roles objectEnumerator]; + currentRole = [userRoles nextObject]; + while (currentRole) + { + SQL = [NSString stringWithFormat: @"INSERT INTO %@" + @" (c_object, c_uid, c_role)" + @" VALUES ('/%@', '%@', '%@')", + [folder aclTableName], + objectPath, uid, currentRole]; + [channel evaluateExpressionX: SQL]; + currentRole = [userRoles nextObject]; + } + + [folder releaseChannel: channel]; +} + +- (void) setRoles: (NSArray *) roles + forUser: (NSString *) uid + forObjectAtPath: (NSArray *) objectPathArray +{ + NSString *objectPath; + NSMutableArray *newRoles; + + [self removeAclsForUsers: [NSArray arrayWithObject: uid] + forObjectAtPath: objectPathArray]; + + newRoles = [NSMutableArray arrayWithArray: roles]; + [newRoles removeObject: SOGoRole_AuthorizedSubscriber]; + [newRoles removeObject: SOGoRole_None]; + objectPath = [objectPathArray componentsJoinedByString: @"/"]; + [self _cacheRoles: newRoles forUser: uid + forObjectAtPath: objectPath]; + if (![newRoles count]) + [newRoles addObject: SOGoRole_None]; + + [self _commitRoles: newRoles forUID: uid forObject: objectPath]; +} + +/* acls */ +- (NSArray *) aclUsers +{ + return [self aclUsersForObjectAtPath: [self pathArrayToSoObject]]; +} + +- (NSArray *) aclsForUser: (NSString *) uid +{ + NSMutableArray *acls; + NSArray *ownAcls, *containerAcls; + + acls = [NSMutableArray array]; + ownAcls = [self aclsForUser: uid + forObjectAtPath: [self pathArrayToSoObject]]; + [acls addObjectsFromArray: ownAcls]; + if ([container respondsToSelector: @selector (aclsForUser:)]) + { + containerAcls = [container aclsForUser: uid]; + if ([containerAcls count] > 0) + { + if ([containerAcls containsObject: SOGoRole_ObjectReader]) + [acls addObject: SOGoRole_ObjectViewer]; +#warning this should be checked + if ([containerAcls containsObject: SOGoRole_ObjectEraser]) + [acls addObject: SOGoRole_ObjectEraser]; + } + } + + return acls; +} + +- (void) setRoles: (NSArray *) roles + forUser: (NSString *) uid +{ + return [self setRoles: roles + forUser: uid + forObjectAtPath: [self pathArrayToSoObject]]; +} + +- (void) removeAclsForUsers: (NSArray *) users +{ + return [self removeAclsForUsers: users + forObjectAtPath: [self pathArrayToSoObject]]; +} + +- (NSString *) defaultUserID +{ + return defaultUserID; +} + +- (NSString *) httpURLForAdvisoryToUser: (NSString *) uid +{ + return [[self soURL] absoluteString]; +} + +- (NSString *) resourceURLForAdvisoryToUser: (NSString *) uid +{ + return [[self davURL] absoluteString]; } /* WebDAV */ -- (BOOL)davIsCollection { +- (BOOL) davIsCollection +{ return [self isFolderish]; }