]> 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 ee96bf3b8e9e8eaf6778a050308bdfdf9611b53d..7d914d396780f425236abec414f435bfeb7318db 100644 (file)
   02111-1307, USA.
 */
 
-#include "SOGoFolder.h"
-#include "common.h"
-#include <GDLContentStore/GCSFolderManager.h>
-#include <GDLContentStore/GCSFolder.h>
-#include <unistd.h>
-#include <stdlib.h>
+#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"
+
+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 {
-  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 {
     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;
   
   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];
 }