2010-12-13 17:28:18 +01:00
|
|
|
/* SOGoMAPIFSFolder.m - this file is part of SOGo
|
|
|
|
*
|
|
|
|
* Copyright (C) 2010 Inverse inc.
|
|
|
|
*
|
|
|
|
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
|
|
|
*
|
|
|
|
* This file is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 3, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This file is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; see the file COPYING. If not, write to
|
|
|
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#import <Foundation/NSArray.h>
|
2011-11-18 16:26:03 +01:00
|
|
|
#import <Foundation/NSData.h>
|
|
|
|
#import <Foundation/NSDictionary.h>
|
2010-12-13 17:28:18 +01:00
|
|
|
#import <Foundation/NSException.h>
|
|
|
|
#import <Foundation/NSFileManager.h>
|
2011-11-18 16:26:03 +01:00
|
|
|
#import <Foundation/NSPropertyList.h>
|
2010-12-13 17:28:18 +01:00
|
|
|
#import <Foundation/NSString.h>
|
|
|
|
#import <Foundation/NSValue.h>
|
|
|
|
#import <Foundation/NSURL.h>
|
|
|
|
|
|
|
|
#import <NGExtensions/NSObject+Logs.h>
|
2011-11-18 16:26:03 +01:00
|
|
|
#import <SOGo/NSArray+Utilities.h>
|
2010-12-13 17:28:18 +01:00
|
|
|
|
2011-10-27 01:52:55 +02:00
|
|
|
#import "EOQualifier+MAPI.h"
|
2010-12-13 17:28:18 +01:00
|
|
|
#import "SOGoMAPIFSMessage.h"
|
|
|
|
|
|
|
|
#import "SOGoMAPIFSFolder.h"
|
|
|
|
|
|
|
|
#undef DEBUG
|
2011-11-09 16:02:29 +01:00
|
|
|
#include <talloc.h>
|
|
|
|
#include <util/time.h>
|
2010-12-13 17:28:18 +01:00
|
|
|
#include <mapistore/mapistore.h>
|
|
|
|
#include <mapistore/mapistore_errors.h>
|
|
|
|
#include <libmapiproxy.h>
|
|
|
|
#include <param.h>
|
|
|
|
|
|
|
|
static NSString *privateDir = nil;
|
|
|
|
|
|
|
|
@implementation SOGoMAPIFSFolder
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
{
|
|
|
|
struct loadparm_context *lpCtx;
|
|
|
|
const char *cPrivateDir;
|
|
|
|
|
|
|
|
if (!privateDir)
|
|
|
|
{
|
|
|
|
lpCtx = loadparm_init_global (true);
|
|
|
|
cPrivateDir = lpcfg_private_dir (lpCtx);
|
|
|
|
privateDir = [NSString stringWithUTF8String: cPrivateDir];
|
|
|
|
[privateDir retain];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (id) folderWithURL: (NSURL *) url
|
2010-12-30 15:51:35 +01:00
|
|
|
andTableType: (uint8_t) tableType
|
2010-12-13 17:28:18 +01:00
|
|
|
{
|
|
|
|
SOGoMAPIFSFolder *newFolder;
|
|
|
|
|
2010-12-30 15:51:35 +01:00
|
|
|
newFolder = [[self alloc] initWithURL: url
|
|
|
|
andTableType: tableType];
|
2010-12-13 17:28:18 +01:00
|
|
|
[newFolder autorelease];
|
|
|
|
|
|
|
|
return newFolder;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) init
|
|
|
|
{
|
|
|
|
if ((self = [super init]))
|
|
|
|
{
|
|
|
|
directory = nil;
|
|
|
|
directoryIsSane = NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
[directory release];
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initWithURL: (NSURL *) url
|
2010-12-30 15:51:35 +01:00
|
|
|
andTableType: (uint8_t) tableType
|
2010-12-13 17:28:18 +01:00
|
|
|
{
|
2010-12-30 15:51:35 +01:00
|
|
|
NSString *path, *tableParticle;
|
2010-12-13 17:28:18 +01:00
|
|
|
|
|
|
|
if ((self = [self init]))
|
|
|
|
{
|
2010-12-30 15:51:35 +01:00
|
|
|
if (tableType == MAPISTORE_MESSAGE_TABLE)
|
|
|
|
tableParticle = @"message";
|
|
|
|
else if (tableType == MAPISTORE_FAI_TABLE)
|
|
|
|
tableParticle = @"fai";
|
2011-06-04 02:13:43 +02:00
|
|
|
else if (tableType == MAPISTORE_FOLDER_TABLE)
|
|
|
|
tableParticle = @"folder";
|
2010-12-30 15:51:35 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
[NSException raise: @"MAPIStoreIOException"
|
|
|
|
format: @"unsupported table type: %d", tableType];
|
|
|
|
tableParticle = nil;
|
|
|
|
}
|
|
|
|
|
2010-12-13 17:28:18 +01:00
|
|
|
path = [url path];
|
|
|
|
if (![path hasSuffix: @"/"])
|
|
|
|
path = [NSString stringWithFormat: @"%@/", path];
|
2010-12-30 15:51:35 +01:00
|
|
|
directory = [NSString stringWithFormat: @"%@/mapistore/SOGo/%@/%@/%@%@",
|
|
|
|
privateDir, [url user], tableParticle,
|
|
|
|
[url host], path];
|
2010-12-13 17:28:18 +01:00
|
|
|
[self logWithFormat: @"directory: %@", directory];
|
|
|
|
[directory retain];
|
|
|
|
ASSIGN (nameInContainer, [path stringByDeletingLastPathComponent]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2011-07-08 21:58:54 +02:00
|
|
|
- (id) initWithName: (NSString *) newName
|
|
|
|
inContainer: (id) newContainer
|
|
|
|
{
|
|
|
|
if ((self = [super initWithName: newName inContainer: newContainer]))
|
|
|
|
{
|
|
|
|
directory = [[newContainer directory]
|
|
|
|
stringByAppendingPathComponent: newName];
|
|
|
|
[directory retain];
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2010-12-13 17:28:18 +01:00
|
|
|
- (NSString *) directory
|
|
|
|
{
|
|
|
|
return directory;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (SOGoMAPIFSMessage *) newMessage
|
|
|
|
{
|
|
|
|
NSString *filename;
|
|
|
|
|
|
|
|
filename = [NSString stringWithFormat: @"%@.plist",
|
|
|
|
[SOGoObject globallyUniqueObjectId]];
|
|
|
|
|
|
|
|
return [SOGoMAPIFSMessage objectWithName: filename inContainer: self];
|
|
|
|
}
|
|
|
|
|
2011-01-06 04:20:24 +01:00
|
|
|
- (void) ensureDirectory
|
2010-12-13 17:28:18 +01:00
|
|
|
{
|
|
|
|
NSFileManager *fm;
|
|
|
|
NSDictionary *attributes;
|
|
|
|
BOOL isDir;
|
|
|
|
|
2011-07-08 21:58:54 +02:00
|
|
|
if (!directory)
|
|
|
|
[NSException raise: @"MAPIStoreIOException"
|
|
|
|
format: @"directory is nil"];
|
|
|
|
|
2010-12-13 17:28:18 +01:00
|
|
|
fm = [NSFileManager defaultManager];
|
|
|
|
if ([fm fileExistsAtPath: directory isDirectory: &isDir])
|
|
|
|
{
|
|
|
|
if (!isDir)
|
|
|
|
[NSException raise: @"MAPIStoreIOException"
|
|
|
|
format: @"object at path '%@' is not a directory",
|
|
|
|
directory];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
attributes
|
|
|
|
= [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: 0700]
|
|
|
|
forKey: NSFilePosixPermissions];
|
|
|
|
[fm createDirectoryAtPath: directory
|
|
|
|
attributes: attributes];
|
|
|
|
}
|
|
|
|
|
|
|
|
directoryIsSane = YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) _objectsInDirectory: (BOOL) dirs
|
|
|
|
{
|
|
|
|
NSFileManager *fm;
|
|
|
|
NSArray *contents;
|
|
|
|
NSMutableArray *files;
|
|
|
|
NSUInteger count, max;
|
|
|
|
NSString *file, *fullName;
|
|
|
|
BOOL isDir;
|
|
|
|
|
|
|
|
if (!directoryIsSane)
|
2011-01-06 04:20:24 +01:00
|
|
|
[self ensureDirectory];
|
2010-12-13 17:28:18 +01:00
|
|
|
|
|
|
|
fm = [NSFileManager defaultManager];
|
|
|
|
contents = [fm directoryContentsAtPath: directory];
|
|
|
|
max = [contents count];
|
|
|
|
files = [NSMutableArray arrayWithCapacity: max];
|
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
{
|
|
|
|
file = [contents objectAtIndex: count];
|
2011-11-18 16:26:03 +01:00
|
|
|
if (![file isEqualToString: @"permissions.plist"])
|
|
|
|
{
|
|
|
|
fullName = [directory stringByAppendingPathComponent: file];
|
|
|
|
if ([fm fileExistsAtPath: fullName
|
|
|
|
isDirectory: &isDir]
|
|
|
|
&& dirs == isDir)
|
|
|
|
[files addObject: file];
|
|
|
|
}
|
2010-12-13 17:28:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return files;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) toManyRelationshipKeys
|
|
|
|
{
|
|
|
|
return [self _objectsInDirectory: YES];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) toOneRelationshipKeys
|
|
|
|
{
|
|
|
|
return [self _objectsInDirectory: NO];
|
|
|
|
}
|
|
|
|
|
2011-07-27 23:59:37 +02:00
|
|
|
- (NSArray *) toOneRelationshipKeysMatchingQualifier: (EOQualifier *) qualifier
|
|
|
|
andSortOrderings: (NSArray *) sortOrderings
|
|
|
|
{
|
|
|
|
NSArray *allKeys;
|
|
|
|
NSMutableArray *keys;
|
|
|
|
NSUInteger count, max;
|
|
|
|
NSString *messageKey;
|
|
|
|
SOGoMAPIFSMessage *message;
|
|
|
|
|
|
|
|
if (sortOrderings)
|
|
|
|
[self warnWithFormat: @"sorting is not handled yet"];
|
|
|
|
|
|
|
|
allKeys = [self toOneRelationshipKeys];
|
|
|
|
if (qualifier)
|
|
|
|
{
|
|
|
|
[self logWithFormat: @"%s: getting restricted FAI keys", __PRETTY_FUNCTION__];
|
|
|
|
max = [allKeys count];
|
|
|
|
keys = [NSMutableArray arrayWithCapacity: max];
|
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
{
|
|
|
|
messageKey = [allKeys objectAtIndex: count];
|
|
|
|
message = [self lookupName: messageKey
|
|
|
|
inContext: nil
|
|
|
|
acquire: NO];
|
2011-10-27 01:52:55 +02:00
|
|
|
if ([qualifier evaluateMAPIVolatileMessage: message])
|
2011-07-27 23:59:37 +02:00
|
|
|
[keys addObject: messageKey];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
keys = (NSMutableArray *) allKeys;
|
|
|
|
|
|
|
|
return keys;
|
|
|
|
}
|
|
|
|
|
2010-12-13 17:28:18 +01:00
|
|
|
- (id) lookupName: (NSString *) fileName
|
|
|
|
inContext: (WOContext *) woContext
|
|
|
|
acquire: (BOOL) acquire
|
|
|
|
{
|
|
|
|
NSFileManager *fm;
|
|
|
|
NSString *fullName;
|
|
|
|
id object;
|
|
|
|
BOOL isDir;
|
|
|
|
|
|
|
|
if (!directoryIsSane)
|
2011-01-06 04:20:24 +01:00
|
|
|
[self ensureDirectory];
|
2010-12-13 17:28:18 +01:00
|
|
|
|
|
|
|
fm = [NSFileManager defaultManager];
|
|
|
|
fullName = [directory stringByAppendingPathComponent: fileName];
|
|
|
|
if ([fm fileExistsAtPath: fullName
|
|
|
|
isDirectory: &isDir])
|
|
|
|
{
|
|
|
|
if (isDir)
|
2011-07-08 21:58:54 +02:00
|
|
|
object = [isa objectWithName: fileName
|
|
|
|
inContainer: self];
|
2010-12-13 17:28:18 +01:00
|
|
|
else
|
|
|
|
object = [SOGoMAPIFSMessage objectWithName: fileName
|
|
|
|
inContainer: self];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
object = nil;
|
|
|
|
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
2011-06-04 02:13:43 +02:00
|
|
|
- (id) _fileAttributeForKey: (NSString *) key
|
|
|
|
{
|
|
|
|
NSDictionary *attributes;
|
|
|
|
|
|
|
|
attributes = [[NSFileManager defaultManager]
|
|
|
|
fileAttributesAtPath: directory
|
|
|
|
traverseLink: NO];
|
|
|
|
|
|
|
|
return [attributes objectForKey: key];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSCalendarDate *) creationTime
|
|
|
|
{
|
|
|
|
return [self _fileAttributeForKey: NSFileCreationDate];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSCalendarDate *) lastModificationTime
|
|
|
|
{
|
|
|
|
return [self _fileAttributeForKey: NSFileModificationDate];
|
|
|
|
}
|
|
|
|
|
2011-11-18 16:26:03 +01:00
|
|
|
/* acl */
|
|
|
|
- (NSString *) defaultUserID
|
|
|
|
{
|
|
|
|
return @"default";
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSMutableDictionary *) _aclEntries
|
|
|
|
{
|
|
|
|
NSMutableDictionary *aclEntries;
|
|
|
|
NSData *content;
|
|
|
|
NSString *error, *filename;
|
|
|
|
NSPropertyListFormat format;
|
|
|
|
|
|
|
|
filename = [directory stringByAppendingPathComponent: @"permissions.plist"];
|
|
|
|
content = [NSData dataWithContentsOfFile: filename];
|
|
|
|
if (content)
|
|
|
|
aclEntries = [NSPropertyListSerialization propertyListFromData: content
|
|
|
|
mutabilityOption: NSPropertyListMutableContainers
|
|
|
|
format: &format
|
|
|
|
errorDescription: &error];
|
|
|
|
else
|
|
|
|
aclEntries = nil;
|
|
|
|
if (!aclEntries)
|
|
|
|
{
|
|
|
|
aclEntries = [NSMutableDictionary dictionary];
|
|
|
|
[aclEntries setObject: [NSMutableArray array] forKey: @"users"];
|
|
|
|
[aclEntries setObject: [NSMutableDictionary dictionary]
|
|
|
|
forKey: @"entries"];
|
|
|
|
}
|
|
|
|
|
|
|
|
return aclEntries;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) _saveAcl: (NSDictionary *) acl
|
|
|
|
{
|
|
|
|
NSString *filename;
|
|
|
|
NSData *content;
|
|
|
|
|
|
|
|
filename = [directory stringByAppendingPathComponent: @"permissions.plist"];
|
|
|
|
[self ensureDirectory];
|
|
|
|
|
|
|
|
if (acl)
|
|
|
|
content = [NSPropertyListSerialization
|
|
|
|
dataFromPropertyList: acl
|
|
|
|
format: NSPropertyListBinaryFormat_v1_0
|
|
|
|
errorDescription: NULL];
|
|
|
|
else
|
|
|
|
content = [NSData data];
|
|
|
|
if (![content writeToFile: filename atomically: NO])
|
|
|
|
[NSException raise: @"MAPIStoreIOException"
|
|
|
|
format: @"could not save acl"];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) addUserInAcls: (NSString *) user
|
|
|
|
{
|
|
|
|
NSMutableDictionary *acl;
|
|
|
|
NSMutableArray *users;
|
|
|
|
|
|
|
|
acl = [self _aclEntries];
|
|
|
|
users = [acl objectForKey: @"users"];
|
|
|
|
[users addObjectUniquely: user];
|
|
|
|
[self _saveAcl: acl];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) removeAclsForUsers: (NSArray *) oldUsers
|
|
|
|
{
|
|
|
|
NSDictionary *acl;
|
|
|
|
NSMutableDictionary *entries;
|
|
|
|
NSMutableArray *users;
|
|
|
|
|
|
|
|
acl = [self _aclEntries];
|
|
|
|
entries = [acl objectForKey: @"entries"];
|
|
|
|
[entries removeObjectsForKeys: oldUsers];
|
|
|
|
users = [acl objectForKey: @"users"];
|
|
|
|
[users removeObjectsInArray: oldUsers];
|
|
|
|
[self _saveAcl: acl];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) aclUsers
|
|
|
|
{
|
|
|
|
return [[self _aclEntries] objectForKey: @"users"];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) aclsForUser: (NSString *) uid
|
|
|
|
{
|
|
|
|
NSDictionary *entries;
|
|
|
|
|
|
|
|
entries = [[self _aclEntries] objectForKey: @"entries"];
|
|
|
|
|
|
|
|
return [entries objectForKey: uid];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) setRoles: (NSArray *) roles
|
|
|
|
forUser: (NSString *) uid
|
|
|
|
{
|
|
|
|
NSMutableDictionary *acl;
|
|
|
|
NSMutableDictionary *entries;
|
|
|
|
|
|
|
|
acl = [self _aclEntries];
|
|
|
|
entries = [acl objectForKey: @"entries"];
|
|
|
|
[entries setObject: roles forKey: uid];
|
|
|
|
[self _saveAcl: acl];
|
|
|
|
}
|
|
|
|
|
2010-12-13 17:28:18 +01:00
|
|
|
@end
|