diff --git a/ChangeLog b/ChangeLog index 75c27fef1..4e45209ef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-07-25 Wolfgang Sourdeau + + * OpenChange/MAPIStoreDBFolder.m (-createFolder:withFID:andKey:): + invoke "reloadIfNeeded" on the created folder object in order to + initialize it. + 2012-07-25 Francis Lachapelle * SoObjects/Mailer/SOGoMailFolder.m @@ -15,6 +21,15 @@ * UI/WebServerResources/MailerUI.js (initMailer): define default columns widths when not set. +2012-07-24 Wolfgang Sourdeau + + * OpenChange/MAPIStoreUserContext.m + (-initWithUsername:andTDBIndexing:): attempt to read the user + password from a property list. + + * OpenChange/samba-get-config.py: new utility taking a samba + configuration variable and prints the value on stdout + 2012-07-24 Francis Lachapelle * UI/WebServerResources/UIxPreferences.js (savePreferences): @@ -33,8 +48,115 @@ (_shouldDisplayAsAttachment:): refactored to consider the "bodyId" parameter only for non text/* parts. +2012-07-20 Francis Lachapelle + + * UI/WebServerResources/MailerUI.js (onEmailTo): append the email + address from the href attribute if it doesn't appear in the link content. + + * UI/MailPartViewers/UIxMailPartHTMLViewer.m + (-startElement:namespace:rawName:attributes:): don't skip "mailto:" + href. + + * SoObjects/Appointments/SOGoAptMailReceipt.m (aptSummary-): new + method that returns a properly formatted string of the event title + with respect to the current operation (creation/deletion/update). + 2012-07-20 Wolfgang Sourdeau + * OpenChange/NSObject+MAPIStore.m (-getSMTPAddrType:inMemCtx:): + new helper getter. + + * OpenChange/MAPIStoreSOGo.m + (sogo_message_attachment_create_embedded_message): new backend method. + + * OpenChange/NSObject+MAPIStore.m + (+fillAvailableProperties:withExclusions:): new method that fills + an existing array of properties with properties existing in + another class, as long as they are not listed in the array of + exclusions. + + * OpenChange/MAPIStoreObject.m (-init): assigned a mutable array + to "proxies" + (-canGetProperty:): test the proxies for the availability of + properties so that -getAvailableProperties:inMemCtx: can return an + accurate result. + + * OpenChange/MAPIStoreMessage.m (-getPidTagSubject:inMemCtx:): now + compute the return value based on PidTagNormalizedSubject and + PidTagSubjectPrefix as PidTagSubject is never actually set from + the client. + +2012-07-19 Wolfgang Sourdeau + + * OpenChange/MAPIStoreObject.m (-nameInContainer): moved method + from MAPIStoreSOGoObject and made mandatory for subclasses. + (-url): new methed moved from MAPIStoreSOGoObject. + + * OpenChange/MAPIStoreAppointmentWrapper.m: now a subclass of + MAPIStoreObjectProxy. + + * OpenChange/MAPIStoreCalendarMessage.m + (-initWithSOGoObject:inContainer:): we now register our + appointment wrapper as a proxy. + + * OpenChange/MAPIStoreObject.m (-addProxy:): new method that keeps + proxy objects in the new "proxies" ivar. + (-getProperty:withTag:inMemCtx:): added code that pass the request + to the available object proxies, when the property getters have + not been found in the local class. + + * OpenChange/MAPIStoreObjectProxy.[hm]: new class module that + provide a facility for providing property getters in the name of + another class, working around the fact that Objective-C does not + provide multiple-inheritance. + + * OpenChange/NSObject+MAPIStore.m + (+getAvailableProperties:inMemCtx:) + (-getAvailableProperties:inMemCtx:, canGetProperty:): methods + moved from MAPIStoreObject.m + +2012-07-18 Wolfgang Sourdeau + + * OpenChange/MAPIStoreCalendarFolder.m (-createMessage): attach a + WOContext to the newEntry in order to enable page templates + resolution when notifications are sent. + + * OpenChange/MAPIApplication.m (-init): a WEResourceManager is + setup for the application so that page templates can be properly + be initialized. + + * OpenChange/MAPIStoreDBMessage.m (-objectVersion): shift the + version number by 16 bits, instead of doing it in -save. + (-save): don t swap the bytes of the version number as it would + return a wrong change number and a wrong change key for DB objects. + +####### Ancestor +======= end +2012-07-20 Wolfgang Sourdeau + + * OpenChange/NSObject+MAPIStore.m (-getSMTPAddrType:inMemCtx:): + new helper getter. + + * OpenChange/MAPIStoreSOGo.m + (sogo_message_attachment_create_embedded_message): new backend method. + + * OpenChange/NSObject+MAPIStore.m + (+fillAvailableProperties:withExclusions:): new method that fills + an existing array of properties with properties existing in + another class, as long as they are not listed in the array of + exclusions. + + * OpenChange/MAPIStoreObject.m (-init): assigned a mutable array + to "proxies" + (-canGetProperty:): test the proxies for the availability of + properties so that -getAvailableProperties:inMemCtx: can return an + accurate result. + + * OpenChange/MAPIStoreMessage.m (-getPidTagSubject:inMemCtx:): now + compute the return value based on PidTagNormalizedSubject and + PidTagSubjectPrefix as PidTagSubject is never actually set from + the client. + * SoObjects/Appointments/SOGoAppointmentFolder.m (_appendCycleException:firstInstanceCalendarDateRange:fromRow:forRange:withTimeZone:toArray:): return immediately if the occurrence does not have a valid @@ -53,6 +175,52 @@ method that returns a properly formatted string of the event title with respect to the current operation (creation/deletion/update). +2012-07-19 Wolfgang Sourdeau + + * OpenChange/MAPIStoreObject.m (-nameInContainer): moved method + from MAPIStoreSOGoObject and made mandatory for subclasses. + (-url): new methed moved from MAPIStoreSOGoObject. + + * OpenChange/MAPIStoreAppointmentWrapper.m: now a subclass of + MAPIStoreObjectProxy. + + * OpenChange/MAPIStoreCalendarMessage.m + (-initWithSOGoObject:inContainer:): we now register our + appointment wrapper as a proxy. + + * OpenChange/MAPIStoreObject.m (-addProxy:): new method that keeps + proxy objects in the new "proxies" ivar. + (-getProperty:withTag:inMemCtx:): added code that pass the request + to the available object proxies, when the property getters have + not been found in the local class. + + * OpenChange/MAPIStoreObjectProxy.[hm]: new class module that + provide a facility for providing property getters in the name of + another class, working around the fact that Objective-C does not + provide multiple-inheritance. + + * OpenChange/NSObject+MAPIStore.m + (+getAvailableProperties:inMemCtx:) + (-getAvailableProperties:inMemCtx:, canGetProperty:): methods + moved from MAPIStoreObject.m + +2012-07-18 Wolfgang Sourdeau + + * OpenChange/MAPIStoreCalendarFolder.m (-createMessage): attach a + WOContext to the newEntry in order to enable page templates + resolution when notifications are sent. + + * OpenChange/MAPIApplication.m (-init): a WEResourceManager is + setup for the application so that page templates can be properly + be initialized. + + * OpenChange/MAPIStoreDBMessage.m (-objectVersion): shift the + version number by 16 bits, instead of doing it in -save. + (-save): don t swap the bytes of the version number as it would + return a wrong change number and a wrong change key for DB objects. + +####### Ancestor +======= end 2012-07-18 Ludovic Marcotte * SoObjects/Appointments/SOGoAppointmentObject.m @@ -230,6 +398,25 @@ Show all addresses returned from secondaryEmails. This still need some css tweaks. +2012-07-01 Wolfgang Sourdeau + + * OpenChange/MAPIStoreRecurrenceUtils.m + (-setupRecurrenceWithMasterEntity:fromRecurrencePattern:): add + exception dates to master entity based on the + "DeletedInstanceDates" member of the struct. + (-fillRecurrencePattern:withEvent:inTimeZone:inMemCtx:): new name + for fillRecurrencePattern:withStartDate:andEndDate:, add exception + dates to struct. + + * OpenChange/NSDate+MAPIStore.m (NSDateCompare): new comparison + function for sorting array of NSDate instances. + +2012-06-30 Wolfgang Sourdeau + + * OpenChange/NSObject+MAPIStore.h: renamed + MAPIStoreTallocWrapper.MAPIStoreSOGoObject to .instance, to avoid + confusion in certain versions of GCC with our new class type. + 2012-06-29 Jean Raby * SoObjects/SOGo/WORequest+SOGo.[mh] @@ -240,6 +427,23 @@ Let sogo append system sources if the request comes from an android client even if its user agent matches the IPhoneAddressBook +2012-06-29 Wolfgang Sourdeau + + * OpenChange/MAPIStoreSOGo.m + (sogo_message_attachment_open_embedded_message): added the "mode" + parameter. + + * 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 + sure that "_name" is neither nil nor empty. + 2012-06-27 Jean Raby * SoObjects/Appointments/SOGoAppointmentObject.m diff --git a/Documentation/SOGo Native Microsoft Outlook Configuration.odt b/Documentation/SOGo Native Microsoft Outlook Configuration.odt index 8b3802886..3761cc832 100644 Binary files a/Documentation/SOGo Native Microsoft Outlook Configuration.odt and b/Documentation/SOGo Native Microsoft Outlook Configuration.odt differ diff --git a/Main/SOGo.m b/Main/SOGo.m index f2b3f9e0a..8fe51d242 100644 --- a/Main/SOGo.m +++ b/Main/SOGo.m @@ -201,6 +201,7 @@ static BOOL debugLeaks; fileSuffix = [channelURL scheme]; tc = [cm acquireOpenChannelForURL: channelURL]; + /* FIXME: make use of [EOChannelAdaptor describeTableNames] instead */ tableName = [url lastPathComponent]; if ([tc evaluateExpressionX: [NSString stringWithFormat: @"SELECT count(*) FROM %@", 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..03002e1c1 100644 --- a/OpenChange/GNUmakefile +++ b/OpenChange/GNUmakefile @@ -26,6 +26,17 @@ BUNDLE_INSTALL_DIR = $(SOGO_LIBDIR) UNRTF_DIR = unrtf-$(UNRTF_VERSION) +PYTHON = /usr/bin/python +PYTHON_IS_GOOD = $(shell $(PYTHON) -c 'from sys import version_info; a=version_info; print a.major == 2 and a.minor >= 6') +ifeq (${PYTHON_IS_GOOD},False) +PYTHON = /usr/bin/python2.6 +endif + +all:: + @echo " Python executable: ${PYTHON}" + +SAMBA_PRIVATE_DIR = $(shell $(PYTHON) ./samba-get-config.py "private dir") + $(SOGOBACKEND)_SUBPROJECTS += $(UNRTF_DIR)/src $(SOGOBACKEND)_PRINCIPAL_CLASS = MAPIApplication @@ -41,9 +52,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 +66,18 @@ $(SOGOBACKEND)_OBJC_FILES += \ MAPIStoreFolder.m \ MAPIStoreMessage.m \ MAPIStoreObject.m \ + MAPIStoreObjectProxy.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 \ @@ -78,6 +91,7 @@ $(SOGOBACKEND)_OBJC_FILES += \ MAPIStoreCalendarContext.m \ MAPIStoreCalendarFolder.m \ MAPIStoreCalendarMessage.m \ + MAPIStoreCalendarEmbeddedMessage.m \ MAPIStoreCalendarMessageTable.m \ MAPIStoreRecurrenceUtils.m \ \ @@ -112,8 +126,13 @@ $(SOGOBACKEND)_OBJC_FILES += \ NSString+MAPIStore.m \ NSValue+MAPIStore.m \ \ - EOBitmaskQualifier.m \ + iCalEvent+MAPIStore.m \ + \ + GCSSpecialQueries+OpenChange.m\ + \ EOQualifier+MAPI.m \ + \ + EOBitmaskQualifier.m $(SOGOBACKEND)_RESOURCE_FILES += \ @@ -145,7 +164,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) @@ -176,6 +201,7 @@ $(SOGOBACKEND)_LIB_DIRS += \ ADDITIONAL_INCLUDE_DIRS += \ -Werror -Wall \ + -DSAMBA_PRIVATE_DIR=@"\"$(SAMBA_PRIVATE_DIR)\"" \ $(LIBMAPI_CFLAGS) \ $(LIBMAPISTORE_CFLAGS) \ -I$(UNRTF_DIR)/src \ diff --git a/OpenChange/GNUmakefile.preamble b/OpenChange/GNUmakefile.preamble index 74046108b..27b4b5692 100644 --- a/OpenChange/GNUmakefile.preamble +++ b/OpenChange/GNUmakefile.preamble @@ -2,4 +2,4 @@ all:: MAPIStorePropertySelectors.m MAPIStorePropertySelectors.h MAPIStorePropertySelectors.m MAPIStorePropertySelectors.h: gen-property-selectors.py code-MAPIStorePropertySelectors.m code-MAPIStorePropertySelectors.h @echo " Auto-generating MAPIStorePropertySelectors.[hm]..." - @./gen-property-selectors.py -o MAPIStorePropertySelectors $(LIBMAPISTORE_CFLAGS) + @$(PYTHON) ./gen-property-selectors.py -o MAPIStorePropertySelectors $(LIBMAPISTORE_CFLAGS) diff --git a/OpenChange/MAPIApplication.m b/OpenChange/MAPIApplication.m index 8da1c1078..ecf3bedb0 100644 --- a/OpenChange/MAPIApplication.m +++ b/OpenChange/MAPIApplication.m @@ -22,6 +22,7 @@ #import #import +#import #import #import @@ -46,12 +47,18 @@ MAPIApplication *MAPIApp = nil; { if (!MAPIApp) { + WEResourceManager *rm; + // TODO publish [iCalEntityObject initializeSOGoExtensions]; MAPIApp = [super init]; [MAPIApp retain]; + rm = [[WEResourceManager alloc] init]; + [self setResourceManager:rm]; + [rm release]; + utcTZ = [NSTimeZone timeZoneWithName: @"UTC"]; [utcTZ retain]; } diff --git a/OpenChange/MAPIStoreAppointmentWrapper.h b/OpenChange/MAPIStoreAppointmentWrapper.h index 74b275275..ba3377965 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.h +++ b/OpenChange/MAPIStoreAppointmentWrapper.h @@ -23,10 +23,11 @@ #ifndef MAPISTORECALENDARWRAPPER_H #define MAPISTORECALENDARWRAPPER_H -#import #import #import +#import "MAPIStoreObjectProxy.h" + @class NSTimeZone; @class iCalAlarm; @@ -35,7 +36,7 @@ @class SOGoUser; -@interface MAPIStoreAppointmentWrapper : NSObject +@interface MAPIStoreAppointmentWrapper : MAPIStoreObjectProxy { struct mapistore_connection_info *connInfo; iCalCalendar *calendar; @@ -120,8 +121,8 @@ inMemCtx: (TALLOC_CTX *) memCtx; - (int) getPidLidIndentedBusyStatus: (void **) data // TODO inMemCtx: (TALLOC_CTX *) memCtx; -- (int) getPidTagSubject: (void **) data // SUMMARY - inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getPidTagNormalizedSubject: (void **) data // SUMMARY + inMemCtx: (TALLOC_CTX *) memCtx; - (int) getPidLidLocation: (void **) data // LOCATION inMemCtx: (TALLOC_CTX *) memCtx; - (int) getPidLidPrivate: (void **) data // private (bool), should depend on CLASS and permissions diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index 7862980aa..c6c707694 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -1,6 +1,6 @@ /* MAPIStoreAppointmentWrapper.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011, 2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -26,13 +26,11 @@ #import #import #import +#import #import #import -#import #import #import -#import -#import #import #import #import @@ -435,7 +433,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagIconIndex: (void **) data // TODO - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { uint32_t longValue; @@ -580,7 +578,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagMessageClass: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { const char *className; @@ -633,7 +631,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagStartDate: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { NSCalendarDate *dateValue; NSInteger offset; @@ -827,7 +825,7 @@ static NSCharacterSet *hexCharacterSet = nil; /* sender (organizer) */ - (int) getPidTagSenderEmailAddress: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getEmailAddress: data forICalPerson: [event organizer] @@ -835,7 +833,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagSenderAddressType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getAddrType: data forICalPerson: [event organizer] @@ -843,7 +841,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagSenderName: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getName: data forICalPerson: [event organizer] @@ -851,16 +849,41 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagSenderEntryId: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getEntryId: data forICalPerson: [event organizer] inMemCtx: memCtx]; } +/* sender representing */ +- (int) getPidTagSentRepresentingEmailAddress: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidTagSenderEmailAddress: data inMemCtx: memCtx]; +} + +- (int) getPidTagSentRepresentingAddressType: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getSMTPAddrType: data inMemCtx: memCtx]; +} + +- (int) getPidTagSentRepresentingName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidTagSenderName: data inMemCtx: memCtx]; +} + +- (int) getPidTagSentRepresentingEntryId: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getPidTagSenderEntryId: data inMemCtx: memCtx]; +} + /* attendee */ - (int) getPidTagReceivedByEmailAddress: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getEmailAddress: data forICalPerson: [event userAsAttendee: user] @@ -868,7 +891,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagReceivedByAddressType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getAddrType: data forICalPerson: [event userAsAttendee: user] @@ -876,7 +899,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagReceivedByName: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getName: data forICalPerson: [event userAsAttendee: user] @@ -884,7 +907,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagReceivedByEntryId: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { return [self _getEntryId: data forICalPerson: [event userAsAttendee: user] @@ -893,7 +916,7 @@ static NSCharacterSet *hexCharacterSet = nil; /* /attendee */ - (int) getPidTagEndDate: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { NSCalendarDate *dateValue; NSInteger offset; @@ -966,8 +989,8 @@ static NSCharacterSet *hexCharacterSet = nil; return [self getPidLidBusyStatus: data inMemCtx: memCtx]; } -- (int) getPidTagSubject: (void **) data // SUMMARY - inMemCtx: (TALLOC_CTX *) memCtx +- (int) getPidTagNormalizedSubject: (void **) data // SUMMARY + inMemCtx: (TALLOC_CTX *) memCtx { *data = [[event summary] asUnicodeInMemCtx: memCtx]; @@ -995,7 +1018,8 @@ static NSCharacterSet *hexCharacterSet = nil; return [self getPidLidLocation: data inMemCtx: memCtx]; } -- (int) getPidLidServerProcessed: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +- (int) getPidLidServerProcessed: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { /* TODO: we need to check whether the event has been processed internally by SOGo or if it was received only by mail. We only assume the SOGo case @@ -1003,7 +1027,8 @@ static NSCharacterSet *hexCharacterSet = nil; return [self getYes: data inMemCtx: memCtx]; } -- (int) getPidLidServerProcessingActions: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +- (int) getPidLidServerProcessingActions: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { *data = MAPILongValue (memCtx, 0x00000010 /* cpsCreatedOnPrincipal */ @@ -1020,14 +1045,14 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagSensitivity: (void **) data // not implemented, depends on CLASS - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { // normal = 0, personal?? = 1, private = 2, confidential = 3 return [self getLongZero: data inMemCtx: memCtx]; } - (int) getPidTagImportance: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { uint32_t v; if ([[event priority] isEqualToString: @"9"]) @@ -1043,7 +1068,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagBody: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { int rc = MAPISTORE_SUCCESS; NSString *stringValue; @@ -1058,14 +1083,6 @@ static NSCharacterSet *hexCharacterSet = nil; return rc; } -- (int) getPidLidIsRecurring: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - *data = MAPIBoolValue (memCtx, [event isRecurrent]); - - return MAPISTORE_SUCCESS; -} - - (int) getPidLidRecurring: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -1074,37 +1091,57 @@ static NSCharacterSet *hexCharacterSet = nil; return MAPISTORE_SUCCESS; } -static void -_fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, - NSCalendarDate *startDate, NSTimeInterval duration, - NSCalendarDate * endDate, iCalRecurrenceRule *rule) +- (int) getPidLidIsRecurring: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { - uint32_t startMinutes; + *data = MAPIBoolValue (memCtx, + [event isRecurrent] + || ([event recurrenceId] != nil)); - [rule fillRecurrencePattern: &arp->RecurrencePattern - withStartDate: startDate andEndDate: endDate]; - arp->ReaderVersion2 = 0x00003006; - arp->WriterVersion2 = 0x00003009; - - startMinutes = ([startDate hourOfDay] * 60 + [startDate minuteOfHour]); - arp->StartTimeOffset = startMinutes; - arp->EndTimeOffset = startMinutes + (uint32_t) (duration / 60); - - arp->ExceptionCount = 0; - arp->ReservedBlock1Size = 0; - - /* Currently ignored in property.idl: - arp->ReservedBlock2Size = 0; */ + return MAPISTORE_SUCCESS; } -- (struct SBinary_short *) _computeAppointmentRecurInMemCtx: (TALLOC_CTX *) memCtx +- (int) getPidLidIsException: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = MAPIBoolValue (memCtx, [event recurrenceId] != nil); + return MAPISTORE_SUCCESS; +} + +- (void) _fillExceptionInfo: (struct ExceptionInfo *) exceptionInfo + withException: (iCalEvent *) exceptionEvent +{ + memset (exceptionInfo, 0, sizeof (struct ExceptionInfo)); + exceptionInfo->OverrideFlags = 0; + exceptionInfo->StartDateTime = [[exceptionEvent startDate] asMinutesSince1601]; + exceptionInfo->EndDateTime = [[exceptionEvent endDate] asMinutesSince1601]; + exceptionInfo->OriginalStartDate = [[[exceptionEvent recurrenceId] hour: 0 + minute: 0 + second: 0] + asMinutesSince1601]; +} + +- (void) _fillExtendedException: (struct ExtendedException *) extendedException + withException: (iCalEvent *) exceptionEvent +{ + memset (extendedException, 0, sizeof (struct ExtendedException)); + extendedException->ChangeHighlight.Size = sizeof (uint32_t); + extendedException->ChangeHighlight.Value = 1 << 31 | 1 << 30; +} + +// - (struct SBinary_short *) _computeAppointmentRecurInMemCtx: (TALLOC_CTX *) memCtx +- (struct Binary_r *) _computeAppointmentRecurInMemCtx: (TALLOC_CTX *) memCtx { struct AppointmentRecurrencePattern *arp; struct Binary_r *bin; - struct SBinary_short *sBin; + // struct SBinary_short *sBin; NSCalendarDate *firstStartDate; iCalRecurrenceRule *rule; + NSUInteger startMinutes; + NSArray *events, *exceptions; + iCalEvent *exceptionEvent; + NSUInteger count, max; rule = [[event recurrenceRules] objectAtIndex: 0]; @@ -1113,15 +1150,46 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, { [firstStartDate setTimeZone: timeZone]; - arp = talloc_zero (memCtx, struct AppointmentRecurrencePattern); - _fillAppointmentRecurrencePattern (arp, firstStartDate, - [event durationAsTimeInterval], - [event lastPossibleRecurrenceStartDate], - rule); - sBin = talloc_zero (memCtx, struct SBinary_short); - bin = set_AppointmentRecurrencePattern (sBin, arp); - sBin->cb = bin->cb; - sBin->lpb = bin->lpb; + arp = talloc_zero (NULL, struct AppointmentRecurrencePattern); + [rule fillRecurrencePattern: &arp->RecurrencePattern + withEvent: event + inTimeZone: timeZone + inMemCtx: arp]; + arp->ReaderVersion2 = 0x00003006; + arp->WriterVersion2 = 0x00003009; + + startMinutes = ([firstStartDate hourOfDay] * 60 + + [firstStartDate minuteOfHour]); + arp->StartTimeOffset = startMinutes; + arp->EndTimeOffset = (startMinutes + + (NSUInteger) ([event durationAsTimeInterval] + / 60)); + + events = [[event parent] events]; + exceptions + = [events subarrayWithRange: NSMakeRange (1, [events count] - 1)]; + max = [exceptions count]; + arp->ExceptionCount = max; + arp->ExceptionInfo = talloc_array (memCtx, struct ExceptionInfo, max); + arp->ExtendedException = talloc_array (memCtx, struct ExtendedException, max); + for (count = 0; count < max; count++) + { + exceptionEvent = [exceptions objectAtIndex: count]; + [self _fillExceptionInfo: arp->ExceptionInfo + count + withException: exceptionEvent]; + [self _fillExtendedException: arp->ExtendedException + count + withException: exceptionEvent]; + } + arp->ReservedBlock1Size = 0; + arp->ReservedBlock2Size = 0; + + /* Currently ignored in property.idl: arp->ReservedBlock2Size = 0; */ + + /* convert struct to blob */ + // sBin = talloc_zero (memCtx, struct SBinary_short); + bin = set_AppointmentRecurrencePattern (memCtx, arp); + // sBin->cb = bin->cb; + // sBin->lpb = bin->lpb; talloc_free (arp); // DEBUG(5, ("To client:\n")); @@ -1130,10 +1198,11 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, else { [self errorWithFormat: @"no first occurrence found in rule: %@", rule]; - sBin = NULL; + // bin = NULL; + bin = NULL; } - return sBin; + return bin; } - (int) getPidLidAppointmentRecur: (void **) data diff --git a/OpenChange/MAPIStoreAttachment.h b/OpenChange/MAPIStoreAttachment.h index f9716f7e7..76afd8539 100644 --- a/OpenChange/MAPIStoreAttachment.h +++ b/OpenChange/MAPIStoreAttachment.h @@ -40,6 +40,9 @@ withMID: (uint64_t *) mid withMAPIStoreMsg: (struct mapistore_message **) mapistoreMsgPtr inMemCtx: (TALLOC_CTX *) memCtx; +- (int) createEmbeddedMessage: (MAPIStoreEmbeddedMessage **) messagePtr + withMAPIStoreMsg: (struct mapistore_message **) mapistoreMsgPtr + inMemCtx: (TALLOC_CTX *) memCtx; /* helpers */ - (NSData *) mimeAttachTag; diff --git a/OpenChange/MAPIStoreAttachment.m b/OpenChange/MAPIStoreAttachment.m index 59c8832df..9e1551eb0 100644 --- a/OpenChange/MAPIStoreAttachment.m +++ b/OpenChange/MAPIStoreAttachment.m @@ -103,20 +103,34 @@ mapping = [self mapping]; + // if (attMessage) attMessage = [self openEmbeddedMessage]; if (attMessage) { *mid = [mapping idFromURL: [attMessage url]]; + [mapping registerURL: [attMessage url] + withID: *mid]; + *messagePtr = attMessage; + *mapistoreMsgPtr = mapistoreMsg; + } + + return (attMessage ? MAPISTORE_SUCCESS : MAPISTORE_ERROR); +} + +- (int) createEmbeddedMessage: (MAPIStoreEmbeddedMessage **) messagePtr + withMAPIStoreMsg: (struct mapistore_message **) mapistoreMsgPtr + inMemCtx: (TALLOC_CTX *) memCtx +{ + MAPIStoreEmbeddedMessage *attMessage; + struct mapistore_message *mapistoreMsg; + + mapistoreMsg = talloc_zero (memCtx, struct mapistore_message); + attMessage = [self createEmbeddedMessage]; + if (attMessage) + { *messagePtr = attMessage; *mapistoreMsgPtr = mapistoreMsg; } - // else if (flags == MAPI_CREATE) - // { - // attMessage = [self createEmbeddedMessage]; - // if (attMessage) - // [mapping registerURL: [attMessage url] - // withID: *mid]; - // } return (attMessage ? MAPISTORE_SUCCESS : MAPISTORE_ERROR); } diff --git a/OpenChange/MAPIStoreCalendarAttachment.h b/OpenChange/MAPIStoreCalendarAttachment.h index d95c3f560..c97f752d5 100644 --- a/OpenChange/MAPIStoreCalendarAttachment.h +++ b/OpenChange/MAPIStoreCalendarAttachment.h @@ -25,7 +25,15 @@ #import "MAPIStoreAttachment.h" -@interface MAPIStoreCalendarAttachment : MAPIStoreAttachment +@class iCalEvent; + +@interface MAPIStoreCalendarAttachment : MAPIStoreAttachment +{ + iCalEvent *event; +} + +- (void) setEvent: (iCalEvent *) newEvent; +- (iCalEvent *) event; @end diff --git a/OpenChange/MAPIStoreCalendarAttachment.m b/OpenChange/MAPIStoreCalendarAttachment.m index 63aa68df8..a6d7848a2 100644 --- a/OpenChange/MAPIStoreCalendarAttachment.m +++ b/OpenChange/MAPIStoreCalendarAttachment.m @@ -20,9 +20,14 @@ * Boston, MA 02111-1307, USA. */ -#import "MAPIStoreTypes.h" +#import -#import "MAPIStoreEmbeddedMessage.h" +#import +#import + +#import "iCalEvent+MAPIStore.h" +#import "MAPIStoreTypes.h" +#import "MAPIStoreCalendarEmbeddedMessage.h" #import "MAPIStoreCalendarAttachment.h" @@ -34,6 +39,32 @@ @implementation MAPIStoreCalendarAttachment +- (id) init +{ + if ((self = [super init])) + { + event = nil; + } + + return self; +} + +- (void) dealloc +{ + [event release]; + [super dealloc]; +} + +- (void) setEvent: (iCalEvent *) newEvent +{ + ASSIGN (event, newEvent); +} + +- (iCalEvent *) event +{ + return event; +} + - (int) getPidTagAttachmentHidden: (void **) data inMemCtx: (TALLOC_CTX *) localMemCtx { @@ -53,7 +84,7 @@ - (int) getPidTagAttachMethod: (void **) data inMemCtx: (TALLOC_CTX *) localMemCtx { - *data = MAPILongValue (localMemCtx, 0x00000005); /* afEmbeddedMessage */ + *data = MAPILongValue (localMemCtx, afEmbeddedMessage); return MAPISTORE_SUCCESS; } @@ -63,21 +94,24 @@ // case PidTagExceptionReplaceTime: /* subclasses */ -- (MAPIStoreEmbeddedMessage *) openEmbeddedMessage +- (MAPIStoreCalendarEmbeddedMessage *) openEmbeddedMessage { - MAPIStoreEmbeddedMessage *msg; + MAPIStoreCalendarEmbeddedMessage *msg; - if (isNew) - msg = nil; - else - msg = nil; + msg = [MAPIStoreCalendarEmbeddedMessage + mapiStoreObjectInContainer: self]; return msg; } -- (MAPIStoreEmbeddedMessage *) createEmbeddedMessage +- (MAPIStoreCalendarEmbeddedMessage *) createEmbeddedMessage { - return [MAPIStoreEmbeddedMessage embeddedMessageWithAttachment: self]; + MAPIStoreCalendarEmbeddedMessage *msg; + + msg = [self openEmbeddedMessage]; + [msg setIsNew: YES]; + + return msg; } @end diff --git a/OpenChange/MAPIStoreCalendarEmbeddedMessage.h b/OpenChange/MAPIStoreCalendarEmbeddedMessage.h new file mode 100644 index 000000000..3e27c575c --- /dev/null +++ b/OpenChange/MAPIStoreCalendarEmbeddedMessage.h @@ -0,0 +1,34 @@ +/* MAPIStoreCalendarEmbeddedMessage.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 MAPISTORECALENDAREMBEDDEDMESSAGE_H +#define MAPISTORECALENDAREMBEDDEDMESSAGE_H + +#import "MAPIStoreEmbeddedMessage.h" + +@class MAPIStoreAppointmentWrapper; + +@interface MAPIStoreCalendarEmbeddedMessage : MAPIStoreEmbeddedMessage + +@end + +#endif /* MAPISTORECALENDAREMBEDDEDMESSAGE_H */ diff --git a/OpenChange/MAPIStoreCalendarEmbeddedMessage.m b/OpenChange/MAPIStoreCalendarEmbeddedMessage.m new file mode 100644 index 000000000..361b10d6f --- /dev/null +++ b/OpenChange/MAPIStoreCalendarEmbeddedMessage.m @@ -0,0 +1,162 @@ +/* MAPIStoreCalendarEmbeddedMessage.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 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. + */ + +#include + +#import +#import + +#import + +#import +#import "iCalEvent+MAPIStore.h" + +#import "MAPIStoreAppointmentWrapper.h" +#import "MAPIStoreCalendarAttachment.h" +#import "MAPIStoreContext.h" +#import "MAPIStoreUserContext.h" +#import "MAPIStoreTypes.h" +#import "NSObject+MAPIStore.h" + +#import "MAPIStoreCalendarEmbeddedMessage.h" + +#include + +@implementation MAPIStoreCalendarEmbeddedMessage + +- (id) initInContainer: (id) newContainer +{ + MAPIStoreContext *context; + MAPIStoreUserContext *userContext; + MAPIStoreAppointmentWrapper *appointmentWrapper; + + if ((self = [super initInContainer: newContainer])) + { + context = [self context]; + userContext = [self userContext]; + appointmentWrapper + = [MAPIStoreAppointmentWrapper + wrapperWithICalEvent: [newContainer event] + andUser: [userContext sogoUser] + andSenderEmail: nil + inTimeZone: [userContext timeZone] + withConnectionInfo: [context connectionInfo]]; + [self addProxy: appointmentWrapper]; + } + + return self; +} + +- (NSDate *) creationTime +{ + return [[container event] created]; +} + +- (NSDate *) lastModificationTime +{ + return [[container event] lastModified]; +} + +- (void) getMessageData: (struct mapistore_message **) dataPtr + inMemCtx: (TALLOC_CTX *) memCtx +{ + struct mapistore_message *msgData; + + [super getMessageData: &msgData inMemCtx: memCtx]; + + /* HACK: we know the first (and only) proxy is our appointment wrapper + instance, but this might not always be true */ + [[proxies objectAtIndex: 0] fillMessageData: msgData + inMemCtx: memCtx]; + *dataPtr = msgData; +} + +- (int) getPidTagMessageClass: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = talloc_strdup (memCtx, "IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}"); + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagProcessed: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getYes: data inMemCtx: memCtx]; +} + +- (int) getPidTagResponseRequested: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getYes: data inMemCtx: memCtx]; +} + +- (void) save +{ +// (gdb) po embeddedMessage->properties +// 2442592320 = "2012-07-11 22:30:00 +0000"; +// 2448359488 = "2012-07-11 22:30:00 +0000"; +// 2442723392 = "2012-07-11 22:30:00 +0000"; +// 2442068032 = "2012-07-11 22:30:00 +0000"; +// 2441740352 = "2012-07-11 23:00:00 +0000"; +// 131083 = 1; 2442330115 = 2; +// 235339779 = 9; +// 6291520 = "2012-07-11 16:00:00 +0000"; +// 2442526784 = "2012-07-11 23:00:00 +0000"; +// 2818059 = 0; +// 1703967 = "IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}"; +// 3538947 = 0; +// 1071513603 = 28591; 805830720 = "2012-07-10 16:42:00 +0000"; +// 2485977346 = <02013000 02001500 45006100 73007400 +// 65007200 6e002000 53007400 61006e00 64006100 72006400 20005400 69006d00 +// 65000200 02013e00 0000d607 00000000 00000000 00000000 00002c01 00000000 +// 0000c4ff ffff0000 0a000000 05000200 00000000 00000000 04000000 01000200 +// 00000000 00000201 3e000200 d7070000 00000000 00000000 00000000 2c010000 +// 00000000 c4ffffff 00000b00 00000100 02000000 00000000 00000300 00000200 +// 02000000 00000000>; 2454257728 = "2012-07-11 16:00:00 +0000"; 2442985475 = +// 118330; 1507331 = 1; 805765184 = "2012-07-09 18:32:00 +0000"; 2442657856 = +// "2012-07-11 23:00:00 +0000"; 2443051039 = "11.0"; 236912651 = 1; 2485911810 = +// <02013000 02001500 45006100 73007400 65007200 6e002000 53007400 61006e00 +// 64006100 72006400 20005400 69006d00 65000200 02013e00 0000d607 00000000 +// 00000000 00000000 00002c01 00000000 0000c4ff ffff0000 0a000000 05000200 +// 00000000 00000000 04000000 01000200 00000000 00000201 3e000200 d7070000 +// 00000000 00000000 00000000 2c010000 00000000 c4ffffff 00000b00 00000100 +// 02000000 00000000 00000300 00000200 02000000 00000000>; 2441543683 = 30; +// 2442068032 = "2012-07-11 22:30:00 +0000"; +// 1073348639 = "OpenChange User"; +// 806027522 = <2d64f6f5 89a59243 992d29d1 49173b3a>; 6357056 = "2012-07-11 +// 16:30:00 +0000"; +// */ + +// // 0x92490040 = 2454257728 + +// } + + SOGoUser *activeUser; + + activeUser = [[self context] activeUser]; + + [[container event] updateFromMAPIProperties: properties + inUserContext: [self userContext] + withActiveUser: activeUser]; +} + +@end diff --git a/OpenChange/MAPIStoreCalendarFolder.m b/OpenChange/MAPIStoreCalendarFolder.m index 71dcddb4e..f35918596 100644 --- a/OpenChange/MAPIStoreCalendarFolder.m +++ b/OpenChange/MAPIStoreCalendarFolder.m @@ -35,6 +35,7 @@ #import "MAPIStoreCalendarContext.h" #import "MAPIStoreCalendarMessage.h" #import "MAPIStoreCalendarMessageTable.h" +#import "MAPIStoreUserContext.h" #import "NSString+MAPIStore.h" #import "MAPIStoreCalendarFolder.h" @@ -67,6 +68,8 @@ newEntry = [SOGoAppointmentObject objectWithName: name inContainer: sogoObject]; [newEntry setIsNew: YES]; + /* the WOContext is required here for resolving notification pages */ + [newEntry setContext: [[self userContext] woContext]]; newMessage = [MAPIStoreCalendarMessage mapiStoreObjectWithSOGoObject: newEntry inContainer: self]; diff --git a/OpenChange/MAPIStoreCalendarMessage.h b/OpenChange/MAPIStoreCalendarMessage.h index 4ccab5cdd..a98149ac2 100644 --- a/OpenChange/MAPIStoreCalendarMessage.h +++ b/OpenChange/MAPIStoreCalendarMessage.h @@ -25,11 +25,14 @@ #import "MAPIStoreGCSMessage.h" +@class iCalCalendar; +@class iCalEvent; @class MAPIStoreAppointmentWrapper; @interface MAPIStoreCalendarMessage : MAPIStoreGCSMessage { - MAPIStoreAppointmentWrapper *appointmentWrapper; + iCalCalendar *calendar; + iCalEvent *masterEvent; } @end diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index daa9cc83d..f4dd3fbd6 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -49,6 +49,7 @@ #import #import +#import "iCalEvent+MAPIStore.h" #import "MAPIStoreAppointmentWrapper.h" #import "MAPIStoreCalendarAttachment.h" #import "MAPIStoreCalendarFolder.h" @@ -87,11 +88,93 @@ @implementation MAPIStoreCalendarMessage ++ (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP + inMemCtx: (TALLOC_CTX *) memCtx +{ + BOOL listedProperties[65536]; + NSUInteger count; + + memset (listedProperties, NO, 65536 * sizeof (BOOL)); + [super getAvailableProperties: propertiesP inMemCtx: memCtx]; + for (count = 0; count < (*propertiesP)->cValues; count++) + listedProperties[(*propertiesP)->aulPropTag[count] >> 16] = YES; + [MAPIStoreAppointmentWrapper fillAvailableProperties: *propertiesP + withExclusions: listedProperties]; + + return MAPISTORE_SUCCESS; +} + - (id) init { if ((self = [super init])) { - appointmentWrapper = nil; + calendar = nil; + masterEvent = nil; + } + + return self; +} + +- (void) _setupAttachmentParts +{ + NSUInteger count, max; + NSArray *events; + NSString *newKey; + MAPIStoreCalendarAttachment *attachment; + NSUInteger aid; + + events = [calendar events]; + max = [events count]; + for (count = 1; count < max; count++) + { + attachment = [MAPIStoreCalendarAttachment + mapiStoreObjectInContainer: self]; + /* we now that there are no attachments yet, so we can assume that the + right AID is 0 from the start */ + aid = count - 1; + [attachment setAID: aid]; + [attachment setEvent: [events objectAtIndex: count]]; + newKey = [NSString stringWithFormat: @"%ul", aid]; + [attachmentParts setObject: attachment forKey: newKey]; + } +} + +- (id) initWithSOGoObject: (id) newSOGoObject + inContainer: (MAPIStoreObject *) newFolder +{ + MAPIStoreContext *context; + MAPIStoreUserContext *userContext; + iCalCalendar *origCalendar; + MAPIStoreAppointmentWrapper *appointmentWrapper; + + if ((self = [super initWithSOGoObject: newSOGoObject + inContainer: newFolder])) + { + if ([newSOGoObject isNew]) + { + ASSIGN (calendar, [iCalCalendar groupWithTag: @"vcalendar"]); + [calendar setVersion: @"2.0"]; + [calendar setProdID: @"-//Inverse inc.//OpenChange+SOGo//EN"]; + masterEvent = [iCalEvent groupWithTag: @"vevent"]; + [calendar addChild: masterEvent]; + [masterEvent setCreated: [NSCalendarDate date]]; + } + else + { + origCalendar = [sogoObject calendar: YES secure: YES]; + calendar = [origCalendar mutableCopy]; + masterEvent = [[calendar events] objectAtIndex: 0]; + [self _setupAttachmentParts]; + } + context = [self context]; + userContext = [self userContext]; + appointmentWrapper + = [MAPIStoreAppointmentWrapper wrapperWithICalEvent: masterEvent + andUser: [userContext sogoUser] + andSenderEmail: nil + inTimeZone: [userContext timeZone] + withConnectionInfo: [context connectionInfo]]; + [self addProxy: appointmentWrapper]; } return self; @@ -99,39 +182,11 @@ - (void) dealloc { - [appointmentWrapper release]; + [calendar release]; [super dealloc]; } -- (MAPIStoreAppointmentWrapper *) appointmentWrapper -{ - iCalEvent *event; - MAPIStoreContext *context; - MAPIStoreUserContext *userContext; - - if (!appointmentWrapper) - { - event = [sogoObject component: NO secure: YES]; - context = [self context]; - userContext = [self userContext]; - ASSIGN (appointmentWrapper, - [MAPIStoreAppointmentWrapper wrapperWithICalEvent: event - andUser: [userContext sogoUser] - andSenderEmail: nil - inTimeZone: [userContext timeZone] - withConnectionInfo: [context connectionInfo]]); - } - - return appointmentWrapper; -} - /* getters */ -- (int) getPidTagIconIndex: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagIconIndex: data inMemCtx: memCtx]; -} - - (int) getPidLidFInvited: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -154,93 +209,6 @@ return MAPISTORE_SUCCESS; } -- (int) getPidTagOwnerAppointmentId: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagOwnerAppointmentId: data inMemCtx: memCtx]; -} - -- (int) getPidTagStartDate: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagStartDate: data inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentSequence: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentSequence: data - inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentStateFlags: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentStateFlags: data inMemCtx: memCtx]; -} - -- (int) getPidLidResponseStatus: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidResponseStatus: data - inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentStartWhole: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentStartWhole: data inMemCtx: memCtx]; -} - -- (int) getPidLidCommonStart: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidCommonStart: data inMemCtx: memCtx]; -} - -- (int) getPidTagEndDate: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagEndDate: data inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentEndWhole: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentEndWhole: data inMemCtx: memCtx]; -} - -- (int) getPidLidCommonEnd: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidCommonEnd: data inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentDuration: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentDuration: data inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentSubType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentSubType: data - inMemCtx: memCtx]; -} - -- (int) getPidLidBusyStatus: (void **) data // TODO - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidBusyStatus: data inMemCtx: memCtx]; -} - -- (int) getPidTagSubject: (void **) data // SUMMARY - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagSubject: data inMemCtx: memCtx]; -} - - (int) getPidLidSideEffects: (void **) data // TODO inMemCtx: (TALLOC_CTX *) memCtx { @@ -251,182 +219,76 @@ return MAPISTORE_SUCCESS; } -- (int) getPidLidLocation: (void **) data // LOCATION - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidLocation: data inMemCtx: memCtx]; -} - -- (int) getPidLidPrivate: (void **) data // private (bool), should depend on CLASS and permissions - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidPrivate: data inMemCtx: memCtx]; -} - -- (int) getPidTagSensitivity: (void **) data // not implemented, depends on CLASS - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagSensitivity: data inMemCtx: memCtx]; -} - -- (int) getPidTagImportance: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagImportance: data inMemCtx: memCtx]; -} - -- (int) getPidTagBody: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagBody: data inMemCtx: memCtx]; -} - -- (int) getPidLidIsRecurring: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidIsRecurring: data inMemCtx: memCtx]; -} - -- (int) getPidLidRecurring: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidRecurring: data inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentRecur: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentRecur: data - inMemCtx: memCtx]; -} - -- (int) getPidLidGlobalObjectId: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidGlobalObjectId: data - inMemCtx: memCtx]; -} - -- (int) getPidLidCleanGlobalObjectId: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidCleanGlobalObjectId: data - inMemCtx: memCtx]; -} - - (int) getPidTagProcessed: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getYes: data inMemCtx: memCtx]; } -- (int) getPidLidServerProcessed: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidServerProcessed: data - inMemCtx: memCtx]; -} - -- (int) getPidLidServerProcessingActions: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidServerProcessingActions: data - inMemCtx: memCtx]; -} - -- (int) getPidLidAppointmentReplyTime: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidAppointmentReplyTime: data - inMemCtx: memCtx]; -} - - (void) getMessageData: (struct mapistore_message **) dataPtr inMemCtx: (TALLOC_CTX *) memCtx { struct mapistore_message *msgData; [super getMessageData: &msgData inMemCtx: memCtx]; - [[self appointmentWrapper] fillMessageData: msgData - inMemCtx: memCtx]; + /* HACK: we know the first (and only) proxy is our appointment wrapper + instance, but this might not always be true */ + [[proxies objectAtIndex: 0] fillMessageData: msgData + inMemCtx: memCtx]; + *dataPtr = msgData; } -/* sender */ -- (int) getPidTagSenderEmailAddress: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagSenderEmailAddress: data - inMemCtx: memCtx]; -} - -- (int) getPidTagSenderAddressType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagSenderAddressType: data - inMemCtx: memCtx]; -} - -- (int) getPidTagSenderName: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagSenderName: data - inMemCtx: memCtx]; -} - -- (int) getPidTagSenderEntryId: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidTagSenderEntryId: data - inMemCtx: memCtx]; -} - /* sender representing */ -- (int) getPidTagSentRepresentingEmailAddress: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getPidTagSenderEmailAddress: data inMemCtx: memCtx]; -} +// - (int) getPidTagSentRepresentingEmailAddress: (void **) data +// inMemCtx: (TALLOC_CTX *) memCtx +// { +// return [self getPidTagSenderEmailAddress: data inMemCtx: memCtx]; +// } -- (int) getPidTagSentRepresentingAddressType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getSMTPAddrType: data inMemCtx: memCtx]; -} +// - (int) getPidTagSentRepresentingAddressType: (void **) data +// inMemCtx: (TALLOC_CTX *) memCtx +// { +// return [self getSMTPAddrType: data inMemCtx: memCtx]; +// } -- (int) getPidTagSentRepresentingName: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getPidTagSenderName: data inMemCtx: memCtx]; -} +// - (int) getPidTagSentRepresentingName: (void **) data +// inMemCtx: (TALLOC_CTX *) memCtx +// { +// return [self getPidTagSenderName: data inMemCtx: memCtx]; +// } -- (int) getPidTagSentRepresentingEntryId: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getPidTagSenderEntryId: data inMemCtx: memCtx]; -} +// - (int) getPidTagSentRepresentingEntryId: (void **) data +// inMemCtx: (TALLOC_CTX *) memCtx +// { +// return [self getPidTagSenderEntryId: data inMemCtx: memCtx]; +// } /* attendee */ // - (int) getPidTagReceivedByAddressType: (void **) data // inMemCtx: (TALLOC_CTX *) memCtx // { -// return [[self appointmentWrapper] getPidTagReceivedByAddressType: data +// return [appointmentWrapper getPidTagReceivedByAddressType: data // inMemCtx: memCtx]; // } // - (int) getPidTagReceivedByEmailAddress: (void **) data // inMemCtx: (TALLOC_CTX *) memCtx // { -// return [[self appointmentWrapper] getPidTagReceivedByEmailAddress: data +// return [appointmentWrapper getPidTagReceivedByEmailAddress: data // inMemCtx: memCtx]; // } // - (int) getPidTagReceivedByName: (void **) data // inMemCtx: (TALLOC_CTX *) memCtx // { -// return [[self appointmentWrapper] getPidTagReceivedByName: data +// return [appointmentWrapper getPidTagReceivedByName: data // inMemCtx: memCtx]; // } // - (int) getPidTagReceivedByEntryId: (void **) data // inMemCtx: (TALLOC_CTX *) memCtx // { -// return [[self appointmentWrapper] getPidTagReceivedByEntryId: data +// return [appointmentWrapper getPidTagReceivedByEntryId: data // inMemCtx: memCtx]; // } @@ -461,85 +323,6 @@ return [self getYes: data inMemCtx: memCtx]; } -/* alarms */ -- (int) getPidLidReminderSet: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderSet: data - inMemCtx: memCtx]; -} - -- (int) getPidLidReminderDelta: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderDelta: data - inMemCtx: memCtx]; -} - -- (int) getPidLidReminderTime: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderTime: data - inMemCtx: memCtx]; -} - -- (int) getPidLidReminderSignalTime: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderSignalTime: data - inMemCtx: memCtx]; -} - -- (int) getPidLidReminderOverride: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderOverride: data - inMemCtx: memCtx]; -} - -- (int) getPidLidReminderType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderType: data - inMemCtx: memCtx]; -} - -- (int) getPidLidReminderPlaySound: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderPlaySound: data - inMemCtx: memCtx]; -} - -- (int) getPidLidReminderFileParameter: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [[self appointmentWrapper] getPidLidReminderFileParameter: data - inMemCtx: memCtx]; -} - -/* attendee */ -- (void) _setupRecurrenceInCalendar: (iCalCalendar *) calendar - withEvent: (iCalEvent *) event - fromData: (NSData *) mapiRecurrenceData -{ - struct Binary_r *blob; - struct AppointmentRecurrencePattern *pattern; - NSMutableArray *otherEvents; - - /* cleanup */ - otherEvents = [[calendar events] mutableCopy]; - [otherEvents removeObject: event]; - [calendar removeChildren: otherEvents]; - [otherEvents release]; - - blob = [mapiRecurrenceData asBinaryInMemCtx: NULL]; - pattern = get_AppointmentRecurrencePattern (blob, blob); - [calendar setupRecurrenceWithMasterEntity: event - fromRecurrencePattern: &pattern->RecurrencePattern]; - talloc_free (blob); -} - - (NSString *) _uidFromGlobalObjectId { NSData *objectId; @@ -549,7 +332,8 @@ /* NOTE: we only handle the generic case at the moment, see MAPIStoreAppointmentWrapper */ - objectId = [properties objectForKey: MAPIPropertyKey (PidLidGlobalObjectId)]; + objectId = [properties + objectForKey: MAPIPropertyKey (PidLidGlobalObjectId)]; if (objectId) { length = [objectId length]; @@ -613,50 +397,6 @@ ASSIGN (sogoObject, newObject); } -- (void) _setupAlarmDataInEvent: (iCalEvent *) newEvent -{ - NSArray *alarms; - iCalAlarm *currentAlarm, *alarm = nil; - iCalTrigger *trigger; - NSNumber *delta; - NSString *action; - NSUInteger count, max; - - /* find and remove first display alarm */ - alarms = [newEvent alarms]; - max = [alarms count]; - for (count = 0; !alarm && count < max; count++) - { - currentAlarm = [alarms objectAtIndex: count]; - action = [[currentAlarm action] lowercaseString]; - if (!action || [action isEqualToString: @"display"]) - alarm = currentAlarm; - } - - if (alarm) - [newEvent removeChild: alarm]; - - if ([[properties objectForKey: MAPIPropertyKey (PidLidReminderSet)] - boolValue]) - { - delta - = [properties objectForKey: MAPIPropertyKey (PidLidReminderDelta)]; - if (delta) - { - alarm = [iCalAlarm new]; - [alarm setAction: @"DISPLAY"]; - trigger = [iCalTrigger elementWithTag: @"trigger"]; - [trigger setValueType: @"DURATION"]; - [trigger - setSingleValue: [NSString stringWithFormat: @"-PT%@M", delta] - forKey: @""]; - [alarm setTrigger: trigger]; - [newEvent addToAlarms: alarm]; - [alarm release]; - } - } -} - - (BOOL) subscriberCanReadMessage { NSArray *roles; @@ -682,20 +422,51 @@ return rc; } +- (void) _updateAttachedEvent: (MAPIStoreCalendarAttachment *) attachment + withUID: (NSString *) uid +{ + iCalEvent *newEvent; + SOGoUser *activeUser; + + newEvent = [iCalEvent groupWithTag: @"vevent"]; + [calendar addToEvents: newEvent]; + activeUser = [[self context] activeUser]; + [newEvent setUid: uid]; + [newEvent updateFromMAPIProperties: [attachment properties] + inUserContext: [self userContext] + withActiveUser: activeUser]; +} + +- (void) _updateAttachedEvents +{ + NSMutableArray *otherEvents; + NSArray *allAttachments; + NSUInteger count, max; + NSString *uid; + + /* cleanup all recurring events */ + otherEvents = [[calendar events] mutableCopy]; + [otherEvents removeObject: masterEvent]; + [calendar removeChildren: otherEvents]; + [otherEvents release]; + + uid = [masterEvent uid]; + + allAttachments = [attachmentParts allValues]; + max = [allAttachments count]; + for (count = 0; count < max; count++) + [self _updateAttachedEvent: [allAttachments objectAtIndex: count] + withUID: uid]; +} + - (void) save { - iCalCalendar *vCalendar; - BOOL isAllDay; - iCalDateTime *start, *end; - iCalTimeZone *tz; - NSCalendarDate *now; - NSString *uid, *content, *tzName, *priority, *newParticipationStatus = nil; - iCalEvent *newEvent; + // iCalCalendar *vCalendar; + // NSCalendarDate *now; + NSString *uid; + // iCalEvent *newEvent; // iCalPerson *userPerson; - NSUInteger responseStatus = 0; - NSInteger tzOffset; - SOGoUser *activeUser, *ownerUser; - id value; + SOGoUser *activeUser; if (isNew) { @@ -703,397 +474,32 @@ if (uid) { /* Hack required because of what's explained in oxocal 3.1.4.7.1: - basically, Outlook creates a copy of the event and then removes the - old instance. We perform a trickery to avoid performing those - operations in the backend, in a way that enables us to recover the - initial instance and act solely on it. */ + basically, Outlook creates a copy of the event and then removes + the old instance. We perform a trickery to avoid performing those + operations in the backend, in a way that enables us to recover + the initial instance and act solely on it. */ [self _fixupAppointmentObjectWithUID: uid]; } else uid = [SOGoObject globallyUniqueObjectId]; + [masterEvent setUid: uid]; + [sogoObject setNameInContainer: + [NSString stringWithFormat: @"%@.ics", uid]]; } - [self logWithFormat: @"-save, event props:"]; + // [self logWithFormat: @"-save, event props:"]; // MAPIStoreDumpMessageProperties (newProperties); - now = [NSCalendarDate date]; + // now = [NSCalendarDate date]; - content = [sogoObject contentAsString]; - if (![content length]) - { - newEvent = [sogoObject component: YES secure: NO]; - vCalendar = [newEvent parent]; - [vCalendar setProdID: @"-//Inverse inc.//OpenChange+SOGo//EN"]; - [newEvent setCreated: now]; - // CREATED = PidTagCreationTime - value = [properties objectForKey: MAPIPropertyKey (PidTagCreationTime)]; - if (value) - [newEvent setCreated: value]; - [newEvent setUid: uid]; - content = [vCalendar versitString]; - } + activeUser = [[self context] activeUser]; + [masterEvent updateFromMAPIProperties: properties + inUserContext: [self userContext] + withActiveUser: activeUser]; + [self _updateAttachedEvents]; + [sogoObject updateContentWithCalendar: calendar + fromRequest: nil]; - vCalendar = [iCalCalendar parseSingleFromSource: content]; - newEvent = [[vCalendar events] objectAtIndex: 0]; - - // DTSTAMP = PidLidOwnerCriticalChange or PidLidAttendeeCriticalChange - value = [properties objectForKey: MAPIPropertyKey (PidLidOwnerCriticalChange)]; - if (!value || [value isNever]) - value = now; - [newEvent setTimeStampAsDate: value]; - - // LAST-MODIFIED = PidTagLastModificationTime - value = [properties objectForKey: MAPIPropertyKey (PidTagLastModificationTime)]; - if (!value) - value = now; - [newEvent setLastModified: value]; - - // summary - value = [properties - objectForKey: MAPIPropertyKey (PR_NORMALIZED_SUBJECT_UNICODE)]; - if (value) - [newEvent setSummary: value]; - - // Location - value = [properties objectForKey: MAPIPropertyKey (PidLidLocation)]; - if (value) - [newEvent setLocation: value]; - - isAllDay = [newEvent isAllDay]; - value = [properties - objectForKey: MAPIPropertyKey (PidLidAppointmentSubType)]; - if (value) - isAllDay = [value boolValue]; - if (!isAllDay) - { - tzName = [[[self userContext] timeZone] name]; - tz = [iCalTimeZone timeZoneForName: tzName]; - [vCalendar addTimeZone: tz]; - } - else - tz = nil; - - // start - value = [properties objectForKey: MAPIPropertyKey (PR_START_DATE)]; - if (!value) - value = [properties - objectForKey: MAPIPropertyKey (PidLidAppointmentStartWhole)]; - if (value) - { - start = (iCalDateTime *) [newEvent uniqueChildWithTag: @"dtstart"]; - [start setTimeZone: tz]; - if (isAllDay) - { - [start setDate: value]; - [start setTimeZone: nil]; - } - else - { - tzOffset = [[value timeZone] secondsFromGMTForDate: value]; - value = [value dateByAddingYears: 0 months: 0 days: 0 - hours: 0 minutes: 0 - seconds: tzOffset]; - [start setDateTime: value]; - } - } - - /* end */ - value = [properties objectForKey: MAPIPropertyKey (PR_END_DATE)]; - if (!value) - value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentEndWhole)]; - if (value) - { - end = (iCalDateTime *) [newEvent uniqueChildWithTag: @"dtend"]; - [end setTimeZone: tz]; - if (isAllDay) - { - [end setDate: value]; - [end setTimeZone: nil]; - } - else - { - tzOffset = [[value timeZone] secondsFromGMTForDate: value]; - value = [value dateByAddingYears: 0 months: 0 days: 0 - hours: 0 minutes: 0 - seconds: tzOffset]; - [end setDateTime: value]; - } - } - - /* priority */ - value = [properties objectForKey: MAPIPropertyKey(PR_IMPORTANCE)]; - if (value) - { - switch ([value intValue]) - { - case 0: // IMPORTANCE_LOW - priority = @"9"; - break; - case 2: // IMPORTANCE_HIGH - priority = @"1"; - break; - default: // IMPORTANCE_NORMAL - priority = @"5"; - } - } - else - priority = @"0"; // None - [newEvent setPriority: priority]; - - /* show time as free/busy/tentative/out of office. Possible values are: - 0x00000000 - olFree - 0x00000001 - olTentative - 0x00000002 - olBusy - 0x00000003 - olOutOfOffice */ - value = [properties objectForKey: MAPIPropertyKey(PidLidBusyStatus)]; - if (value) - { - switch ([value intValue]) - { - case 0: - [newEvent setTransparency: @"TRANSPARENT"]; - break; - case 1: - case 2: - case 3: - default: - [newEvent setTransparency: @"OPAQUE"]; - } - } - - /* Comment */ - value = [properties objectForKey: MAPIPropertyKey (PR_BODY_UNICODE)]; - if (!value) - { - value = [properties objectForKey: MAPIPropertyKey (PR_HTML)]; - if (value) - { - value = [[NSString alloc] initWithData: value - encoding: NSUTF8StringEncoding]; - [value autorelease]; - value = [value htmlToText]; - } - } - if (value) - { - if ([value length] == 0 || [value isEqualToString: @"\\n"]) - value = nil; - [newEvent setComment: value]; - } - - /* recurrence */ - value = [properties - objectForKey: MAPIPropertyKey (PidLidAppointmentRecur)]; - if (value) - [self _setupRecurrenceInCalendar: vCalendar - withEvent: newEvent - fromData: value]; - - /* alarm */ - [self _setupAlarmDataInEvent: newEvent]; - - // Organizer - value = [properties objectForKey: @"recipients"]; - if (value) - { - NSArray *recipients; - NSDictionary *dict; - NSString *orgEmail, *sentBy, *attEmail; - iCalPerson *person; - iCalPersonPartStat newPartStat; - NSNumber *flags, *trackStatus; - int i, effective; - BOOL organizerIsSet = NO; - - [newEvent setOrganizer: nil]; - [newEvent removeAllAttendees]; - - recipients = [value objectForKey: @"to"]; - effective = 0; - for (i = 0; i < [recipients count]; i++) - { - dict = [recipients objectAtIndex: i]; - person = [iCalPerson new]; - [person setCn: [dict objectForKey: @"fullName"]]; - attEmail = [dict objectForKey: @"email"]; - [person setEmail: attEmail]; - - flags = [dict objectForKey: MAPIPropertyKey (PR_RECIPIENT_FLAGS)]; - if (!flags) - { - [self logWithFormat: - @"no recipient flags specified: skipping recipient"]; - continue; - } - - if (([flags unsignedIntValue] & 0x0002)) /* recipOrganizer */ - { - [newEvent setOrganizer: person]; - organizerIsSet = YES; - [self logWithFormat: @"organizer set via recipient flags"]; - } - else - { - BOOL isOrganizer = NO; - - // /* Work-around: it happens that Outlook still passes the - // organizer as a recipient, maybe because of a feature - // documented in a pre-mesozoic PDF still buried in a - // cavern... In that case we remove it, and we keep the - // number of effective recipients in "effective". If the - // total is 0, we remove the "ORGANIZER" too. */ - // if ([attEmail isEqualToString: orgEmail]) - // { - // [self logWithFormat: - // @"avoiding setting organizer as recipient"]; - // continue; - // } - - trackStatus = [dict objectForKey: MAPIPropertyKey (PidTagRecipientTrackStatus)]; - if (trackStatus) - { - /* FIXME: we should provide a data converter between OL - partstats and SOGo */ - switch ([trackStatus unsignedIntValue]) - { - case 0x01: /* respOrganized */ - isOrganizer = YES; - break; - case 0x02: /* respTentative */ - newPartStat = iCalPersonPartStatTentative; - break; - case 0x03: /* respAccepted */ - newPartStat = iCalPersonPartStatAccepted; - break; - case 0x04: /* respDeclined */ - newPartStat = iCalPersonPartStatDeclined; - break; - default: - newPartStat = iCalPersonPartStatNeedsAction; - } - - if (isOrganizer) - { - [newEvent setOrganizer: person]; - organizerIsSet = YES; - [self logWithFormat: @"organizer set via track status"]; - } - else - { - [person setParticipationStatus: newPartStat]; - [person setRsvp: @"TRUE"]; - [person setRole: @"REQ-PARTICIPANT"]; - [newEvent addToAttendees: person]; - effective++; - } - } - else - [self errorWithFormat: @"skipped recipient due" - @" to missing track status"]; - } - - [person release]; - } - - if (effective == 0) /* See work-around above */ - [newEvent setOrganizer: nil]; - else - { - // SEQUENCE = PidLidAppointmentSequence - value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentSequence)]; - if (value) - [newEvent setSequence: value]; - - ownerUser = [[self userContext] sogoUser]; - if (organizerIsSet) - { - /* We must reset the participation status to the value - obtained from PidLidResponseStatus as the value in - PidTagRecipientTrackStatus is not correct. Note (hack): - the method used here requires that the user directory - from LDAP and Samba matches perfectly. This can be solved - more appropriately by making use of the sender - properties... */ - person = [newEvent userAsAttendee: ownerUser]; - if (person) - { - value - = [properties objectForKey: MAPIPropertyKey (PidLidResponseStatus)]; - if (value) - responseStatus = [value unsignedLongValue]; - - /* FIXME: we should provide a data converter between OL partstats and - SOGo */ - switch (responseStatus) - { - case 0x02: /* respTentative */ - newPartStat = iCalPersonPartStatTentative; - break; - case 0x03: /* respAccepted */ - newPartStat = iCalPersonPartStatAccepted; - break; - case 0x04: /* respDeclined */ - newPartStat = iCalPersonPartStatDeclined; - break; - default: - newPartStat = iCalPersonPartStatNeedsAction; - } - [person setParticipationStatus: newPartStat]; - newParticipationStatus = [person partStatWithDefault]; - - value = [properties objectForKey: MAPIPropertyKey (PidLidAttendeeCriticalChange)]; - if (value && ![value isNever]) - [newEvent setTimeStampAsDate: value]; - // if (newPartStat // != iCalPersonPartStatUndefined - // ) - // { - // // iCalPerson *participant; - - // // participant = [newEvent userAsAttendee: ownerUser]; - // // [participant setParticipationStatus: newPartStat]; - // // [sogoObject saveComponent: newEvent]; - - // [sogoObject changeParticipationStatus: newPartStat - // withDelegate: nil]; - // // [[self context] tearDownRequest]; - // } - // // }1005 - - // // else - // // { - } - } - else - { - [self errorWithFormat: @"organizer was not set although a" - @" recipient list was specified"]; - /* We must set the organizer preliminarily here because, unlike what - the doc states, Outlook does not always pass the real organizer - in the recipients list. */ - dict = [ownerUser primaryIdentity]; - person = [iCalPerson new]; - [person setCn: [dict objectForKey: @"fullName"]]; - orgEmail = [dict objectForKey: @"email"]; - [person setEmail: orgEmail]; - - activeUser = [[self context] activeUser]; - if (![activeUser isEqual: ownerUser]) - { - dict = [activeUser primaryIdentity]; - sentBy = [NSString stringWithFormat: @"mailto:%@", - [dict objectForKey: @"email"]]; - [person setSentBy: sentBy]; - } - [newEvent setOrganizer: person]; - [person release]; - } - } - } - - [sogoObject saveComponent: newEvent]; - if (newParticipationStatus) - [sogoObject changeParticipationStatus: newParticipationStatus - withDelegate: nil]; [self updateVersions]; } @@ -1111,9 +517,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..bc8d3a6d4 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" @@ -179,8 +180,8 @@ return MAPISTORE_SUCCESS; } -- (int) getPidTagSubject: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx +- (int) getPidTagNormalizedSubject: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { return [self getPidTagDisplayName: data inMemCtx: memCtx]; } @@ -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 17907e93b..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" @@ -294,9 +292,11 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) [MAPIStoreUserContext userContextWithUsername: username andTDBIndexing: indexingTdb]); +#if 0 mapistore_mgmt_backend_register_user (newConnInfo, "SOGo", [username UTF8String]); +#endif connInfo = newConnInfo; username = [NSString stringWithUTF8String: newConnInfo->username]; @@ -315,9 +315,12 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) - (void) dealloc { +#if 0 mapistore_mgmt_backend_unregister_user ([self connectionInfo], "SOGo", [[userContext username] UTF8String]); +#endif + [contextUrl release]; [userContext release]; [containersBag release]; @@ -428,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) @@ -455,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 70% rename from OpenChange/MAPIStoreFSFolder.m rename to OpenChange/MAPIStoreDBFolder.m index 68f57545f..d8af710ad 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 * @@ -24,6 +24,7 @@ #import #import +#import #import #import #import @@ -31,21 +32,21 @@ #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 #include -static Class EOKeyValueQualifierK; +static Class EOKeyValueQualifierK, SOGoMAPIDBFolderK; static NSString *MAPIStoreRightReadItems = @"RightsReadItems"; static NSString *MAPIStoreRightCreateItems = @"RightsCreateItems"; @@ -57,54 +58,83 @@ static NSString *MAPIStoreRightCreateSubfolders = @"RightsCreateSubfolders"; static NSString *MAPIStoreRightFolderOwner = @"RightsFolderOwner"; static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; -@implementation MAPIStoreFSFolder +@implementation MAPIStoreDBFolder + (void) initialize { EOKeyValueQualifierK = [EOKeyValueQualifier class]; + SOGoMAPIDBFolderK = [SOGoMAPIDBFolder 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; + enum mapistore_error rc; + NSString *folderName, *nameInContainer; + SOGoMAPIDBFolder *newFolder; + struct SPropValue *value; - newKey = [NSString stringWithFormat: @"0x%.16"PRIx64, (unsigned long long) newFID]; + value = get_SPropValue_SRow (aRow, PidTagDisplayName); + if (value) + folderName = [NSString stringWithUTF8String: value->value.lpszW]; + else + { + value = get_SPropValue_SRow (aRow, PidTagDisplayName_string8); + if (value) + folderName = [NSString stringWithUTF8String: value->value.lpszA]; + else + folderName = nil; + } - urlString = [NSString stringWithFormat: @"%@/%@", [self url], newKey]; - childURL = [NSURL URLWithString: [urlString stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]]; - childFolder = [SOGoMAPIFSFolder folderWithURL: childURL - andTableType: MAPISTORE_MESSAGE_TABLE]; - [childFolder ensureDirectory]; - *newKeyP = newKey; + if (folderName) + { + nameInContainer = [NSString stringWithFormat: @"0x%.16"PRIx64, + (unsigned long long) newFID]; + newFolder = [SOGoMAPIDBFolderK objectWithName: nameInContainer + inContainer: sogoObject]; + [newFolder reloadIfNeeded]; + [[newFolder properties] setObject: folderName + forKey: MAPIPropertyKey (PidTagDisplayName)]; + [newFolder save]; + *newKeyP = nameInContainer; + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_INVALID_PARAMETER; - return MAPISTORE_SUCCESS; + return rc; } - (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]; + [fsObject reloadIfNeeded]; + newMessage = [MAPIStoreDBMessage mapiStoreObjectWithSOGoObject: fsObject inContainer: self]; return newMessage; @@ -119,9 +149,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 +162,26 @@ 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]; } +/* TODO: now that we are DB-based, this method can easily be implemented + +- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum + andCN: (NSNumber **) cnNbrs + inTableType: (enum mapistore_table_type) tableType +{ +} +*/ + - (NSDate *) lastMessageModificationTime { NSUInteger count, max; NSDate *date, *fileDate; - MAPIStoreFSMessage *msg; + MAPIStoreDBMessage *msg; NSArray *messageKeys; messageKeys = [self messageKeys]; @@ -189,7 +207,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 62% rename from OpenChange/MAPIStoreFSMessage.m rename to OpenChange/MAPIStoreDBMessage.m index 7b7939884..3ea3704d0 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,79 @@ /* 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] >> 16; + 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; +} + +- (void) addProperties: (NSDictionary *) newNewProperties +{ + [sogoObject reloadIfNeeded]; + + [super addProperties: newNewProperties]; +} + - (void) save { uint64_t newVersion; @@ -74,15 +141,13 @@ if ([attachmentKeys count] > 0) [properties setObject: attachmentParts forKey: @"attachments"]; - newVersion = exchange_globcnt ([[self context] getNewChangeNumber] >> 16); + newVersion = [[self context] getNewChangeNumber]; [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 +156,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 +180,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/MAPIStoreEmbeddedMessage.h b/OpenChange/MAPIStoreEmbeddedMessage.h index 431f60e80..62c9431ba 100644 --- a/OpenChange/MAPIStoreEmbeddedMessage.h +++ b/OpenChange/MAPIStoreEmbeddedMessage.h @@ -26,13 +26,6 @@ #import "MAPIStoreMessage.h" @interface MAPIStoreEmbeddedMessage : MAPIStoreMessage -{ - id attachment; -} - -+ (id) embeddedMessageWithAttachment: (id) newAttachment; - -- (id) initWithAttachment: (id) newAttachment; @end diff --git a/OpenChange/MAPIStoreEmbeddedMessage.m b/OpenChange/MAPIStoreEmbeddedMessage.m index fe0e28105..63f093095 100644 --- a/OpenChange/MAPIStoreEmbeddedMessage.m +++ b/OpenChange/MAPIStoreEmbeddedMessage.m @@ -26,6 +26,8 @@ #import "MAPIStoreEmbeddedMessage.h" +#include + static Class MAPIStoreAttachmentK; @implementation MAPIStoreEmbeddedMessage @@ -35,25 +37,28 @@ static Class MAPIStoreAttachmentK; MAPIStoreAttachmentK = [MAPIStoreAttachment class]; } -+ (id) embeddedMessageWithAttachment: (id) newAttachment +- (int) getPidTagFolderId: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { - MAPIStoreEmbeddedMessage *newMessage; - - newMessage = [[self alloc] initWithAttachment: newAttachment]; - [newMessage autorelease]; - - return newMessage; + return MAPISTORE_ERR_NOT_FOUND; } -- (id) initWithAttachment: (id) newAttachment +- (int) getPidTagChangeKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { - if ((self = [self init])) - { - if ([newAttachment isKindOfClass: MAPIStoreAttachmentK]) - ASSIGN (container, newAttachment); - } + return MAPISTORE_ERR_NOT_FOUND; +} - return self; +- (int) getPidTagParentSourceKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagChangeNumber: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; } - (NSString *) nameInContainer @@ -61,4 +66,14 @@ static Class MAPIStoreAttachmentK; return @"as-message"; } +- (uint64_t) objectVersion +{ + return ULLONG_MAX; +} + +- (void) save +{ + [self subclassResponsibility: _cmd]; +} + @end 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..d035810ac 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" @@ -448,19 +448,6 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) return MAPISTORE_SUCCESS; } -- (int) getPidTagSubject: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - NSString *stringValue; - - stringValue = [self subject]; - if (!stringValue) - stringValue = @""; - *data = [stringValue asUnicodeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - - (int) getPidTagSubjectPrefix: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -1529,8 +1516,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..ec33c54dd 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,99 @@ 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) 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 +354,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 +758,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 +772,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NGMutableHashMap *headers; NSUInteger count, max; + attachmentParts = [mailProperties objectForKey: @"attachments"]; textBody = MakeTextPartBody (mailProperties, attachmentParts, &textContentType); @@ -707,22 +809,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 +875,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, - (int) submitWithFlags: (enum SubmitFlags) flags { - NSDictionary *mailProperties, *recipients; + NSDictionary *recipients; NSData *messageData; NSMutableArray *recipientEmails; NSArray *list; @@ -785,19 +885,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 +917,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 +932,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 +958,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..51fa56ec3 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; @@ -66,9 +66,6 @@ - (int) setReadFlag: (uint8_t) flag; - (enum mapistore_error) saveMessage; -/* helper getters */ -- (int) getSMTPAddrType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; - (NSArray *) activeContainerMessageTables; - (NSArray *) activeUserRoles; diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index 35ea1036d..1217d295e 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" @@ -55,6 +56,7 @@ #include static NSString *resourcesDir = nil; +static Class MAPIStoreFolderK = nil; /* rtf conversion via unrtf */ static int @@ -116,7 +118,6 @@ rtf2html (NSData *compressedRTF) @interface SOGoObject (MAPIStoreProtocol) -- (NSString *) davEntityTag; - (NSString *) davContentLength; @end @@ -130,6 +131,7 @@ rtf2html (NSData *compressedRTF) resourcesDir = [[NSBundle bundleForClass: self] resourcePath]; [resourcesDir retain]; } + MAPIStoreFolderK = [MAPIStoreFolder class]; } - (id) init @@ -304,6 +306,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 +342,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 @@ -443,62 +444,68 @@ rtf2html (NSData *compressedRTF) || (!isNew && [self subscriberCanModifyMessage]))) { /* notifications */ - folderId = [(MAPIStoreFolder *) container objectId]; - mstoreCtx = [[self context] connectionInfo]->mstore_ctx; - - /* folder modified */ - notif_parameters - = talloc_zero(NULL, struct mapistore_object_notification_parameters); - notif_parameters->object_id = folderId; - if (isNew) + if ([container isKindOfClass: MAPIStoreFolderK]) { - notif_parameters->tag_count = 3; - notif_parameters->tags = talloc_array (notif_parameters, - enum MAPITAGS, 3); - notif_parameters->tags[0] = PR_CONTENT_COUNT; - notif_parameters->tags[1] = PR_MESSAGE_SIZE; - notif_parameters->tags[2] = PR_NORMAL_MESSAGE_SIZE; - notif_parameters->new_message_count = true; - notif_parameters->message_count - = [[(MAPIStoreFolder *) container messageKeys] count] + 1; - } - mapistore_push_notification (mstoreCtx, - MAPISTORE_FOLDER, MAPISTORE_OBJECT_MODIFIED, - notif_parameters); - talloc_free (notif_parameters); + folderId = [(MAPIStoreFolder *) container objectId]; + mstoreCtx = [[self context] connectionInfo]->mstore_ctx; - /* message created */ - if (isNew) - { + /* folder modified */ notif_parameters - = talloc_zero(NULL, - struct mapistore_object_notification_parameters); - notif_parameters->object_id = [self objectId]; - notif_parameters->folder_id = folderId; - - notif_parameters->tag_count = 0xffff; + = talloc_zero(NULL, struct mapistore_object_notification_parameters); + notif_parameters->object_id = folderId; + if (isNew) + { + notif_parameters->tag_count = 3; + notif_parameters->tags = talloc_array (notif_parameters, + enum MAPITAGS, 3); + notif_parameters->tags[0] = PR_CONTENT_COUNT; + notif_parameters->tags[1] = PR_MESSAGE_SIZE; + notif_parameters->tags[2] = PR_NORMAL_MESSAGE_SIZE; + notif_parameters->new_message_count = true; + notif_parameters->message_count + = [[(MAPIStoreFolder *) container messageKeys] count] + 1; + } mapistore_push_notification (mstoreCtx, - MAPISTORE_MESSAGE, MAPISTORE_OBJECT_CREATED, + MAPISTORE_FOLDER, + MAPISTORE_OBJECT_MODIFIED, notif_parameters); talloc_free (notif_parameters); - } - /* we ensure the table caches are loaded so that old and new state - can be compared */ - containerTables = [self activeContainerMessageTables]; - max = [containerTables count]; - for (count = 0; count < max; count++) - [[containerTables objectAtIndex: count] restrictedChildKeys]; + /* message created */ + if (isNew) + { + notif_parameters + = talloc_zero(NULL, + struct mapistore_object_notification_parameters); + notif_parameters->object_id = [self objectId]; + notif_parameters->folder_id = folderId; + + notif_parameters->tag_count = 0xffff; + mapistore_push_notification (mstoreCtx, + MAPISTORE_MESSAGE, MAPISTORE_OBJECT_CREATED, + notif_parameters); + talloc_free (notif_parameters); + } + + /* we ensure the table caches are loaded so that old and new state + can be compared */ + containerTables = [self activeContainerMessageTables]; + max = [containerTables count]; + for (count = 0; count < max; count++) + [[containerTables objectAtIndex: count] restrictedChildKeys]; + } [self save]; - /* table modified */ - for (count = 0; count < max; count++) - [[containerTables objectAtIndex: count] - notifyChangesForChild: self]; + if ([container isKindOfClass: MAPIStoreFolderK]) + { + /* table modified */ + for (count = 0; count < max; count++) + [[containerTables objectAtIndex: count] + notifyChangesForChild: self]; + [container cleanupCaches]; + } [self setIsNew: NO]; - [properties removeAllObjects]; - [container cleanupCaches]; rc = MAPISTORE_SUCCESS; } else @@ -507,14 +514,6 @@ rtf2html (NSData *compressedRTF) return rc; } -/* helper getters */ -- (int) getSMTPAddrType: (void **) data inMemCtx: (TALLOC_CTX *) memCtx -{ - *data = [@"SMTP" asUnicodeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - /* getters */ - (int) getPidTagInstID: (void **) data // TODO: DOUBT inMemCtx: (TALLOC_CTX *) memCtx @@ -655,9 +654,19 @@ rtf2html (NSData *compressedRTF) - (int) getPidTagMid: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = MAPILongLongValue (memCtx, [self objectId]); + int rc; + uint64_t obId; - return MAPISTORE_SUCCESS; + obId = [self objectId]; + if (obId == ULLONG_MAX) + rc = MAPISTORE_ERR_NOT_FOUND; + else + { + *data = MAPILongLongValue (memCtx, obId); + rc = MAPISTORE_SUCCESS; + } + + return rc; } - (int) getPidTagMessageLocaleId: (void **) data @@ -708,21 +717,35 @@ rtf2html (NSData *compressedRTF) - (int) getPidTagSubject: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - [self subclassResponsibility: _cmd]; + int rc; + TALLOC_CTX *localMemCtx; + char *prefix, *normalizedSubject; - return MAPISTORE_ERR_NOT_FOUND; + localMemCtx = talloc_zero (NULL, TALLOC_CTX); + if ([self getProperty: (void **) &prefix + withTag: PidTagSubjectPrefix + inMemCtx: localMemCtx] + != MAPISTORE_SUCCESS) + prefix = ""; + rc = [self getProperty: (void **) &normalizedSubject + withTag: PidTagNormalizedSubject + inMemCtx: localMemCtx]; + if (rc == MAPISTORE_SUCCESS) + *data = talloc_asprintf (memCtx, "%s%s", prefix, normalizedSubject); + + return rc; } - (int) getPidTagNormalizedSubject: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidTagSubject: data inMemCtx: memCtx]; + return MAPISTORE_ERR_NOT_FOUND; } - (int) getPidTagOriginalSubject: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidTagNormalizedSubject: data inMemCtx: memCtx]; + return [self getPidTagSubject: data inMemCtx: memCtx]; } - (int) getPidTagConversationTopic: (void **) data @@ -792,7 +815,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..ddb28ada0 100644 --- a/OpenChange/MAPIStoreObject.h +++ b/OpenChange/MAPIStoreObject.h @@ -33,60 +33,41 @@ @class NSMutableArray; @class NSMutableDictionary; -@class EOQualifier; - @class MAPIStoreContext; -@class MAPIStoreFolder; @class MAPIStoreMapping; -@class MAPIStoreTable; +@class MAPIStoreObjectProxy; @class MAPIStoreUserContext; +@class MAPIStoreSOGoObject; @interface MAPIStoreObject : NSObject { const IMP *classGetters; NSMutableArray *parentContainersBag; - MAPIStoreObject *container; - id sogoObject; + NSMutableArray *proxies; + id container; NSMutableDictionary *properties; - BOOL isNew; } -+ (id) mapiStoreObjectWithSOGoObject: (id) newSOGoObject - inContainer: (MAPIStoreObject *) newContainer; -+ (int) getAvailableProperties: (struct SPropTagArray **) propertiesP - inMemCtx: (TALLOC_CTX *) memCtx; ++ (id) mapiStoreObjectInContainer: (MAPIStoreObject *) newContainer; +- (id) initInContainer: (MAPIStoreObject *) newContainer; -- (id) initWithSOGoObject: (id) newSOGoObject - inContainer: (MAPIStoreObject *) newFolder; +- (void) addProxy: (MAPIStoreObjectProxy *) newProxy; -- (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 - inMemCtx: (TALLOC_CTX *) localMemCtx; - (int) getProperties: (struct mapistore_property_data *) data withTags: (enum MAPITAGS *) tags andCount: (uint16_t) columnCount @@ -104,26 +85,13 @@ 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; +- (NSString *) nameInContainer; - (NSDate *) creationTime; - (NSDate *) lastModificationTime; diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index e3d379d6b..eba69c966 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -58,47 +58,16 @@ 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; } -+ (int) getAvailableProperties: (struct SPropTagArray **) propertiesP - inMemCtx: (TALLOC_CTX *) memCtx -{ - struct SPropTagArray *properties; - const MAPIStorePropertyGetter *classGetters; - NSUInteger count; - enum MAPITAGS propTag; - uint16_t propValue; - - properties = talloc_zero (memCtx, struct SPropTagArray); - properties->aulPropTag = talloc_array (properties, enum MAPITAGS, - MAPIStoreSupportedPropertiesCount); - classGetters = MAPIStorePropertyGettersForClass (self); - for (count = 0; count < MAPIStoreSupportedPropertiesCount; count++) - { - propTag = MAPIStoreSupportedProperties[count]; - propValue = (propTag & 0xffff0000) >> 16; - if (classGetters[propValue]) - { - properties->aulPropTag[properties->cValues] = propTag; - properties->cValues++; - } - } - - *propertiesP = properties; - - return MAPISTORE_SUCCESS; -} - - (id) init { if ((self = [super init])) @@ -106,22 +75,19 @@ static Class NSExceptionK, MAPIStoreFolderK; classGetters = (IMP *) MAPIStorePropertyGettersForClass (isa); parentContainersBag = [NSMutableArray new]; container = nil; - sogoObject = nil; properties = [NSMutableDictionary new]; - isNew = NO; + proxies = [NSMutableArray new]; } - [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 +96,22 @@ static Class NSExceptionK, MAPIStoreFolderK; - (void) dealloc { - [self logWithFormat: @"-dealloc"]; - [sogoObject release]; + // [self logWithFormat: @"-dealloc"]; + [proxies release]; [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,32 +124,11 @@ 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]; + containerURL = (NSString *) [container url]; if ([containerURL hasSuffix: @"/"]) format = @"%@%@"; else @@ -213,12 +138,14 @@ static Class NSExceptionK, MAPIStoreFolderK; containerURL, [self nameInContainer]]; } +/* helpers */ + - (void) addProperties: (NSDictionary *) newNewProperties { [properties addEntriesFromDictionary: newNewProperties]; } -- (NSDictionary *) properties +- (NSMutableDictionary *) properties { return properties; } @@ -232,6 +159,7 @@ static Class NSExceptionK, MAPIStoreFolderK; SEL methodSel; id value; int rc = MAPISTORE_ERR_NOT_FOUND; + NSUInteger count, max; value = [properties objectForKey: MAPIPropertyKey (propTag)]; if (value) @@ -245,127 +173,21 @@ static Class NSExceptionK, MAPIStoreFolderK; rc = method (self, methodSel, data, memCtx); } - 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++) + if (rc == MAPISTORE_ERR_NOT_FOUND) { - 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; + max = [proxies count]; + for (count = 0; rc == MAPISTORE_ERR_NOT_FOUND && count < max; count++) + rc = [[proxies objectAtIndex: count] + getProperty: data + withTag: propTag + inMemCtx: memCtx]; } return rc; } - (int) getPidTagCreationTime: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { *data = [[self creationTime] asFileTimeInMemCtx: memCtx]; @@ -380,39 +202,21 @@ static Class NSExceptionK, MAPIStoreFolderK; return MAPISTORE_SUCCESS; } -- (int) getAvailableProperties: (struct SPropTagArray **) propertiesP - inMemCtx: (TALLOC_CTX *) memCtx -{ - NSUInteger count; - struct SPropTagArray *availableProps; - enum MAPITAGS propTag; - - availableProps = talloc_zero (memCtx, struct SPropTagArray); - availableProps->aulPropTag = talloc_array (availableProps, enum MAPITAGS, - MAPIStoreSupportedPropertiesCount); - for (count = 0; count < MAPIStoreSupportedPropertiesCount; count++) - { - propTag = MAPIStoreSupportedProperties[count]; - if ([self canGetProperty: propTag]) - { - availableProps->aulPropTag[availableProps->cValues] = propTag; - availableProps->cValues++; - } - } - - *propertiesP = availableProps; - - return MAPISTORE_SUCCESS; -} - - (BOOL) canGetProperty: (enum MAPITAGS) propTag { uint16_t propValue; + BOOL canGetProperty; + NSUInteger count, max; propValue = (propTag & 0xffff0000) >> 16; - return (classGetters[propValue] - || [properties objectForKey: MAPIPropertyKey (propTag)]); + canGetProperty = (classGetters[propValue] + || [properties objectForKey: MAPIPropertyKey (propTag)]); + max = [proxies count]; + for (count = 0; !canGetProperty && count < max; count++) + canGetProperty = [[proxies objectAtIndex: count] canGetProperty: propTag]; + + return canGetProperty; } - (int) getProperties: (struct mapistore_property_data *) data @@ -430,6 +234,11 @@ static Class NSExceptionK, MAPIStoreFolderK; return MAPISTORE_SUCCESS; } +- (void) addProxy: (MAPIStoreObjectProxy *) newProxy +{ + [proxies addObject: newProxy]; +} + - (int) addPropertiesFromRow: (struct SRow *) aRow { struct SPropValue *cValue; @@ -474,7 +283,46 @@ 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 */ +- (NSString *) nameInContainer +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + - (NSDate *) creationTime { [self subclassResponsibility: _cmd]; diff --git a/OpenChange/MAPIStoreObjectProxy.h b/OpenChange/MAPIStoreObjectProxy.h new file mode 100644 index 000000000..6e9aee13e --- /dev/null +++ b/OpenChange/MAPIStoreObjectProxy.h @@ -0,0 +1,41 @@ +/* MAPIStoreObjectProxy.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 MAPISTOREOBJECTPROXY_H +#define MAPISTOREOBJECTPROXY_H + +#include + +#import + +@interface MAPIStoreObjectProxy : NSObject +{ + const IMP *classGetters; +} + +- (enum mapistore_error) getProperty: (void **) data + withTag: (enum MAPITAGS) propTag + inMemCtx: (TALLOC_CTX *) localMemCtx; + +@end + +#endif /* MAPISTOREOBJECTPROXY_H */ diff --git a/OpenChange/MAPIStoreObjectProxy.m b/OpenChange/MAPIStoreObjectProxy.m new file mode 100644 index 000000000..945d16167 --- /dev/null +++ b/OpenChange/MAPIStoreObjectProxy.m @@ -0,0 +1,67 @@ +/* MAPIStoreObjectProxy.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 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. + */ + +#import "MAPIStorePropertySelectors.h" +#import "NSString+MAPIStore.h" + +#import "MAPIStoreObjectProxy.h" + +#undef DEBUG +#include +#include +#include +#include +#include + +@implementation MAPIStoreObjectProxy + +- (id) init +{ + if ((self = [super init])) + { + classGetters = (IMP *) MAPIStorePropertyGettersForClass (isa); + } + + return self; +} + +- (enum mapistore_error) getProperty: (void **) data + withTag: (enum MAPITAGS) propTag + inMemCtx: (TALLOC_CTX *) memCtx +{ + MAPIStorePropertyGetter method; + uint16_t propValue; + SEL methodSel; + int rc; + + propValue = (propTag & 0xffff0000) >> 16; + methodSel = MAPIStoreSelectorForPropertyGetter (propValue); + method = (MAPIStorePropertyGetter) classGetters[propValue]; + if (method) + rc = method (self, methodSel, data, memCtx); + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + +@end 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/MAPIStoreRecurrenceUtils.h b/OpenChange/MAPIStoreRecurrenceUtils.h index 4fdf8c54e..a72a23af8 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.h +++ b/OpenChange/MAPIStoreRecurrenceUtils.h @@ -23,10 +23,14 @@ #ifndef MAPISTORERECURRENCEUTILS_H #define MAPISTORERECURRENCEUTILS_H +#include + #import #import -@class NSCalendarDate; +@class NSTimeZone; + +@class iCalEvent; @class iCalRepeatableEntityObject; @class iCalRecurrenceRule; @@ -44,8 +48,9 @@ @interface iCalRecurrenceRule (MAPIStoreRecurrence) - (void) fillRecurrencePattern: (struct RecurrencePattern *) rp - withStartDate: (NSCalendarDate *) startDate - andEndDate: (NSCalendarDate *) endDate; + withEvent: (iCalEvent *) event + inTimeZone: (NSTimeZone *) timeZone + inMemCtx: (TALLOC_CTX *) memCtx; @end diff --git a/OpenChange/MAPIStoreRecurrenceUtils.m b/OpenChange/MAPIStoreRecurrenceUtils.m index 09d6ce793..d07d640f6 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.m +++ b/OpenChange/MAPIStoreRecurrenceUtils.m @@ -21,17 +21,23 @@ */ #import +#import +#import #import #import #import +#import +#import +#import #import #import -#import +#import #import "NSDate+MAPIStore.h" #import "MAPIStoreRecurrenceUtils.h" +#import "MAPIStoreTypes.h" #include #include @@ -43,13 +49,15 @@ - (void) setupRecurrenceWithMasterEntity: (iCalRepeatableEntityObject *) entity fromRecurrencePattern: (struct RecurrencePattern *) rp { - NSCalendarDate *startDate, *olEndDate, *untilDate; + NSCalendarDate *startDate, *olEndDate, *untilDate, *exDate; NSString *monthDay, *month; + NSMutableSet *exceptionDates; + NSArray *realExDates; iCalRecurrenceRule *rule; iCalByDayMask *byDayMask; iCalWeekOccurrence weekOccurrence; iCalWeekOccurrences dayMaskDays; - NSUInteger count; + NSUInteger count, max; NSInteger bySetPos; unsigned char maskValue; @@ -203,6 +211,37 @@ [self errorWithFormat: @"invalid value for EndType: %.4x", rp->EndType]; } + + /* exception dates: + - take all deleted instances + - remove all modified instances from the above set + - add remaining instances, in chronological order + */ + exceptionDates = [NSMutableSet set]; + for (count = 0; count < rp->DeletedInstanceCount; count++) + { + exDate + = [NSDate dateFromMinutesSince1601: rp->DeletedInstanceDates[count]]; + exDate = [exDate hour: [startDate hourOfDay] + minute: [startDate minuteOfHour] + second: [startDate secondOfMinute]]; + [exceptionDates addObject: exDate]; + } + for (count = 0; count < rp->ModifiedInstanceCount; count++) + { + exDate + = [NSDate dateFromMinutesSince1601: rp->ModifiedInstanceDates[count]]; + exDate = [exDate hour: [startDate hourOfDay] + minute: [startDate minuteOfHour] + second: [startDate secondOfMinute]]; + [exceptionDates removeObject: exDate]; + } + + realExDates = [[exceptionDates allObjects] + sortedArrayUsingSelector: @selector (compare:)]; + max = [realExDates count]; + for (count = 0; count < max; count++) + [entity addToExceptionDates: [realExDates objectAtIndex: count]]; } @end @@ -210,17 +249,27 @@ @implementation iCalRecurrenceRule (MAPIStoreRecurrence) - (void) fillRecurrencePattern: (struct RecurrencePattern *) rp - withStartDate: (NSCalendarDate *) startDate - andEndDate: (NSCalendarDate *) endDate + withEvent: (iCalEvent *) event + inTimeZone: (NSTimeZone *) timeZone + inMemCtx: (TALLOC_CTX *) memCtx { iCalRecurrenceFrequency freq; iCalByDayMask *byDayMask; NSString *byMonthDay, *bySetPos; - NSCalendarDate *untilDate, *beginOfWeek, *minimumDate, *moduloDate, *midnight; + NSCalendarDate *startDate, *endDate, *untilDate, *beginOfWeek, *minimumDate, + *moduloDate, *midnight; iCalWeekOccurrences *days; - NSInteger dayOfWeek, repeatInterval, repeatCount, count, firstOccurrence; + NSInteger dayOfWeek, repeatInterval, repeatCount, count, firstOccurrence, + max; uint32_t nbrMonths, mask; + NSArray *events; + NSMutableArray *deletedDates, *modifiedDates; + startDate = [event firstRecurrenceStartDate]; + [startDate setTimeZone: timeZone]; + endDate = [event lastPossibleRecurrenceStartDate]; + [endDate setTimeZone: timeZone]; + rp->ReaderVersion = 0x3004; rp->WriterVersion = 0x3004; @@ -370,6 +419,40 @@ [self errorWithFormat: @"rule for an event that never occurs"]; } } + + events = [[event parent] events]; + max = [events count]; + modifiedDates = [NSMutableArray arrayWithCapacity: max]; + for (count = 1; count < max; count++) + { + startDate = [[events objectAtIndex: count] recurrenceId]; + [modifiedDates addObject: startDate]; + } + max = [modifiedDates count]; + rp->ModifiedInstanceCount = max; + rp->ModifiedInstanceDates = talloc_array (memCtx, uint32_t, max); + for (count = 0; count < max; count++) + { + startDate = [[modifiedDates objectAtIndex: count] + hour: 0 minute: 0 second: 0]; + *(rp->ModifiedInstanceDates + count) = [startDate asMinutesSince1601]; + } + + deletedDates = [modifiedDates mutableCopy]; + [deletedDates autorelease]; + [deletedDates + addObjectsFromArray: [event exceptionDatesWithTimeZone: utcTZ]]; + [deletedDates sortUsingFunction: NSDateCompare context: NULL]; + + max = [deletedDates count]; + rp->DeletedInstanceCount = max; + rp->DeletedInstanceDates = talloc_array (memCtx, uint32_t, max); + for (count = 0; count < max; count++) + { + startDate = [[deletedDates objectAtIndex: count] + hour: 0 minute: 0 second: 0]; + *(rp->DeletedInstanceDates + count) = [startDate asMinutesSince1601]; + } } @end diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 1a5fc64d0..2dd78074b 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -273,7 +273,7 @@ sogo_context_get_path(void *backend_object, TALLOC_CTX *mem_ctx, if (backend_object) { wrapper = backend_object; - context = wrapper->MAPIStoreSOGoObject; + context = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [context getPath: path ofFMID: fmid inMemCtx: mem_ctx]; @@ -303,7 +303,7 @@ sogo_context_get_root_folder(void *backend_object, TALLOC_CTX *mem_ctx, if (backend_object) { wrapper = backend_object; - context = wrapper->MAPIStoreSOGoObject; + context = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [context getRootFolder: &folder withFID: fid]; @@ -342,7 +342,7 @@ sogo_folder_open_folder(void *folder_object, TALLOC_CTX *mem_ctx, uint64_t fid, if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder openFolder: &childFolder withFID: fid]; @@ -382,7 +382,7 @@ sogo_folder_create_folder(void *folder_object, TALLOC_CTX *mem_ctx, if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder createFolder: &childFolder withRow: aRow andFID: fid]; @@ -421,7 +421,7 @@ sogo_folder_delete(void *folder_object) if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder deleteFolder]; @@ -449,7 +449,7 @@ sogo_folder_get_child_count(void *folder_object, enum mapistore_table_type table if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder getChildCount: child_count ofTableType: table_type]; @@ -481,7 +481,7 @@ sogo_folder_open_message(void *folder_object, if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder openMessage: &message @@ -519,7 +519,7 @@ sogo_folder_create_message(void *folder_object, if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder createMessage: &message @@ -551,7 +551,7 @@ sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags) if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder deleteMessageWithMID: mid andFlags: flags]; @@ -584,10 +584,10 @@ sogo_folder_move_copy_messages(void *folder_object, if (folder_object) { wrapper = folder_object; - targetFolder = wrapper->MAPIStoreSOGoObject; + targetFolder = wrapper->instance; wrapper = source_folder_object; - sourceFolder = wrapper->MAPIStoreSOGoObject; + sourceFolder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; @@ -623,7 +623,7 @@ sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx, if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder getDeletedFMIDs: fmidsp @@ -658,7 +658,7 @@ sogo_folder_open_table(void *folder_object, TALLOC_CTX *mem_ctx, if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder getTable: &table @@ -693,7 +693,7 @@ sogo_folder_modify_permissions(void *folder_object, uint8_t flags, if (folder_object) { wrapper = folder_object; - folder = wrapper->MAPIStoreSOGoObject; + folder = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [folder modifyPermissions: permissions @@ -725,7 +725,7 @@ sogo_message_get_message_data(void *message_object, if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; [message getMessageData: msg_dataP @@ -756,7 +756,7 @@ sogo_message_create_attachment (void *message_object, TALLOC_CTX *mem_ctx, void if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [message createAttachment: &attachment inAID: aidp]; @@ -789,7 +789,7 @@ sogo_message_open_attachment (void *message_object, TALLOC_CTX *mem_ctx, if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [message getAttachment: &attachment withAID: aid]; @@ -821,7 +821,7 @@ sogo_message_get_attachment_table (void *message_object, TALLOC_CTX *mem_ctx, vo if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [message getAttachmentTable: &table @@ -856,7 +856,7 @@ sogo_message_modify_recipients (void *message_object, if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [message modifyRecipientsWithRecipients: recipients @@ -887,7 +887,7 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag) if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [message setReadFlag: flag]; @@ -916,7 +916,7 @@ sogo_message_save (void *message_object) if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [message saveMessage]; @@ -945,7 +945,7 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags) if (message_object) { wrapper = message_object; - message = wrapper->MAPIStoreSOGoObject; + message = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [message submitWithFlags: flags]; @@ -962,11 +962,11 @@ sogo_message_submit (void *message_object, enum SubmitFlags flags) } static enum mapistore_error -sogo_message_attachment_open_embedded_message -(void *attachment_object, - TALLOC_CTX *mem_ctx, void **message_object, - uint64_t *midP, - struct mapistore_message **msg) +sogo_message_attachment_open_embedded_message (void *attachment_object, + TALLOC_CTX *mem_ctx, + void **message_object, + uint64_t *midP, + struct mapistore_message **msg) { struct MAPIStoreTallocWrapper *wrapper; NSAutoreleasePool *pool; @@ -979,7 +979,7 @@ sogo_message_attachment_open_embedded_message if (attachment_object) { wrapper = attachment_object; - attachment = wrapper->MAPIStoreSOGoObject; + attachment = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [attachment openEmbeddedMessage: &message @@ -999,6 +999,42 @@ sogo_message_attachment_open_embedded_message return rc; } +static enum mapistore_error +sogo_message_attachment_create_embedded_message (void *attachment_object, + TALLOC_CTX *mem_ctx, + void **message_object, + struct mapistore_message **msg) +{ + struct MAPIStoreTallocWrapper *wrapper; + NSAutoreleasePool *pool; + MAPIStoreAttachment *attachment; + MAPIStoreEmbeddedMessage *message; + int rc; + + DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + + if (attachment_object) + { + wrapper = attachment_object; + attachment = wrapper->instance; + GSRegisterCurrentThread (); + pool = [NSAutoreleasePool new]; + rc = [attachment createEmbeddedMessage: &message + withMAPIStoreMsg: msg + inMemCtx: mem_ctx]; + if (rc == MAPISTORE_SUCCESS) + *message_object = [message tallocWrapper: mem_ctx]; + [pool release]; + GSUnregisterCurrentThread (); + } + else + { + rc = sogo_backend_unexpected_error(); + } + + return rc; +} + static enum mapistore_error sogo_table_get_available_properties(void *table_object, TALLOC_CTX *mem_ctx, struct SPropTagArray **propertiesP) { @@ -1012,7 +1048,7 @@ static enum mapistore_error sogo_table_get_available_properties(void *table_obje if (table_object) { wrapper = table_object; - table = wrapper->MAPIStoreSOGoObject; + table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [table getAvailableProperties: propertiesP inMemCtx: mem_ctx]; @@ -1040,7 +1076,7 @@ sogo_table_set_columns (void *table_object, uint16_t count, enum MAPITAGS *prope if (table_object) { wrapper = table_object; - table = wrapper->MAPIStoreSOGoObject; + table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [table setColumns: properties @@ -1069,7 +1105,7 @@ sogo_table_set_restrictions (void *table_object, struct mapi_SRestriction *restr if (table_object) { wrapper = table_object; - table = wrapper->MAPIStoreSOGoObject; + table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; [table setRestrictions: restrictions]; @@ -1100,7 +1136,7 @@ sogo_table_set_sort_order (void *table_object, struct SSortOrderSet *sort_order, if (table_object) { wrapper = table_object; - table = wrapper->MAPIStoreSOGoObject; + table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; [table setSortOrder: sort_order]; @@ -1133,7 +1169,7 @@ sogo_table_get_row (void *table_object, TALLOC_CTX *mem_ctx, if (table_object) { wrapper = table_object; - table = wrapper->MAPIStoreSOGoObject; + table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [table getRow: data withRowID: row_id andQueryType: query_type @@ -1164,7 +1200,7 @@ sogo_table_get_row_count (void *table_object, if (table_object) { wrapper = table_object; - table = wrapper->MAPIStoreSOGoObject; + table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [table getRowCount: row_countp @@ -1193,7 +1229,7 @@ sogo_table_handle_destructor (void *table_object, uint32_t handle_id) if (table_object) { wrapper = table_object; - table = wrapper->MAPIStoreSOGoObject; + table = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; [table destroyHandle: handle_id]; @@ -1223,7 +1259,7 @@ static enum mapistore_error sogo_properties_get_available_properties(void *objec if (object) { wrapper = object; - propObject = wrapper->MAPIStoreSOGoObject; + propObject = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [propObject getAvailableProperties: propertiesP inMemCtx: mem_ctx]; @@ -1254,7 +1290,7 @@ sogo_properties_get_properties (void *object, if (object) { wrapper = object; - propObject = wrapper->MAPIStoreSOGoObject; + propObject = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [propObject getProperties: data withTags: properties @@ -1284,7 +1320,7 @@ sogo_properties_set_properties (void *object, struct SRow *aRow) if (object) { wrapper = object; - propObject = wrapper->MAPIStoreSOGoObject; + propObject = wrapper->instance; GSRegisterCurrentThread (); pool = [NSAutoreleasePool new]; rc = [propObject addPropertiesFromRow: aRow]; @@ -1386,6 +1422,7 @@ int mapistore_init_backend(void) backend.message.get_attachment_table = sogo_message_get_attachment_table; backend.message.open_attachment = sogo_message_open_attachment; backend.message.open_embedded_message = sogo_message_attachment_open_embedded_message; + backend.message.create_embedded_message = sogo_message_attachment_create_embedded_message; backend.message.get_message_data = sogo_message_get_message_data; backend.message.modify_recipients = sogo_message_modify_recipients; backend.message.set_read_flag = sogo_message_set_read_flag; diff --git a/OpenChange/MAPIStoreSOGoObject.h b/OpenChange/MAPIStoreSOGoObject.h new file mode 100644 index 000000000..cacdf23b1 --- /dev/null +++ b/OpenChange/MAPIStoreSOGoObject.h @@ -0,0 +1,86 @@ +/* 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; + +- (MAPIStoreObject *) container; + +- (void) cleanupCaches; + +- (uint64_t) objectId; + +/* 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..421337505 --- /dev/null +++ b/OpenChange/MAPIStoreSOGoObject.m @@ -0,0 +1,241 @@ +/* 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; +} + +/* 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..53bfbc50c 100644 --- a/OpenChange/MAPIStoreTable.h +++ b/OpenChange/MAPIStoreTable.h @@ -25,7 +25,7 @@ #include -#import +#import "NSObject+MAPIStore.h" #undef DEBUG #include @@ -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..81a4e974e 100644 --- a/OpenChange/MAPIStoreTable.m +++ b/OpenChange/MAPIStoreTable.m @@ -841,8 +841,7 @@ static Class NSDataK, NSStringK; struct mapistore_property_data *rowData; int rc; - child = [self childAtRowID: rowId - forQueryType: queryType]; + child = [self childAtRowID: rowId forQueryType: queryType]; if (child) { rowData = talloc_array(memCtx, struct mapistore_property_data, columnsCount); @@ -874,61 +873,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/MAPIStoreTasksMessage.m b/OpenChange/MAPIStoreTasksMessage.m index e1a5a9df4..08b580085 100644 --- a/OpenChange/MAPIStoreTasksMessage.m +++ b/OpenChange/MAPIStoreTasksMessage.m @@ -91,8 +91,8 @@ return MAPISTORE_SUCCESS; } -- (int) getPidTagSubject: (void **) data // SUMMARY - inMemCtx: (TALLOC_CTX *) memCtx +- (int) getPidTagNormalizedSubject: (void **) data // SUMMARY + inMemCtx: (TALLOC_CTX *) memCtx { iCalToDo *task; 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..7e6f7ec5a 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, @@ -20,20 +20,26 @@ * Boston, MA 02111-1307, USA. */ +#import #import #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 +86,9 @@ static NSMapTable *contextsTable = nil; mapping = nil; + userDbTableExists = NO; + folderTableURL = nil; + authenticator = nil; woContext = [WOContext contextWithRequest: nil]; [woContext retain]; @@ -88,9 +97,37 @@ static NSMapTable *contextsTable = nil; return self; } +- (NSString *) _readUserPassword: (NSString *) newUsername +{ + NSString *password; + NSData *content; + id plist; + NSPropertyListFormat plistFormat; + NSString *error; + + password = nil; + + content = [NSData dataWithContentsOfFile: SAMBA_PRIVATE_DIR + @"/mapistore/SOGo/userpwds.plist"]; + if (content) + { + plist = [NSPropertyListSerialization + propertyListFromData: content + mutabilityOption: NSPropertyListImmutable + format: &plistFormat + errorDescription: &error]; + if ([plist respondsToSelector: @selector (objectForKey:)]) + password = [plist objectForKey: newUsername]; + } + + return password; +} + - (id) initWithUsername: (NSString *) newUsername andTDBIndexing: (struct tdb_wrap *) indexingTdb { + NSString *userPassword; + if ((self = [self init])) { /* "username" will be retained by table */ @@ -102,7 +139,10 @@ static NSMapTable *contextsTable = nil; authenticator = [MAPIStoreAuthenticator new]; [authenticator setUsername: username]; /* TODO: very hackish (IMAP access) */ - [authenticator setPassword: username]; + userPassword = [self _readUserPassword: newUsername]; + if ([userPassword length] == 0) + userPassword = username; + [authenticator setPassword: userPassword]; } return self; @@ -117,6 +157,8 @@ static NSMapTable *contextsTable = nil; [authenticator release]; [mapping release]; + [folderTableURL release]; + [sogoUser release]; [contextsTable removeObjectForKey: username]; @@ -213,6 +255,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.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/NSDate+MAPIStore.h b/OpenChange/NSDate+MAPIStore.h index 3c7809f79..93f09be37 100644 --- a/OpenChange/NSDate+MAPIStore.h +++ b/OpenChange/NSDate+MAPIStore.h @@ -25,9 +25,11 @@ #import +@class NSCalendarDate; + @interface NSDate (MAPIStoreDataTypes) -+ (id) dateFromMinutesSince1601: (uint32_t) minutes; ++ (NSCalendarDate *) dateFromMinutesSince1601: (uint32_t) minutes; - (uint32_t) asMinutesSince1601; + (id) dateFromFileTime: (const struct FILETIME *) timeValue; @@ -37,4 +39,6 @@ @end +NSComparisonResult NSDateCompare (id date1, id date2, void *); + #endif /* NSCALENDARDATE+MAPISTORE_H */ diff --git a/OpenChange/NSDate+MAPIStore.m b/OpenChange/NSDate+MAPIStore.m index eb873978b..06e55f1d7 100644 --- a/OpenChange/NSDate+MAPIStore.m +++ b/OpenChange/NSDate+MAPIStore.m @@ -51,7 +51,7 @@ _setupRefDate () timeZone: [NSTimeZone timeZoneWithName: @"UTC"]]; } -+ (id) dateFromMinutesSince1601: (uint32_t) minutes ++ (NSCalendarDate *) dateFromMinutesSince1601: (uint32_t) minutes { NSCalendarDate *result; @@ -129,3 +129,22 @@ _setupRefDate () } @end + +NSComparisonResult +NSDateCompare (id date1, id date2, void *ctx) +{ + NSTimeInterval secs1, secs2; + NSComparisonResult result; + + secs1 = [date1 timeIntervalSince1970]; + secs2 = [date2 timeIntervalSince1970]; + if (secs1 == secs2) + result = NSOrderedSame; + else if (secs1 < secs2) + result = NSOrderedAscending; + else + result = NSOrderedDescending; + + return result; +} + diff --git a/OpenChange/NSObject+MAPIStore.h b/OpenChange/NSObject+MAPIStore.h index 19254456f..8e992f958 100644 --- a/OpenChange/NSObject+MAPIStore.h +++ b/OpenChange/NSObject+MAPIStore.h @@ -26,10 +26,11 @@ #import #include +#include struct MAPIStoreTallocWrapper { - id MAPIStoreSOGoObject; + id instance; }; @interface NSObject (MAPIStoreTallocHelpers) @@ -49,6 +50,7 @@ struct MAPIStoreTallocWrapper - (int) getLongZero: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; - (int) getYes: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; - (int) getNo: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; +- (int) getSMTPAddrType: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; @end @@ -58,4 +60,17 @@ struct MAPIStoreTallocWrapper @end +@interface NSObject (MAPIStoreProperties) + ++ (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP + inMemCtx: (TALLOC_CTX *) memCtx; ++ (void) fillAvailableProperties: (struct SPropTagArray *) properties + withExclusions: (BOOL *) exclusions; + +- (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP + inMemCtx: (TALLOC_CTX *) memCtx; +- (BOOL) canGetProperty: (enum MAPITAGS) propTag; + +@end + #endif /* NSOBJECT_MAPISTORE_H */ diff --git a/OpenChange/NSObject+MAPIStore.m b/OpenChange/NSObject+MAPIStore.m index 475395755..7eb14a768 100644 --- a/OpenChange/NSObject+MAPIStore.m +++ b/OpenChange/NSObject+MAPIStore.m @@ -25,6 +25,7 @@ #import #import +#import "MAPIStorePropertySelectors.h" #import "MAPIStoreTypes.h" #import "NSArray+MAPIStore.h" #import "NSData+MAPIStore.h" @@ -50,7 +51,7 @@ MAPIStoreTallocWrapperDestroy (void *data) pool = [NSAutoreleasePool new]; wrapper = data; // NSLog (@"destroying wrapped object (wrapper: %p; object: %p)...\n", wrapper, wrapper->MAPIStoreSOGoObject); - [wrapper->MAPIStoreSOGoObject release]; + [wrapper->instance release]; [pool release]; GSUnregisterCurrentThread (); @@ -63,7 +64,7 @@ MAPIStoreTallocWrapperDestroy (void *data) wrapper = talloc_zero (tallocCtx, struct MAPIStoreTallocWrapper); talloc_set_destructor ((void *) wrapper, MAPIStoreTallocWrapperDestroy); - wrapper->MAPIStoreSOGoObject = self; + wrapper->instance = self; [self retain]; // NSLog (@"returning wrapper: %p; object: %p", wrapper, self); @@ -167,4 +168,104 @@ MAPIStoreTallocWrapperDestroy (void *data) return MAPISTORE_SUCCESS; } +- (int) getSMTPAddrType: (void **) data inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = [@"SMTP" asUnicodeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +@end + +@implementation NSObject (MAPIStoreProperties) + ++ (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP + inMemCtx: (TALLOC_CTX *) memCtx +{ + struct SPropTagArray *properties; + const MAPIStorePropertyGetter *classGetters; + NSUInteger count; + enum MAPITAGS propTag; + uint16_t propValue; + + properties = talloc_zero (memCtx, struct SPropTagArray); + properties->aulPropTag = talloc_array (properties, enum MAPITAGS, + MAPIStoreSupportedPropertiesCount); + classGetters = MAPIStorePropertyGettersForClass (self); + for (count = 0; count < MAPIStoreSupportedPropertiesCount; count++) + { + propTag = MAPIStoreSupportedProperties[count]; + propValue = (propTag & 0xffff0000) >> 16; + if (classGetters[propValue]) + { + properties->aulPropTag[properties->cValues] = propTag; + properties->cValues++; + } + } + + *propertiesP = properties; + + return MAPISTORE_SUCCESS; +} + ++ (void) fillAvailableProperties: (struct SPropTagArray *) properties + withExclusions: (BOOL *) exclusions +{ + TALLOC_CTX *localMemCtx; + struct SPropTagArray *subProperties; + uint16_t propId; + NSUInteger count; + + localMemCtx = talloc_zero (NULL, TALLOC_CTX); + [self getAvailableProperties: &subProperties inMemCtx: localMemCtx]; + for (count = 0; count < subProperties->cValues; count++) + { + propId = (subProperties->aulPropTag[count] >> 16); + if (!exclusions[propId]) + { + properties->aulPropTag[properties->cValues] + = subProperties->aulPropTag[count]; + properties->cValues++; + exclusions[propId] = YES; + } + } + talloc_free (localMemCtx); +} + +- (enum mapistore_error) getAvailableProperties: (struct SPropTagArray **) propertiesP + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSUInteger count; + struct SPropTagArray *availableProps; + enum MAPITAGS propTag; + + availableProps = talloc_zero (memCtx, struct SPropTagArray); + availableProps->aulPropTag = talloc_array (availableProps, enum MAPITAGS, + MAPIStoreSupportedPropertiesCount); + for (count = 0; count < MAPIStoreSupportedPropertiesCount; count++) + { + propTag = MAPIStoreSupportedProperties[count]; + if ([self canGetProperty: propTag]) + { + availableProps->aulPropTag[availableProps->cValues] = propTag; + availableProps->cValues++; + } + } + + *propertiesP = availableProps; + + return MAPISTORE_SUCCESS; +} + +- (BOOL) canGetProperty: (enum MAPITAGS) propTag +{ + uint16_t propValue; + const IMP *classGetters; + + classGetters = (IMP *) MAPIStorePropertyGettersForClass (isa); + propValue = (propTag & 0xffff0000) >> 16; + + return (classGetters[propValue] != NULL); +} + @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/MAPIStoreVolatileMessage.h b/OpenChange/SOGoMAPIDBMessage.h similarity index 68% rename from OpenChange/MAPIStoreVolatileMessage.h rename to OpenChange/SOGoMAPIDBMessage.h index 71e02c5f8..29909a60a 100644 --- a/OpenChange/MAPIStoreVolatileMessage.h +++ b/OpenChange/SOGoMAPIDBMessage.h @@ -1,6 +1,6 @@ -/* MAPIStoreVolatileMessage.h - this file is part of SOGo +/* SOGoMAPIDBMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -20,18 +20,15 @@ * Boston, MA 02111-1307, USA. */ -#ifndef MAPISTOREVOLATILEMESSAGE_H -#define MAPISTOREVOLATILEMESSAGE_H +#ifndef SOGOMAPIDBMESSAGE_H +#define SOGOMAPIDBMESSAGE_H -#import "MAPIStoreMessage.h" +#import "SOGoMAPIDBObject.h" -@interface MAPIStoreVolatileMessage : MAPIStoreMessage -{ - BOOL fetchedAttachments; - NSDate *creationTime; - NSDate *lastModificationTime; -} +@class NSDate; +@class NSString; +@interface SOGoMAPIDBMessage : SOGoMAPIDBObject @end -#endif /* MAPISTOREVOLATILEMESSAGE_H */ +#endif /* SOGOMAPIDBMESSAGE_H */ diff --git a/OpenChange/SOGoMAPIDBMessage.m b/OpenChange/SOGoMAPIDBMessage.m new file mode 100644 index 000000000..f17093be1 --- /dev/null +++ b/OpenChange/SOGoMAPIDBMessage.m @@ -0,0 +1,61 @@ +/* SOGoMAPIDBMessage.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 "SOGoMAPIDBFolder.h" + +#import "SOGoMAPIDBMessage.h" + +@implementation SOGoMAPIDBMessage + +- (Class) mapistoreMessageClass +{ + // NSArray *dirMembers; + NSString *className; + + [NSException raise: @"whereisthisusedexception" + format: @"this exception should be triggered only for tracing"]; + // /* 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 = @"MAPIStoreDBMessage"; + + className = @"nimportequoi"; + return NSClassFromString (className); +} + +@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/dbmsgreader.m b/OpenChange/dbmsgreader.m new file mode 100644 index 000000000..b4b4332b3 --- /dev/null +++ b/OpenChange/dbmsgreader.m @@ -0,0 +1,109 @@ +/* dbmsgreader.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 readerer. + Usage: dbmsgreader [username] [filename] */ + +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import "MAPIStoreUserContext.h" +#import "SOGoMAPIDBObject.h" + +#import "NSObject+PropertyList.m" + +Class MAPIStoreUserContextK, SOGoMAPIDBObjectK; + +static void +DbDumpObject (NSString *username, NSString *path) +{ + id ctx; + NSData *content; + id dbobject; + NSDictionary *record; + + ctx = [MAPIStoreUserContextK userContextWithUsername: username + andTDBIndexing: NULL]; + dbobject = [SOGoMAPIDBObjectK new]; + [dbobject setTableUrl: [ctx folderTableURL]]; + record = [dbobject lookupRecord: path newerThanVersion: -1]; + if (record) + { + content = [[record objectForKey: @"c_content"] dataByDecodingBase64]; + OCDumpPListData (content); + } + else + NSLog (@"record not found"); + + [dbobject release]; +} + +int main (int argc, char *argv[], char *envp[]) +{ + NSAutoreleasePool *pool; + SOGoProductLoader *loader; + NSUserDefaults *ud; + SoProductRegistry *registry; + NSArray *arguments; + + /* Here we work around a bug in GNUstep which decodes XML user + defaults using the system encoding rather than honouring + the encoding specified in the file. */ + putenv ("GNUSTEP_STRING_ENCODING=NSUTF8StringEncoding"); + + pool = [NSAutoreleasePool new]; + + [SOGoSystemDefaults sharedSystemDefaults]; + + /* We force the plugin to base its configuration on the SOGo tree. */ + ud = [NSUserDefaults standardUserDefaults]; + [ud registerDefaults: [ud persistentDomainForName: @"sogod"]]; + + [NSProcessInfo initializeWithArguments: argv + count: argc + environment: envp]; + + registry = [SoProductRegistry sharedProductRegistry]; + [registry scanForProductsInDirectory: SOGO_BUNDLES_DIR]; + + loader = [SOGoProductLoader productLoader]; + [loader loadProducts: [NSArray arrayWithObject: BACKEND_BUNDLE_NAME]]; + + MAPIStoreUserContextK = NSClassFromString (@"MAPIStoreUserContext"); + SOGoMAPIDBObjectK = NSClassFromString (@"SOGoMAPIDBObject"); + + arguments = [[NSProcessInfo processInfo] arguments]; + if ([arguments count] > 2) + DbDumpObject ([arguments objectAtIndex: 1], + [arguments objectAtIndex: 2]); + + [pool release]; + + return 0; +} diff --git a/OpenChange/iCalEvent+MAPIStore.h b/OpenChange/iCalEvent+MAPIStore.h new file mode 100644 index 000000000..171813e2b --- /dev/null +++ b/OpenChange/iCalEvent+MAPIStore.h @@ -0,0 +1,41 @@ +/* iCalEvent+MAPIStore.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 ICALEVENT_MAPISTORE_H +#define ICALEVENT_MAPISTORE_H + +#import + +@class MAPIStoreUserContext; +@class NSDictionary; +@class NSString; +@class SOGoUser; + +@interface iCalEvent (MAPIStoreProperties) + +- (void) updateFromMAPIProperties: (NSDictionary *) properties + inUserContext: (MAPIStoreUserContext *) userContext + withActiveUser: (SOGoUser *) activeUser; + +@end + +#endif /* ICALEVENT_MAPISTORE_H */ diff --git a/OpenChange/iCalEvent+MAPIStore.m b/OpenChange/iCalEvent+MAPIStore.m new file mode 100644 index 000000000..cacec6ea2 --- /dev/null +++ b/OpenChange/iCalEvent+MAPIStore.m @@ -0,0 +1,522 @@ +/* iCalEvent+MAPIStore.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 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. + */ + +#include +#include + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import "MAPIStoreAppointmentWrapper.h" +#import "MAPIStoreCalendarAttachment.h" +#import "MAPIStoreCalendarFolder.h" +#import "MAPIStoreContext.h" +#import "MAPIStoreMapping.h" +#import "MAPIStoreRecurrenceUtils.h" +#import "MAPIStoreTypes.h" +#import "MAPIStoreUserContext.h" +#import "NSDate+MAPIStore.h" +#import "NSData+MAPIStore.h" +#import "NSObject+MAPIStore.h" +#import "NSString+MAPIStore.h" +#import "NSValue+MAPIStore.h" + +#import "MAPIStoreCalendarMessage.h" + +#undef DEBUG +#include +#include +#include +#include +#include +#include +#include + +#import "iCalEvent+MAPIStore.h" + +@implementation iCalEvent (MAPIStoreProperties) + +- (void) _setupEventRecurrence: (NSData *) mapiRecurrenceData +{ + struct Binary_r *blob; + struct AppointmentRecurrencePattern *pattern; + + blob = [mapiRecurrenceData asBinaryInMemCtx: NULL]; + pattern = get_AppointmentRecurrencePattern (blob, blob); + [(iCalCalendar *) parent + setupRecurrenceWithMasterEntity: self + fromRecurrencePattern: &pattern->RecurrencePattern]; + talloc_free (blob); +} + +- (void) _setupEventAlarmFromProperties: (NSDictionary *) properties +{ + NSArray *alarms; + iCalAlarm *currentAlarm, *alarm = nil; + iCalTrigger *trigger; + NSNumber *delta; + NSString *action; + NSUInteger count, max; + + /* find and remove first display alarm */ + alarms = [self alarms]; + max = [alarms count]; + for (count = 0; !alarm && count < max; count++) + { + currentAlarm = [alarms objectAtIndex: count]; + action = [[currentAlarm action] lowercaseString]; + if (!action || [action isEqualToString: @"display"]) + alarm = currentAlarm; + } + + if (alarm) + [self removeChild: alarm]; + + if ([[properties objectForKey: MAPIPropertyKey (PidLidReminderSet)] + boolValue]) + { + delta + = [properties objectForKey: MAPIPropertyKey (PidLidReminderDelta)]; + if (delta) + { + alarm = [iCalAlarm new]; + [alarm setAction: @"DISPLAY"]; + trigger = [iCalTrigger elementWithTag: @"trigger"]; + [trigger setValueType: @"DURATION"]; + [trigger + setSingleValue: [NSString stringWithFormat: @"-PT%@M", delta] + forKey: @""]; + [alarm setTrigger: trigger]; + [self addToAlarms: alarm]; + [alarm release]; + } + } +} + +- (void) updateFromMAPIProperties: (NSDictionary *) properties + inUserContext: (MAPIStoreUserContext *) userContext + withActiveUser: (SOGoUser *) activeUser +{ + BOOL isAllDay; + iCalDateTime *start, *end; + iCalTimeZone *tz; + NSTimeZone *userTimeZone; + NSString *priority; + NSUInteger responseStatus = 0; + NSInteger tzOffset; + SOGoUser *ownerUser; + id value; + + // value = [properties objectForKey: MAPIPropertyKey (PidTagMessageClass)]; + // if (value) + // isException = [value isEqualToString: @"IPM.OLE.CLASS.{00061055-0000-0000-C000-000000000046}"]; + // else + // isException = NO; + + userTimeZone = [userContext timeZone]; + + /* CREATED */ + value = [properties objectForKey: MAPIPropertyKey (PidTagCreationTime)]; + if (value) + [self setCreated: value]; + + // LAST-MODIFIED = PidTagLastModificationTime + value = [properties objectForKey: MAPIPropertyKey (PidTagLastModificationTime)]; + if (value) + [self setLastModified: value]; + + /* DTSTAMP = PidLidOwnerCriticalChange or PidLidAttendeeCriticalChange */ + value = [properties objectForKey: MAPIPropertyKey (PidLidOwnerCriticalChange)]; + if (value) + [self setTimeStampAsDate: value]; + + /* SUMMARY */ + value = [properties objectForKey: MAPIPropertyKey (PidTagNormalizedSubject)]; + if (value) + [self setSummary: value]; + + // Location + value = [properties objectForKey: MAPIPropertyKey (PidLidLocation)]; + if (value) + [self setLocation: value]; + + isAllDay = [self isAllDay]; + value = [properties + objectForKey: MAPIPropertyKey (PidLidAppointmentSubType)]; + if (value) + isAllDay = [value boolValue]; + if (!isAllDay) + { + tz = [iCalTimeZone timeZoneForName: [userTimeZone name]]; + [(iCalCalendar *) parent addTimeZone: tz]; + } + else + tz = nil; + + // recurrence-id + value + = [properties objectForKey: MAPIPropertyKey (PidLidExceptionReplaceTime)]; + if (value) + { + if (!isAllDay) + { + tzOffset = [userTimeZone secondsFromGMTForDate: value]; + value = [value dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: tzOffset]; + } + [self setRecurrenceId: value]; + } + + // start + value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentStartWhole)]; + if (!value) + value = [properties objectForKey: MAPIPropertyKey (PR_START_DATE)]; + if (value) + { + start = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"]; + [start setTimeZone: tz]; + if (isAllDay) + { + [start setDate: value]; + [start setTimeZone: nil]; + } + else + { + tzOffset = [userTimeZone secondsFromGMTForDate: value]; + value = [value dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: tzOffset]; + [start setDateTime: value]; + } + } + + /* end */ + value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentEndWhole)]; + if (!value) + value = [properties objectForKey: MAPIPropertyKey (PR_END_DATE)]; + if (value) + { + end = (iCalDateTime *) [self uniqueChildWithTag: @"dtend"]; + [end setTimeZone: tz]; + if (isAllDay) + { + [end setDate: value]; + [end setTimeZone: nil]; + } + else + { + tzOffset = [[value timeZone] secondsFromGMTForDate: value]; + value = [value dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: tzOffset]; + [end setDateTime: value]; + } + } + + /* priority */ + value = [properties objectForKey: MAPIPropertyKey(PR_IMPORTANCE)]; + if (value) + { + switch ([value intValue]) + { + case 0: // IMPORTANCE_LOW + priority = @"9"; + break; + case 2: // IMPORTANCE_HIGH + priority = @"1"; + break; + default: // IMPORTANCE_NORMAL + priority = @"5"; + } + } + else + priority = @"0"; // None + [self setPriority: priority]; + + /* show time as free/busy/tentative/out of office. Possible values are: + 0x00000000 - olFree + 0x00000001 - olTentative + 0x00000002 - olBusy + 0x00000003 - olOutOfOffice */ + value = [properties objectForKey: MAPIPropertyKey(PidLidBusyStatus)]; + if (value) + { + switch ([value intValue]) + { + case 0: + [self setTransparency: @"TRANSPARENT"]; + break; + case 1: + case 2: + case 3: + default: + [self setTransparency: @"OPAQUE"]; + } + } + + /* Comment */ + value = [properties objectForKey: MAPIPropertyKey (PR_BODY_UNICODE)]; + if (!value) + { + value = [properties objectForKey: MAPIPropertyKey (PR_HTML)]; + if (value) + { + value = [[NSString alloc] initWithData: value + encoding: NSUTF8StringEncoding]; + [value autorelease]; + value = [value htmlToText]; + } + } + if (value) + { + if ([value length] == 0 || [value isEqualToString: @"\\n"]) + value = nil; + [self setComment: value]; + } + + /* recurrence */ + value = [properties + objectForKey: MAPIPropertyKey (PidLidAppointmentRecur)]; + if (value) + [self _setupEventRecurrence: value]; + + /* alarm */ + [self _setupEventAlarmFromProperties: properties]; + + // Organizer + value = [properties objectForKey: @"recipients"]; + if (value) + { + NSArray *recipients; + NSDictionary *dict; + NSString *orgEmail, *sentBy, *attEmail; + iCalPerson *person; + iCalPersonPartStat newPartStat; + NSNumber *flags, *trackStatus; + int i, effective; + BOOL organizerIsSet = NO; + + [self setOrganizer: nil]; + [self removeAllAttendees]; + + recipients = [value objectForKey: @"to"]; + effective = 0; + for (i = 0; i < [recipients count]; i++) + { + dict = [recipients objectAtIndex: i]; + person = [iCalPerson new]; + [person setCn: [dict objectForKey: @"fullName"]]; + attEmail = [dict objectForKey: @"email"]; + [person setEmail: attEmail]; + + flags = [dict objectForKey: MAPIPropertyKey (PR_RECIPIENT_FLAGS)]; + if (!flags) + { + [self logWithFormat: + @"no recipient flags specified: skipping recipient"]; + continue; + } + + if (([flags unsignedIntValue] & 0x0002)) /* recipOrganizer */ + { + [self setOrganizer: person]; + organizerIsSet = YES; + [self logWithFormat: @"organizer set via recipient flags"]; + } + else + { + BOOL isOrganizer = NO; + + // /* Work-around: it happens that Outlook still passes the + // organizer as a recipient, maybe because of a feature + // documented in a pre-mesozoic PDF still buried in a + // cavern... In that case we remove it, and we keep the + // number of effective recipients in "effective". If the + // total is 0, we remove the "ORGANIZER" too. */ + // if ([attEmail isEqualToString: orgEmail]) + // { + // [self logWithFormat: + // @"avoiding setting organizer as recipient"]; + // continue; + // } + + trackStatus = [dict objectForKey: MAPIPropertyKey (PidTagRecipientTrackStatus)]; + if (trackStatus) + { + /* FIXME: we should provide a data converter between OL + partstats and SOGo */ + switch ([trackStatus unsignedIntValue]) + { + case 0x01: /* respOrganized */ + isOrganizer = YES; + break; + case 0x02: /* respTentative */ + newPartStat = iCalPersonPartStatTentative; + break; + case 0x03: /* respAccepted */ + newPartStat = iCalPersonPartStatAccepted; + break; + case 0x04: /* respDeclined */ + newPartStat = iCalPersonPartStatDeclined; + break; + default: + newPartStat = iCalPersonPartStatNeedsAction; + } + + if (isOrganizer) + { + [self setOrganizer: person]; + organizerIsSet = YES; + [self logWithFormat: @"organizer set via track status"]; + } + else + { + [person setParticipationStatus: newPartStat]; + [person setRsvp: @"TRUE"]; + [person setRole: @"REQ-PARTICIPANT"]; + [self addToAttendees: person]; + effective++; + } + } + else + [self errorWithFormat: @"skipped recipient due" + @" to missing track status"]; + } + + [person release]; + } + + if (effective == 0) /* See work-around above */ + [self setOrganizer: nil]; + else + { + // SEQUENCE = PidLidAppointmentSequence + value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentSequence)]; + if (value) + [self setSequence: value]; + + ownerUser = [userContext sogoUser]; + if (organizerIsSet) + { + /* We must reset the participation status to the value + obtained from PidLidResponseStatus as the value in + PidTagRecipientTrackStatus is not correct. Note (hack): + the method used here requires that the user directory + from LDAP and Samba matches perfectly. This can be solved + more appropriately by making use of the sender + properties... */ + person = [self userAsAttendee: ownerUser]; + if (person) + { + value + = [properties objectForKey: MAPIPropertyKey (PidLidResponseStatus)]; + if (value) + responseStatus = [value unsignedLongValue]; + + /* FIXME: we should provide a data converter between OL partstats and + SOGo */ + switch (responseStatus) + { + case 0x02: /* respTentative */ + newPartStat = iCalPersonPartStatTentative; + break; + case 0x03: /* respAccepted */ + newPartStat = iCalPersonPartStatAccepted; + break; + case 0x04: /* respDeclined */ + newPartStat = iCalPersonPartStatDeclined; + break; + default: + newPartStat = iCalPersonPartStatNeedsAction; + } + [person setParticipationStatus: newPartStat]; + + value = [properties objectForKey: MAPIPropertyKey (PidLidAttendeeCriticalChange)]; + if (value && ![value isNever]) + [self setTimeStampAsDate: value]; + // if (newPartStat // != iCalPersonPartStatUndefined + // ) + // { + // // iCalPerson *participant; + + // // participant = [self userAsAttendee: ownerUser]; + // // [participant setParticipationStatus: newPartStat]; + // // [sogoObject saveComponent: self]; + + // [sogoObject changeParticipationStatus: newPartStat + // withDelegate: nil]; + // // [[self context] tearDownRequest]; + // } + // // }1005 + + // // else + // // { + } + } + else + { + [self errorWithFormat: @"organizer was not set although a" + @" recipient list was specified"]; + /* We must set the organizer preliminarily here because, unlike what + the doc states, Outlook does not always pass the real organizer + in the recipients list. */ + dict = [ownerUser primaryIdentity]; + person = [iCalPerson new]; + [person setCn: [dict objectForKey: @"fullName"]]; + orgEmail = [dict objectForKey: @"email"]; + [person setEmail: orgEmail]; + + if (![activeUser isEqual: ownerUser]) + { + dict = [activeUser primaryIdentity]; + sentBy = [NSString stringWithFormat: @"mailto:%@", + [dict objectForKey: @"email"]]; + [person setSentBy: sentBy]; + } + [self setOrganizer: person]; + [person release]; + } + } + } +} + +@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() diff --git a/OpenChange/samba-get-config.py b/OpenChange/samba-get-config.py new file mode 100755 index 000000000..c91c3ed44 --- /dev/null +++ b/OpenChange/samba-get-config.py @@ -0,0 +1,8 @@ +#!/usr/bin/python + +import sys +import samba.param + +a = samba.param.LoadParm() +a.load_default() +print a.get(sys.argv[1]) diff --git a/SOPE/GDLContentStore/GCSSpecialQueries.h b/SOPE/GDLContentStore/GCSSpecialQueries.h index 08c2c3e69..24330d848 100644 --- a/SOPE/GDLContentStore/GCSSpecialQueries.h +++ b/SOPE/GDLContentStore/GCSSpecialQueries.h @@ -48,4 +48,15 @@ @end +/* interfaces exposed so that categories can be created from them */ +@interface GCSPostgreSQLSpecialQueries : GCSSpecialQueries +@end + +@interface GCSMySQLSpecialQueries : GCSSpecialQueries +@end + +@interface GCSOracleSpecialQueries : GCSSpecialQueries +@end + + #endif /* GCSSPECIALQUERIES_H */ diff --git a/SOPE/GDLContentStore/GCSSpecialQueries.m b/SOPE/GDLContentStore/GCSSpecialQueries.m index 600cb742d..e99afbaf5 100644 --- a/SOPE/GDLContentStore/GCSSpecialQueries.m +++ b/SOPE/GDLContentStore/GCSSpecialQueries.m @@ -27,15 +27,6 @@ #import "GCSSpecialQueries.h" -@interface GCSPostgreSQLSpecialQueries : GCSSpecialQueries -@end - -@interface GCSMySQLSpecialQueries : GCSSpecialQueries -@end - -@interface GCSOracleSpecialQueries : GCSSpecialQueries -@end - @implementation EOAdaptorChannel (GCSSpecialQueries) - (GCSSpecialQueries *) specialQueries @@ -163,7 +154,7 @@ { static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" - @" c_name VARCHAR (255) NOT NULL PRIMARY KEY,\n" + @" c_name VARCHAR (255) PRIMARY KEY,\n" @" c_content TEXT NOT NULL,\n" @" c_creationdate INT4 NOT NULL,\n" @" c_lastmodified INT4 NOT NULL,\n" @@ -190,7 +181,7 @@ { static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (" - @" c_id VARCHAR(255) NOT NULL PRIMARY KEY," + @" c_id VARCHAR(255) PRIMARY KEY," @" c_value VARCHAR(255) NOT NULL," @" c_creationdate INT4 NOT NULL," @" c_lastseen INT4 NOT NULL)"); @@ -257,7 +248,7 @@ { static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" - @" c_name VARCHAR (255) NOT NULL PRIMARY KEY,\n" + @" c_name VARCHAR (255) PRIMARY KEY,\n" @" c_content MEDIUMTEXT NOT NULL,\n" @" c_creationdate INT NOT NULL,\n" @" c_lastmodified INT NOT NULL,\n" @@ -284,7 +275,7 @@ { static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (" - @" c_id VARCHAR(255) NOT NULL PRIMARY KEY," + @" c_id VARCHAR(255) PRIMARY KEY," @" c_value VARCHAR(255) NOT NULL," @" c_creationdate INT NOT NULL," @" c_lastseen INT NOT NULL)"); @@ -351,7 +342,7 @@ { static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (\n" - @" c_name VARCHAR2 (255) NOT NULL PRIMARY KEY,\n" + @" c_name VARCHAR2 (255) PRIMARY KEY,\n" @" c_content CLOB NOT NULL,\n" @" c_creationdate INTEGER NOT NULL,\n" @" c_lastmodified INTEGER NOT NULL,\n" @@ -377,7 +368,7 @@ { static NSString *sqlFolderFormat = (@"CREATE TABLE %@ (" - @" c_id VARCHAR2(255) NOT NULL PRIMARY KEY," + @" c_id VARCHAR2(255) PRIMARY KEY," @" c_value VARCHAR2(255) NOT NULL," @" c_creationdate INTEGER NOT NULL," @" c_lastseen INTEGER NOT NULL)"); diff --git a/SoObjects/SOGo/SOGoObject.m b/SoObjects/SOGo/SOGoObject.m index 44cc83647..8a0f0e24d 100644 --- a/SoObjects/SOGo/SOGoObject.m +++ b/SoObjects/SOGo/SOGoObject.m @@ -178,6 +178,9 @@ { if ((self = [self init])) { + if ([_name length] == 0) + [NSException raise: NSInvalidArgumentException + format: @"'_name' must not be an empty string"]; context = [[WOApplication application] context]; nameInContainer = [_name copy]; container = _container; diff --git a/Version b/Version index 0de612ba1..09503ebca 100644 --- a/Version +++ b/Version @@ -2,6 +2,6 @@ # This file is included by library makefiles to set the version information # of the executable. -MAJOR_VERSION=1 -MINOR_VERSION=3 -SUBMINOR_VERSION=17 +MAJOR_VERSION=2 +MINOR_VERSION=0 +SUBMINOR_VERSION=0 diff --git a/debian-multiarch/control b/debian-multiarch/control index 0f1790b3e..1f861a83f 100644 --- a/debian-multiarch/control +++ b/debian-multiarch/control @@ -35,6 +35,20 @@ Description: a modern and scalable groupware - development files . This package contains the development files for developing SOGo modules. +Package: sogo-openchange +Pre-Depends: ${misc:Pre-Depends} +Multi-Arch: same +Section: net +Priority: extra +Architecture: any +Depends: sogo (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: a modern and scalable groupware - OpenChange backend + SOGo is a groupware server built around OpenGroupware.org (OGo) and + the SOPE application server with focus on scalability. + . + This package contains the backend plugin for using SOGo as a backend + to OpenChange. + Package: sogo-dbg Section: debug Priority: extra diff --git a/debian-multiarch/rules b/debian-multiarch/rules index edfc67f6f..6f06fb1ac 100755 --- a/debian-multiarch/rules +++ b/debian-multiarch/rules @@ -20,6 +20,9 @@ build-arch: build-arch-stamp build-arch-stamp: config.make # Add here commands to compile the arch part of the package. $(MAKE) + if pkg-config --atleast-version=1.0 libmapi; \ + then (cd OpenChange; $(MAKE)); \ + fi touch $@ clean: @@ -31,8 +34,15 @@ clean: -find Tests -name "*.pyc" -exec rm -f {} \; if [ -f config.make ]; \ then \ + if pkg-config --atleast-version=1.0 libmapi; \ + then \ + (cd OpenChange; make clean); \ + fi; \ make clean; \ fi + -rm -f OpenChange/MAPIStorePropertySelectors.* + -find OpenChange -type d -name "unrtf-*" -exec rm -rf {} \; + -rm -f OpenChange/unrtf*-stamp -rm -f config.make dh_clean @@ -50,6 +60,18 @@ install-arch: build-arch # dh_installdirs -s $(MAKE) DESTDIR=$(DESTDIR) GNUSTEP_INSTALLATION_DOMAIN=SYSTEM install + if pkg-config --atleast-version=1.0 libmapi; \ + then \ + (cd OpenChange; \ + $(MAKE) \ + DESTDIR=$(DESTDIR) \ + GNUSTEP_INSTALLATION_DOMAIN=SYSTEM \ + install); \ + rm -f $(DESTDIR)/usr/lib/$(DEB_HOST_MULTIARCH)/mapistore_backends/libMAPIStoreSOGo.so.1; \ + rm -f $(DESTDIR)/usr/lib/$(DEB_HOST_MULTIARCH)/mapistore_backends/libMAPIStoreSOGo.so; \ + mv -f $(DESTDIR)/usr/lib/$(DEB_HOST_MULTIARCH)/mapistore_backends/libMAPIStoreSOGo.so.1.0.0 \ + $(DESTDIR)/usr/lib/$(DEB_HOST_MULTIARCH)/mapistore_backends/SOGo.so; \ + fi mkdir -p debian/tmp/etc/default cp Scripts/sogo-default debian/tmp/etc/default/sogo diff --git a/debian-multiarch/sogo-openchange.install b/debian-multiarch/sogo-openchange.install new file mode 100644 index 000000000..d3f119d33 --- /dev/null +++ b/debian-multiarch/sogo-openchange.install @@ -0,0 +1,2 @@ +usr/lib/*/mapistore_backends/* +usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore diff --git a/debian/rules b/debian/rules index 4f2ffd513..b3b41ce65 100755 --- a/debian/rules +++ b/debian/rules @@ -19,6 +19,9 @@ build-arch: build-arch-stamp build-arch-stamp: config.make # Add here commands to compile the arch part of the package. $(MAKE) + if pkg-config --atleast-version=1.0 libmapi; \ + then (cd OpenChange; $(MAKE)); \ + fi touch $@ clean: @@ -30,8 +33,15 @@ clean: -find Tests -name "*.pyc" -exec rm -f {} \; if [ -f config.make ]; \ then \ + if pkg-config --atleast-version=1.0 libmapi; \ + then \ + (cd OpenChange; make clean); \ + fi; \ make clean; \ fi + -rm -f OpenChange/MAPIStorePropertySelectors.* + -find OpenChange -type d -name "unrtf-*" -exec rm -rf {} \; + -rm -f OpenChange/unrtf*-stamp -rm -f config.make dh_clean @@ -49,6 +59,18 @@ install-arch: build-arch # dh_installdirs -s $(MAKE) DESTDIR=$(DESTDIR) GNUSTEP_INSTALLATION_DOMAIN=SYSTEM install + if pkg-config --atleast-version=1.0 libmapi; \ + then \ + (cd OpenChange; \ + $(MAKE) \ + DESTDIR=$(DESTDIR) \ + GNUSTEP_INSTALLATION_DOMAIN=SYSTEM \ + install); \ + rm -f $(DESTDIR)/usr/lib/mapistore_backends/libMAPIStoreSOGo.so.1; \ + rm -f $(DESTDIR)/usr/lib/mapistore_backends/libMAPIStoreSOGo.so; \ + mv -f $(DESTDIR)/usr/lib/mapistore_backends/libMAPIStoreSOGo.so.1.0.0 \ + $(DESTDIR)/usr/lib/mapistore_backends/SOGo.so; \ + fi mkdir -p debian/tmp/etc/default cp Scripts/sogo-default debian/tmp/etc/default/sogo