]> err.no Git - scalable-opengroupware.org/blobdiff - SoObjects/SOGo/SOGoFolder.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1087 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / SoObjects / SOGo / SOGoFolder.m
index c79c0df949770111324e2145aa2e797c48eed7c7..7d914d396780f425236abec414f435bfeb7318db 100644 (file)
   02111-1307, USA.
 */
 
+#import <unistd.h>
+#import <stdlib.h>
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSDictionary.h>
+#import <Foundation/NSException.h>
+#import <Foundation/NSURL.h>
+
 #import <NGObjWeb/SoObject.h>
+#import <NGExtensions/NSNull+misc.h>
+#import <NGExtensions/NSObject+Logs.h>
+#import <EOControl/EOQualifier.h>
+#import <GDLAccess/EOAdaptorChannel.h>
 #import <GDLContentStore/GCSFolderManager.h>
 #import <GDLContentStore/GCSFolder.h>
 #import <GDLContentStore/GCSFolderType.h>
+#import <SaxObjC/XMLNamespaces.h>
+
+#import "SOGoPermissions.h"
 
 #import "SOGoFolder.h"
-#import "common.h"
-#import <unistd.h>
-#import <stdlib.h>
 
-#import "SOGoAclsFolder.h"
+static NSString *defaultUserID = @"<default>";
 
 @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 {
+- (GCSFolderManager *) folderManager
+{
   static GCSFolderManager *folderManager = nil;
 
   if (!folderManager)
   return folderManager;
 }
 
-- (GCSFolder *)ocsFolderForPath:(NSString *)_path {
+- (GCSFolder *) ocsFolderForPath: (NSString *) _path
+{
   return [[self folderManager] folderAtPath:_path];
 }
 
-- (GCSFolder *) ocsFolder {
+- (GCSFolder *) ocsFolder
+{
   GCSFolder *folder;
 
   if (!ocsFolder)
   if ([self respondsToSelector: @selector (groupDavResourceType)])
     {
       groupDavCollection = [NSArray arrayWithObjects: [self groupDavResourceType],
-                                    @"http://groupdav.org/", @"G", nil];
+                                    XMLNS_GROUPDAV, nil];
       rType = [NSArray arrayWithObjects: @"collection", groupDavCollection, nil];
     }
   else
   return rType;
 }
 
+- (NSString *) davContentType
+{
+  return @"httpd/unix-directory";
+}
+
 - (NSArray *) toOneRelationshipKeys {
   /* toOneRelationshipKeys are the 'files' contained in a folder */
   NSMutableArray *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];
 }