diff --git a/ChangeLog b/ChangeLog index f749e20f6..a2d6e0ffe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2012-06-29 Wolfgang Sourdeau + + * OpenChange/SOGoMAPIDBObject.m: new class module that replaced + SOGoMAPIFSMessage. + + * OpenChange/SOGoMAPIDBFolder.m: new class module that replaced + SOGoMAPIFSFolder. + 2012-06-28 Wolfgang Sourdeau * SoObjects/SOGo/SOGoObject.m (-initWithName:inContainer:): make diff --git a/OpenChange/EOQualifier+MAPI.h b/OpenChange/EOQualifier+MAPI.h index cbe65b915..72f368b63 100644 --- a/OpenChange/EOQualifier+MAPI.h +++ b/OpenChange/EOQualifier+MAPI.h @@ -25,11 +25,11 @@ #import -@class SOGoMAPIVolatileMessage; +@class SOGoMAPIDBObject; @interface EOQualifier (MAPIStoreRestrictions) -- (BOOL) evaluateMAPIVolatileMessage: (SOGoMAPIVolatileMessage *) message; +- (BOOL) evaluateSOGoMAPIDBObject: (SOGoMAPIDBObject *) object; @end diff --git a/OpenChange/EOQualifier+MAPI.m b/OpenChange/EOQualifier+MAPI.m index 0584e2789..8707dd788 100644 --- a/OpenChange/EOQualifier+MAPI.m +++ b/OpenChange/EOQualifier+MAPI.m @@ -28,28 +28,28 @@ #import -#import "SOGoMAPIVolatileMessage.h" +#import "EOBitmaskQualifier.h" +#import "SOGoMAPIDBObject.h" #import "EOQualifier+MAPI.h" -#import "EOBitmaskQualifier.h" @implementation EOQualifier (MAPIStoreRestrictions) -- (BOOL) _evaluateMAPIVolatileMessageProperties: (NSDictionary *) properties +- (BOOL) _evaluateSOGoMAPIDBObject: (NSDictionary *) properties { [self subclassResponsibility: _cmd]; return NO; } -- (BOOL) evaluateMAPIVolatileMessage: (SOGoMAPIVolatileMessage *) message +- (BOOL) evaluateSOGoMAPIDBObject: (SOGoMAPIDBObject *) object { NSDictionary *properties; BOOL rc; - [self logWithFormat: @"evaluating message '%@'", message]; + [self logWithFormat: @"evaluating object '%@'", object]; - properties = [message properties]; - rc = [self _evaluateMAPIVolatileMessageProperties: properties]; + properties = [object properties]; + rc = [self _evaluateSOGoMAPIDBObject: properties]; [self logWithFormat: @" evaluation result: %d", rc]; @@ -60,7 +60,7 @@ @implementation EOAndQualifier (MAPIStoreRestrictionsPrivate) -- (BOOL) _evaluateMAPIVolatileMessageProperties: (NSDictionary *) properties +- (BOOL) _evaluateSOGoMAPIDBObject: (NSDictionary *) properties { NSUInteger i; BOOL rc; @@ -69,7 +69,7 @@ for (i = 0; rc && i < count; i++) rc = [[qualifiers objectAtIndex: i] - _evaluateMAPIVolatileMessageProperties: properties]; + _evaluateSOGoMAPIDBObject: properties]; return rc; } @@ -78,7 +78,7 @@ @implementation EOOrQualifier (MAPIStoreRestrictionsPrivate) -- (BOOL) _evaluateMAPIVolatileMessageProperties: (NSDictionary *) properties +- (BOOL) _evaluateSOGoMAPIDBObject: (NSDictionary *) properties { NSUInteger i; BOOL rc; @@ -87,7 +87,7 @@ for (i = 0; !rc && i < count; i++) rc = [[qualifiers objectAtIndex: i] - _evaluateMAPIVolatileMessageProperties: properties]; + _evaluateSOGoMAPIDBObject: properties]; return rc; } @@ -96,9 +96,9 @@ @implementation EONotQualifier (MAPIStoreRestrictionsPrivate) -- (BOOL) _evaluateMAPIVolatileMessageProperties: (NSDictionary *) properties +- (BOOL) _evaluateSOGoMAPIDBObject: (NSDictionary *) properties { - return ![qualifier _evaluateMAPIVolatileMessageProperties: properties]; + return ![qualifier _evaluateSOGoMAPIDBObject: properties]; } @end @@ -107,7 +107,7 @@ typedef BOOL (*EOComparator) (id, SEL, id); -- (BOOL) _evaluateMAPIVolatileMessageProperties: (NSDictionary *) properties +- (BOOL) _evaluateSOGoMAPIDBObject: (NSDictionary *) properties { id finalKey; id propValue; @@ -136,7 +136,7 @@ typedef BOOL (*EOComparator) (id, SEL, id); @implementation EOBitmaskQualifier (MAPIStoreRestrictionsPrivate) -- (BOOL) _evaluateMAPIVolatileMessageProperties: (NSDictionary *) properties +- (BOOL) _evaluateSOGoMAPIDBObject: (NSDictionary *) properties { NSNumber *propTag; id propValue; diff --git a/OpenChange/GCSSpecialQueries+OpenChange.h b/OpenChange/GCSSpecialQueries+OpenChange.h new file mode 100644 index 000000000..4caaca54b --- /dev/null +++ b/OpenChange/GCSSpecialQueries+OpenChange.h @@ -0,0 +1,34 @@ +/* GCSSpecialQueries+OpenChange.h - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * 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 + +@interface GCSSpecialQueries (OpenChangeHelpers) + +- (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName; + +@end + +#endif /* GCSSPECIALQUERIES_OPENCHANGE_H */ diff --git a/OpenChange/GCSSpecialQueries+OpenChange.m b/OpenChange/GCSSpecialQueries+OpenChange.m new file mode 100644 index 000000000..aa336bf99 --- /dev/null +++ b/OpenChange/GCSSpecialQueries+OpenChange.m @@ -0,0 +1,102 @@ +/* GCSSpecialQueries+OpenChange.m - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * 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 + +#import "GCSSpecialQueries+OpenChange.h" + +@interface GCSPostgreSQLSpecialQueries (OpenChangeHelpers) +@end + +@interface GCSMySQLSpecialQueries (OpenChangeHelpers) +@end + +@interface GCSOracleSpecialQueries (OpenChangeHelpers) +@end + +@implementation GCSSpecialQueries (OpenChangeHelpers) + +- (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_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_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 TEXT)"); + + 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_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 diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 0f3fb1a39..6f4803ba9 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -41,9 +41,11 @@ $(SOGOBACKEND)_OBJC_FILES += \ MAPIStoreSamDBUtils.m \ MAPIStoreUserContext.m \ \ - SOGoMAPIVolatileMessage.m \ - SOGoMAPIFSFolder.m \ - SOGoMAPIFSMessage.m \ + SOGoMAPIObject.m \ + \ + SOGoMAPIDBObject.m \ + SOGoMAPIDBMessage.m \ + SOGoMAPIDBFolder.m \ \ MAPIStoreAppointmentWrapper.m \ MAPIStoreAttachment.m \ @@ -53,18 +55,17 @@ $(SOGOBACKEND)_OBJC_FILES += \ MAPIStoreFolder.m \ MAPIStoreMessage.m \ MAPIStoreObject.m \ + MAPIStoreSOGoObject.m \ MAPIStoreTable.m \ MAPIStoreMessageTable.m \ MAPIStoreFolderTable.m \ MAPIStorePermissionsTable.m \ \ - MAPIStoreVolatileMessage.m \ - \ - MAPIStoreFSBaseContext.m \ - MAPIStoreFSFolder.m \ - MAPIStoreFSFolderTable.m \ - MAPIStoreFSMessage.m \ - MAPIStoreFSMessageTable.m \ + MAPIStoreDBBaseContext.m \ + MAPIStoreDBFolder.m \ + MAPIStoreDBFolderTable.m \ + MAPIStoreDBMessage.m \ + MAPIStoreDBMessageTable.m \ \ MAPIStoreFAIMessage.m \ MAPIStoreFAIMessageTable.m \ @@ -113,7 +114,10 @@ $(SOGOBACKEND)_OBJC_FILES += \ NSValue+MAPIStore.m \ \ EOBitmaskQualifier.m \ - EOQualifier+MAPI.m \ + \ + GCSSpecialQueries+OpenChange.m\ + \ + EOQualifier+MAPI.m $(SOGOBACKEND)_RESOURCE_FILES += \ @@ -145,7 +149,13 @@ PLREADER_TOOL = plreader $(PLREADER_TOOL)_OBJC_FILES += \ plreader.m \ -TEST_TOOL_NAME += $(PLREADER_TOOL) +DBMSGREADER_TOOL = dbmsgreader +$(DBMSGREADER_TOOL)_OBJC_FILES += \ + dbmsgreader.m + +$(DBMSGREADER_TOOL)_LIB_DIRS += -L../SoObjects/SOGo/ -lSOGo -lNGObjWeb + +TEST_TOOL_NAME += $(PLREADER_TOOL) $(DBMSGREADER_TOOL) ### cflags and libs LIBMAPI_CFLAGS = $(shell pkg-config libmapi --cflags) diff --git a/OpenChange/MAPIStoreCalendarAttachment.m b/OpenChange/MAPIStoreCalendarAttachment.m index 63aa68df8..1ba40ac17 100644 --- a/OpenChange/MAPIStoreCalendarAttachment.m +++ b/OpenChange/MAPIStoreCalendarAttachment.m @@ -67,10 +67,10 @@ { MAPIStoreEmbeddedMessage *msg; - if (isNew) - msg = nil; - else + // if (isNew) msg = nil; + // else + // msg = nil; return msg; } diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index daa9cc83d..5d2eb48a6 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -1111,9 +1111,7 @@ newAid = [[self attachmentKeys] count]; newAttachment = [MAPIStoreCalendarAttachment - mapiStoreObjectWithSOGoObject: nil - inContainer: self]; - [newAttachment setIsNew: YES]; + mapiStoreObjectInContainer: self]; [newAttachment setAID: newAid]; newKey = [NSString stringWithFormat: @"%ul", newAid]; [attachmentParts setObject: newAttachment diff --git a/OpenChange/MAPIStoreContactsMessage.m b/OpenChange/MAPIStoreContactsMessage.m index c8af5c05b..99f297ea1 100644 --- a/OpenChange/MAPIStoreContactsMessage.m +++ b/OpenChange/MAPIStoreContactsMessage.m @@ -35,6 +35,7 @@ #import #import +#import "MAPIStoreAttachment.h" #import "MAPIStoreContactsAttachment.h" #import "MAPIStoreContactsFolder.h" #import "MAPIStorePropertySelectors.h" @@ -767,8 +768,7 @@ || [encoding isEqualToString: @"BASE64"]) { attachment = [MAPIStoreContactsAttachment - mapiStoreObjectWithSOGoObject: nil - inContainer: self]; + mapiStoreObjectInContainer: self]; [attachment setAID: 0]; [attachment setPhoto: photo]; [attachmentParts setObject: attachment forKey: @"photo"]; diff --git a/OpenChange/MAPIStoreContext.m b/OpenChange/MAPIStoreContext.m index 1817658ea..a3704289b 100644 --- a/OpenChange/MAPIStoreContext.m +++ b/OpenChange/MAPIStoreContext.m @@ -28,11 +28,9 @@ #import #import +#import #import -#import "SOGoMAPIFSFolder.h" -#import "SOGoMAPIFSMessage.h" - #import "MAPIStoreAttachment.h" // #import "MAPIStoreAttachmentTable.h" #import "MAPIStoreFallbackContext.h" @@ -433,25 +431,29 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) [self ensureContextFolder]; currentFolder = [self rootSOGoFolder]; + [containersBag addObject: currentFolder]; path = [contextUrl path]; if ([path hasPrefix: @"/"]) path = [path substringFromIndex: 1]; if ([path hasSuffix: @"/"]) path = [path substringToIndex: [path length] - 1]; - pathComponents = [path componentsSeparatedByString: @"/"]; - max = [pathComponents count]; - for (count = 0; currentFolder && count < max; count++) + if ([path length] > 0) { - [woContext setClientObject: currentFolder]; - currentFolder - = [currentFolder lookupName: [pathComponents objectAtIndex: count] - inContext: woContext + pathComponents = [path componentsSeparatedByString: @"/"]; + max = [pathComponents count]; + for (count = 0; currentFolder && count < max; count++) + { + [woContext setClientObject: currentFolder]; + currentFolder = [currentFolder + lookupName: [pathComponents objectAtIndex: count] + inContext: woContext acquire: NO]; - if ([currentFolder isKindOfClass: SOGoObjectK]) /* class common to all - SOGo folder types */ - [containersBag addObject: currentFolder]; - else - currentFolder = nil; + if ([currentFolder isKindOfClass: SOGoObjectK]) /* class common to all + SOGo folder types */ + [containersBag addObject: currentFolder]; + else + currentFolder = nil; + } } if (currentFolder) @@ -460,7 +462,6 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) mapiStoreObjectWithSOGoObject: currentFolder inContainer: nil]; [baseFolder setContext: self]; - *folderPtr = baseFolder; rc = MAPISTORE_SUCCESS; } diff --git a/OpenChange/MAPIStoreFSBaseContext.h b/OpenChange/MAPIStoreDBBaseContext.h similarity index 76% rename from OpenChange/MAPIStoreFSBaseContext.h rename to OpenChange/MAPIStoreDBBaseContext.h index ecc63d1e6..62f5bd489 100644 --- a/OpenChange/MAPIStoreFSBaseContext.h +++ b/OpenChange/MAPIStoreDBBaseContext.h @@ -1,6 +1,6 @@ -/* MAPIStoreFSBaseContext.h - this file is part of SOGo +/* MAPIStoreDBBaseContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -20,13 +20,13 @@ * Boston, MA 02111-1307, USA. */ -#ifndef MAPISTOREFSBASECONTEXT_H -#define MAPISTOREFSBASECONTEXT_H +#ifndef MAPISTOREDBBASECONTEXT_H +#define MAPISTOREDBBASECONTEXT_H #import "MAPIStoreContext.h" -@interface MAPIStoreFSBaseContext : MAPIStoreContext +@interface MAPIStoreDBBaseContext : MAPIStoreContext @end -#endif /* MAPISTOREFSBASECONTEXT_H */ +#endif /* MAPISTOREDBBASECONTEXT_H */ diff --git a/OpenChange/MAPIStoreDBBaseContext.m b/OpenChange/MAPIStoreDBBaseContext.m new file mode 100644 index 000000000..d82538083 --- /dev/null +++ b/OpenChange/MAPIStoreDBBaseContext.m @@ -0,0 +1,116 @@ +/* MAPIStoreDBBaseContext.m - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc. + * + * Author: Wolfgang Sourdeau + * + * 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. + */ + +/* A generic parent class for all context that will store their data on the + disk in the form of a plist. */ + +#import +#import +#import + +#import + +#import "MAPIStoreDBFolder.h" +#import "MAPIStoreMapping.h" +#import "MAPIStoreUserContext.h" +#import "SOGoMAPIDBFolder.h" + +#import "MAPIStoreDBBaseContext.h" + +#undef DEBUG +#include + +static Class MAPIStoreDBFolderK; + +@implementation MAPIStoreDBBaseContext + ++ (void) initialize +{ + MAPIStoreDBFolderK = [MAPIStoreDBFolder class]; +} + ++ (NSString *) MAPIModuleName +{ + return nil; +} + +- (Class) MAPIStoreFolderClass +{ + return MAPIStoreDBFolderK; +} + +- (void) ensureContextFolder +{ + SOGoMAPIDBFolder *currentFolder; + NSArray *parts; + NSMutableArray *folders; + NSString *folderName; + NSUInteger count, max; + + parts = [[contextUrl path] componentsSeparatedByString: @"/"]; + max = [parts count]; + folders = [NSMutableArray arrayWithCapacity: max]; + + /* build the folder chain */ + currentFolder = [self rootSOGoFolder]; + [folders addObject: currentFolder]; + for (count = 1; count < max; count++) + { + folderName = [parts objectAtIndex: count]; + if ([folderName length] > 0) + { + currentFolder = [SOGoMAPIDBFolder objectWithName: folderName + inContainer: currentFolder]; + [folders addObject: currentFolder]; + } + } + + /* ensure each folder in the chain actually exists, so that it becomes + "listable" in further operations */ + max = [folders count]; + for (count = 0; count < max; count++) + { + currentFolder = [folders objectAtIndex: count]; + [currentFolder reloadIfNeeded]; + if ([currentFolder isNew]) + [currentFolder save]; + } +} + +- (id) rootSOGoFolder +{ + SOGoMAPIDBFolder *folder; + + [userContext ensureFolderTableExists]; + + folder = [SOGoMAPIDBFolder objectWithName: [isa MAPIModuleName] + inContainer: nil]; + [folder setTableUrl: [userContext folderTableURL]]; + // [folder reloadIfNeeded]; + + /* we don't need to set the "path prefix" of the folder since the module + name is used as the label for the top folder */ + + return folder; +} + +@end diff --git a/OpenChange/MAPIStoreFSFolder.h b/OpenChange/MAPIStoreDBFolder.h similarity index 78% rename from OpenChange/MAPIStoreFSFolder.h rename to OpenChange/MAPIStoreDBFolder.h index 75e3f08e5..2415af934 100644 --- a/OpenChange/MAPIStoreFSFolder.h +++ b/OpenChange/MAPIStoreDBFolder.h @@ -1,6 +1,6 @@ -/* MAPIStoreFSFolder.h - this file is part of SOGo +/* MAPIStoreDBFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -20,14 +20,14 @@ * Boston, MA 02111-1307, USA. */ -#ifndef MAPISTOREFSFOLDER_H -#define MAPISTOREFSFOLDER_H +#ifndef MAPISTOREDBFOLDER_H +#define MAPISTOREDBFOLDER_H #import "MAPIStoreFolder.h" -@interface MAPIStoreFSFolder : MAPIStoreFolder +@interface MAPIStoreDBFolder : MAPIStoreFolder @end -#endif /* MAPISTOREFSFOLDER_H */ +#endif /* MAPISTOREDBFOLDER_H */ diff --git a/OpenChange/MAPIStoreFSFolder.m b/OpenChange/MAPIStoreDBFolder.m similarity index 75% rename from OpenChange/MAPIStoreFSFolder.m rename to OpenChange/MAPIStoreDBFolder.m index 68f57545f..641b9dc59 100644 --- a/OpenChange/MAPIStoreFSFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -1,4 +1,4 @@ -/* MAPIStoreFSFolder.m - this file is part of SOGo +/* MAPIStoreDBFolder.m - this file is part of SOGo * * Copyright (C) 2011 Inverse inc * @@ -31,15 +31,15 @@ #import #import "EOQualifier+MAPI.h" #import "MAPIStoreContext.h" -#import "MAPIStoreFSFolderTable.h" -#import "MAPIStoreFSMessage.h" -#import "MAPIStoreFSMessageTable.h" +#import "MAPIStoreDBFolderTable.h" +#import "MAPIStoreDBMessage.h" +#import "MAPIStoreDBMessageTable.h" #import "MAPIStoreTypes.h" #import "MAPIStoreUserContext.h" -#import "SOGoMAPIFSFolder.h" -#import "SOGoMAPIFSMessage.h" +#import "SOGoMAPIDBFolder.h" +#import "SOGoMAPIDBMessage.h" -#import "MAPIStoreFSFolder.h" +#import "MAPIStoreDBFolder.h" #undef DEBUG #include @@ -57,39 +57,34 @@ static NSString *MAPIStoreRightCreateSubfolders = @"RightsCreateSubfolders"; static NSString *MAPIStoreRightFolderOwner = @"RightsFolderOwner"; static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; -@implementation MAPIStoreFSFolder +@implementation MAPIStoreDBFolder + (void) initialize { EOKeyValueQualifierK = [EOKeyValueQualifier class]; } +- (void) setupAuxiliaryObjects +{ + [super setupAuxiliaryObjects]; + ASSIGN (sogoObject, dbFolder); +} + - (MAPIStoreMessageTable *) messageTable { - return [MAPIStoreFSMessageTable tableForContainer: self]; + return [MAPIStoreDBMessageTable tableForContainer: self]; } - (MAPIStoreFolderTable *) folderTable { - return [MAPIStoreFSFolderTable tableForContainer: self]; + return [MAPIStoreDBFolderTable tableForContainer: self]; } - (enum mapistore_error) createFolder: (struct SRow *) aRow withFID: (uint64_t) newFID andKey: (NSString **) newKeyP { - NSString *newKey, *urlString; - NSURL *childURL; - SOGoMAPIFSFolder *childFolder; - - newKey = [NSString stringWithFormat: @"0x%.16"PRIx64, (unsigned long long) newFID]; - - urlString = [NSString stringWithFormat: @"%@/%@", [self url], newKey]; - childURL = [NSURL URLWithString: [urlString stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]]; - childFolder = [SOGoMAPIFSFolder folderWithURL: childURL - andTableType: MAPISTORE_MESSAGE_TABLE]; - [childFolder ensureDirectory]; - *newKeyP = newKey; + *newKeyP = [NSString stringWithFormat: @"0x%.16"PRIx64, (unsigned long long) newFID]; return MAPISTORE_SUCCESS; } @@ -97,14 +92,15 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; - (MAPIStoreMessage *) createMessage { MAPIStoreMessage *newMessage; - SOGoMAPIFSMessage *fsObject; + SOGoMAPIDBMessage *fsObject; NSString *newKey; newKey = [NSString stringWithFormat: @"%@.plist", [SOGoObject globallyUniqueObjectId]]; - fsObject = [SOGoMAPIFSMessage objectWithName: newKey + fsObject = [SOGoMAPIDBMessage objectWithName: newKey inContainer: sogoObject]; - newMessage = [MAPIStoreFSMessage mapiStoreObjectWithSOGoObject: fsObject + [fsObject setObjectType: MAPIDBObjectTypeMessage]; + newMessage = [MAPIStoreDBMessage mapiStoreObjectWithSOGoObject: fsObject inContainer: self]; return newMessage; @@ -119,9 +115,10 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; ownerUser = [[self userContext] sogoUser]; if ([[context activeUser] isEqual: ownerUser] || [self subscriberCanReadMessages]) - keys = [(SOGoMAPIFSFolder *) sogoObject - toOneRelationshipKeysMatchingQualifier: qualifier - andSortOrderings: sortOrderings]; + keys = [(SOGoMAPIDBFolder *) sogoObject childKeysOfType: MAPIDBObjectTypeMessage + includeDeleted: NO + matchingQualifier: qualifier + andSortOrderings: sortOrderings]; else keys = [NSArray array]; @@ -131,39 +128,17 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; - (NSArray *) folderKeysMatchingQualifier: (EOQualifier *) qualifier andSortOrderings: (NSArray *) sortOrderings { - NSArray *entries; - NSMutableArray *filteredEntries; - NSUInteger count, max; - MAPIStoreFSFolder *subfolder; - SOGoMAPIFSMessage *propertiesMessage; - NSString *subfolderKey; - - entries = [(SOGoMAPIFSFolder *) sogoObject toManyRelationshipKeys]; - if (qualifier) - { - max = [entries count]; - filteredEntries = [NSMutableArray arrayWithCapacity: max]; - for (count = 0; count < max; count++) - { - subfolderKey = [entries objectAtIndex: count]; - subfolder = [self lookupFolder: subfolderKey]; - propertiesMessage = [subfolder propertiesMessage]; - if ([qualifier evaluateMAPIVolatileMessage: propertiesMessage]) - [filteredEntries addObject: subfolderKey]; - } - entries = filteredEntries; - } - if (sortOrderings) - [self errorWithFormat: @"sort orderings are not used for folders"]; - - return entries; + return [dbFolder childKeysOfType: MAPIDBObjectTypeFolder + includeDeleted: NO + matchingQualifier: qualifier + andSortOrderings: sortOrderings]; } - (NSDate *) lastMessageModificationTime { NSUInteger count, max; NSDate *date, *fileDate; - MAPIStoreFSMessage *msg; + MAPIStoreDBMessage *msg; NSArray *messageKeys; messageKeys = [self messageKeys]; @@ -189,7 +164,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; - (SOGoFolder *) aclFolder { - return propsFolder; + return sogoObject; } - (NSArray *) rolesForExchangeRights: (uint32_t) rights diff --git a/OpenChange/MAPIStoreFSFolderTable.h b/OpenChange/MAPIStoreDBFolderTable.h similarity index 76% rename from OpenChange/MAPIStoreFSFolderTable.h rename to OpenChange/MAPIStoreDBFolderTable.h index f5a5dfb4e..afc3018e2 100644 --- a/OpenChange/MAPIStoreFSFolderTable.h +++ b/OpenChange/MAPIStoreDBFolderTable.h @@ -1,6 +1,6 @@ -/* MAPIStoreFSFolderTable.h - this file is part of SOGo +/* MAPIStoreDBFolderTable.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -20,12 +20,12 @@ * Boston, MA 02111-1307, USA. */ -#ifndef MAPISTOREFSFOLDERTABLE_H -#define MAPISTOREFSFOLDERTABLE_H +#ifndef MAPISTOREDBFOLDERTABLE_H +#define MAPISTOREDBFOLDERTABLE_H #import "MAPIStoreFolderTable.h" -@interface MAPIStoreFSFolderTable : MAPIStoreFolderTable +@interface MAPIStoreDBFolderTable : MAPIStoreFolderTable @end -#endif /* MAPISTOREFSFOLDERTABLE_H */ +#endif /* MAPISTOREDBFOLDERTABLE_H */ diff --git a/OpenChange/MAPIStoreFSFolderTable.m b/OpenChange/MAPIStoreDBFolderTable.m similarity index 85% rename from OpenChange/MAPIStoreFSFolderTable.m rename to OpenChange/MAPIStoreDBFolderTable.m index a834c5fb4..01a40b7f0 100644 --- a/OpenChange/MAPIStoreFSFolderTable.m +++ b/OpenChange/MAPIStoreDBFolderTable.m @@ -1,6 +1,6 @@ -/* MAPIStoreFSFolderTable.m - this file is part of SOGo +/* MAPIStoreDBFolderTable.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -24,9 +24,9 @@ #import "MAPIStoreTypes.h" -#import "MAPIStoreFSFolderTable.h" +#import "MAPIStoreDBFolderTable.h" -@implementation MAPIStoreFSFolderTable +@implementation MAPIStoreDBFolderTable - (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property { diff --git a/OpenChange/MAPIStoreFSMessage.h b/OpenChange/MAPIStoreDBMessage.h similarity index 74% rename from OpenChange/MAPIStoreFSMessage.h rename to OpenChange/MAPIStoreDBMessage.h index 20084a4f2..532f53a8e 100644 --- a/OpenChange/MAPIStoreFSMessage.h +++ b/OpenChange/MAPIStoreDBMessage.h @@ -1,6 +1,6 @@ -/* MAPIStoreFSMessage.h - this file is part of SOGo +/* MAPIStoreDBMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -20,12 +20,12 @@ * Boston, MA 02111-1307, USA. */ -#ifndef MAPISTOREFSMESSAGE_H -#define MAPISTOREFSMESSAGE_H +#ifndef MAPISTOREDBMESSAGE_H +#define MAPISTOREDBMESSAGE_H -#import "MAPIStoreVolatileMessage.h" +#import "MAPIStoreMessage.h" -@interface MAPIStoreFSMessage : MAPIStoreVolatileMessage +@interface MAPIStoreDBMessage : MAPIStoreMessage @end -#endif /* MAPISTOREFSMESSAGE_H */ +#endif /* MAPISTOREDBMESSAGE_H */ diff --git a/OpenChange/MAPIStoreFSMessage.m b/OpenChange/MAPIStoreDBMessage.m similarity index 59% rename from OpenChange/MAPIStoreFSMessage.m rename to OpenChange/MAPIStoreDBMessage.m index 7b7939884..945b41c8e 100644 --- a/OpenChange/MAPIStoreFSMessage.m +++ b/OpenChange/MAPIStoreDBMessage.m @@ -1,4 +1,4 @@ -/* MAPIStoreFSMessage.m - this file is part of SOGo +/* MAPIStoreDBMessage.m - this file is part of SOGo * * Copyright (C) 2011 Inverse inc * @@ -21,24 +21,25 @@ */ #import +#import #import #import #import #import "MAPIStoreContext.h" #import "MAPIStorePropertySelectors.h" -#import "SOGoMAPIFSMessage.h" +#import "SOGoMAPIDBMessage.h" -#import "MAPIStoreFSFolder.h" -#import "MAPIStoreFSMessage.h" +#import "MAPIStoreDBFolder.h" +#import "MAPIStoreDBMessage.h" #import "MAPIStoreTypes.h" -#import "NSData+MAPIStore.h" +#import "NSObject+MAPIStore.h" #undef DEBUG #include #include -@implementation MAPIStoreFSMessage +@implementation MAPIStoreDBMessage + (int) getAvailableProperties: (struct SPropTagArray **) propertiesP inMemCtx: (TALLOC_CTX *) memCtx @@ -60,13 +61,96 @@ /* FIXME (hack): append a few undocumented properties that can be added to FAI messages */ for (count = 0; count < 8; count++) - properties->aulPropTag[MAPIStoreSupportedPropertiesCount+count] = faiProperties[count]; + properties->aulPropTag[MAPIStoreSupportedPropertiesCount+count] + = faiProperties[count]; *propertiesP = properties; return MAPISTORE_SUCCESS; } +- (id) initWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newContainer +{ + if ((self = [super initWithSOGoObject: newSOGoObject + inContainer: newContainer])) + { + [properties release]; + properties = [newSOGoObject properties]; + [properties retain]; + } + + return self; +} + +- (uint64_t) objectVersion +{ + NSNumber *versionNbr; + uint64_t objectVersion; + + [(SOGoMAPIDBMessage *) sogoObject reloadIfNeeded]; + versionNbr = [properties objectForKey: @"version"]; + if (versionNbr) + objectVersion = [versionNbr unsignedLongLongValue]; + else + objectVersion = ULLONG_MAX; + + return objectVersion; +} + +- (int) getProperties: (struct mapistore_property_data *) data + withTags: (enum MAPITAGS *) tags + andCount: (uint16_t) columnCount + inMemCtx: (TALLOC_CTX *) memCtx +{ + [sogoObject reloadIfNeeded]; + + return [super getProperties: data + withTags: tags + andCount: columnCount + inMemCtx: memCtx]; +} + +- (int) getProperty: (void **) data + withTag: (enum MAPITAGS) propTag + inMemCtx: (TALLOC_CTX *) memCtx +{ + id value; + int rc; + + value = [properties objectForKey: MAPIPropertyKey (propTag)]; + if (value) + rc = [value getValue: data forTag: propTag inMemCtx: memCtx]; + else + rc = [super getProperty: data withTag: propTag inMemCtx: memCtx]; + + return rc; +} + +- (int) getPidTagSubject: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + id value; + int rc; + + value = [properties + objectForKey: MAPIPropertyKey (PidTagNormalizedSubject)]; + if (value) + rc = [value getValue: data forTag: PidTagNormalizedSubject + inMemCtx: memCtx]; + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + +- (void) addProperties: (NSDictionary *) newNewProperties +{ + [sogoObject reloadIfNeeded]; + + [super addProperties: newNewProperties]; +} + - (void) save { uint64_t newVersion; @@ -76,13 +160,11 @@ newVersion = exchange_globcnt ([[self context] getNewChangeNumber] >> 16); [properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion] - forKey: @"version"]; + forKey: @"version"]; [self logWithFormat: @"%d props in dict", [properties count]]; - [sogoObject appendProperties: properties]; [sogoObject save]; - [properties removeAllObjects]; } - (BOOL) _messageIsFreeBusy @@ -91,7 +173,7 @@ /* This is a HACK until we figure out how to determine a message position in the mailbox hierarchy.... (missing: folderid and role) */ - msgClass = [[sogoObject properties] + msgClass = [properties objectForKey: MAPIPropertyKey (PR_MESSAGE_CLASS_UNICODE)]; return [msgClass isEqualToString: @"IPM.Microsoft.ScheduleData.FreeBusy"]; @@ -115,12 +197,12 @@ - (NSDate *) creationTime { - return [sogoObject creationTime]; + return [sogoObject creationDate]; } - (NSDate *) lastModificationTime { - return [sogoObject lastModificationTime]; + return [sogoObject lastModified]; } @end diff --git a/OpenChange/MAPIStoreFSMessageTable.h b/OpenChange/MAPIStoreDBMessageTable.h similarity index 76% rename from OpenChange/MAPIStoreFSMessageTable.h rename to OpenChange/MAPIStoreDBMessageTable.h index 452c8ffdb..4b9f66480 100644 --- a/OpenChange/MAPIStoreFSMessageTable.h +++ b/OpenChange/MAPIStoreDBMessageTable.h @@ -1,6 +1,6 @@ -/* MAPIStoreFSMessageTable.h - this file is part of SOGo +/* MAPIStoreDBMessageTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -20,12 +20,12 @@ * Boston, MA 02111-1307, USA. */ -#ifndef MAPISTOREFSMESSAGETABLE_H -#define MAPISTOREFSMESSAGETABLE_H +#ifndef MAPISTOREDBMESSAGETABLE_H +#define MAPISTOREDBMESSAGETABLE_H #import "MAPIStoreMessageTable.h" -@interface MAPIStoreFSMessageTable : MAPIStoreMessageTable +@interface MAPIStoreDBMessageTable : MAPIStoreMessageTable @end -#endif /* MAPISTOREFSMESSAGETABLE_H */ +#endif /* MAPISTOREDBMESSAGETABLE_H */ diff --git a/OpenChange/MAPIStoreFSMessageTable.m b/OpenChange/MAPIStoreDBMessageTable.m similarity index 92% rename from OpenChange/MAPIStoreFSMessageTable.m rename to OpenChange/MAPIStoreDBMessageTable.m index 7c8504c67..9f791d68a 100644 --- a/OpenChange/MAPIStoreFSMessageTable.m +++ b/OpenChange/MAPIStoreDBMessageTable.m @@ -1,6 +1,6 @@ -/* MAPIStoreFSMessageTable.m - this file is part of SOGo +/* MAPIStoreDBMessageTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -25,25 +25,25 @@ #import #import "MAPIStoreTypes.h" -#import "MAPIStoreFSMessage.h" +#import "MAPIStoreDBMessage.h" -#import "MAPIStoreFSMessageTable.h" +#import "MAPIStoreDBMessageTable.h" #undef DEBUG #include -static Class MAPIStoreFSMessageK = Nil; +static Class MAPIStoreDBMessageK = Nil; -@implementation MAPIStoreFSMessageTable +@implementation MAPIStoreDBMessageTable + (void) initialize { - MAPIStoreFSMessageK = [MAPIStoreFSMessage class]; + MAPIStoreDBMessageK = [MAPIStoreDBMessage class]; } + (Class) childObjectClass { - return MAPIStoreFSMessageK; + return MAPIStoreDBMessageK; } - (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property diff --git a/OpenChange/MAPIStoreFAIMessage.h b/OpenChange/MAPIStoreFAIMessage.h index 4ac10e143..fd4d08930 100644 --- a/OpenChange/MAPIStoreFAIMessage.h +++ b/OpenChange/MAPIStoreFAIMessage.h @@ -23,9 +23,9 @@ #ifndef MAPISTOREFAIMESSAGE_H #define MAPISTOREFAIMESSAGE_H -#import "MAPIStoreFSMessage.h" +#import "MAPIStoreDBMessage.h" -@interface MAPIStoreFAIMessage : MAPIStoreFSMessage +@interface MAPIStoreFAIMessage : MAPIStoreDBMessage @end #endif /* MAPISTOREFAIMESSAGE_H */ diff --git a/OpenChange/MAPIStoreFAIMessageTable.h b/OpenChange/MAPIStoreFAIMessageTable.h index 70e12f43f..0aa6d7230 100644 --- a/OpenChange/MAPIStoreFAIMessageTable.h +++ b/OpenChange/MAPIStoreFAIMessageTable.h @@ -23,9 +23,9 @@ #ifndef MAPISTOREFAIMESSAGETABLE_H #define MAPISTOREFAIMESSAGETABLE_H -#import "MAPIStoreFSMessageTable.h" +#import "MAPIStoreDBMessageTable.h" -@interface MAPIStoreFAIMessageTable : MAPIStoreFSMessageTable +@interface MAPIStoreFAIMessageTable : MAPIStoreDBMessageTable @end #endif /* MAPISTOREFAIMESSAGETABLE_H */ diff --git a/OpenChange/MAPIStoreFSBaseContext.m b/OpenChange/MAPIStoreFSBaseContext.m deleted file mode 100644 index a3e448082..000000000 --- a/OpenChange/MAPIStoreFSBaseContext.m +++ /dev/null @@ -1,79 +0,0 @@ -/* MAPIStoreFSBaseContext.m - this file is part of SOGo - * - * Copyright (C) 2010 Inverse inc. - * - * Author: Wolfgang Sourdeau - * - * 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. - */ - -/* A generic parent class for all context that will store their data on the - disk in the form of a plist. */ - -#import -#import - -#import - -#import "MAPIStoreFSFolder.h" -#import "MAPIStoreMapping.h" -#import "MAPIStoreUserContext.h" -#import "SOGoMAPIFSFolder.h" - -#import "MAPIStoreFSBaseContext.h" - -#undef DEBUG -#include - -static Class MAPIStoreFSFolderK; - -@implementation MAPIStoreFSBaseContext - -+ (void) initialize -{ - MAPIStoreFSFolderK = [MAPIStoreFSFolder class]; -} - -+ (NSString *) MAPIModuleName -{ - return nil; -} - -- (Class) MAPIStoreFolderClass -{ - return MAPIStoreFSFolderK; -} - -- (void) ensureContextFolder -{ - SOGoMAPIFSFolder *contextFolder; - - contextFolder = [SOGoMAPIFSFolder folderWithURL: contextUrl - andTableType: MAPISTORE_MESSAGE_TABLE]; - [contextFolder ensureDirectory]; -} - -- (id) rootSOGoFolder -{ - NSString *urlString; - - urlString = [NSString stringWithFormat: @"sogo://%@@%@/", - [userContext username], [isa MAPIModuleName]]; - return [SOGoMAPIFSFolder folderWithURL: [NSURL URLWithString: urlString] - andTableType: MAPISTORE_MESSAGE_TABLE]; -} - -@end diff --git a/OpenChange/MAPIStoreFallbackContext.h b/OpenChange/MAPIStoreFallbackContext.h index da8e03c0d..eaf992bb7 100644 --- a/OpenChange/MAPIStoreFallbackContext.h +++ b/OpenChange/MAPIStoreFallbackContext.h @@ -23,9 +23,9 @@ #ifndef MAPISTOREFALLBACKCONTEXT_H #define MAPISTOREFALLBACKCONTEXT_H -#import "MAPIStoreFSBaseContext.h" +#import "MAPIStoreDBBaseContext.h" -@interface MAPIStoreFallbackContext : MAPIStoreFSBaseContext +@interface MAPIStoreFallbackContext : MAPIStoreDBBaseContext @end diff --git a/OpenChange/MAPIStoreFallbackContext.m b/OpenChange/MAPIStoreFallbackContext.m index c5270d055..37da58d7d 100644 --- a/OpenChange/MAPIStoreFallbackContext.m +++ b/OpenChange/MAPIStoreFallbackContext.m @@ -26,7 +26,7 @@ #import "MAPIStoreUserContext.h" #import "NSString+MAPIStore.h" -#import "SOGoMAPIFSFolder.h" +#import "SOGoMAPIDBFolder.h" #import "MAPIStoreFallbackContext.h" @@ -51,10 +51,11 @@ inMemCtx: (TALLOC_CTX *) memCtx { struct mapistore_contexts_list *firstContext = NULL, *context; - SOGoMAPIFSFolder *root; + SOGoMAPIDBFolder *root; NSArray *names; NSUInteger count, max; NSString *baseURL, *url, *name; + MAPIStoreUserContext *userContext; baseURL = [NSString stringWithFormat: @"sogo://%@@fallback/", userName]; @@ -67,11 +68,15 @@ DLIST_ADD_END (firstContext, context, void); - /* Maybe emsmdbp_provisioning should be fixed in order to only take the uri returned above to avoid deleting its entries... */ - root = [SOGoMAPIFSFolder folderWithURL: [NSURL URLWithString: baseURL] - andTableType: MAPISTORE_MESSAGE_TABLE]; + root = [SOGoMAPIDBFolder objectWithName: [self MAPIModuleName] + inContainer: nil]; + [root setOwner: userName]; + userContext = [MAPIStoreUserContext userContextWithUsername: userName + andTDBIndexing: indexingTdb]; + [userContext ensureFolderTableExists]; + [root setTableUrl: [userContext folderTableURL]]; names = [root toManyRelationshipKeys]; max = [names count]; for (count = 0; count < max; count++) diff --git a/OpenChange/MAPIStoreFolder.h b/OpenChange/MAPIStoreFolder.h index 41b3bdd61..b29a93d3d 100644 --- a/OpenChange/MAPIStoreFolder.h +++ b/OpenChange/MAPIStoreFolder.h @@ -38,29 +38,34 @@ @class MAPIStoreMessageTable; @class MAPIStorePermissionsTable; @class SOGoFolder; -@class SOGoMAPIFSFolder; -@class SOGoMAPIFSMessage; +@class SOGoMAPIDBFolder; +@class SOGoMAPIDBMessage; -#import "MAPIStoreObject.h" +#import "MAPIStoreSOGoObject.h" -@interface MAPIStoreFolder : MAPIStoreObject +@interface MAPIStoreFolder : MAPIStoreSOGoObject { MAPIStoreContext *context; // NSArray *messageKeys; // NSArray *faiMessageKeys; // NSArray *folderKeys; - SOGoMAPIFSFolder *faiFolder; - SOGoMAPIFSFolder *propsFolder; - SOGoMAPIFSMessage *propsMessage; + SOGoMAPIDBFolder *dbFolder; + // SOGoMAPIDBFolder *faiFolder; + // SOGoMAPIDBFolder *propsFolder; + // SOGoMAPIDBMessage *propsMessage; } - (void) setContext: (MAPIStoreContext *) newContext; +- (void) setupAuxiliaryObjects; + +- (SOGoMAPIDBFolder *) dbFolder; + - (NSArray *) activeMessageTables; - (NSArray *) activeFAIMessageTables; -- (SOGoMAPIFSMessage *) propertiesMessage; +// - (SOGoMAPIDBMessage *) propertiesMessage; - (id) lookupMessageByURL: (NSString *) messageURL; - (id) lookupFolderByURL: (NSString *) folderURL; diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 3e480f11d..f4128695d 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -48,8 +48,8 @@ #import "NSDate+MAPIStore.h" #import "NSString+MAPIStore.h" #import "NSObject+MAPIStore.h" -#import "SOGoMAPIFSFolder.h" -#import "SOGoMAPIFSMessage.h" +#import "SOGoMAPIDBFolder.h" +#import "SOGoMAPIDBMessage.h" #include @@ -79,33 +79,67 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe // messageKeys = nil; // faiMessageKeys = nil; // folderKeys = nil; - faiFolder = nil; + dbFolder = nil; context = nil; - propsFolder = nil; - propsMessage = nil; + // propsFolder = nil; + // propsMessage = nil; } return self; } -- (void) _setupAuxiliaryObjects +- (void) setupAuxiliaryObjects { - NSURL *propsURL; - NSString *urlString; + NSURL *folderURL; + NSMutableString *pathPrefix; + NSString *path, *folderName; + NSArray *parts; + NSUInteger lastPartIdx; + MAPIStoreUserContext *userContext; + + folderURL = [NSURL URLWithString: [self url]]; + path = [folderURL path]; + path = [path substringFromIndex: 1]; + if ([path length] > 0) + { + parts = [path componentsSeparatedByString: @"/"]; + lastPartIdx = [parts count] - 1; + if ([path hasSuffix: @"/"]) + lastPartIdx--; + folderName = [parts objectAtIndex: lastPartIdx]; + } + else + folderName = [folderURL host]; + + userContext = [self userContext]; + [userContext ensureFolderTableExists]; + + ASSIGN (dbFolder, + [SOGoMAPIDBFolder objectWithName: folderName + inContainer: [container dbFolder]]); + [dbFolder setTableUrl: [userContext folderTableURL]]; + if (!container && [path length] > 0) + { + pathPrefix = [NSMutableString stringWithCapacity: 64]; + [pathPrefix appendFormat: @"/%@", [folderURL host]]; + parts = [parts subarrayWithRange: NSMakeRange (0, lastPartIdx)]; + if ([parts count] > 0) + [pathPrefix appendFormat: @"/%@", [parts componentsJoinedByString: @"/"]]; + [dbFolder setPathPrefix: pathPrefix]; + } + [dbFolder reloadIfNeeded]; + + /* propsMessage and self share the same properties dictionary */ + // ASSIGN (propsMessage, + // [SOGoMAPIDBMessage objectWithName: @"properties.plist" + // inContainer: dbFolder]); + // [propsMessage setObjectType: MAPIDBObjectTypeInternal]; + // [propsMessage reloadIfNeeded]; + [properties release]; + properties = [dbFolder properties]; + [properties retain]; - urlString = [[self url] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; - propsURL = [NSURL URLWithString: urlString]; - [self logWithFormat: @"_setupAuxiliaryObjects: %@", propsURL]; - ASSIGN (faiFolder, - [SOGoMAPIFSFolder folderWithURL: propsURL - andTableType: MAPISTORE_FAI_TABLE]); - ASSIGN (propsFolder, - [SOGoMAPIFSFolder folderWithURL: propsURL - andTableType: MAPISTORE_FOLDER_TABLE]); - ASSIGN (propsMessage, - [SOGoMAPIFSMessage objectWithName: @"properties.plist" - inContainer: propsFolder]); [self setupVersionsMessage]; } @@ -119,7 +153,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe inContainer: newContainer]) && newContainer) { - [self _setupAuxiliaryObjects]; + [self setupAuxiliaryObjects]; } return self; @@ -129,13 +163,13 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe { ASSIGN (context, newContext); if (newContext) - [self _setupAuxiliaryObjects]; + [self setupAuxiliaryObjects]; } - (MAPIStoreContext *) context { if (!context) - [self setContext: [container context]]; + [self setContext: (MAPIStoreContext *) [container context]]; return context; } @@ -145,29 +179,31 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe // [messageKeys release]; // [faiMessageKeys release]; // [folderKeys release]; - [propsMessage release]; - [propsFolder release]; - [faiFolder release]; + // [propsMessage release]; + [dbFolder release]; [context release]; [super dealloc]; } +- (SOGoMAPIDBFolder *) dbFolder +{ + return dbFolder; +} + /* backend interface */ -- (SOGoMAPIFSMessage *) propertiesMessage -{ - return propsMessage; -} +// - (SOGoMAPIDBMessage *) propertiesMessage +// { +// return propsMessage; +// } - (uint64_t) objectVersion { NSNumber *value; - NSDictionary *props; uint64_t cn; - props = [propsMessage properties]; - value = [props objectForKey: MAPIPropertyKey (PidTagChangeNumber)]; + value = [properties objectForKey: MAPIPropertyKey (PidTagChangeNumber)]; if (value) cn = [value unsignedLongLongValue]; else @@ -175,10 +211,10 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe [self logWithFormat: @"no value for PidTagChangeNumber, adding one now"]; cn = [[self context] getNewChangeNumber]; value = [NSNumber numberWithUnsignedLongLong: cn]; - props = [NSDictionary dictionaryWithObject: value - forKey: MAPIPropertyKey (PidTagChangeNumber)]; - [propsMessage appendProperties: props]; - [propsMessage save]; + + [properties setObject: value + forKey: MAPIPropertyKey (PidTagChangeNumber)]; + [dbFolder save]; } return cn >> 16; @@ -186,21 +222,24 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (id) lookupFolder: (NSString *) folderKey { - MAPIStoreFolder *childFolder = nil; + MAPIStoreFolder *childFolder; SOGoFolder *sogoFolder; WOContext *woContext; if ([[self folderKeys] containsObject: folderKey]) { woContext = [[self userContext] woContext]; - sogoFolder = [sogoObject lookupName: folderKey - inContext: woContext + sogoFolder = [sogoObject lookupName: folderKey inContext: woContext acquire: NO]; - [sogoFolder setContext: woContext]; if (sogoFolder && ![sogoFolder isKindOfClass: NSExceptionK]) - childFolder = [isa mapiStoreObjectWithSOGoObject: sogoFolder - inContainer: self]; + { + [sogoFolder setContext: woContext]; + childFolder = [isa mapiStoreObjectWithSOGoObject: sogoFolder + inContainer: self]; + } } + else + childFolder = nil; return childFolder; } @@ -264,9 +303,9 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe { if ([[self faiMessageKeys] containsObject: messageKey]) { - msgObject = [faiFolder lookupName: messageKey - inContext: nil - acquire: NO]; + msgObject = [dbFolder lookupName: messageKey + inContext: nil + acquire: NO]; childMessage = [MAPIStoreFAIMessageK mapiStoreObjectWithSOGoObject: msgObject inContainer: self]; @@ -383,9 +422,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (int) deleteFolder { - [propsMessage delete]; - [propsFolder delete]; - [faiFolder delete]; + // [propsMessage delete]; + [dbFolder delete]; [self cleanupCaches]; @@ -1004,7 +1042,11 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe /* TODO: this should no longer be required once mapistore v2 API is in place, when we can then do this from -dealloc below */ + [dbFolder reloadIfNeeded]; + propsCopy = [newProperties mutableCopy]; + [propsCopy autorelease]; + currentProp = bannedProps; while (*currentProp) { @@ -1012,9 +1054,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe currentProp++; } - [propsMessage appendProperties: propsCopy]; - [propsMessage save]; - [propsCopy release]; + [properties addEntriesFromDictionary: propsCopy]; + [dbFolder save]; } - (NSArray *) messageKeys @@ -1039,9 +1080,10 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (NSArray *) faiMessageKeysMatchingQualifier: (EOQualifier *) qualifier andSortOrderings: (NSArray *) sortOrderings { - return [faiFolder - toOneRelationshipKeysMatchingQualifier: qualifier - andSortOrderings: sortOrderings]; + return [dbFolder childKeysOfType: MAPIDBObjectTypeFAI + includeDeleted: NO + matchingQualifier: qualifier + andSortOrderings: sortOrderings]; } - (NSArray *) faiMessageKeys @@ -1287,6 +1329,19 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe return MAPISTORE_SUCCESS; } +- (int) getProperties: (struct mapistore_property_data *) data + withTags: (enum MAPITAGS *) tags + andCount: (uint16_t) columnCount + inMemCtx: (TALLOC_CTX *) memCtx +{ + [dbFolder reloadIfNeeded]; + + return [super getProperties: data + withTags: tags + andCount: columnCount + inMemCtx: memCtx]; +} + - (int) getProperty: (void **) data withTag: (enum MAPITAGS) propTag inMemCtx: (TALLOC_CTX *) memCtx @@ -1294,8 +1349,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe int rc; id value; - value = [[propsMessage properties] - objectForKey: MAPIPropertyKey (propTag)]; + value = [properties objectForKey: MAPIPropertyKey (propTag)]; if (value) rc = [value getValue: data forTag: propTag inMemCtx: memCtx]; else @@ -1307,13 +1361,15 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (MAPIStoreMessage *) _createAssociatedMessage { MAPIStoreMessage *newMessage; - SOGoMAPIFSMessage *fsObject; + SOGoMAPIDBMessage *dbObject; NSString *newKey; newKey = [NSString stringWithFormat: @"%@.plist", [SOGoObject globallyUniqueObjectId]]; - fsObject = [SOGoMAPIFSMessage objectWithName: newKey inContainer: faiFolder]; - newMessage = [MAPIStoreFAIMessageK mapiStoreObjectWithSOGoObject: fsObject + dbObject = [SOGoMAPIDBMessage objectWithName: newKey inContainer: dbFolder]; + [dbObject setObjectType: MAPIDBObjectTypeFAI]; + [dbObject setIsNew: YES]; + newMessage = [MAPIStoreFAIMessageK mapiStoreObjectWithSOGoObject: dbObject inContainer: self]; return newMessage; @@ -1328,9 +1384,15 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe newMessage = [self _createAssociatedMessage]; else newMessage = [self createMessage]; - [newMessage setIsNew: YES]; + /* FIXME: this is ugly as the specifics of message creation should all be + delegated to subclasses */ + if ([newMessage respondsToSelector: @selector (setIsNew:)]) + [newMessage setIsNew: YES]; woContext = [[self userContext] woContext]; - [[newMessage sogoObject] setContext: woContext]; + /* FIXME: this is ugly too as the specifics of message creation should all + be delegated to subclasses */ + if ([newMessage respondsToSelector: @selector (sogoObject:)]) + [[newMessage sogoObject] setContext: woContext]; return newMessage; } @@ -1598,12 +1660,12 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (NSDate *) creationTime { - return [propsMessage creationTime]; + return [dbFolder creationDate]; } - (NSDate *) lastModificationTime { - return [propsMessage lastModificationTime]; + return [dbFolder lastModified]; } /* subclasses */ diff --git a/OpenChange/MAPIStoreGCSFolder.h b/OpenChange/MAPIStoreGCSFolder.h index 0d0c1e6df..d889b78a9 100644 --- a/OpenChange/MAPIStoreGCSFolder.h +++ b/OpenChange/MAPIStoreGCSFolder.h @@ -34,7 +34,7 @@ @interface MAPIStoreGCSFolder : MAPIStoreFolder { - SOGoMAPIFSMessage *versionsMessage; + SOGoMAPIDBMessage *versionsMessage; NSArray *activeUserRoles; EOQualifier *componentQualifier; } diff --git a/OpenChange/MAPIStoreGCSFolder.m b/OpenChange/MAPIStoreGCSFolder.m index e5f6bbd65..b94f10ad5 100644 --- a/OpenChange/MAPIStoreGCSFolder.m +++ b/OpenChange/MAPIStoreGCSFolder.m @@ -40,7 +40,7 @@ #import "NSData+MAPIStore.h" #import "NSDate+MAPIStore.h" #import "NSString+MAPIStore.h" -#import "SOGoMAPIFSMessage.h" +#import "SOGoMAPIDBMessage.h" #import "MAPIStoreGCSFolder.h" @@ -71,8 +71,9 @@ static Class NSNumberK; - (void) setupVersionsMessage { ASSIGN (versionsMessage, - [SOGoMAPIFSMessage objectWithName: @"versions.plist" - inContainer: propsFolder]); + [SOGoMAPIDBMessage objectWithName: @"versions.plist" + inContainer: dbFolder]); + [versionsMessage setObjectType: MAPIDBObjectTypeInternal]; } - (void) dealloc @@ -288,7 +289,8 @@ static Class NSNumberK; forKey: @"PredecessorChangeList"]; [changeList release]; } - [changeList setObject: globCnt forKey: guid]; + [changeList setObject: globCnt + forKey: guid]; } - (EOQualifier *) componentQualifier @@ -349,6 +351,7 @@ static Class NSNumberK; [sortOrdering retain]; } + [versionsMessage reloadIfNeeded]; currentProperties = [versionsMessage properties]; lastModificationDate = [currentProperties objectForKey: @"SyncLastModificationDate"]; @@ -451,7 +454,6 @@ static Class NSNumberK; forKey: @"SyncLastSynchronisationDate"]; [currentProperties setObject: lastModificationDate forKey: @"SyncLastModificationDate"]; - [versionsMessage appendProperties: currentProperties]; [versionsMessage save]; } } diff --git a/OpenChange/MAPIStoreMailAttachment.h b/OpenChange/MAPIStoreMailAttachment.h index 5fded594c..f9f0011e9 100644 --- a/OpenChange/MAPIStoreMailAttachment.h +++ b/OpenChange/MAPIStoreMailAttachment.h @@ -30,9 +30,11 @@ @interface MAPIStoreMailAttachment : MAPIStoreAttachment { NSDictionary *bodyInfo; + SOGoMailBodyPart *bodyPart; } - (void) setBodyInfo: (NSDictionary *) newBodyInfo; +- (void) setBodyPart: (SOGoMailBodyPart *) newBodyPart; @end diff --git a/OpenChange/MAPIStoreMailAttachment.m b/OpenChange/MAPIStoreMailAttachment.m index 7b9641548..6834b8c1d 100644 --- a/OpenChange/MAPIStoreMailAttachment.m +++ b/OpenChange/MAPIStoreMailAttachment.m @@ -52,6 +52,7 @@ if ((self = [super init])) { bodyInfo = nil; + bodyPart = nil; } return self; @@ -60,6 +61,7 @@ - (void) dealloc { [bodyInfo release]; + [bodyPart release]; [super dealloc]; } @@ -68,6 +70,11 @@ ASSIGN (bodyInfo, newBodyInfo); } +- (void) setBodyPart: (SOGoMailBodyPart *) newBodyPart +{ + ASSIGN (bodyPart, newBodyPart); +} + - (int) getPidTagAttachMethod: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -187,7 +194,7 @@ - (int) getPidTagAttachDataBinary: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = [[sogoObject fetchBLOBWithPeek: YES] asBinaryInMemCtx: memCtx]; + *data = [[bodyPart fetchBLOBWithPeek: YES] asBinaryInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } diff --git a/OpenChange/MAPIStoreMailFolder.h b/OpenChange/MAPIStoreMailFolder.h index 7e47e8c09..ab6430489 100644 --- a/OpenChange/MAPIStoreMailFolder.h +++ b/OpenChange/MAPIStoreMailFolder.h @@ -36,7 +36,7 @@ @interface MAPIStoreMailFolder : MAPIStoreFolder { - SOGoMAPIFSMessage *versionsMessage; + SOGoMAPIDBMessage *versionsMessage; } - (BOOL) ensureFolderExists; diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index f5cfe3340..8fffd8d9d 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -54,9 +54,8 @@ #import "MAPIStoreTypes.h" #import "NSData+MAPIStore.h" #import "NSString+MAPIStore.h" -#import "SOGoMAPIFSMessage.h" +#import "SOGoMAPIDBMessage.h" -#import "SOGoMAPIVolatileMessage.h" #import "MAPIStoreMailVolatileMessage.h" #import "MAPIStoreMailFolder.h" @@ -97,8 +96,9 @@ static Class SOGoMailFolderK, MAPIStoreOutboxFolderK; - (void) setupVersionsMessage { ASSIGN (versionsMessage, - [SOGoMAPIFSMessage objectWithName: @"versions.plist" - inContainer: propsFolder]); + [SOGoMAPIDBMessage objectWithName: @"versions.plist" + inContainer: dbFolder]); + [versionsMessage setObjectType: MAPIDBObjectTypeInternal]; } - (BOOL) ensureFolderExists @@ -119,6 +119,9 @@ static Class SOGoMailFolderK, MAPIStoreOutboxFolderK; && ![[(SOGoMailFolder *) sogoObject displayName] isEqualToString: newDisplayName]) { + [NSException raise: @"MAPIStoreIOException" + format: @"renaming a mail folder via OpenChange is" + @" currently a bad idea"]; [(SOGoMailFolder *) sogoObject renameTo: newDisplayName]; propsCopy = [newProperties mutableCopy]; [propsCopy removeObjectForKey: key]; @@ -489,10 +492,8 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) now = [NSCalendarDate date]; [now setTimeZone: utcTZ]; - currentProperties = [[versionsMessage properties] mutableCopy]; - if (!currentProperties) - currentProperties = [NSMutableDictionary new]; - [currentProperties autorelease]; + [versionsMessage reloadIfNeeded]; + currentProperties = [versionsMessage properties]; messages = [currentProperties objectForKey: @"Messages"]; if (!messages) { @@ -613,7 +614,6 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) ti = [NSNumber numberWithDouble: [now timeIntervalSince1970]]; [currentProperties setObject: ti forKey: @"SyncLastSynchronisationDate"]; - [versionsMessage appendProperties: currentProperties]; [versionsMessage save]; } @@ -1004,20 +1004,16 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) - (MAPIStoreMessage *) createMessage { - MAPIStoreMailVolatileMessage *newMessage; - SOGoMAPIVolatileMessage *newObject; + SOGoMAPIObject *childObject; - newObject = [SOGoMAPIVolatileMessage - objectWithName: [SOGoObject globallyUniqueObjectId] - inContainer: sogoObject]; - newMessage - = [MAPIStoreMailVolatileMessage mapiStoreObjectWithSOGoObject: newObject - inContainer: self]; - - return newMessage; + childObject = [SOGoMAPIObject objectWithName: [SOGoMAPIObject + globallyUniqueObjectId] + inContainer: sogoObject]; + return [MAPIStoreMailVolatileMessage + mapiStoreObjectWithSOGoObject: childObject + inContainer: self]; } - - (NSArray *) rolesForExchangeRights: (uint32_t) rights { NSMutableArray *roles; diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 85081c2db..8e8070ae2 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -373,7 +373,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) if (uid) { changeNumber = [(MAPIStoreMailFolder *) container - changeNumberForMessageUID: uid]; + changeNumberForMessageUID: uid]; if (!changeNumber) { [self warnWithFormat: @"attempting to get change number" @@ -1529,8 +1529,8 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) if (currentPart) { attachment = [MAPIStoreMailAttachment - mapiStoreObjectWithSOGoObject: currentPart - inContainer: self]; + mapiStoreObjectInContainer: self]; + [attachment setBodyPart: currentPart]; [attachment setBodyInfo: [attachmentParts objectForKey: childKey]]; [attachment setAID: [[self attachmentKeys] indexOfObject: childKey]]; } diff --git a/OpenChange/MAPIStoreMailMessageTable.m b/OpenChange/MAPIStoreMailMessageTable.m index 62dc406fd..c1561bbd5 100644 --- a/OpenChange/MAPIStoreMailMessageTable.m +++ b/OpenChange/MAPIStoreMailMessageTable.m @@ -332,7 +332,7 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK; if (!fetchedCoreInfos) { fetchedCoreInfos = YES; - [(SOGoMailFolder *) [container sogoObject] + [(SOGoMailFolder *) [(MAPIStoreMailFolder *) container sogoObject] prefetchCoreInfosForMessageKeys: [self restrictedChildKeys]]; } diff --git a/OpenChange/MAPIStoreMailVolatileMessage.h b/OpenChange/MAPIStoreMailVolatileMessage.h index 82959cc6f..53a51847f 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.h +++ b/OpenChange/MAPIStoreMailVolatileMessage.h @@ -23,9 +23,9 @@ #ifndef MAPISTOREMAILVOLATILEMESSAGE_H #define MAPISTOREMAILVOLATILEMESSAGE_H -#import "MAPIStoreVolatileMessage.h" +#import "MAPIStoreMessage.h" -@interface MAPIStoreMailVolatileMessage : MAPIStoreVolatileMessage +@interface MAPIStoreMailVolatileMessage : MAPIStoreMessage - (int) submitWithFlags: (enum SubmitFlags) flags; diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index 3a3d66be3..b3bb2145f 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -51,6 +51,7 @@ #import #import "MAPIStoreAttachment.h" +#import "MAPIStoreAttachmentTable.h" #import "MAPIStoreContext.h" #import "MAPIStoreMailFolder.h" #import "MAPIStoreMIME.h" @@ -60,7 +61,7 @@ #import "NSData+MAPIStore.h" #import "NSObject+MAPIStore.h" #import "NSString+MAPIStore.h" -#import "SOGoMAPIVolatileMessage.h" +#import "SOGoMAPIObject.h" #import "MAPIStoreMailVolatileMessage.h" @@ -68,6 +69,8 @@ #include #include +static Class NSNumberK = Nil; + static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" }; // @@ -242,6 +245,106 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" }; @implementation MAPIStoreMailVolatileMessage ++ (void) initialize +{ + NSNumberK = [NSNumber class]; +} + +- (id) initWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newContainer +{ + if ((self = [super initWithSOGoObject: newSOGoObject + inContainer: newContainer])) + { + ASSIGN (properties, [sogoObject properties]); + } + + return self; +} + +- (void) addProperties: (NSDictionary *) newProperties +{ + [super addProperties: newProperties]; + [sogoObject adjustLastModified]; +} + +- (BOOL) canGetProperty: (enum MAPITAGS) propTag +{ + return ([super canGetProperty: propTag] + || [properties objectForKey: MAPIPropertyKey (propTag)] != nil); +} + +- (uint64_t) objectVersion +{ + NSNumber *version; + + version = [properties objectForKey: @"version"]; + + return (version + ? exchange_globcnt ([version unsignedLongLongValue]) + : ULLONG_MAX); +} + +- (int) getPidTagSubject: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +{ + /* if we get here, it means that the properties file didn't contain a + relevant value */ + return [self getEmptyString: data inMemCtx: memCtx]; +} + +- (int) getPidTagMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = [@"IPM.Note" asUnicodeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagChangeKey: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +{ + NSData *changeKey; + int rc; + + changeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)]; + if (changeKey) + { + *data = [changeKey asBinaryInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + else + rc = [super getPidTagChangeKey: data inMemCtx: memCtx]; + + return rc; +} + +- (NSArray *) attachmentsKeysMatchingQualifier: (EOQualifier *) qualifier + andSortOrderings: (NSArray *) sortOrderings +{ + NSDictionary *attachments; + + attachments = [properties objectForKey: @"attachments"]; + + return [attachments allKeys]; +} + +- (NSDate *) creationTime +{ + return [sogoObject creationDate]; +} + +- (NSDate *) lastModificationTime +{ + return [sogoObject lastModified]; +} + +- (id) lookupAttachment: (NSString *) childKey +{ + NSDictionary *attachments; + + attachments = [properties objectForKey: @"attachments"]; + + return [attachments objectForKey: childKey]; +} + - (void) getMessageData: (struct mapistore_message **) dataPtr inMemCtx: (TALLOC_CTX *) memCtx { @@ -258,9 +361,11 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" }; samCtx = [[self context] connectionInfo]->sam_ctx; - [super getMessageData: &msgData inMemCtx: memCtx]; + // [super getMessageData: &msgData inMemCtx: memCtx]; - allRecipients = [[sogoObject properties] objectForKey: @"recipients"]; + msgData = talloc_zero (memCtx, struct mapistore_message); + + allRecipients = [properties objectForKey: @"recipients"]; msgData->columns = set_SPropTagArray (msgData, 9, PR_OBJECT_TYPE, PR_DISPLAY_TYPE, @@ -660,10 +765,13 @@ MakeTextPartBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, return textBody; } +// static id +// MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, +// NSString **contentType) static id -MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, - NSString **contentType) +MakeMessageBody (NSDictionary *mailProperties, NSString **contentType) { + NSDictionary *attachmentParts; id messageBody, textBody; NSString *textContentType; NSArray *parts; @@ -671,6 +779,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NGMutableHashMap *headers; NSUInteger count, max; + attachmentParts = [mailProperties objectForKey: @"attachments"]; textBody = MakeTextPartBody (mailProperties, attachmentParts, &textContentType); @@ -707,22 +816,20 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, - (NGMimeMessage *) _generateMessage { - NSDictionary *mailProperties; NSString *contentType; NGMimeMessage *message; NGMutableHashMap *headers; id messageBody; - mailProperties = [sogoObject properties]; - headers = [[NGMutableHashMap alloc] initWithCapacity: 16]; - FillMessageHeadersFromProperties (headers, mailProperties, + FillMessageHeadersFromProperties (headers, properties, [[self context] connectionInfo]); message = [[NGMimeMessage alloc] initWithHeader: headers]; [message autorelease]; [headers release]; - messageBody = MakeMessageBody (mailProperties, attachmentParts, &contentType); + messageBody = MakeMessageBody (properties, &contentType); + // messageBody = MakeMessageBody (mailProperties, attachmentParts, &contentType); if (messageBody) { [headers setObject: contentType forKey: @"content-type"]; @@ -775,7 +882,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, - (int) submitWithFlags: (enum SubmitFlags) flags { - NSDictionary *mailProperties, *recipients; + NSDictionary *recipients; NSData *messageData; NSMutableArray *recipientEmails; NSArray *list; @@ -785,19 +892,17 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, // SOGoMailFolder *sentFolder; SOGoDomainDefaults *dd; NSException *error; - MAPIStoreMapping *mapping; + // MAPIStoreMapping *mapping; - mailProperties = [sogoObject properties]; - msgClass = [mailProperties objectForKey: MAPIPropertyKey (PidTagMessageClass)]; + msgClass = [properties objectForKey: MAPIPropertyKey (PidTagMessageClass)]; if ([msgClass isEqualToString: @"IPM.Note"]) /* we skip invitation replies */ { /* send mail */ messageData = [self _generateMailDataWithBcc: NO]; - mailProperties = [sogoObject properties]; recipientEmails = [NSMutableArray arrayWithCapacity: 32]; - recipients = [mailProperties objectForKey: @"recipients"]; + recipients = [properties objectForKey: @"recipients"]; for (count = 0; count < 3; count++) { recId = recTypes[count]; @@ -819,11 +924,11 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, if (error) [self logWithFormat: @"an error occurred: '%@'", error]; - mapping = [self mapping]; - [mapping unregisterURLWithID: [self objectId]]; - [self setIsNew: NO]; - [properties removeAllObjects]; - [[self container] cleanupCaches]; + // mapping = [self mapping]; + // [mapping unregisterURLWithID: [self objectId]]; + // [self setIsNew: NO]; + // [properties removeAllObjects]; + [(MAPIStoreMailFolder *) [self container] cleanupCaches]; } else [self logWithFormat: @"skipping submit of message with class '%@'", @@ -834,14 +939,14 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, - (void) save { - NSString *folderName, *flag, *newIdString; + NSString *folderName, *flag, *newIdString, *messageKey; NSData *changeKey, *messageData; NGImap4Connection *connection; NGImap4Client *client; SOGoMailFolder *containerFolder; NSDictionary *result, *responseResult; - MAPIStoreMapping *mapping; - uint64_t mid; + // MAPIStoreMapping *mapping; + // uint64_t mid; messageData = [self _generateMailDataWithBcc: YES]; @@ -860,21 +965,24 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, flag = [responseResult objectForKey: @"flag"]; newIdString = [[flag componentsSeparatedByString: @" "] objectAtIndex: 2]; - mid = [self objectId]; - mapping = [self mapping]; - [mapping unregisterURLWithID: mid]; - [sogoObject setNameInContainer: [NSString stringWithFormat: @"%@.eml", newIdString]]; - [mapping registerURL: [self url] withID: mid]; - } + // mid = [self objectId]; + // mapping = [self mapping]; + // [mapping unregisterURLWithID: mid]; + // [sogoObject setNameInContainer: ]; + messageKey = [NSString stringWithFormat: @"%@.eml", newIdString]; + // [mapping registerURL: [NSString stringWithFormat: @"%@%@", + // [(MAPIStoreMailFolder *) container url], messageKey] + // withID: mid]; - /* synchronise the cache and update the change key with the one provided by - the client */ - [(MAPIStoreMailFolder *) container synchroniseCache]; - changeKey = [[sogoObject properties] - objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)]; - if (changeKey) - [(MAPIStoreMailFolder *) container - setChangeKey: changeKey forMessageWithKey: [self nameInContainer]]; + /* synchronise the cache and update the change key with the one provided + by the client */ + [(MAPIStoreMailFolder *) container synchroniseCache]; + changeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)]; + if (changeKey) + [(MAPIStoreMailFolder *) container + setChangeKey: changeKey + forMessageWithKey: messageKey]; + } } @end diff --git a/OpenChange/MAPIStoreMessage.h b/OpenChange/MAPIStoreMessage.h index d1494c060..b7ba24ae7 100644 --- a/OpenChange/MAPIStoreMessage.h +++ b/OpenChange/MAPIStoreMessage.h @@ -35,9 +35,9 @@ @class MAPIStoreAttachmentTable; @class MAPIStoreFolder; -#import "MAPIStoreObject.h" +#import "MAPIStoreSOGoObject.h" -@interface MAPIStoreMessage : MAPIStoreObject +@interface MAPIStoreMessage : MAPIStoreSOGoObject { NSArray *attachmentKeys; NSMutableDictionary *attachmentParts; diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index 35ea1036d..0d42eb048 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -36,6 +36,7 @@ #import "MAPIStoreAttachmentTable.h" #import "MAPIStoreContext.h" #import "MAPIStoreFolder.h" +#import "MAPIStoreMessageTable.h" #import "MAPIStorePropertySelectors.h" #import "MAPIStoreSamDBUtils.h" #import "MAPIStoreTypes.h" @@ -116,7 +117,6 @@ rtf2html (NSData *compressedRTF) @interface SOGoObject (MAPIStoreProtocol) -- (NSString *) davEntityTag; - (NSString *) davContentLength; @end @@ -304,6 +304,7 @@ rtf2html (NSData *compressedRTF) NSData *htmlData, *rtfData; static NSNumber *htmlKey = nil, *rtfKey = nil; + /* we intercept any RTF content and convert it to HTML */ [super addProperties: newNewProperties]; if (!htmlKey) @@ -339,10 +340,8 @@ rtf2html (NSData *compressedRTF) newAid = [[self attachmentKeys] count]; - newAttachment = [MAPIStoreAttachment - mapiStoreObjectWithSOGoObject: nil - inContainer: self]; - [newAttachment setIsNew: YES]; + newAttachment = [MAPIStoreAttachment mapiStoreObjectInContainer: self]; + // [newAttachment setIsNew: YES]; [newAttachment setAID: newAid]; newKey = [NSString stringWithFormat: @"%ul", newAid]; [attachmentParts setObject: newAttachment @@ -497,7 +496,6 @@ rtf2html (NSData *compressedRTF) [[containerTables objectAtIndex: count] notifyChangesForChild: self]; [self setIsNew: NO]; - [properties removeAllObjects]; [container cleanupCaches]; rc = MAPISTORE_SUCCESS; } @@ -792,7 +790,7 @@ rtf2html (NSData *compressedRTF) - (int) getPidTagOriginalMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidTagMessageClass: data inMemCtx: memCtx]; + return [self getProperty: data withTag: PidTagMessageClass inMemCtx: memCtx]; } - (int) getPidTagHasAttachments: (void **) data diff --git a/OpenChange/MAPIStoreMessageTable.h b/OpenChange/MAPIStoreMessageTable.h index 7c3935bba..0779afaef 100644 --- a/OpenChange/MAPIStoreMessageTable.h +++ b/OpenChange/MAPIStoreMessageTable.h @@ -28,6 +28,7 @@ @interface MAPIStoreMessageTable : MAPIStoreTable - (void) setSortOrder: (const struct SSortOrderSet *) set; +- (void) notifyChangesForChild: (MAPIStoreMessage *) child; @end diff --git a/OpenChange/MAPIStoreMessageTable.m b/OpenChange/MAPIStoreMessageTable.m index 33703dc23..3c08e2bab 100644 --- a/OpenChange/MAPIStoreMessageTable.m +++ b/OpenChange/MAPIStoreMessageTable.m @@ -27,6 +27,7 @@ #import #import +#import "MAPIStoreContext.h" #import "MAPIStoreFolder.h" #import "MAPIStoreTypes.h" #import "NSData+MAPIStore.h" @@ -83,4 +84,60 @@ return [(MAPIStoreFolder *) container lookupMessage: childKey]; } +- (void) notifyChangesForChild: (MAPIStoreMessage *) child +{ + NSUInteger currentChildRow, newChildRow; + NSArray *list; + NSString *childName; + struct mapistore_table_notification_parameters notif_parameters; + struct mapistore_context *mstoreCtx; + + mstoreCtx = [[(MAPIStoreFolder *) container context] + connectionInfo]->mstore_ctx; + + notif_parameters.table_type = tableType; + notif_parameters.handle = handleId; + notif_parameters.folder_id = [(MAPIStoreFolder *) container objectId]; + notif_parameters.object_id = [child objectId]; + notif_parameters.instance_id = 0; /* TODO: always 0 ? */ + + childName = [child nameInContainer]; + list = [self restrictedChildKeys]; + currentChildRow = [list indexOfObject: childName]; + notif_parameters.row_id = currentChildRow; + + [self cleanupCaches]; + list = [self restrictedChildKeys]; + newChildRow = [list indexOfObject: childName]; + + if (currentChildRow == NSNotFound) + { + if (newChildRow != NSNotFound) + { + notif_parameters.row_id = newChildRow; + mapistore_push_notification (mstoreCtx, + MAPISTORE_TABLE, + MAPISTORE_OBJECT_CREATED, + ¬if_parameters); + } + } + else + { + if (newChildRow == NSNotFound) + mapistore_push_notification (mstoreCtx, + MAPISTORE_TABLE, + MAPISTORE_OBJECT_DELETED, + ¬if_parameters); + else + { + /* the fact that the row order has changed has no impact here */ + notif_parameters.row_id = newChildRow; + mapistore_push_notification (mstoreCtx, + MAPISTORE_TABLE, + MAPISTORE_OBJECT_MODIFIED, + ¬if_parameters); + } + } +} + @end diff --git a/OpenChange/MAPIStoreNotesContext.h b/OpenChange/MAPIStoreNotesContext.h index ad4a581e1..3f44d575d 100644 --- a/OpenChange/MAPIStoreNotesContext.h +++ b/OpenChange/MAPIStoreNotesContext.h @@ -23,9 +23,9 @@ #ifndef MAPISTORENOTESCONTEXT_H #define MAPISTORENOTESCONTEXT_H -#import "MAPIStoreFSBaseContext.h" +#import "MAPIStoreDBBaseContext.h" -@interface MAPIStoreNotesContext : MAPIStoreFSBaseContext +@interface MAPIStoreNotesContext : MAPIStoreDBBaseContext @end diff --git a/OpenChange/MAPIStoreNotesFolder.h b/OpenChange/MAPIStoreNotesFolder.h index de2eb2748..9baebab27 100644 --- a/OpenChange/MAPIStoreNotesFolder.h +++ b/OpenChange/MAPIStoreNotesFolder.h @@ -23,9 +23,9 @@ #ifndef MAPISTORENOTESFOLDER_H #define MAPISTORENOTESFOLDER_H -#import "MAPIStoreFSFolder.h" +#import "MAPIStoreDBFolder.h" -@interface MAPIStoreNotesFolder : MAPIStoreFSFolder +@interface MAPIStoreNotesFolder : MAPIStoreDBFolder @end #endif /* MAPISTORENOTESFOLDER_H */ diff --git a/OpenChange/MAPIStoreNotesMessage.h b/OpenChange/MAPIStoreNotesMessage.h index 81adfc0dc..d4ec7e1ba 100644 --- a/OpenChange/MAPIStoreNotesMessage.h +++ b/OpenChange/MAPIStoreNotesMessage.h @@ -23,9 +23,9 @@ #ifndef MAPISTORENOTESMESSAGE_H #define MAPISTORENOTESMESSAGE_H -#import "MAPIStoreFSMessage.h" +#import "MAPIStoreDBMessage.h" -@interface MAPIStoreNotesMessage : MAPIStoreFSMessage +@interface MAPIStoreNotesMessage : MAPIStoreDBMessage @end #endif /* MAPISTORENOTESMESSAGE_H */ diff --git a/OpenChange/MAPIStoreNotesMessage.m b/OpenChange/MAPIStoreNotesMessage.m index d59d9a2f8..7cac637b8 100644 --- a/OpenChange/MAPIStoreNotesMessage.m +++ b/OpenChange/MAPIStoreNotesMessage.m @@ -53,21 +53,4 @@ return MAPISTORE_SUCCESS; } -- (int) getPidTagSubject: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - id value; - int rc; - - value = [[sogoObject properties] - objectForKey: MAPIPropertyKey (PidTagNormalizedSubject)]; - if (value) - rc = [value getValue: data forTag: PidTagNormalizedSubject - inMemCtx: memCtx]; - else - rc = MAPISTORE_ERR_NOT_FOUND; - - return rc; -} - @end diff --git a/OpenChange/MAPIStoreObject.h b/OpenChange/MAPIStoreObject.h index cb7ed7809..709396e9f 100644 --- a/OpenChange/MAPIStoreObject.h +++ b/OpenChange/MAPIStoreObject.h @@ -33,56 +33,38 @@ @class NSMutableArray; @class NSMutableDictionary; -@class EOQualifier; - @class MAPIStoreContext; -@class MAPIStoreFolder; @class MAPIStoreMapping; -@class MAPIStoreTable; @class MAPIStoreUserContext; +@class MAPIStoreSOGoObject; @interface MAPIStoreObject : NSObject { const IMP *classGetters; NSMutableArray *parentContainersBag; - MAPIStoreObject *container; - id sogoObject; + id container; NSMutableDictionary *properties; - BOOL isNew; } -+ (id) mapiStoreObjectWithSOGoObject: (id) newSOGoObject - inContainer: (MAPIStoreObject *) newContainer; ++ (id) mapiStoreObjectInContainer: (MAPIStoreObject *) newContainer; +- (id) initInContainer: (MAPIStoreObject *) newContainer; + + (int) getAvailableProperties: (struct SPropTagArray **) propertiesP inMemCtx: (TALLOC_CTX *) memCtx; -- (id) initWithSOGoObject: (id) newSOGoObject - inContainer: (MAPIStoreObject *) newFolder; - -- (void) setIsNew: (BOOL) newIsNew; -- (BOOL) isNew; - -- (NSString *) nameInContainer; - -- (id) sogoObject; - (MAPIStoreObject *) container; - (MAPIStoreContext *) context; - (MAPIStoreUserContext *) userContext; - (MAPIStoreMapping *) mapping; -- (void) cleanupCaches; - -- (uint64_t) objectId; -- (NSString *) url; - /* properties */ - (BOOL) canGetProperty: (enum MAPITAGS) propTag; - (void) addProperties: (NSDictionary *) newProperties; -- (NSDictionary *) properties; +- (NSMutableDictionary *) properties; /* ops */ - (int) getAvailableProperties: (struct SPropTagArray **) propertiesP @@ -104,26 +86,12 @@ fromGlobCnt: (uint64_t) objectCnt inMemCtx: (TALLOC_CTX *) memCtx; -/* implemented getters */ -- (int) getPidTagDisplayName: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; -- (int) getPidTagSearchKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; -- (int) getPidTagGenerateExchangeViews: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; -- (int) getPidTagParentSourceKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; -- (int) getPidTagSourceKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; -- (int) getPidTagChangeKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; - (int) getPidTagCreationTime: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; - (int) getPidTagLastModificationTime: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; /* subclasses */ -- (uint64_t) objectVersion; - (NSDate *) creationTime; - (NSDate *) lastModificationTime; diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index e3d379d6b..ac782cdc8 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -58,13 +58,11 @@ static Class NSExceptionK, MAPIStoreFolderK; MAPIStoreFolderK = [MAPIStoreFolder class]; } -+ (id) mapiStoreObjectWithSOGoObject: (id) newSOGoObject - inContainer: (MAPIStoreObject *) newContainer ++ (id) mapiStoreObjectInContainer: (MAPIStoreObject *) newContainer { id newObject; - newObject = [[self alloc] initWithSOGoObject: newSOGoObject - inContainer: newContainer]; + newObject = [[self alloc] initInContainer: newContainer]; [newObject autorelease]; return newObject; @@ -106,22 +104,18 @@ static Class NSExceptionK, MAPIStoreFolderK; classGetters = (IMP *) MAPIStorePropertyGettersForClass (isa); parentContainersBag = [NSMutableArray new]; container = nil; - sogoObject = nil; properties = [NSMutableDictionary new]; - isNew = NO; } - [self logWithFormat: @"-init"]; + // [self logWithFormat: @"-init"]; return self; } -- (id) initWithSOGoObject: (id) newSOGoObject - inContainer: (MAPIStoreObject *) newContainer +- (id) initInContainer: (MAPIStoreObject *) newContainer { if ((self = [self init])) { - ASSIGN (sogoObject, newSOGoObject); ASSIGN (container, newContainer); } @@ -130,42 +124,21 @@ static Class NSExceptionK, MAPIStoreFolderK; - (void) dealloc { - [self logWithFormat: @"-dealloc"]; - [sogoObject release]; + // [self logWithFormat: @"-dealloc"]; [properties release]; [parentContainersBag release]; [container release]; [super dealloc]; } -- (void) setIsNew: (BOOL) newIsNew -{ - isNew = newIsNew; -} - -- (BOOL) isNew -{ - return isNew; -} - -- (id) sogoObject -{ - return sogoObject; -} - - (MAPIStoreObject *) container { return container; } -- (NSString *) nameInContainer -{ - return [sogoObject nameInContainer]; -} - - (MAPIStoreContext *) context { - return [container context]; + return (MAPIStoreContext *) [container context]; } - (MAPIStoreUserContext *) userContext @@ -178,47 +151,14 @@ static Class NSExceptionK, MAPIStoreFolderK; return [[self userContext] mapping]; } -- (void) cleanupCaches -{ -} - /* helpers */ -- (uint64_t) objectId -{ - uint64_t objectId; - - if ([container isKindOfClass: MAPIStoreFolderK]) - objectId = [(MAPIStoreFolder *) container - idForObjectWithKey: [sogoObject nameInContainer]]; - else - { - [self errorWithFormat: @"%s: container is not a folder", __PRETTY_FUNCTION__]; - objectId = (uint64_t) -1; - } - - return objectId; -} - -- (NSString *) url -{ - NSString *containerURL, *format; - - containerURL = [container url]; - if ([containerURL hasSuffix: @"/"]) - format = @"%@%@"; - else - format = @"%@/%@"; - - return [NSString stringWithFormat: format, - containerURL, [self nameInContainer]]; -} - (void) addProperties: (NSDictionary *) newNewProperties { [properties addEntriesFromDictionary: newNewProperties]; } -- (NSDictionary *) properties +- (NSMutableDictionary *) properties { return properties; } @@ -248,124 +188,8 @@ static Class NSExceptionK, MAPIStoreFolderK; return rc; } -/* helper getters */ -- (NSData *) getReplicaKeyFromGlobCnt: (uint64_t) objectCnt -{ - struct mapistore_connection_info *connInfo; - NSMutableData *replicaKey; - char buffer[6]; - NSUInteger count; - - connInfo = [[self context] connectionInfo]; - - for (count = 0; count < 6; count++) - { - buffer[count] = objectCnt & 0xff; - objectCnt >>= 8; - } - - replicaKey = [NSMutableData dataWithCapacity: 22]; - [replicaKey appendBytes: &connInfo->replica_guid - length: sizeof (struct GUID)]; - [replicaKey appendBytes: buffer length: 6]; - - return replicaKey; -} - -- (int) getReplicaKey: (void **) data - fromGlobCnt: (uint64_t) objectCnt - inMemCtx: (TALLOC_CTX *) memCtx -{ - *data = [[self getReplicaKeyFromGlobCnt: objectCnt] asBinaryInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - -/* getters */ -- (int) getPidTagDisplayName: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - *data = [[sogoObject displayName] asUnicodeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - -- (int) getPidTagSearchKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - NSString *stringValue; - - stringValue = [sogoObject nameInContainer]; - *data = [[stringValue dataUsingEncoding: NSASCIIStringEncoding] - asBinaryInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - -- (int) getPidTagGenerateExchangeViews: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getNo: data inMemCtx: memCtx]; -} - -- (int) getPidTagParentSourceKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getReplicaKey: data fromGlobCnt: [container objectId] >> 16 - inMemCtx: memCtx]; -} - -- (int) getPidTagSourceKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getReplicaKey: data fromGlobCnt: [self objectId] >> 16 - inMemCtx: memCtx]; -} - -- (uint64_t) objectVersion -{ - [self subclassResponsibility: _cmd]; - - return ULLONG_MAX; -} - -- (int) getPidTagChangeKey: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - int rc; - uint64_t obVersion; - - obVersion = [self objectVersion]; - if (obVersion == ULLONG_MAX) - rc = MAPISTORE_ERR_NOT_FOUND; - else - rc = [self getReplicaKey: data fromGlobCnt: obVersion - inMemCtx: memCtx]; - - return rc; -} - -- (int) getPidTagChangeNumber: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - int rc; - uint64_t obVersion; - - obVersion = [self objectVersion]; - if (obVersion == ULLONG_MAX) - rc = MAPISTORE_ERR_NOT_FOUND; - else - { - *data = MAPILongLongValue (memCtx, ((obVersion << 16) - | 0x0001)); - rc = MAPISTORE_SUCCESS; - } - - return rc; -} - - (int) getPidTagCreationTime: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { *data = [[self creationTime] asFileTimeInMemCtx: memCtx]; @@ -474,6 +298,38 @@ static Class NSExceptionK, MAPIStoreFolderK; return MAPISTORE_SUCCESS; } +- (NSData *) getReplicaKeyFromGlobCnt: (uint64_t) objectCnt +{ + struct mapistore_connection_info *connInfo; + NSMutableData *replicaKey; + char buffer[6]; + NSUInteger count; + + connInfo = [[self context] connectionInfo]; + + for (count = 0; count < 6; count++) + { + buffer[count] = objectCnt & 0xff; + objectCnt >>= 8; + } + + replicaKey = [NSMutableData dataWithCapacity: 22]; + [replicaKey appendBytes: &connInfo->replica_guid + length: sizeof (struct GUID)]; + [replicaKey appendBytes: buffer length: 6]; + + return replicaKey; +} + +- (int) getReplicaKey: (void **) data + fromGlobCnt: (uint64_t) objectCnt + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = [[self getReplicaKeyFromGlobCnt: objectCnt] asBinaryInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + /* subclasses */ - (NSDate *) creationTime { diff --git a/OpenChange/MAPIStorePermissionsTable.m b/OpenChange/MAPIStorePermissionsTable.m index 6d4c57c55..2385ee8a5 100644 --- a/OpenChange/MAPIStorePermissionsTable.m +++ b/OpenChange/MAPIStorePermissionsTable.m @@ -50,7 +50,7 @@ MAPIStorePermissionEntry *newEntry; newEntry = [[self alloc] initWithUserId: newUserId andMemberId: newMemberId - forFolder: newFolder]; + forFolder: newFolder]; [newEntry autorelease]; return newEntry; @@ -60,7 +60,7 @@ andMemberId: (uint64_t) newMemberId forFolder: (MAPIStoreFolder *) newFolder { - if ((self = [self initWithSOGoObject: nil inContainer: newFolder])) + if ((self = [self initInContainer: newFolder])) { ASSIGN (userId, newUserId); memberId = newMemberId; diff --git a/OpenChange/MAPIStoreSOGoObject.h b/OpenChange/MAPIStoreSOGoObject.h new file mode 100644 index 000000000..90524558f --- /dev/null +++ b/OpenChange/MAPIStoreSOGoObject.h @@ -0,0 +1,89 @@ +/* MAPIStoreObject.h - this file is part of SOGo + * + * Copyright (C) 2011 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * 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 MAPISTORESOGOOBJECT_H +#define MAPISTORESOGOOBJECT_H + +#include + +#import "MAPIStoreObject.h" + +@class NSDate; +@class NSData; +@class NSString; +@class NSMutableArray; +@class NSMutableDictionary; + +@class EOQualifier; + +@class MAPIStoreContext; +@class MAPIStoreFolder; +@class MAPIStoreMapping; +@class MAPIStoreTable; +@class MAPIStoreUserContext; + +@interface MAPIStoreSOGoObject : MAPIStoreObject +{ + id sogoObject; + BOOL isNew; +} + ++ (id) mapiStoreObjectWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newContainer; + +- (id) initWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newFolder; + +- (void) setIsNew: (BOOL) newIsNew; +- (BOOL) isNew; + +- (id) sogoObject; + +- (NSString *) nameInContainer; + +- (MAPIStoreObject *) container; + +- (void) cleanupCaches; + +- (uint64_t) objectId; +- (NSString *) url; + +/* implemented getters */ +- (int) getPidTagDisplayName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidTagSearchKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidTagGenerateExchangeViews: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidTagParentSourceKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidTagSourceKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidTagChangeKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx; + +/* subclasses */ +- (uint64_t) objectVersion; + +@end + +#endif /* MAPISTORESOGOOBJECT_H */ diff --git a/OpenChange/MAPIStoreSOGoObject.m b/OpenChange/MAPIStoreSOGoObject.m new file mode 100644 index 000000000..d2d3b4790 --- /dev/null +++ b/OpenChange/MAPIStoreSOGoObject.m @@ -0,0 +1,255 @@ +/* MAPIStoreObject.m - this file is part of SOGo + * + * Copyright (C) 2011 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * 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 +#import +#import +#import +#import +#import +#import +#import + +#import "MAPIStoreContext.h" +#import "MAPIStoreFolder.h" +#import "MAPIStorePropertySelectors.h" +#import "MAPIStoreTypes.h" +#import "MAPIStoreUserContext.h" +#import "NSDate+MAPIStore.h" +#import "NSData+MAPIStore.h" +#import "NSObject+MAPIStore.h" +#import "NSString+MAPIStore.h" + +#import "MAPIStoreSOGoObject.h" + +#undef DEBUG +#include +#include +#include +#include +#include + +@implementation MAPIStoreSOGoObject + +static Class MAPIStoreFolderK; + ++ (void) initialize +{ + MAPIStoreFolderK = [MAPIStoreFolder class]; +} + ++ (id) mapiStoreObjectWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newContainer +{ + id newObject; + + newObject = [[self alloc] initWithSOGoObject: newSOGoObject + inContainer: newContainer]; + [newObject autorelease]; + + return newObject; +} + +- (id) init +{ + if ((self = [super init])) + { + sogoObject = nil; + isNew = NO; + } + + [self logWithFormat: @"-init"]; + + return self; +} + +- (id) initWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newContainer +{ + if ((self = [self initInContainer: newContainer])) + { + ASSIGN (sogoObject, newSOGoObject); + } + + return self; +} + +- (void) dealloc +{ + // [self logWithFormat: @"-dealloc"]; + [sogoObject release]; + [super dealloc]; +} + +- (void) setIsNew: (BOOL) newIsNew +{ + isNew = newIsNew; +} + +- (BOOL) isNew +{ + return isNew; +} + +- (id) sogoObject +{ + return sogoObject; +} + +- (MAPIStoreObject *) container +{ + return container; +} + +- (NSString *) nameInContainer +{ + return [sogoObject nameInContainer]; +} + +- (void) cleanupCaches +{ +} + +/* helpers */ +- (uint64_t) objectId +{ + uint64_t objectId; + + if ([container isKindOfClass: MAPIStoreFolderK]) + objectId = [(MAPIStoreFolder *) container + idForObjectWithKey: [sogoObject nameInContainer]]; + else + { + [self errorWithFormat: @"%s: container is not a folder", __PRETTY_FUNCTION__]; + objectId = (uint64_t) -1; + } + + return objectId; +} + +- (NSString *) url +{ + NSString *containerURL, *format; + + containerURL = (NSString *) [container url]; + if ([containerURL hasSuffix: @"/"]) + format = @"%@%@"; + else + format = @"%@/%@"; + + return [NSString stringWithFormat: format, + containerURL, [self nameInContainer]]; +} + +/* getters */ +- (int) getPidTagDisplayName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = [[sogoObject displayName] asUnicodeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagSearchKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSString *stringValue; + + stringValue = [sogoObject nameInContainer]; + *data = [[stringValue dataUsingEncoding: NSASCIIStringEncoding] + asBinaryInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagGenerateExchangeViews: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getNo: data inMemCtx: memCtx]; +} + +- (int) getPidTagParentSourceKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getReplicaKey: data fromGlobCnt: [container objectId] >> 16 + inMemCtx: memCtx]; +} + +- (int) getPidTagSourceKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getReplicaKey: data fromGlobCnt: [self objectId] >> 16 + inMemCtx: memCtx]; +} + +/* helper getters */ +- (int) getPidTagChangeKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + int rc; + uint64_t obVersion; + + obVersion = [self objectVersion]; + if (obVersion == ULLONG_MAX) + rc = MAPISTORE_ERR_NOT_FOUND; + else + rc = [self getReplicaKey: data fromGlobCnt: obVersion + inMemCtx: memCtx]; + + return rc; +} + +- (int) getPidTagChangeNumber: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + int rc; + uint64_t obVersion; + + obVersion = [self objectVersion]; + if (obVersion == ULLONG_MAX) + rc = MAPISTORE_ERR_NOT_FOUND; + else + { + *data = MAPILongLongValue (memCtx, ((obVersion << 16) + | 0x0001)); + rc = MAPISTORE_SUCCESS; + } + + return rc; +} + +/* subclasses */ +- (uint64_t) objectVersion +{ + [self subclassResponsibility: _cmd]; + + return ULLONG_MAX; +} + +/* logging */ +- (NSString *) loggingPrefix +{ + return [NSString stringWithFormat:@"<%@:%p:%@>", + NSStringFromClass (isa), self, [self nameInContainer]]; +} + +@end diff --git a/OpenChange/MAPIStoreTable.h b/OpenChange/MAPIStoreTable.h index fbf13a680..7695c79f0 100644 --- a/OpenChange/MAPIStoreTable.h +++ b/OpenChange/MAPIStoreTable.h @@ -100,8 +100,6 @@ typedef enum { - (int) getRowCount: (uint32_t *) countP withQueryType: (enum mapistore_query_type) queryType; -- (void) notifyChangesForChild: (MAPIStoreObject *) child; - /* helpers */ - (SEL) operatorFromRestrictionOperator: (uint32_t) resOp; diff --git a/OpenChange/MAPIStoreTable.m b/OpenChange/MAPIStoreTable.m index 620b8f248..b47ce8a72 100644 --- a/OpenChange/MAPIStoreTable.m +++ b/OpenChange/MAPIStoreTable.m @@ -874,61 +874,6 @@ static Class NSDataK, NSStringK; return MAPISTORE_SUCCESS; } -- (void) notifyChangesForChild: (MAPIStoreObject *) child -{ - NSUInteger currentChildRow, newChildRow; - NSArray *list; - NSString *childName; - struct mapistore_table_notification_parameters notif_parameters; - struct mapistore_context *mstoreCtx; - - mstoreCtx = [[container context] connectionInfo]->mstore_ctx; - - notif_parameters.table_type = tableType; - notif_parameters.handle = handleId; - notif_parameters.folder_id = [container objectId]; - notif_parameters.object_id = [child objectId]; - notif_parameters.instance_id = 0; /* TODO: always 0 ? */ - - childName = [child nameInContainer]; - list = [self restrictedChildKeys]; - currentChildRow = [list indexOfObject: childName]; - notif_parameters.row_id = currentChildRow; - - [self cleanupCaches]; - list = [self restrictedChildKeys]; - newChildRow = [list indexOfObject: childName]; - - if (currentChildRow == NSNotFound) - { - if (newChildRow != NSNotFound) - { - notif_parameters.row_id = newChildRow; - mapistore_push_notification (mstoreCtx, - MAPISTORE_TABLE, - MAPISTORE_OBJECT_CREATED, - ¬if_parameters); - } - } - else - { - if (newChildRow == NSNotFound) - mapistore_push_notification (mstoreCtx, - MAPISTORE_TABLE, - MAPISTORE_OBJECT_DELETED, - ¬if_parameters); - else - { - /* the fact that the row order has changed has no impact here */ - notif_parameters.row_id = newChildRow; - mapistore_push_notification (mstoreCtx, - MAPISTORE_TABLE, - MAPISTORE_OBJECT_MODIFIED, - ¬if_parameters); - } - } -} - /* subclasses */ - (NSString *) backendIdentifierForProperty: (enum MAPITAGS) property { diff --git a/OpenChange/MAPIStoreUserContext.h b/OpenChange/MAPIStoreUserContext.h index 5cdd38710..70f142b3d 100644 --- a/OpenChange/MAPIStoreUserContext.h +++ b/OpenChange/MAPIStoreUserContext.h @@ -28,6 +28,7 @@ @class NSMutableDictionary; @class NSString; @class NSTimeZone; +@class NSURL; @class WOContext; @@ -52,6 +53,9 @@ MAPIStoreMapping *mapping; + BOOL userDbTableExists; + NSURL *folderTableURL; + WOContext *woContext; MAPIStoreAuthenticator *authenticator; } @@ -71,8 +75,11 @@ - (NSDictionary *) rootFolders; +- (NSURL *) folderTableURL; - (MAPIStoreMapping *) mapping; +- (void) ensureFolderTableExists; + /* SOGo hacky magic */ - (void) activateWithUser: (SOGoUser *) activeUser; - (MAPIStoreAuthenticator *) authenticator; diff --git a/OpenChange/MAPIStoreUserContext.m b/OpenChange/MAPIStoreUserContext.m index dcb3cfb72..bf5d97f0c 100644 --- a/OpenChange/MAPIStoreUserContext.m +++ b/OpenChange/MAPIStoreUserContext.m @@ -6,7 +6,7 @@ * * 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) + * 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, @@ -23,17 +23,21 @@ #import #import #import +#import #import #import #import +#import +#import #import #import #import #import +#import "GCSSpecialQueries+OpenChange.h" #import "MAPIApplication.h" #import "MAPIStoreAuthenticator.h" #import "MAPIStoreMapping.h" @@ -80,6 +84,9 @@ static NSMapTable *contextsTable = nil; mapping = nil; + userDbTableExists = NO; + folderTableURL = nil; + authenticator = nil; woContext = [WOContext contextWithRequest: nil]; [woContext retain]; @@ -117,6 +124,8 @@ static NSMapTable *contextsTable = nil; [authenticator release]; [mapping release]; + [folderTableURL release]; + [sogoUser release]; [contextsTable removeObjectForKey: username]; @@ -213,6 +222,72 @@ static NSMapTable *contextsTable = nil; return mapping; } + +/* OpenChange db table */ + +- (NSURL *) folderTableURL +{ + NSString *urlString, *ocFSTableName; + NSMutableArray *parts; + SOGoUser *user; + + if (!folderTableURL) + { + user = [self sogoUser]; + urlString = [[user domainDefaults] folderInfoURL]; + parts = [[urlString componentsSeparatedByString: @"/"] + mutableCopy]; + [parts autorelease]; + if ([parts count] == 5) + { + /* If "OCSFolderInfoURL" is properly configured, we must have 5 + parts in this url. */ + ocFSTableName = [NSString stringWithFormat: @"socfs_%@", username]; + [parts replaceObjectAtIndex: 4 withObject: ocFSTableName]; + folderTableURL + = [NSURL URLWithString: [parts componentsJoinedByString: @"/"]]; + [folderTableURL retain]; + } + else + [NSException raise: @"MAPIStoreIOException" + format: @"'OCSFolderInfoURL' is not set"]; + } + + return folderTableURL; +} + +- (void) ensureFolderTableExists +{ + GCSChannelManager *cm; + EOAdaptorChannel *channel; + NSString *tableName, *query; + GCSSpecialQueries *queries; + + [self folderTableURL]; + + cm = [GCSChannelManager defaultChannelManager]; + channel = [cm acquireOpenChannelForURL: folderTableURL]; + + /* FIXME: make use of [EOChannelAdaptor describeTableNames] instead */ + tableName = [[folderTableURL path] lastPathComponent]; + if ([channel evaluateExpressionX: + [NSString stringWithFormat: @"SELECT count(*) FROM %@", + tableName]]) + { + queries = [channel specialQueries]; + query = [queries createOpenChangeFSTableWithName: tableName]; + if ([channel evaluateExpressionX: query]) + [NSException raise: @"MAPIStoreIOException" + format: @"could not create special table '%@'", tableName]; + } + else + [channel cancelFetch]; + + + [cm releaseChannel: channel]; +} + +/* SOGo context objects */ - (WOContext *) woContext { return woContext; diff --git a/OpenChange/MAPIStoreVolatileMessage.h b/OpenChange/MAPIStoreVolatileMessage.h deleted file mode 100644 index 71e02c5f8..000000000 --- a/OpenChange/MAPIStoreVolatileMessage.h +++ /dev/null @@ -1,37 +0,0 @@ -/* MAPIStoreVolatileMessage.h - this file is part of SOGo - * - * Copyright (C) 2011 Inverse inc - * - * Author: Wolfgang Sourdeau - * - * 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 MAPISTOREVOLATILEMESSAGE_H -#define MAPISTOREVOLATILEMESSAGE_H - -#import "MAPIStoreMessage.h" - -@interface MAPIStoreVolatileMessage : MAPIStoreMessage -{ - BOOL fetchedAttachments; - NSDate *creationTime; - NSDate *lastModificationTime; -} - -@end - -#endif /* MAPISTOREVOLATILEMESSAGE_H */ diff --git a/OpenChange/MAPIStoreVolatileMessage.m b/OpenChange/MAPIStoreVolatileMessage.m deleted file mode 100644 index b248ef12a..000000000 --- a/OpenChange/MAPIStoreVolatileMessage.m +++ /dev/null @@ -1,208 +0,0 @@ -/* MAPIStoreVolatileMessage.m - this file is part of SOGo - * - * Copyright (C) 2011 Inverse inc - * - * Author: Wolfgang Sourdeau - * - * 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 -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -#import "MAPIStoreContext.h" -#import "MAPIStoreMailFolder.h" -#import "MAPIStoreMapping.h" -#import "MAPIStoreTypes.h" -#import "NSData+MAPIStore.h" -#import "NSObject+MAPIStore.h" -#import "NSString+MAPIStore.h" -#import "SOGoMAPIVolatileMessage.h" - -#import "MAPIStoreVolatileMessage.h" - -#undef DEBUG -#include -#include - -Class NSNumberK; - -@implementation MAPIStoreVolatileMessage - -+ (void) initialize -{ - NSNumberK = [NSNumber class]; -} - -- (id) init -{ - if ((self = [super init])) - { - fetchedAttachments = NO; - ASSIGN (creationTime, [NSDate date]); - lastModificationTime = [creationTime copy]; - } - - return self; -} - -- (void) dealloc -{ - [creationTime release]; - [lastModificationTime release]; - [super dealloc]; -} - -- (void) addProperties: (NSDictionary *) newProperties -{ - [super addProperties: newProperties]; - [sogoObject appendProperties: properties]; - [properties removeAllObjects]; - ASSIGN (lastModificationTime, [NSDate date]); -} - -- (BOOL) canGetProperty: (enum MAPITAGS) propTag -{ - return ([super canGetProperty: propTag] - || [[sogoObject properties] objectForKey: MAPIPropertyKey (propTag)]); -} - -- (uint64_t) objectVersion -{ - NSNumber *version; - - version = [[sogoObject properties] objectForKey: @"version"]; - - return (version - ? exchange_globcnt ([version unsignedLongLongValue]) - : ULLONG_MAX); -} - -- (int) getProperty: (void **) data - withTag: (enum MAPITAGS) propTag - inMemCtx: (TALLOC_CTX *) memCtx -{ - id value; - int rc; - - value = [[sogoObject properties] objectForKey: MAPIPropertyKey (propTag)]; - if (value) - rc = [value getValue: data forTag: propTag inMemCtx: memCtx]; - else - rc = [super getProperty: data withTag: propTag inMemCtx: memCtx]; - - return rc; -} - -- (int) getPidTagSubject: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - /* if we get here, it means that the properties file didn't contain a - relevant value */ - return [self getEmptyString: data inMemCtx: memCtx]; -} - -- (int) getPidTagMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - *data = [@"IPM.Note" asUnicodeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - -- (int) getPidTagChangeKey: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - NSData *changeKey; - int rc; - - changeKey = [[sogoObject properties] - objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)]; - if (changeKey) - { - *data = [changeKey asBinaryInMemCtx: memCtx]; - rc = MAPISTORE_SUCCESS; - } - else - rc = [super getPidTagChangeKey: data inMemCtx: memCtx]; - - return rc; -} - -- (NSArray *) attachmentsKeysMatchingQualifier: (EOQualifier *) qualifier - andSortOrderings: (NSArray *) sortOrderings -{ - NSDictionary *attachments; - NSArray *keys; - NSString *key, *newKey; - NSUInteger count, max, aid; - MAPIStoreAttachment *attachment; - - if (!fetchedAttachments) - { - attachments = [[sogoObject properties] objectForKey: @"attachments"]; - keys = [attachments allKeys]; - max = [keys count]; - if (max > 0) - { - aid = [keys count]; - for (count = 0; count < max; count++) - { - key = [keys objectAtIndex: count]; - attachment = [attachments objectForKey: key]; - newKey = [NSString stringWithFormat: @"%ul", (aid + count)]; - [attachmentParts setObject: attachment forKey: newKey]; - } - } - fetchedAttachments = YES; - } - - return [super attachmentKeysMatchingQualifier: qualifier - andSortOrderings: sortOrderings]; -} - -- (NSDate *) creationTime -{ - return creationTime; -} - -- (NSDate *) lastModificationTime -{ - return lastModificationTime; -} - -- (id) lookupAttachment: (NSString *) childKey -{ - return [attachmentParts objectForKey: childKey]; -} - -- (void) save -{ - [self subclassResponsibility: _cmd]; -} - -@end diff --git a/OpenChange/NSObject+PropertyList.m b/OpenChange/NSObject+PropertyList.m new file mode 100644 index 000000000..9f9762508 --- /dev/null +++ b/OpenChange/NSObject+PropertyList.m @@ -0,0 +1,182 @@ +/* dbmsgdump.m - this file is part of SOGo + * + * Copyright (C) 2011 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * 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. + */ + +/* A format-agnostic property list dumper. + Usage: dbmsgdump [filename] */ + +#import +#import +#import +#import +#import +#import +#import +#import +#import + +const char *indentationStep = " "; + +@interface NSObject (plext) + +- (void) displayWithIndentation: (NSInteger) anInt; + +@end + +@implementation NSObject (plext) + +- (void) _outputIndentation: (NSInteger) anInt +{ + NSInteger i; + + for (i = 0; i < anInt; i++) + printf ("%s", indentationStep); +} + +- (void) displayWithIndentation: (NSInteger) anInt +{ + printf ("(%s) %s", + [NSStringFromClass (isa) UTF8String], + [[self description] UTF8String]); +} + +@end + +@implementation NSDictionary (plext) + +- (void) displayKey: (NSString *) key + withIndentation: (NSInteger) anInt +{ + [self _outputIndentation: anInt]; + + printf ("%s ", [[key description] UTF8String]); + if ([key isKindOfClass: [NSValue class]]) + printf ("(%s: 0x%.8x) ", [(NSValue *) key objCType], [key intValue]); + + printf ("= "); +} + +- (void) displayWithIndentation: (NSInteger) anInt +{ + NSUInteger i, max; + NSArray *keys; + NSInteger subIndent; + NSString *key; + + keys = [self allKeys]; + max = [keys count]; + + printf ("{ (%ld) items\n", (long) max); + + subIndent = anInt + 1; + + for (i = 0; i < max; i++) + { + key = [keys objectAtIndex: i]; + [self displayKey: key withIndentation: subIndent]; + [[self objectForKey: key] displayWithIndentation: subIndent]; + if (i < (max - 1)) + printf (","); + printf ("\n"); + } + + [self _outputIndentation: anInt]; + printf ("}"); +} + +@end + +@implementation NSArray (plext) + +- (void) displayCount: (NSUInteger) count + withIndentation: (NSInteger) anInt +{ + [self _outputIndentation: anInt]; + printf ("%lu = ", (unsigned long) count); +} + +- (void) displayWithIndentation: (NSInteger) anInt +{ + NSUInteger i, max; + NSInteger subIndent; + + max = [self count]; + + printf ("[ (%ld) items\n", (long) max); + + subIndent = anInt + 1; + + for (i = 0; i < max; i++) + { + [self displayCount: i withIndentation: subIndent]; + [[self objectAtIndex: i] displayWithIndentation: subIndent]; + if (i < (max - 1)) + printf (","); + printf ("\n"); + } + + [self _outputIndentation: anInt]; + printf ("]"); +} + +@end + +static void +OCDumpPListData (NSData *content) +{ + NSDictionary *d; + NSPropertyListFormat format; + NSString *error = nil; + const char *formatName; + + d = [NSPropertyListSerialization propertyListFromData: content + mutabilityOption: NSPropertyListImmutable + format: &format + errorDescription: &error]; + if (d) + { + switch (format) + { + case NSPropertyListOpenStepFormat: + formatName = "OpenStep"; + break; + case NSPropertyListXMLFormat_v1_0: + formatName = "XML"; + break; + case NSPropertyListBinaryFormat_v1_0: + formatName = "Binary"; + break; + case NSPropertyListGNUstepFormat: + formatName = "GNUstep"; + break; + case NSPropertyListGNUstepBinaryFormat: + formatName = "GNUstep binary"; + break; + default: formatName = "unknown"; + } + + printf ("File format is: %s\n", formatName); + [d displayWithIndentation: 0]; + printf ("\n"); + } + else + printf ("an error occurred: %s\n", [error UTF8String]); +} diff --git a/OpenChange/SOGoMAPIFSFolder.h b/OpenChange/SOGoMAPIDBFolder.h similarity index 52% rename from OpenChange/SOGoMAPIFSFolder.h rename to OpenChange/SOGoMAPIDBFolder.h index 244094129..e2d29058f 100644 --- a/OpenChange/SOGoMAPIFSFolder.h +++ b/OpenChange/SOGoMAPIDBFolder.h @@ -1,6 +1,6 @@ -/* SOGoMAPIFSFolder.h - this file is part of SOGo +/* SOGoMAPIDBFolder.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -20,41 +20,38 @@ * Boston, MA 02111-1307, USA. */ -#ifndef SOGOMAPIFSFOLDER_H -#define SOGOMAPIFSFOLDER_H +#ifndef SOGOMAPIDBFOLDER_H +#define SOGOMAPIDBFOLDER_H -#import +#import "SOGoMAPIDBObject.h" @class NSArray; +@class NSMutableString; @class NSString; @class NSURL; @class EOQualifier; -@class SOGoMAPIFSMessage; +@class SOGoMAPIDBMessage; -@interface SOGoMAPIFSFolder : SOGoFolder +@interface SOGoMAPIDBFolder : SOGoMAPIDBObject { - NSString *directory; - BOOL directoryIsSane; + NSString *pathPrefix; /* for root folders */ + SOGoMAPIDBObject *aclMessage; } -+ (id) folderWithURL: (NSURL *) url - andTableType: (uint8_t) tableType; -- (id) initWithURL: (NSURL *) url - andTableType: (uint8_t) tableType; +- (void) setPathPrefix: (NSString *) newPathPrefix; -- (NSString *) directory; +- (NSMutableString *) pathForChild: (NSString *) childName; -- (SOGoMAPIFSMessage *) newMessage; -- (void) ensureDirectory; +- (NSArray *) toOneRelationshipKeys; +- (NSArray *) toManyRelationshipKeys; -- (NSCalendarDate *) creationTime; -- (NSCalendarDate *) lastModificationTime; - -- (NSArray *) toOneRelationshipKeysMatchingQualifier: (EOQualifier *) qualifier - andSortOrderings: (NSArray *) sortOrderings; +- (NSArray *) childKeysOfType: (MAPIDBObjectType) type + includeDeleted: (BOOL) includeDeleted + matchingQualifier: (EOQualifier *) qualifier + andSortOrderings: (NSArray *) sortOrderings; @end -#endif /* SOGOMAPIFSFOLDER_H */ +#endif /* SOGOMAPIDBFOLDER_H */ diff --git a/OpenChange/SOGoMAPIDBFolder.m b/OpenChange/SOGoMAPIDBFolder.m new file mode 100644 index 000000000..ddd6086a6 --- /dev/null +++ b/OpenChange/SOGoMAPIDBFolder.m @@ -0,0 +1,402 @@ +/* SOGoMAPIDBFolder.m - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc. + * + * Author: Wolfgang Sourdeau + * + * 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 +#import +#import +#import +#import +#import +#import +#import + +#import +#import +#import +// #import + +#import +#import +#import +#import "EOQualifier+MAPI.h" +#import "GCSSpecialQueries+OpenChange.h" +#import "SOGoMAPIDBMessage.h" + +#import "SOGoMAPIDBFolder.h" + +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include + +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 = MAPIDBObjectTypeFolder; + aclMessage = [SOGoMAPIDBObject objectWithName: @"permissions" + inContainer: self]; + [aclMessage setObjectType: MAPIDBObjectTypeInternal]; + [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: (MAPIDBObjectType) 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]; + childPathPrefix = [NSString stringWithFormat: @"%@/", [self path]]; + [whereClause addObject: [NSString stringWithFormat: @"c_path LIKE '%@%%'", + childPathPrefix]]; + [whereClause addObject: [NSString stringWithFormat: @"c_type = %d", type]]; + if (!includeDeleted) + [whereClause addObject: @"c_deleted = 0"]; + + [sql appendFormat: @" WHERE %@", + [whereClause componentsJoinedByString: @" AND "]]; + + /* 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: MAPIDBObjectTypeFolder + includeDeleted: NO + matchingQualifier: nil + andSortOrderings: nil]; +} + +- (NSArray *) toOneRelationshipKeys +{ + return [self childKeysOfType: MAPIDBObjectTypeMessage + includeDeleted: NO + matchingQualifier: nil + andSortOrderings: nil]; +} + +// - (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] == MAPIDBObjectTypeFolder) + 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]; +// } + +- (NSException *) delete +{ + [self notImplemented: _cmd]; + + // NSFileManager *fm; + // NSException *error; + + // fm = [NSFileManager defaultManager]; + + // if (![fm removeFileAtPath: directory handler: NULL]) + // error = [NSException exceptionWithName: @"MAPIStoreIOException" + // reason: @"could not delete folder" + // userInfo: nil]; + // else + // error = nil; + + // return error; + return nil; +} + +/* 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 diff --git a/OpenChange/SOGoMAPIDBObject.h b/OpenChange/SOGoMAPIDBObject.h new file mode 100644 index 000000000..ea0a7a58a --- /dev/null +++ b/OpenChange/SOGoMAPIDBObject.h @@ -0,0 +1,83 @@ +/* SOGoMAPIDBObject.h - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * 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 { + MAPIDBObjectTypeFolder = 1, + MAPIDBObjectTypeMessage = 2, + MAPIDBObjectTypeFAI = 3, + MAPIDBObjectTypeInternal = 99 /* object = property list */ +} MAPIDBObjectType; + +@interface SOGoMAPIDBObject : SOGoMAPIObject +{ + NSURL *tableUrl; + + BOOL initialized; /* safe guard */ + MAPIDBObjectType 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: (MAPIDBObjectType) newObjectType; +- (MAPIDBObjectType) objectType; /* message, fai, folder */ + +/* automatically set from actions */ +- (BOOL) deleted; + +/* db helpers */ +- (EOAdaptor *) tableChannelAdaptor; +- (NSArray *) performSQLQuery: (NSString *) sql; + + +@end + +#endif /* SOGOMAPIDBOBJECT_H */ diff --git a/OpenChange/SOGoMAPIDBObject.m b/OpenChange/SOGoMAPIDBObject.m new file mode 100644 index 000000000..b80af8fc5 --- /dev/null +++ b/OpenChange/SOGoMAPIDBObject.m @@ -0,0 +1,483 @@ +/* SOGoMAPIDBObject.m - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc + * + * Author: Wolfgang Sourdeau + * + * 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 +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import "GCSSpecialQueries+OpenChange.h" +#import "MAPIStoreTypes.h" +#import "SOGoMAPIDBFolder.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_type VARCHAR(20) 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," +*/ + +/* 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 = [NSPropertyListSerialization propertyListFromData: [propsValue dataByDecodingBase64] + mutabilityOption: NSPropertyListMutableContainers + format: &format + errorDescription: &error]; + [properties addEntriesFromDictionary: newValues]; + // [properties addEntriesFromDictionary: [propsValue + // objectFromJSONString]]; + } + 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: (MAPIDBObjectType) newObjectType +{ + objectType = newObjectType; +} + +- (MAPIDBObjectType) 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 MAPIDBObjectTypeMessage: + 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 MAPIDBObjectTypeFAI: + className = @"MAPIStoreFAIMessage"; + break; + default: + [NSException raise: @"MAPIStoreIOException" + format: @"message class should not be queried for objects" + @" of type '%d'", objectType]; + } + + return NSClassFromString (className); +} + +/* actions */ +- (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; +} + +- (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, *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 = [NSPropertyListSerialization + dataFromPropertyList: properties + format: NSPropertyListBinaryFormat_v1_0 + errorDescription: NULL]; + propsValue = [adaptor formatValue: [content stringByEncodingBase64] + forAttribute: textColumn]; + } + else + propsValue = @"NULL"; + + if (isNew) + { + ASSIGN (creationDate, now); + creationDateValue = (NSInteger) [creationDate timeIntervalSince1970]; + sql = [NSString stringWithFormat: + (@"INSERT INTO %@" + @" (c_path, c_type, c_creationdate, c_lastmodified," + @" c_deleted, c_version, c_content)" + @" VALUES (%@, %d, %d, %d, 0, 0, %@" + @")"), + tableName, + pathValue, 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 diff --git a/OpenChange/SOGoMAPIFSFolder.m b/OpenChange/SOGoMAPIFSFolder.m deleted file mode 100644 index b26e0ea9d..000000000 --- a/OpenChange/SOGoMAPIFSFolder.m +++ /dev/null @@ -1,439 +0,0 @@ -/* SOGoMAPIFSFolder.m - this file is part of SOGo - * - * Copyright (C) 2010 Inverse inc. - * - * Author: Wolfgang Sourdeau - * - * 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 -#import -#import -#import -#import -#import -#import -#import -#import - -#import -#import - -#import "EOQualifier+MAPI.h" -#import "SOGoMAPIFSMessage.h" - -#import "SOGoMAPIFSFolder.h" - -#undef DEBUG -#include -#include -#include -#include -#include -#include -#include - -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 - andTableType: (uint8_t) tableType -{ - SOGoMAPIFSFolder *newFolder; - - newFolder = [[self alloc] initWithURL: url - andTableType: tableType]; - [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 - andTableType: (uint8_t) tableType -{ - NSString *path, *username, *tableParticle; - - if ((self = [self init])) - { - if (tableType == MAPISTORE_MESSAGE_TABLE) - tableParticle = @"message"; - else if (tableType == MAPISTORE_FAI_TABLE) - tableParticle = @"fai"; - else if (tableType == MAPISTORE_FOLDER_TABLE) - tableParticle = @"folder"; - else - { - [NSException raise: @"MAPIStoreIOException" - format: @"unsupported table type: %d", tableType]; - tableParticle = nil; - } - - path = [url path]; - if (![path hasSuffix: @"/"]) - path = [NSString stringWithFormat: @"%@/", path]; - username = [url user]; - directory = [NSString stringWithFormat: @"%@/mapistore/SOGo/%@/%@/%@%@", - privateDir, username, tableParticle, - [url host], path]; - [self setOwner: username]; - [self logWithFormat: @"directory: %@", directory]; - [directory retain]; - ASSIGN (nameInContainer, [path stringByDeletingLastPathComponent]); - } - - return self; -} - -- (id) initWithName: (NSString *) newName - inContainer: (id) newContainer -{ - if ((self = [super initWithName: newName inContainer: newContainer])) - { - directory = [[newContainer directory] - stringByAppendingPathComponent: newName]; - [directory retain]; - } - - return self; -} - -- (NSString *) directory -{ - return directory; -} - -- (SOGoMAPIFSMessage *) newMessage -{ - NSString *filename; - - filename = [NSString stringWithFormat: @"%@.plist", - [SOGoObject globallyUniqueObjectId]]; - - return [SOGoMAPIFSMessage objectWithName: filename inContainer: self]; -} - -- (void) ensureDirectory -{ - NSFileManager *fm; - NSDictionary *attributes; - BOOL isDir; - - if (!directory) - [NSException raise: @"MAPIStoreIOException" - format: @"directory is nil"]; - - 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) - [self ensureDirectory]; - - fm = [NSFileManager defaultManager]; - contents = [fm directoryContentsAtPath: directory]; - max = [contents count]; - files = [NSMutableArray arrayWithCapacity: max]; - for (count = 0; count < max; count++) - { - file = [contents objectAtIndex: count]; - if (![file isEqualToString: @"permissions.plist"]) - { - fullName = [directory stringByAppendingPathComponent: file]; - if ([fm fileExistsAtPath: fullName - isDirectory: &isDir] - && dirs == isDir) - [files addObject: file]; - } - } - - return files; -} - -- (NSArray *) toManyRelationshipKeys -{ - return [self _objectsInDirectory: YES]; -} - -- (NSArray *) toOneRelationshipKeys -{ - return [self _objectsInDirectory: NO]; -} - -- (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]; - if ([qualifier evaluateMAPIVolatileMessage: message]) - [keys addObject: messageKey]; - } - } - else - keys = (NSMutableArray *) allKeys; - - return keys; -} - -- (id) lookupName: (NSString *) fileName - inContext: (WOContext *) woContext - acquire: (BOOL) acquire -{ - NSFileManager *fm; - NSString *fullName; - id object; - BOOL isDir; - - if (!directoryIsSane) - [self ensureDirectory]; - - fm = [NSFileManager defaultManager]; - fullName = [directory stringByAppendingPathComponent: fileName]; - if ([fm fileExistsAtPath: fullName - isDirectory: &isDir]) - { - if (isDir) - object = [isa objectWithName: fileName - inContainer: self]; - else - object = [SOGoMAPIFSMessage objectWithName: fileName - inContainer: self]; - } - else - object = nil; - - 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]; -} - -- (NSException *) delete -{ - NSFileManager *fm; - NSException *error; - - fm = [NSFileManager defaultManager]; - - if (![fm removeFileAtPath: directory handler: NULL]) - error = [NSException exceptionWithName: @"MAPIStoreIOException" - reason: @"could not delete folder" - userInfo: nil]; - else - error = nil; - - return error; -} - -/* 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]; -} - -@end diff --git a/OpenChange/SOGoMAPIFSMessage.h b/OpenChange/SOGoMAPIFSMessage.h deleted file mode 100644 index ec6494938..000000000 --- a/OpenChange/SOGoMAPIFSMessage.h +++ /dev/null @@ -1,47 +0,0 @@ -/* SOGoMAPIFSMessage.h - this file is part of SOGo - * - * Copyright (C) 2010 Inverse inc. - * - * Author: Wolfgang Sourdeau - * - * 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 SOGOMAPIFSMESSAGE_H -#define SOGOMAPIFSMESSAGE_H - -#import "SOGoMAPIVolatileMessage.h" - -@class NSDate; -@class NSString; - -@interface SOGoMAPIFSMessage : SOGoMAPIVolatileMessage -{ - NSString *completeFilename; - NSUInteger inode; - NSData *lastModificationTime; -} - -- (void) save; - -- (NSString *) completeFilename; - -- (NSDate *) creationTime; -- (NSDate *) lastModificationTime; - -@end - -#endif /* SOGOMAPIFSMESSAGE_H */ diff --git a/OpenChange/SOGoMAPIFSMessage.m b/OpenChange/SOGoMAPIFSMessage.m deleted file mode 100644 index 8a854fa1d..000000000 --- a/OpenChange/SOGoMAPIFSMessage.m +++ /dev/null @@ -1,238 +0,0 @@ -/* SOGoMAPIFSMessage.m - this file is part of SOGo - * - * Copyright (C) 2010 Inverse inc. - * - * Author: Wolfgang Sourdeau - * - * 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 -#import -#import -#import -#import -#import -#import - -#import - -#import "SOGoMAPIFSFolder.h" - -#import "SOGoMAPIFSMessage.h" - -@implementation SOGoMAPIFSMessage - -- (id) init -{ - if ((self = [super init])) - { - completeFilename = nil; - inode = 0; - lastModificationTime = nil; - } - - return self; -} - -- (void) dealloc -{ - [completeFilename release]; - [super dealloc]; -} - -- (Class) mapistoreMessageClass -{ - NSArray *dirMembers; - NSString *className; - - /* FIXME: this method is a bit dirty */ - dirMembers = [[container directory] componentsSeparatedByString: @"/"]; - if ([dirMembers containsObject: @"fai"]) /* should not occur as FAI message - are instantiated directly in - MAPIStoreFolder */ - className = @"MAPIStoreFAIMessage"; - else if ([dirMembers containsObject: @"notes"]) - className = @"MAPIStoreNotesMessage"; - else - className = @"MAPIStoreFSMessage"; - - return NSClassFromString (className); -} - -- (NSString *) completeFilename -{ - if (!completeFilename) - { - completeFilename = [[container directory] - stringByAppendingPathComponent: nameInContainer]; - [completeFilename retain]; - } - - return completeFilename; -} - -- (BOOL) _readFileChangesDataWithDate: (NSDate **) newLMTime - andInode: (NSUInteger *) newInode -{ - BOOL rc; - NSDictionary *attributes; - - attributes = [[NSFileManager defaultManager] - fileAttributesAtPath: [self completeFilename] - traverseLink: NO]; - if (attributes) - { - *newLMTime = [attributes fileModificationDate]; - *newInode = [attributes fileSystemFileNumber]; - rc = YES; - } - else - rc = NO; - - return rc; -} - -- (BOOL) _checkFileChangesDataWithDate: (NSDate **) newLMTime - andInode: (NSUInteger *) newInode -{ - BOOL hasChanged = NO; - NSDate *lastLMTime; - NSUInteger lastInode; - - if ([self _readFileChangesDataWithDate: &lastLMTime - andInode: &lastInode]) - { - if (inode != lastInode - || ![lastModificationTime isEqual: lastLMTime]) - { - if (lastLMTime) - *newLMTime = lastLMTime; - if (newInode) - *newInode = lastInode; - hasChanged = YES; - } - } - - return hasChanged; -} - -- (NSMutableDictionary *) properties -{ - NSData *content; - NSString *error; - NSPropertyListFormat format; - NSDate *lastLMTime; - NSUInteger lastInode; - - if ([self _checkFileChangesDataWithDate: &lastLMTime - andInode: &lastInode]) - { - [self logWithFormat: @"file '%@' new or modified: rereading properties", - [self completeFilename]]; - [properties release]; - properties = nil; - content = [NSData dataWithContentsOfFile: [self completeFilename]]; - if (content) - { - properties = [NSPropertyListSerialization propertyListFromData: content - mutabilityOption: NSPropertyListMutableContainers - format: &format - errorDescription: &error]; - [properties retain]; - if (!properties) - [self logWithFormat: @"an error occurred during deserialization" - @" of message: '%@'", error]; - } - ASSIGN (lastModificationTime, lastLMTime); - inode = lastInode; - } - - return [super properties]; -} - -- (void) save -{ - NSData *content; - NSDate *lastLMTime; - NSUInteger lastInode; - - [container ensureDirectory]; - - // [self logWithFormat: @"%d props in whole dict", [properties count]]; - - content = [NSPropertyListSerialization - dataFromPropertyList: [self properties] - format: NSPropertyListBinaryFormat_v1_0 - errorDescription: NULL]; - if (![content writeToFile: [self completeFilename] atomically: YES]) - [NSException raise: @"MAPIStoreIOException" - format: @"could not save message"]; - - [self _readFileChangesDataWithDate: &lastLMTime andInode: &lastInode]; - ASSIGN (lastModificationTime, lastLMTime); - inode = lastInode; - // [self logWithFormat: @"fs message written to '%@'", [self completeFilename]]; -} - -- (NSString *) davEntityTag -{ - NSDate *lm; - - lm = [self lastModificationTime]; - - return [NSString stringWithFormat: @"%d", (int) [lm timeIntervalSince1970]]; -} - -- (NSException *) delete -{ - NSFileManager *fm; - NSException *error; - - fm = [NSFileManager defaultManager]; - - if (![fm removeFileAtPath: [self completeFilename] handler: NULL]) - error = [NSException exceptionWithName: @"MAPIStoreIOException" - reason: @"could not delete message" - userInfo: nil]; - else - error = nil; - - return error; -} - -- (id) _fileAttributeForKey: (NSString *) key -{ - NSDictionary *attributes; - - attributes = [[NSFileManager defaultManager] - fileAttributesAtPath: [self completeFilename] - traverseLink: NO]; - - return [attributes objectForKey: key]; -} - -- (NSDate *) creationTime -{ - return [self _fileAttributeForKey: NSFileCreationDate]; -} - -- (NSDate *) lastModificationTime -{ - return [self _fileAttributeForKey: NSFileModificationDate]; -} - -@end diff --git a/OpenChange/SOGoMAPIVolatileMessage.h b/OpenChange/SOGoMAPIObject.h similarity index 63% rename from OpenChange/SOGoMAPIVolatileMessage.h rename to OpenChange/SOGoMAPIObject.h index 00596fef6..fbebaf641 100644 --- a/OpenChange/SOGoMAPIVolatileMessage.h +++ b/OpenChange/SOGoMAPIObject.h @@ -1,12 +1,12 @@ -/* SOGoMAPIVolatileMessage.h - this file is part of SOGo +/* SOGoMAPIObject.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * * 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) + * 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, @@ -20,22 +20,30 @@ * Boston, MA 02111-1307, USA. */ -#ifndef SOGOMAPIVOLATILEMESSAGE_H -#define SOGOMAPIVOLATILEMESSAGE_H +#ifndef SOGOMAPIOBJECT_H +#define SOGOMAPIOBJECT_H #import -@class NSDictionary; @class NSMutableDictionary; -@interface SOGoMAPIVolatileMessage : SOGoObject +@interface SOGoMAPIObject : SOGoObject { + BOOL isNew; NSMutableDictionary *properties; + NSCalendarDate *creationDate; + NSCalendarDate *lastModified; } +- (void) setIsNew: (BOOL) newIsNew; +- (BOOL) isNew; + +- (void) adjustLastModified; + - (NSMutableDictionary *) properties; -- (void) appendProperties: (NSDictionary *) newProperties; +- (NSCalendarDate *) creationDate; +- (NSCalendarDate *) lastModified; @end -#endif /* SOGOMAPIVOLATILEMESSAGE_H */ +#endif /* SOGOMAPIOBJECT_H */ diff --git a/OpenChange/SOGoMAPIVolatileMessage.m b/OpenChange/SOGoMAPIObject.m similarity index 58% rename from OpenChange/SOGoMAPIVolatileMessage.m rename to OpenChange/SOGoMAPIObject.m index b46a81c61..ec8a9ae52 100644 --- a/OpenChange/SOGoMAPIVolatileMessage.m +++ b/OpenChange/SOGoMAPIObject.m @@ -1,6 +1,6 @@ -/* SOGoMAPIVolatileMessage.m - this file is part of SOGo +/* SOGoMAPIObject.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -20,17 +20,19 @@ * Boston, MA 02111-1307, USA. */ -#import +#import "SOGoMAPIObject.h" -#import "SOGoMAPIVolatileMessage.h" - -@implementation SOGoMAPIVolatileMessage +@implementation SOGoMAPIObject - (id) init { if ((self = [super init])) { - properties = nil; + isNew = NO; + creationDate = [NSCalendarDate date]; + [creationDate retain]; + lastModified = [creationDate copy]; + properties = [NSMutableDictionary new]; } return self; @@ -38,21 +40,45 @@ - (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 { - if (!properties) - properties = [NSMutableDictionary new]; - return properties; } -- (void) appendProperties: (NSDictionary *) newProperties +- (NSCalendarDate *) creationDate { - [[self properties] addEntriesFromDictionary: newProperties]; + return creationDate; +} + +- (NSCalendarDate *) lastModified +{ + return lastModified; } @end diff --git a/OpenChange/plreader.m b/OpenChange/plreader.m index 68c7a81e5..b027a987c 100644 --- a/OpenChange/plreader.m +++ b/OpenChange/plreader.m @@ -23,164 +23,19 @@ /* A format-agnostic property list dumper. Usage: plreader [filename] */ -#import #import -#import -#import +#import #import -#import -#import -#import -#import -const char *indentationStep = " "; - -@interface NSObject (plext) - -- (void) displayWithIndentation: (NSInteger) anInt; - -@end - -@implementation NSObject (plext) - -- (void) _outputIndentation: (NSInteger) anInt -{ - NSInteger i; - - for (i = 0; i < anInt; i++) - printf ("%s", indentationStep); -} - -- (void) displayWithIndentation: (NSInteger) anInt -{ - printf ("(%s) %s", - [NSStringFromClass (isa) UTF8String], - [[self description] UTF8String]); -} - -@end - -@implementation NSDictionary (plext) - -- (void) displayKey: (NSString *) key - withIndentation: (NSInteger) anInt -{ - [self _outputIndentation: anInt]; - - printf ("%s ", [[key description] UTF8String]); - if ([key isKindOfClass: [NSValue class]]) - printf ("(%s: 0x%.8x) ", [(NSValue *) key objCType], [key intValue]); - - printf ("= "); -} - -- (void) displayWithIndentation: (NSInteger) anInt -{ - NSUInteger i, max; - NSArray *keys; - NSInteger subIndent; - NSString *key; - - keys = [self allKeys]; - max = [keys count]; - - printf ("{ (%ld) items\n", (long) max); - - subIndent = anInt + 1; - - for (i = 0; i < max; i++) - { - key = [keys objectAtIndex: i]; - [self displayKey: key withIndentation: subIndent]; - [[self objectForKey: key] displayWithIndentation: subIndent]; - if (i < (max - 1)) - printf (","); - printf ("\n"); - } - - [self _outputIndentation: anInt]; - printf ("}"); -} - -@end - -@implementation NSArray (plext) - -- (void) displayCount: (NSUInteger) count - withIndentation: (NSInteger) anInt -{ - [self _outputIndentation: anInt]; - printf ("%lu = ", (unsigned long) count); -} - -- (void) displayWithIndentation: (NSInteger) anInt -{ - NSUInteger i, max; - NSInteger subIndent; - - max = [self count]; - - printf ("[ (%ld) items\n", (long) max); - - subIndent = anInt + 1; - - for (i = 0; i < max; i++) - { - [self displayCount: i withIndentation: subIndent]; - [[self objectAtIndex: i] displayWithIndentation: subIndent]; - if (i < (max - 1)) - printf (","); - printf ("\n"); - } - - [self _outputIndentation: anInt]; - printf ("]"); -} - -@end +#import "NSObject+PropertyList.m" static void PLReaderDumpPListFile (NSString *filename) { NSData *content; - NSDictionary *d; - NSPropertyListFormat format; - NSString *error = nil; - const char *formatName; content = [NSData dataWithContentsOfFile: filename]; - d = [NSPropertyListSerialization propertyListFromData: content - mutabilityOption: NSPropertyListImmutable - format: &format - errorDescription: &error]; - if (d) - { - switch (format) - { - case NSPropertyListOpenStepFormat: - formatName = "OpenStep"; - break; - case NSPropertyListXMLFormat_v1_0: - formatName = "XML"; - break; - case NSPropertyListBinaryFormat_v1_0: - formatName = "Binary"; - break; - case NSPropertyListGNUstepFormat: - formatName = "GNUstep"; - break; - case NSPropertyListGNUstepBinaryFormat: - formatName = "GNUstep binary"; - break; - default: formatName = "unknown"; - } - - printf ("File format is: %s\n", formatName); - [d displayWithIndentation: 0]; - printf ("\n"); - } - else - printf ("an error occurred: %s\n", [error UTF8String]); + OCDumpPListData (content); } int main()