Renamed cache files for generalization.

The upcoming commit will rename the content.
This commit is contained in:
Ludovic Marcotte committed 2014-05-13 19:58:19 -04:00
1 parent 2922f15ca7
commit ef2188962a
8 files changed

No files matched your search

@@ -0,0 +1,34 @@
/* GCSSpecialQueries+OpenChange.h - this file is part of SOGo
*
* Copyright (C) 2012 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 2, 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.
*/
#ifndef GCSSPECIALQUERIES_OPENCHANGE_H
#define GCSSPECIALQUERIES_OPENCHANGE_H
#import <GDLContentStore/GCSSpecialQueries.h>
@interface GCSSpecialQueries (OpenChangeHelpers)
- (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName;
@end
#endif /* GCSSPECIALQUERIES_OPENCHANGE_H */
@@ -0,0 +1,107 @@
/* GCSSpecialQueries+OpenChange.m - this file is part of SOGo
*
* Copyright (C) 2012 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/NSString.h>
#import "GCSSpecialQueries+OpenChange.h"
@interface GCSPostgreSQLSpecialQueries (OpenChangeHelpers)
@end
@interface GCSMySQLSpecialQueries (OpenChangeHelpers)
@end
@interface GCSOracleSpecialQueries (OpenChangeHelpers)
@end
@implementation GCSSpecialQueries (OpenChangeHelpers)
/* FIXME: c_parent_path should be indexed */
- (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName
{
[self subclassResponsibility: _cmd];
return nil;
}
@end
@implementation GCSPostgreSQLSpecialQueries (OpenChangeHelpers)
- (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName
{
static NSString *sqlFolderFormat
= (@"CREATE TABLE %@ ("
@" c_path VARCHAR(255) PRIMARY KEY,"
@" c_parent_path VARCHAR(255),"
@" c_type SMALLINT NOT NULL,"
@" c_creationdate INT4 NOT NULL,"
@" c_lastmodified INT4 NOT NULL,"
@" c_version INT4 NOT NULL DEFAULT 0,"
@" c_deleted SMALLINT NOT NULL DEFAULT 0,"
@" c_content TEXT)");
return [NSString stringWithFormat: sqlFolderFormat, tableName];
}
@end
@implementation GCSMySQLSpecialQueries (OpenChangeHelpers)
- (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName
{
static NSString *sqlFolderFormat
= (@"CREATE TABLE %@ ("
@" c_path VARCHAR(255) PRIMARY KEY,"
@" c_parent_path VARCHAR(255),"
@" c_type TINYINT NOT NULL,"
@" c_creationdate INT NOT NULL,"
@" c_lastmodified INT NOT NULL,"
@" c_version INT NOT NULL DEFAULT 0,"
@" c_deleted TINYINT NOT NULL DEFAULT 0,"
@" c_content LONGTEXT)");
return [NSString stringWithFormat: sqlFolderFormat, tableName];
}
@end
@implementation GCSOracleSpecialQueries (OpenChangeHelpers)
- (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName
{
static NSString *sqlFolderFormat
= (@"CREATE TABLE %@ ("
@" c_path VARCHAR2(255) PRIMARY KEY,"
@" c_parent_path VARCHAR2(255),"
@" c_type SMALLINT NOT NULL,"
@" c_creationdate INT4 NOT NULL,"
@" c_lastmodified INT4 NOT NULL,"
@" c_version INT4 NOT NULL DEFAULT 0,"
@" c_deleted SMALLINT NOT NULL DEFAULT 0,"
@" c_content CLOB)");
return [NSString stringWithFormat: sqlFolderFormat, tableName];
}
@end
+59
View File
@@ -0,0 +1,59 @@
/* SOGoMAPIDBFolder.h - this file is part of SOGo
*
* Copyright (C) 2012 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.
*/
#ifndef SOGOMAPIDBFOLDER_H
#define SOGOMAPIDBFOLDER_H
#import "SOGoMAPIDBObject.h"
@class NSArray;
@class NSMutableString;
@class NSString;
@class NSURL;
@class EOQualifier;
@class SOGoMAPIDBMessage;
@interface SOGoMAPIDBFolder : SOGoMAPIDBObject
{
NSString *pathPrefix; /* for root folders */
SOGoMAPIDBObject *aclMessage;
}
- (void) setPathPrefix: (NSString *) newPathPrefix;
- (NSMutableString *) pathForChild: (NSString *) childName;
- (NSArray *) toOneRelationshipKeys;
- (NSArray *) toManyRelationshipKeys;
- (NSArray *) childKeysOfType: (SOGoCacheObjectType) type
includeDeleted: (BOOL) includeDeleted
matchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings;
- (void) changePathTo: (NSString *) newPath;
@end
#endif /* SOGOMAPIDBFOLDER_H */
+481
View File
@@ -0,0 +1,481 @@
/* SOGoMAPIDBFolder.m - this file is part of SOGo
*
* Copyright (C) 2012 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>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
#import <Foundation/NSPropertyList.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
#import <Foundation/NSURL.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSNull+misc.h>
#import <GDLAccess/EOAdaptorChannel.h>
#import <GDLContentStore/GCSChannelManager.h>
#import <SOGo/NSArray+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoUser.h>
#import "EOQualifier+MAPI.h"
#import "GCSSpecialQueries+OpenChange.h"
#import "SOGoMAPIDBMessage.h"
#import "SOGoMAPIDBFolder.h"
#undef DEBUG
#include <stdbool.h>
#include <talloc.h>
#include <util/time.h>
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>
#include <libmapiproxy.h>
#include <param.h>
Class SOGoMAPIDBObjectK = Nil;
@implementation SOGoMAPIDBFolder
+ (void) initialize
{
SOGoMAPIDBObjectK = [SOGoMAPIDBObject class];
}
- (id) init
{
if ((self = [super init]))
{
pathPrefix = nil;
}
return self;
}
- (id) initWithName: (NSString *) name inContainer: (id) newContainer
{
if ((self = [super initWithName: name inContainer: newContainer]))
{
objectType = MAPIFolderCacheObject;
aclMessage = [SOGoMAPIDBObject objectWithName: @"permissions"
inContainer: self];
[aclMessage setObjectType: MAPIInternalCacheObject];
[aclMessage retain];
}
return self;
}
- (void) dealloc
{
[aclMessage release];
[pathPrefix release];
[super dealloc];
}
- (BOOL) isFolderish
{
return YES;
}
- (void) setPathPrefix: (NSString *) newPathPrefix
{
ASSIGN (pathPrefix, newPathPrefix);
}
- (NSMutableString *) pathForChild: (NSString *) childName
{
NSMutableString *path;
path = [self path];
[path appendFormat: @"/%@", childName];
return path;
}
- (NSMutableString *) path
{
NSMutableString *path;
path = [super path];
if (pathPrefix)
[path insertString: pathPrefix atIndex: 0];
return path;
}
// - (SOGoMAPIDBMessage *) newMessage
// {
// NSString *newFilename;
// newFilename = [NSString stringWithFormat: @"%@.plist",
// [SOGoObject globallyUniqueObjectId]];
// return [SOGoMAPIDBMessage objectWithName: filename inContainer: self];
// }
- (NSArray *) childKeysOfType: (SOGoCacheObjectType) type
includeDeleted: (BOOL) includeDeleted
matchingQualifier: (EOQualifier *) qualifier
andSortOrderings: (NSArray *) sortOrderings
{
NSMutableArray *childKeys;
NSMutableString *sql// , *qualifierClause
;
NSString *childPathPrefix, *childPath, *childKey;
NSMutableArray *whereClause;
NSArray *records;
NSDictionary *record;
NSUInteger childPathPrefixLen, count, max;
SOGoMAPIDBObject *currentChild;
/* query construction */
sql = [NSMutableString stringWithCapacity: 256];
[sql appendFormat: @"SELECT * FROM %@", [self tableName]];
whereClause = [NSMutableArray arrayWithCapacity: 2];
[whereClause addObject: [NSString stringWithFormat: @"c_parent_path = '%@'",
[self path]]];
[whereClause addObject: [NSString stringWithFormat: @"c_type = %d", type]];
if (!includeDeleted)
[whereClause addObject: @"c_deleted = 0"];
[sql appendFormat: @" WHERE %@",
[whereClause componentsJoinedByString: @" AND "]];
childPathPrefix = [NSString stringWithFormat: @"%@/", [self path]];
/* results */
records = [self performSQLQuery: sql];
if (records)
{
max = [records count];
childKeys = [NSMutableArray arrayWithCapacity: max];
childPathPrefixLen = [childPathPrefix length];
for (count = 0; count < max; count++)
{
record = [records objectAtIndex: count];
childPath = [record objectForKey: @"c_path"];
childKey = [childPath substringFromIndex: childPathPrefixLen];
if ([childKey rangeOfString: @"/"].location == NSNotFound)
{
if (qualifier)
{
currentChild = [SOGoMAPIDBObject objectWithName: childKey
inContainer: self];
[currentChild setupFromRecord: record];
if ([qualifier evaluateSOGoMAPIDBObject: currentChild])
[childKeys addObject: childKey];
}
else
[childKeys addObject: childKey];
}
}
}
else
childKeys = nil;
return childKeys;
}
- (NSArray *) toManyRelationshipKeys
{
return [self childKeysOfType: MAPIFolderCacheObject
includeDeleted: NO
matchingQualifier: nil
andSortOrderings: nil];
}
- (NSArray *) toOneRelationshipKeys
{
return [self childKeysOfType: MAPIMessageCacheObject
includeDeleted: NO
matchingQualifier: nil
andSortOrderings: nil];
}
- (void) setNameInContainer: (NSString *) newName
{
NSMutableString *sql;
NSString *oldPath, *newPath, *path, *parentPath;
NSMutableArray *queries;
NSArray *records;
NSDictionary *record;
NSUInteger count, max;
/* change the paths in children records */
if (nameInContainer)
oldPath = [self path];
[super setNameInContainer: newName];
if (nameInContainer)
{
newPath = [self path];
sql = [NSMutableString stringWithFormat:
@"SELECT c_path, c_parent_path FROM %@"
@" WHERE c_path LIKE '%@/%%'",
[self tableName], oldPath];
records = [self performSQLQuery: sql];
max = [records count];
queries = [NSMutableArray arrayWithCapacity: max + 1];
if (max > 0)
{
for (count = 0; count < max; count++)
{
record = [records objectAtIndex: count];
path = [record objectForKey: @"c_path"];
sql = [NSMutableString stringWithFormat: @"UPDATE %@"
@" SET c_path = '%@'",
[self tableName],
[path stringByReplacingPrefix: oldPath
withPrefix: newPath]];
parentPath = [record objectForKey: @"c_parent_path"];
if ([parentPath isNotNull])
[sql appendFormat: @", c_parent_path = '%@'",
[parentPath stringByReplacingPrefix: oldPath
withPrefix: newPath]];
[sql appendFormat: @" WHERE c_path = '%@'", path];
[queries addObject: sql];
}
[self performBatchSQLQueries: queries];
}
}
}
- (void) changePathTo: (NSString *) newPath
{
NSMutableString *sql// , *qualifierClause
;
NSString *oldPath, *oldPathAsPrefix, *path, *parentPath;
NSMutableArray *queries;
NSArray *records;
NSDictionary *record;
NSUInteger count, max;
/* change the paths in children records */
oldPath = [self path];
oldPathAsPrefix = [NSString stringWithFormat: @"%@/", oldPath];
sql = [NSMutableString stringWithFormat:
@"SELECT c_path, c_parent_path FROM %@"
@" WHERE c_path LIKE '%@%%'",
[self tableName], oldPathAsPrefix];
records = [self performSQLQuery: sql];
max = [records count];
queries = [NSMutableArray arrayWithCapacity: max + 1];
if (max > 0)
{
for (count = 0; count < max; count++)
{
record = [records objectAtIndex: count];
path = [record objectForKey: @"c_path"];
sql = [NSMutableString stringWithFormat: @"UPDATE %@"
@" SET c_path = '%@'",
[self tableName],
[path stringByReplacingPrefix: oldPath
withPrefix: newPath]];
parentPath = [record objectForKey: @"c_parent_path"];
if ([parentPath isNotNull])
[sql appendFormat: @", c_parent_path = '%@'",
[parentPath stringByReplacingPrefix: oldPath
withPrefix: newPath]];
[sql appendFormat: @" WHERE c_path = '%@'", path];
[queries addObject: sql];
}
[self performBatchSQLQueries: queries];
}
/* change the path in this folder record */
[super changePathTo: newPath];
}
// - (NSArray *) toOneRelationshipKeysMatchingQualifier: (EOQualifier *) qualifier
// andSortOrderings: (NSArray *) sortOrderings
// {
// NSArray *allKeys;
// NSMutableArray *keys;
// NSUInteger count, max;
// NSString *messageKey;
// SOGoMAPIDBMessage *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];
// if ([qualifier evaluateMAPIVolatileMessage: message])
// [keys addObject: messageKey];
// }
// }
// else
// keys = (NSMutableArray *) allKeys;
// return keys;
// }
- (id) lookupName: (NSString *) childName
inContext: (WOContext *) woContext
acquire: (BOOL) acquire
{
id object;
Class objectClass;
NSString *childPath;
NSDictionary *record;
childPath = [self pathForChild: childName];
record = [self lookupRecord: childPath newerThanVersion: -1];
if (record)
{
if ([[record objectForKey: @"c_type"] intValue] == MAPIFolderCacheObject)
objectClass = isa;
else
objectClass = SOGoMAPIDBObjectK;
object = [objectClass objectWithName: childName
inContainer: self];
[object setupFromRecord: record];
}
else
object = nil;
return object;
}
- (id) lookupFolder: (NSString *) folderName
inContext: (WOContext *) woContext
{
id object;
object = [SOGoMAPIDBFolder objectWithName: folderName
inContainer: self];
[object reloadIfNeeded];
return object;
}
// - (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];
// }
/* acl */
- (NSString *) defaultUserID
{
return @"default";
}
- (NSMutableDictionary *) _aclEntries
{
NSMutableDictionary *aclEntries;
[aclMessage reloadIfNeeded];
aclEntries = [aclMessage properties];
if (![aclEntries objectForKey: @"users"])
[aclEntries setObject: [NSMutableArray array] forKey: @"users"];
if (![aclEntries objectForKey: @"entries"])
[aclEntries setObject: [NSMutableDictionary dictionary]
forKey: @"entries"];
return aclEntries;
}
- (void) addUserInAcls: (NSString *) user
{
NSMutableDictionary *acl;
NSMutableArray *users;
acl = [self _aclEntries];
users = [acl objectForKey: @"users"];
[users addObjectUniquely: user];
[aclMessage save];
}
- (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];
[aclMessage save];
}
- (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];
[aclMessage save];
}
@end
+85
View File
@@ -0,0 +1,85 @@
/* SOGoMAPIDBObject.h - this file is part of SOGo
*
* Copyright (C) 2012 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.
*/
#ifndef SOGOMAPIDBOBJECT_H
#define SOGOMAPIDBOBJECT_H
#import "SOGoMAPIObject.h"
@class NSArray;
@class NSMutableDictionary;
@class NSMutableString;
@class NSString;
@class NSURL;
@class EOAdaptor;
typedef enum {
MAPIFolderCacheObject = 1,
MAPIMessageCacheObject = 2,
MAPIFAICacheObject = 3,
MAPIInternalCacheObject = 99 /* object = property list */
} SOGoCacheObjectType;
@interface SOGoMAPIDBObject : SOGoMAPIObject
{
NSURL *tableUrl;
BOOL initialized; /* safe guard */
SOGoCacheObjectType objectType;
NSInteger version;
BOOL deleted;
}
/* actions */
- (void) setupFromRecord: (NSDictionary *) record;
- (void) reloadIfNeeded;
- (void) save;
/* accessors */
- (NSMutableString *) path; /* full filename */
- (void) setTableUrl: (NSURL *) newTableUrl;
- (NSURL *) tableUrl;
- (NSString *) tableName;
- (NSArray *) performSQLQuery: (NSString *) sql;
- (NSDictionary *) lookupRecord: (NSString *) path
newerThanVersion: (NSInteger) startVersion;
- (void) setObjectType: (SOGoCacheObjectType) newObjectType;
- (SOGoCacheObjectType) objectType; /* message, fai, folder */
/* automatically set from actions */
- (BOOL) deleted;
- (void) changePathTo: (NSString *) newPath;
/* db helpers */
- (EOAdaptor *) tableChannelAdaptor;
- (NSArray *) performSQLQuery: (NSString *) sql;
- (BOOL) performBatchSQLQueries: (NSArray *) queries;
@end
#endif /* SOGOMAPIDBOBJECT_H */
+565
View File
@@ -0,0 +1,565 @@
/* SOGoMAPIDBObject.m - this file is part of SOGo
*
* Copyright (C) 2012 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>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
#import <Foundation/NSNull.h>
#import <Foundation/NSPropertyList.h>
#import <Foundation/NSString.h>
#import <Foundation/NSURL.h>
#import <Foundation/NSUserDefaults.h>
#import <Foundation/NSValue.h>
#import <GDLAccess/EOAdaptor.h>
#import <GDLAccess/EOAdaptorChannel.h>
#import <GDLAccess/EOAdaptorContext.h>
#import <GDLAccess/EOAttribute.h>
#import <GDLContentStore/GCSChannelManager.h>
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <SOGo/NSObject+Utilities.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoDomainDefaults.h>
#import <SOGo/SOGoUser.h>
#import "GCSSpecialQueries+OpenChange.h"
#import "MAPIStoreTypes.h"
#import "SOGoMAPIDBFolder.h"
#import "BSONCodec.h"
#import "SOGoMAPIDBObject.h"
static EOAttribute *textColumn = nil;
@implementation SOGoMAPIDBObject
+ (void) initialize
{
NSDictionary *description;
if (!textColumn)
{
/* TODO: this is a hack for providing an EOAttribute definition that is
compatible with all the backends that we support. We should make use
of EOModel instead. */
description = [NSDictionary dictionaryWithObjectsAndKeys:
@"c_textfield", @"columnName",
@"VARCHAR", @"externalType",
nil];
textColumn = [EOAttribute attributeFromPropertyList: description];
[textColumn retain];
}
}
/*
= (@"CREATE TABLE %@ ("
@" c_path VARCHAR(255) PRIMARY KEY,"
@" c_parent_path VARCHAR(255),"
@" c_type SMALLINT NOT NULL,"
@" c_creationdate INT4 NOT NULL,"
@" c_lastmodified INT4 NOT NULL,"
@" c_version INT4 NOT NULL DEFAULT 0,"
@" c_deleted SMALLINT NOT NULL DEFAULT 0,"
@" c_content TEXT)");
*/
/* indexes:
c_path (primary key)
c_counter
c_path, c_type
c_path, c_creationdate */
- (id) init
{
if ((self = [super init]))
{
tableUrl = nil;
initialized = NO;
objectType = -1;
deleted = NO;
version = 0;
}
return self;
}
- (void) dealloc
{
[tableUrl release];
[super dealloc];
}
- (void) setTableUrl: (NSURL *) newTableUrl
{
ASSIGN (tableUrl, newTableUrl);
}
- (NSURL *) tableUrl
{
if (!tableUrl)
{
tableUrl = [container tableUrl];
[tableUrl retain];
if (!tableUrl)
[NSException raise: @"MAPIStoreIOException"
format: @"table url is not set for object '%@'", self];
}
return tableUrl;
}
- (NSString *) tableName
{
NSArray *parts;
[self tableUrl];
parts = [[tableUrl path] componentsSeparatedByString: @"/"];
return [parts lastObject];
}
- (void) setupFromRecord: (NSDictionary *) record
{
NSInteger intValue;
NSString *propsValue;//, *error;
NSDictionary *newValues;
//NSPropertyListFormat format;
objectType = [[record objectForKey: @"c_type"] intValue];
intValue = [[record objectForKey: @"c_creationdate"] intValue];
ASSIGN (creationDate,
[NSCalendarDate
dateWithTimeIntervalSince1970: (NSTimeInterval) intValue]);
intValue = [[record objectForKey: @"c_lastmodified"] intValue];
ASSIGN (lastModified,
[NSCalendarDate
dateWithTimeIntervalSince1970: (NSTimeInterval) intValue]);
deleted = ([[record objectForKey: @"c_deleted"] intValue] > 0);
version = [[record objectForKey: @"c_version"] intValue];
propsValue = [record objectForKey: @"c_content"];
if ([propsValue isNotNull])
{
newValues = [[propsValue dataByDecodingBase64] BSONValue];
[properties addEntriesFromDictionary: newValues];
}
else
[properties removeAllObjects];
initialized = YES;
}
/* accessors */
- (NSMutableString *) path
{
NSMutableString *path;
if (container)
path = [container pathForChild: nameInContainer];
else
path = [NSMutableString stringWithFormat: @"/%@", nameInContainer];
if ([path rangeOfString: @"//"].location != NSNotFound)
[NSException raise: @"MAPIStoreIOException"
format: @"object path has not been properly set for"
" folder '%@' (%@)",
self, path];
return path;
}
- (void) setObjectType: (SOGoCacheObjectType) newObjectType
{
objectType = newObjectType;
}
- (SOGoCacheObjectType) objectType /* message, fai, folder */
{
return objectType;
}
- (NSCalendarDate *) creationDate
{
if (!initialized)
[NSException raise: @"MAPIStoreIOException"
format: @"record has not been initialized: %@", self];
return creationDate;
}
- (NSCalendarDate *) lastModified
{
if (!initialized)
[NSException raise: @"MAPIStoreIOException"
format: @"record has not been initialized: %@", self];
return lastModified;
}
- (BOOL) deleted
{
return deleted;
}
- (Class) mapistoreMessageClass
{
NSString *className, *mapiMsgClass;
switch (objectType)
{
case MAPIMessageCacheObject:
mapiMsgClass = [properties
objectForKey: MAPIPropertyKey (PidTagMessageClass)];
if (mapiMsgClass)
{
if ([mapiMsgClass isEqualToString: @"IPM.StickyNote"])
className = @"MAPIStoreNotesMessage";
else
className = @"MAPIStoreDBMessage";
//[self logWithFormat: @"PidTagMessageClass = '%@', returning '%@'",
// mapiMsgClass, className];
}
else
{
//[self warnWithFormat: @"PidTagMessageClass is not set, falling back"
// @" to 'MAPIStoreDBMessage'"];
className = @"MAPIStoreDBMessage";
}
break;
case MAPIFAICacheObject:
className = @"MAPIStoreFAIMessage";
break;
default:
[NSException raise: @"MAPIStoreIOException"
format: @"message class should not be queried for objects"
@" of type '%d'", objectType];
}
return NSClassFromString (className);
}
/* actions */
- (void) setNameInContainer: (NSString *) newNameInContainer
{
NSMutableString *sql;
NSString *oldPath, *newPath;
if (nameInContainer)
oldPath = [self path];
[super setNameInContainer: newNameInContainer];
if (nameInContainer)
{
newPath = [self path];
sql = [NSMutableString stringWithFormat: @"UPDATE %@"
@" SET c_path = '%@'",
[self tableName],
newPath];
[sql appendFormat: @" WHERE c_path = '%@'", oldPath];
[self performBatchSQLQueries: [NSArray arrayWithObject: sql]];
}
}
- (void) changePathTo: (NSString *) newPath
{
NSMutableString *sql;
NSString *oldPath, *newParentPath;
NSRange slashRange;
oldPath = [self path];
slashRange = [newPath rangeOfString: @"/"
options: NSBackwardsSearch];
if (slashRange.location != NSNotFound)
newParentPath = [newPath substringToIndex: slashRange.location];
else
newParentPath = NULL;
sql = [NSMutableString stringWithFormat: @"UPDATE %@"
@" SET c_path = '%@'",
[self tableName],
newPath];
if (newParentPath)
[sql appendFormat: @", c_parent_path = '%@'", newParentPath];
else
[sql appendString: @", c_parent_path = NULL"];
[sql appendFormat: @" WHERE c_path = '%@'", oldPath];
[self performBatchSQLQueries: [NSArray arrayWithObject: sql]];
}
- (EOAdaptor *) tableChannelAdaptor
{
GCSChannelManager *cm;
EOAdaptor *adaptor;
EOAdaptorChannel *channel;
cm = [GCSChannelManager defaultChannelManager];
channel = [cm acquireOpenChannelForURL: [self tableUrl]];
adaptor = [[channel adaptorContext] adaptor];
[cm releaseChannel: channel];
return adaptor;
}
- (NSArray *) performSQLQuery: (NSString *) sql
{
NSMutableArray *records;
GCSChannelManager *cm;
EOAdaptorChannel *channel;
NSException *error;
NSArray *attrs;
NSDictionary *record;
cm = [GCSChannelManager defaultChannelManager];
channel = [cm acquireOpenChannelForURL: [self tableUrl]];
error = [channel evaluateExpressionX: sql];
if (error)
{
records = nil;
[self logWithFormat:
@"an exception occurred when executing query '%@'",
sql];
[self logWithFormat: @"exception is '%@'", error];
}
else
{
records = [NSMutableArray arrayWithCapacity: 256];
attrs = [channel describeResults: NO];
while ((record = [channel fetchAttributes: attrs withZone: NULL]))
[records addObject: record];
}
[cm releaseChannel: channel];
return records;
}
- (BOOL) performBatchSQLQueries: (NSArray *) queries
{
GCSChannelManager *cm;
EOAdaptorChannel *channel;
EOAdaptorContext *dbContext;
NSException *error;
NSUInteger count, max;
NSString *sql;
cm = [GCSChannelManager defaultChannelManager];
channel = [cm acquireOpenChannelForURL: [self tableUrl]];
dbContext = [channel adaptorContext];
[dbContext beginTransaction];
error = nil;
max = [queries count];
for (count = 0; error == nil && count < max; count++)
{
sql = [queries objectAtIndex: count];
error = [channel evaluateExpressionX: sql];
if (error)
[dbContext rollbackTransaction];
}
if (!error)
[dbContext commitTransaction];
[cm releaseChannel: channel];
return (error == nil);
}
- (NSDictionary *) lookupRecord: (NSString *) path
newerThanVersion: (NSInteger) startVersion
{
NSDictionary *record;
NSArray *records;
NSString *tableName, *pathValue;
NSMutableString *sql;
EOAdaptor *adaptor;
if ([path hasSuffix: @"/"])
[NSException raise: @"MAPIStoreIOException"
format: @"path ends with a slash: %@", path];
tableName = [self tableName];
adaptor = [self tableChannelAdaptor];
pathValue = [adaptor formatValue: path
forAttribute: textColumn];
/* query */
sql = [NSMutableString stringWithFormat:
@"SELECT * FROM %@ WHERE c_path = %@",
tableName, pathValue];
if (startVersion > -1)
[sql appendFormat: @" AND c_version > %d", startVersion];
/* execution */
records = [self performSQLQuery: sql];
if ([records count] > 0)
record = [records objectAtIndex: 0];
else
record = nil;
return record;
}
- (void) reloadIfNeeded
{
/* if object is uninitialized: reload without condition, otherwise, load if
c_version > :version */
NSDictionary *record;
if (initialized)
{
if (!isNew)
{
record = [self lookupRecord: [self path]
newerThanVersion: version];
if (record)
[self setupFromRecord: record];
}
}
else
{
record = [self lookupRecord: [self path]
newerThanVersion: -1];
if (record)
{
[self setupFromRecord: record];
isNew = NO;
}
else
isNew = YES;
initialized = YES;
}
}
- (NSException *) delete
{
deleted = YES;
[properties removeAllObjects];
[self save];
return nil;
}
- (void) save
{
NSString *sql;
NSData *content;
NSCalendarDate *now;
GCSChannelManager *cm;
EOAdaptor *adaptor;
EOAdaptorChannel *channel;
NSInteger creationDateValue, lastModifiedValue, deletedValue;
NSString *tableName, *pathValue, *parentPathValue, *propsValue;
NSException *result;
if (!initialized)
[NSException raise: @"MAPIStoreIOException"
format: @"record has not been initialized: %@", self];
cm = [GCSChannelManager defaultChannelManager];
channel = [cm acquireOpenChannelForURL: [self tableUrl]];
tableName = [self tableName];
now = [NSCalendarDate date];
ASSIGN (lastModified, now);
/*
- (NSException *)insertRowX:(NSDictionary *)_row forEntity:(EOEntity *)_entity;
- (NSException *)updateRowX:(NSDictionary*)aRow
describedByQualifier:(EOSQLQualifier*)aQualifier;
*/
adaptor = [[channel adaptorContext] adaptor];
pathValue = [adaptor formatValue: [self path]
forAttribute: textColumn];
lastModifiedValue = (NSInteger) [lastModified timeIntervalSince1970];
if (objectType == -1)
[NSException raise: @"MAPIStoreIOException"
format: @"object type has not been set for object '%@'",
self];
if ([properties count] > 0)
{
content = [properties BSONRepresentation];
propsValue = [adaptor formatValue: [content stringByEncodingBase64]
forAttribute: textColumn];
}
else
propsValue = @"NULL";
if (isNew)
{
ASSIGN (creationDate, now);
creationDateValue = (NSInteger) [creationDate timeIntervalSince1970];
parentPathValue = [adaptor formatValue: [container path]
forAttribute: textColumn];
if (!parentPathValue)
parentPathValue = @"NULL";
sql = [NSString stringWithFormat:
(@"INSERT INTO %@"
@" (c_path, c_parent_path, c_type, c_creationdate, c_lastmodified,"
@" c_deleted, c_version, c_content)"
@" VALUES (%@, %@, %d, %d, %d, 0, 0, %@"
@")"),
tableName,
pathValue, parentPathValue, objectType,
creationDateValue, lastModifiedValue,
propsValue];
isNew = NO;
}
else
{
version++;
deletedValue = (deleted ? 1 : 0);
sql = [NSString stringWithFormat:
(@"UPDATE %@"
@" SET c_lastmodified = %d, c_deleted = %d,"
@" c_version = %d, c_content = %@"
@" WHERE c_path = %@"),
tableName,
lastModifiedValue, deletedValue, version, propsValue,
pathValue];
}
result = [channel evaluateExpressionX: sql];
if (result)
[self errorWithFormat: @"could not insert/update record for record %@"
@" in %@: %@", pathValue, tableName, result];
// @" c_path VARCHAR(255) PRIMARY KEY,"
// @" c_type SMALLINT NOT NULL,"
// @" c_creationdate INT4 NOT NULL,"
// @" c_lastmodified INT4 NOT NULL,"
// @" c_deleted SMALLINT NOT NULL DEFAULT 0,"
// @" c_content BLOB");
[cm releaseChannel: channel];
}
@end
+49
View File
@@ -0,0 +1,49 @@
/* SOGoMAPIObject.h - this file is part of SOGo
*
* Copyright (C) 2012 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 2, 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.
*/
#ifndef SOGOMAPIOBJECT_H
#define SOGOMAPIOBJECT_H
#import <SOGo/SOGoObject.h>
@class NSMutableDictionary;
@interface SOGoMAPIObject : SOGoObject
{
BOOL isNew;
NSMutableDictionary *properties;
NSCalendarDate *creationDate;
NSCalendarDate *lastModified;
}
- (void) setIsNew: (BOOL) newIsNew;
- (BOOL) isNew;
- (void) adjustLastModified;
- (NSMutableDictionary *) properties;
- (NSCalendarDate *) creationDate;
- (NSCalendarDate *) lastModified;
@end
#endif /* SOGOMAPIOBJECT_H */
+87
View File
@@ -0,0 +1,87 @@
/* SOGoMAPIObject.m - this file is part of SOGo
*
* Copyright (C) 2012 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/NSDictionary.h>
#import <Foundation/NSCalendarDate.h>
#import "SOGoMAPIObject.h"
@implementation SOGoMAPIObject
- (id) init
{
if ((self = [super init]))
{
isNew = NO;
creationDate = [NSCalendarDate date];
[creationDate retain];
lastModified = [creationDate copy];
properties = [NSMutableDictionary new];
}
return self;
}
- (void) dealloc
{
[creationDate release];
[lastModified release];
[properties release];
[super dealloc];
}
- (void) setIsNew: (BOOL) newIsNew
{
isNew = newIsNew;
}
- (BOOL) isNew
{
return isNew;
}
- (void) adjustLastModified
{
ASSIGN (lastModified, [NSCalendarDate date]);
}
- (BOOL) isFolderish
{
return NO;
}
- (NSMutableDictionary *) properties
{
return properties;
}
- (NSCalendarDate *) creationDate
{
return creationDate;
}
- (NSCalendarDate *) lastModified
{
return lastModified;
}
@end