mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-10-11 14:57:12 +00:00
Renamed cache files for generalization.
The upcoming commit will rename the content.
This commit is contained in:
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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
Reference in new issue
Block a user