diff --git a/ChangeLog b/ChangeLog index 0899c1fe0..b2bbc2e29 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-08-28 Jean Raby + + * Scripts/openchange_cleanup.py: + New script to clean an openchange user profile + 2012-08-27 Francis Lachapelle * SoObjects/Appointments/SOGoAptMailInvitation.m, @@ -31,6 +36,229 @@ * UI/MailPartViewers/UIxMailPartHTMLViewer.m (-_sanitizeContent): fix invalid void tags to insure proper HTML decoding. Fixes #1581. +2012-08-23 Ludovic Marcotte + + * SoObjects/Mailer/SOGoMailFolder.m - added safety + checks around the ACL code so we don't crash if + we can't read the ACLs. + +2012-08-21 Wolfgang Sourdeau + + * OpenChange/MAPIStoreFolder.m (-getPidTagAccessLevel) + (-getPidTagRights, -getPidTagAccessControlListData): fixed + methods. + + * OpenChange/MAPIStoreMessage.m + (-getPidTagDeleteAfterSubmit:inMemCtx:): moved from + MAPIStoreMailMessage. + + * OpenChange/MAPIStoreContactsMessage.m + (-getPidTagAlternateRecipientAllowed:inMemCtx:) + (-getPidTagMessageFlags:inMemCtx:) + (-getPidTagDeleteAfterSubmit:inMemCtx:): new getters. + + * OpenChange/MAPIStoreGCSFolder.m + (-setChangeKey:forMessageWithKey:): removed useless method. + (-updateVersionsForMessageWithKey:withChangeKey:): set the change + key provided by the client as member of the predecessor + changelist, but never as the actual change key for the object. + This hopefully fixes the issue where Outlook deletes objects that + have a different change list than what they expect. + +2012-08-17 Wolfgang Sourdeau + + * OpenChange/MAPIStoreCalendarMessage.m + (-getPidTagMessageClass:inMemCtx:): return + "IPM.Schedule.Meeting.Request" when the owner user is an attendee. + + * OpenChange/MAPIStoreAppointmentWrapper.m + (-getPidLidAppointmentNotAllowPropose:inMemCtx): new getter that + always return "YES", in order to disallow counter proposals. + + * OpenChange/MAPIStoreContext.m (-getPath:ofFMID:inMemCtx:): + properly escape urls containing non-ascii chars. + (-getRootFoldeR:withFID:): idem. + +2012-08-16 Wolfgang Sourdeau + + * OpenChange/MAPIStoreCalendarMessage.m + (-getMessageData:inMemCtx:): when a "recipients" records is + available in the properties, we must return that list instead of + the list of attendees since it will be the most recent one. + (_fixupAppointmentObjectWithUID::): when an appointment had been + deleted, we first attempt to resurrect it from the database before + reinstantiating it, which allows the event synchronisation to + happen properly in [SOGoAppointmentObject + updateContentWithCalendar:fromRequest:]. + + * OpenChange/MAPIStoreMapping.m (_updateFolderWithURL:withURL:): + we retain and release "oldURL" to avoid releasing it when it + is replaced in the list of urls to modify. + + * OpenChange/MAPIStoreAppointmentWrapper.m + (-getPidTagInternetCodepage:inMemCtx:): new getter for a property + that is sometimes requested. + (-getPidTagBody:inMemCtx:): we return an empty string when no + "description"/"comment" is actually present. + +2012-08-15 Wolfgang Sourdeau + + * OpenChange/MAPIStoreMailFolder.m (-addProperties:): make use of + the new methods below when a mail folder has been renamed, as this + operation affects the url of mail objects. + + * OpenChange/SOGoMAPIDBObject.m (-setNameInContainer): update the + object record in the database to reflect the change of folder + name. + + * OpenChange/MAPIStoreMailContext.m (-updateURLWithFolderName): + change the folder name used in the context url to use the new + folder name after a rename operation, so that further invocations + of -url will return the right url. + + * OpenChange/MAPIStoreMailFolder.m + (-moveCopyToFolder:withNewName:isMove:isRecursive:): implemented + IMAP-based copy operation, for speed. + (-addProperties): restored the ability to rename IMAP folders by + properly updating the fid/url mapping with our new methods. + +2012-08-14 Wolfgang Sourdeau + + * OpenChange/MAPIStoreFolder.m (-moveToFolder:withNewName:): + renamed to "moveCopyToFolder:withNewName:isMove:isRecursive:", + with the ability to specify whether the operation is a move or + copy operation and whether it is recursive or not (for copy). + + * OpenChange/MAPIStoreSOGo.m (sogo_folder_move_folder): if + "target_folder_object", we do not attempt to access the + corresponding instance member. + + * OpenChange/MAPIStoreMailFolder.m (- + moveCopyMessagesWithMIDs:andCount:fromFolder:withMIDs:andChangeKeys:wantCopy:): + do not attempt to access targetChangeKeys when NULL, to avoid a + SEGFAULT. + +2012-08-14 Jean Raby + + * OpenChange/GNUmakefile: use version_info[{0,1}] instead of + version_info.{major,minor} when checking for legacy version + of python since these named attributes where added in python2.7 + +2012-08-13 Wolfgang Sourdeau + + * OpenChange/MAPIStoreSOGo.m (sogo_properties_get_uri): removed + useless backend method. + + * OpenChange/MAPIStoreFolder.m (-createFolder:withRow:andFID:): + append a "/" to the new folder url when registering with the + url/id mapper. + + * OpenChange/MAPIStoreDBFolder.m (-moveToFolder:withNewName:): + implemented method. + + * OpenChange/MAPIStoreMailFolder.m (-moveToFolder:withNewName:): + invoke changePathTo: on the dbFolder. + + * OpenChange/SOGoMAPIDBFolder.m (-changePathTo:): overriden method + in order to update children records too. + + * OpenChange/SOGoMAPIDBObject.m (-performBatchSQLQueries:) new + method to perform void queries under a transaction. + (-changePathTo:) new method that updates the references for the + object record in the dbfs table. + + * SoObjects/SOGo/NSString+Utilities.m + (-stringByReplacingPrefix:withPrefix:): new self-explicit method. + + * OpenChange/SOGoMAPIDBFolder.m + (-childKeysOfType:includeDeleted:matchingQualifier:andSortOrderings:): + records now have a c_parent_path column in order to avoid fetch + the children of children due to the nature of our "LIKE" clause. + + * OpenChange/SOGoMAPIDBObject.m (-save): records now have a + c_parent_path. + + * OpenChange/MAPIStoreMailFolder.m (-supportsSubFolders): + overriden method to return YES. + +2012-08-12 Wolfgang Sourdeau + + * OpenChange/MAPIStoreMailFolder.m (-moveToFolder:withName:): if + the new name is not provided (unlikely), the computed new name + must not have the "folder" prefix. + We now also make use of -[MAPIStoreMapping updateID:withURL:] to + change the references in the mapping database. + + * OpenChange/MAPIStoreFolder.m (-objectId): folder keys always end + with a "/" by convention. + + * OpenChange/MAPIStoreMapping.m (-updateID:withURL:): new method + that perform a change of url on container and leaf entries. + +2012-08-10 Wolfgang Sourdeau + + * OpenChange/MAPIStoreSOGo.m (sogo_properties_get_uri): new + backend method. + +2012-08-10 Ludovic Marcotte + + * Changed OpenChange/SOGoMAPIDBObject.m so we use + GNUstep's binary encoding - which is an order or + magnitude faster at encoding data than any other formats. + +2012-08-10 Wolfgang Sourdeau + + * OpenChange/MAPIStoreSOGo.m (sogo_folder_move_folder) + (sogo_folder_copy_folder): the object on which the backend method + is invoked is now the folder being moved rather than its parent. + +2012-08-09 Wolfgang Sourdeau + + * OpenChange/MAPIStoreMailFolder.m + (-moveFolderWithFID:fromFolder:withNewName:): first implementation + for IMAP folders. + + * OpenChange/MAPIStoreSOGo.m (sogo_folder_move_folder) + (sogo_folder_copy_folder): new backend methods. + (sogo_folder_move_folder): do not instantiate an NSString from a + NULL "new_folder_name" parameter. + +2012-08-08 Wolfgang Sourdeau + + * OpenChange/MAPIStoreCalendarMessage.m (-save): generate a + "nameInContainer" for the new object iif it is not set yet. If + set, we generate a new UID from it instead. + + * OpenChange/MAPIStoreMessage.m (-saveMessage): make sure that the + PidTagChangeKey and PidTagChangeNumber props are no longer set in + the properties dict after the save occurred. + + * OpenChange/MAPIApplication.m (-shouldSetupSignalHandlers): + overriden method by returning "NO". + +2012-08-07 Wolfgang Sourdeau + + * SoObjects/Appointments/SOGoAptMailNotification.m (-setupValues): + test whether each value is non-nil before adding it to the + dictionary. + + * OpenChange/MAPIStoreMailVolatileMessage.m (-save): restored + registration of message url when saved. + +2012-08-06 Wolfgang Sourdeau + + * OpenChange/MAPIStoreRecurrenceUtils.m (-[iCalRecurrenceRule + fillRecurrencePattern:withEvent:inTimeZone:inMemCtx:]): fixed a + crash occurring when the exception has no recurrence-id and + ignore the specific occurrence. + + * OpenChange/MAPIStoreMailVolatileMessage.m (MakeMessageBody): + take "attachmentParts" parameter, deduced from the ivar with the + corresponding name. + + * OpenChange/MAPIStoreSOGoObject.m (-objectId): force generation + of objectId by parent, whether it is a folder or not. + 2012-08-07 Francis Lachapelle * UI/Contacts/UIxListEditor.m (-setReferencesValue:): check for @@ -38,10 +266,16 @@ 2012-08-03 Jean Raby - * SoObjects/SOGo/LDAPSource.m (-changePasswordForLogin): - if userPasswordAlgorithm was not set or was set to "none", - use the plaintext password directly instead of using '{none}plaintext' - which isn't valid. + * SoObjects/SOGo/LDAPSource.m (changePasswordForLogin): + if userPasswordAlgorithm was not set or was set to "none", + use the plaintext password directly instead of using '{none}plaintext' + which isn't valid. + +2012-08-02 Ludovic Marcotte + + * OpenChange/MAPIStoreUserContext.m (-_readUserPassword:) + We now read per-user passwords instead of relying on + a global file. 2012-07-31 Jean Raby @@ -54,6 +288,22 @@ (-sieveScriptWithRequirements:): filters must not be conditional to each other. +2012-07-26 Wolfgang Sourdeau + + * OpenChange/iCalTimeZone+MAPIStore.[hm]: new category module. + (-asTimeZoneStructInMemCtx:): new method that returns a struct + TimeZoneStruct as a binary blob from an iCalTimeZone object. + + * OpenChange/MAPIStoreAppointmentWrapper.m + (-getPidLidTimeZoneStruct:inMemCtx:): new property getter that + returns the equivalent of the iCalTimeZone of the current event. + +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 @@ -71,6 +321,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): @@ -89,8 +348,113 @@ (_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. + +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 @@ -109,6 +473,50 @@ 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. + 2012-07-18 Ludovic Marcotte * SoObjects/Appointments/SOGoAppointmentObject.m @@ -286,6 +694,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] @@ -296,6 +723,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..c208d51c9 100644 Binary files a/Documentation/SOGo Native Microsoft Outlook Configuration.odt and b/Documentation/SOGo Native Microsoft Outlook Configuration.odt differ diff --git a/Documentation/sogo-2.png b/Documentation/sogo-2.png new file mode 100644 index 000000000..0c73b13b9 Binary files /dev/null and b/Documentation/sogo-2.png 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/EOBitmaskQualifier.h b/OpenChange/EOBitmaskQualifier.h index 263e37fc1..405a1f1fa 100644 --- a/OpenChange/EOBitmaskQualifier.h +++ b/OpenChange/EOBitmaskQualifier.h @@ -1,6 +1,6 @@ /* EOBitmaskQualifier.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/EOBitmaskQualifier.m b/OpenChange/EOBitmaskQualifier.m index c2bbf56ae..14f3eee93 100644 --- a/OpenChange/EOBitmaskQualifier.m +++ b/OpenChange/EOBitmaskQualifier.m @@ -1,6 +1,6 @@ /* EOBitmaskQualifier.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/EOQualifier+MAPI.h b/OpenChange/EOQualifier+MAPI.h index cbe65b915..9fabef4b9 100644 --- a/OpenChange/EOQualifier+MAPI.h +++ b/OpenChange/EOQualifier+MAPI.h @@ -1,6 +1,6 @@ /* EOQualifier+MAPI.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -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..65e28c6fd 100644 --- a/OpenChange/EOQualifier+MAPI.m +++ b/OpenChange/EOQualifier+MAPI.m @@ -1,6 +1,6 @@ /* EOQualifier+MAPI.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..914fe6227 --- /dev/null +++ b/OpenChange/GCSSpecialQueries+OpenChange.m @@ -0,0 +1,107 @@ +/* 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) + +/* FIXME: c_parent_path should be indexed */ + +- (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + +@end + +@implementation GCSPostgreSQLSpecialQueries (OpenChangeHelpers) + +- (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName +{ + static NSString *sqlFolderFormat + = (@"CREATE TABLE %@ (" + @" c_path VARCHAR(255) PRIMARY KEY," + @" c_parent_path VARCHAR(255)," + @" c_type SMALLINT NOT NULL," + @" c_creationdate INT4 NOT NULL," + @" c_lastmodified INT4 NOT NULL," + @" c_version INT4 NOT NULL DEFAULT 0," + @" c_deleted SMALLINT NOT NULL DEFAULT 0," + @" c_content TEXT)"); + + return [NSString stringWithFormat: sqlFolderFormat, tableName]; +} + +@end + +@implementation GCSMySQLSpecialQueries (OpenChangeHelpers) + +- (NSString *) createOpenChangeFSTableWithName: (NSString *) tableName +{ + static NSString *sqlFolderFormat + = (@"CREATE TABLE %@ (" + @" c_path VARCHAR(255) PRIMARY KEY," + @" c_parent_path VARCHAR(255)," + @" c_type TINYINT NOT NULL," + @" c_creationdate INT NOT NULL," + @" c_lastmodified INT NOT NULL," + @" c_version INT NOT NULL DEFAULT 0," + @" c_deleted TINYINT NOT NULL DEFAULT 0," + @" c_content 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_parent_path VARCHAR2(255)," + @" c_type SMALLINT NOT NULL," + @" c_creationdate INT4 NOT NULL," + @" c_lastmodified INT4 NOT NULL," + @" c_version INT4 NOT NULL DEFAULT 0," + @" c_deleted SMALLINT NOT NULL DEFAULT 0," + @" c_content CLOB)"); + + return [NSString stringWithFormat: sqlFolderFormat, tableName]; +} + +@end diff --git a/OpenChange/GNUmakefile b/OpenChange/GNUmakefile index 0f3fb1a39..68f3e8dfb 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[0] == 2 and a[1] >= 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,14 @@ $(SOGOBACKEND)_OBJC_FILES += \ NSString+MAPIStore.m \ NSValue+MAPIStore.m \ \ - EOBitmaskQualifier.m \ + iCalEvent+MAPIStore.m \ + iCalTimeZone+MAPIStore.m \ + \ + GCSSpecialQueries+OpenChange.m\ + \ EOQualifier+MAPI.m \ + \ + EOBitmaskQualifier.m $(SOGOBACKEND)_RESOURCE_FILES += \ @@ -145,7 +165,18 @@ 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/SOGo.framework/ -lSOGo \ + -L../OGoContentStore/obj/ -lOGoContentStore \ + -L../SOPE/GDLContentStore/obj/ -lGDLContentStore \ + -L../SOPE/NGCards/obj/ -lNGCards \ + -lNGObjWeb + +TEST_TOOL_NAME += $(PLREADER_TOOL) $(DBMSGREADER_TOOL) ### cflags and libs LIBMAPI_CFLAGS = $(shell pkg-config libmapi --cflags) @@ -160,7 +191,7 @@ SAMBA_LIB_DIR = $(shell pkg-config libmapistore --variable=libdir) LIBMAPI_LIBS = $(shell pkg-config libmapi --libs) LIBMAPISTORE_CFLAGS = $(shell pkg-config libmapistore --cflags) -DSAMBA_PREFIX="\"$(shell pkg-config libmapistore --variable=prefix)\"" -LIBMAPISTORE_LIBS = $(shell pkg-config libmapistore --libs) -lmapiproxy +LIBMAPISTORE_LIBS = $(shell pkg-config libmapistore --libs) -lmapiproxy -lWEExtensions $(MAPISTORESOGO)_INSTALL_DIR = $(DESTDIR)/$(SAMBA_LIB_DIR)/mapistore_backends $(MAPISTORESOGO)_LIB_DIRS += \ @@ -176,6 +207,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.h b/OpenChange/MAPIApplication.h index 2b30e692c..e96d2d545 100644 --- a/OpenChange/MAPIApplication.h +++ b/OpenChange/MAPIApplication.h @@ -1,6 +1,6 @@ /* MAPIApplication.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIApplication.m b/OpenChange/MAPIApplication.m index 8da1c1078..b4ad58073 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]; } @@ -59,6 +66,11 @@ MAPIApplication *MAPIApp = nil; return MAPIApp; } +- (BOOL) shouldSetupSignalHandlers +{ + return NO; +} + - (void) setUserContext: (MAPIStoreUserContext *) newContext { /* user contexts must not be retained here ad their holder (mapistore) diff --git a/OpenChange/MAPIStoreActiveTables.h b/OpenChange/MAPIStoreActiveTables.h index 106e73b1e..8459bd9c1 100644 --- a/OpenChange/MAPIStoreActiveTables.h +++ b/OpenChange/MAPIStoreActiveTables.h @@ -1,6 +1,6 @@ /* MAPIStoreActiveTables.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreActiveTables.m b/OpenChange/MAPIStoreActiveTables.m index d72a62f02..a9cb0c254 100644 --- a/OpenChange/MAPIStoreActiveTables.m +++ b/OpenChange/MAPIStoreActiveTables.m @@ -1,6 +1,6 @@ /* MAPIStoreActiveTables.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreAppointmentWrapper.h b/OpenChange/MAPIStoreAppointmentWrapper.h index 74b275275..aecf2200f 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.h +++ b/OpenChange/MAPIStoreAppointmentWrapper.h @@ -1,6 +1,6 @@ /* MAPIStoreAppointmentWrapper.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -23,10 +23,11 @@ #ifndef MAPISTORECALENDARWRAPPER_H #define MAPISTORECALENDARWRAPPER_H -#import #import #import +#import "MAPIStoreObjectProxy.h" + @class NSTimeZone; @class iCalAlarm; @@ -35,10 +36,11 @@ @class SOGoUser; -@interface MAPIStoreAppointmentWrapper : NSObject +@interface MAPIStoreAppointmentWrapper : MAPIStoreObjectProxy { struct mapistore_connection_info *connInfo; iCalCalendar *calendar; + iCalEvent *firstEvent; iCalEvent *event; NSTimeZone *timeZone; SOGoUser *user; @@ -120,8 +122,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..8e8e308d8 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 * @@ -20,24 +20,28 @@ * Boston, MA 02111-1307, USA. */ +#include + #import #import #import #import #import +#import #import +#import #import #import #import #import +#import #import -#import -#import #import #import #import #import +#import "iCalTimeZone+MAPIStore.h" #import "MAPIStoreRecurrenceUtils.h" #import "MAPIStoreSamDBUtils.h" #import "MAPIStoreTypes.h" @@ -49,7 +53,6 @@ #import "MAPIStoreAppointmentWrapper.h" #undef DEBUG -#include #include #include #include @@ -181,11 +184,15 @@ static NSCharacterSet *hexCharacterSet = nil; inTimeZone: (NSTimeZone *) newTimeZone withConnectionInfo: (struct mapistore_connection_info *) newConnInfo { + NSArray *events; + if ((self = [self init])) { connInfo = newConnInfo; - ASSIGN (event, newEvent); - ASSIGN (calendar, [event parent]); + ASSIGN (calendar, [newEvent parent]); + event = newEvent; + events = [calendar events]; + firstEvent = [events objectAtIndex: 0]; ASSIGN (timeZone, newTimeZone); ASSIGN (user, newUser); ASSIGN (senderEmail, newSenderEmail); @@ -198,7 +205,6 @@ static NSCharacterSet *hexCharacterSet = nil; - (void) dealloc { [calendar release]; - [event release]; [timeZone release]; [user release]; [senderEmail release]; @@ -435,7 +441,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagIconIndex: (void **) data // TODO - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { uint32_t longValue; @@ -580,7 +586,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagMessageClass: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { const char *className; @@ -626,35 +632,20 @@ static NSCharacterSet *hexCharacterSet = nil; return MAPISTORE_SUCCESS; } +- (int) getPidLidAppointmentMessageClass: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = talloc_strdup (memCtx, "IPM.Appointment"); + + return MAPISTORE_SUCCESS; +} + - (int) getPidLidFInvited: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { return [self getYes: data inMemCtx: memCtx]; } -- (int) getPidTagStartDate: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - NSCalendarDate *dateValue; - NSInteger offset; - - if ([event isRecurrent]) - dateValue = [event firstRecurrenceStartDate]; - else - dateValue = [event startDate]; - if ([event isAllDay]) - { - offset = -[timeZone secondsFromGMTForDate: dateValue]; - dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 - hours: 0 minutes: 0 - seconds: offset]; - } - [dateValue setTimeZone: utcTZ]; - *data = [dateValue asFileTimeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - - (int) getPidLidAppointmentSequence: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -718,17 +709,255 @@ static NSCharacterSet *hexCharacterSet = nil; return MAPISTORE_SUCCESS; } + +- (int) getPidLidAppointmentNotAllowPropose: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getYes: data inMemCtx: memCtx]; +} - (int) getPidLidAppointmentStartWhole: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidTagStartDate: data inMemCtx: memCtx]; + NSCalendarDate *dateValue; + NSInteger offset; + + // if ([event isRecurrent]) + // dateValue = [event firstRecurrenceStartDate]; + // else + dateValue = [event startDate]; + if ([event isAllDay]) + { + offset = -[timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + } + [dateValue setTimeZone: utcTZ]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagStartDate: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + /* "The PidTagStartDate property ([MS-OXPROPS] section 2.1077) SHOULD be + set, and when set, it MUST be equal to the value of the + PidLidAppointmentStartWhole property (section 2.2.1.5).". Not true for + exceptions, where it is the normal start date for the day of the + exception. */ + NSCalendarDate *dateValue; + NSInteger offset; + + dateValue = [event recurrenceId]; + if (!dateValue) + dateValue = [event startDate]; + [dateValue setTimeZone: timeZone]; + if ([event isAllDay]) + { + offset = -[timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + } + [dateValue setTimeZone: utcTZ]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; } - (int) getPidLidCommonStart: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidLidAppointmentStartWhole: data inMemCtx: memCtx]; + NSCalendarDate *dateValue; + NSInteger offset; + + dateValue = [firstEvent startDate]; + if ([firstEvent isAllDay]) + { + offset = -[timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + } + [dateValue setTimeZone: utcTZ]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidLidClipStart: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + enum mapistore_error rc; + NSCalendarDate *dateValue; + + if ([event isRecurrent]) + { + dateValue = [[event startDate] hour: 0 minute: 0 second: 0]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + else if ([event recurrenceId] != nil) + rc = MAPISTORE_ERR_NOT_FOUND; + else + rc = [self getPidLidAppointmentStartWhole: data inMemCtx: memCtx]; + + return rc; +} + +- (int) getPidTagExceptionStartTime: (void **) data + inMemCtx: (TALLOC_CTX *) localMemCtx +{ + enum mapistore_error rc; + NSCalendarDate *dateValue; + NSInteger offset; + + if ([event recurrenceId] != nil) + { + dateValue = [event startDate]; + [dateValue setTimeZone: timeZone]; + if (![event isAllDay]) + { + offset = [timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + } + *data = [dateValue asFileTimeInMemCtx: localMemCtx]; + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + +- (int) getPidLidAppointmentEndWhole: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSCalendarDate *dateValue; + NSInteger offset; + + // if ([event isRecurrent]) + // dateValue = [event firstRecurrenceStartDate]; + // else + dateValue = [event startDate]; + offset = [event durationAsTimeInterval]; + if ([event isAllDay]) + offset -= [timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagEndDate: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSCalendarDate *dateValue; + NSInteger offset; + + dateValue = [event recurrenceId]; + if (!dateValue) + dateValue = [event startDate]; + [dateValue setTimeZone: timeZone]; + offset = [firstEvent durationAsTimeInterval]; + if ([firstEvent isAllDay]) + offset -= [timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidLidCommonEnd: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSCalendarDate *dateValue; + NSInteger offset; + + // if ([event isRecurrent]) + // dateValue = [event firstRecurrenceStartDate]; + // else + dateValue = [firstEvent startDate]; + offset = [firstEvent durationAsTimeInterval]; + if ([event isAllDay]) + offset -= [timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidLidClipEnd: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + enum mapistore_error rc; + NSCalendarDate *dateValue; + NSInteger offset; + iCalRecurrenceRule *rrule; + + if ([event isRecurrent]) + { + rrule = [[event recurrenceRules] objectAtIndex: 0]; + dateValue = [rrule untilDate]; + if (dateValue) + { + if ([event isAllDay]) + offset = -[timeZone secondsFromGMTForDate: dateValue]; + else + offset = 0; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + } + else + dateValue = [NSCalendarDate dateWithYear: 4500 month: 8 day: 31 + hour: 23 minute: 59 second: 59 + timeZone: utcTZ]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + else if ([event recurrenceId] != nil) + rc = MAPISTORE_ERR_NOT_FOUND; + else + rc = [self getPidLidAppointmentEndWhole: data inMemCtx: memCtx]; + + return rc; +} + +- (int) getPidTagExceptionEndTime: (void **) data + inMemCtx: (TALLOC_CTX *) localMemCtx +{ + enum mapistore_error rc; + NSCalendarDate *dateValue; + NSInteger offset; + + if ([event recurrenceId] != nil) + { + dateValue = [event startDate]; + [dateValue setTimeZone: timeZone]; + offset = [event durationAsTimeInterval]; + if (![event isAllDay]) + offset += [timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + *data = [dateValue asFileTimeInMemCtx: localMemCtx]; + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; } - (int) _getEntryIdFromCN: (NSString *) cn @@ -827,7 +1056,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 +1064,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 +1072,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 +1080,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 +1122,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 +1130,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 +1138,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] @@ -892,40 +1146,6 @@ static NSCharacterSet *hexCharacterSet = nil; } /* /attendee */ -- (int) getPidTagEndDate: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - NSCalendarDate *dateValue; - NSInteger offset; - - if ([event isRecurrent]) - dateValue = [event firstRecurrenceStartDate]; - else - dateValue = [event startDate]; - offset = [event durationAsTimeInterval]; - if ([event isAllDay]) - offset -= [timeZone secondsFromGMTForDate: dateValue]; - dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 - hours: 0 minutes: 0 - seconds: offset]; - [dateValue setTimeZone: utcTZ]; - *data = [dateValue asFileTimeInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; -} - -- (int) getPidLidAppointmentEndWhole: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getPidTagEndDate: data inMemCtx: memCtx]; -} - -- (int) getPidLidCommonEnd: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getPidLidAppointmentEndWhole: data inMemCtx: memCtx]; -} - - (int) getPidLidAppointmentDuration: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -966,8 +1186,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 +1215,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 +1224,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 +1242,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 +1265,7 @@ static NSCharacterSet *hexCharacterSet = nil; } - (int) getPidTagBody: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { int rc = MAPISTORE_SUCCESS; NSString *stringValue; @@ -1053,15 +1275,23 @@ static NSCharacterSet *hexCharacterSet = nil; if ([stringValue length] > 0) *data = [stringValue asUnicodeInMemCtx: memCtx]; else - rc = MAPISTORE_ERR_NOT_FOUND; + *data = [@"" asUnicodeInMemCtx: memCtx]; return rc; } -- (int) getPidLidIsRecurring: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx +- (int) getPidTagInternetCodepage: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { - *data = MAPIBoolValue (memCtx, [event isRecurrent]); + /* ref: + http://msdn.microsoft.com/en-us/library/dd317756%28v=vs.85%29.aspx + + minimal list that should be handled: + us-ascii: 20127 + iso-8859-1: 28591 + iso-8859-15: 28605 + utf-8: 65001 */ + *data = MAPILongValue(memCtx, 65001); return MAPISTORE_SUCCESS; } @@ -1074,37 +1304,144 @@ 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; +} + +- (int) getPidLidFExceptionalBody: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getNo: data inMemCtx: memCtx]; +} + +- (int) getPidLidExceptionReplaceTime: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + enum mapistore_error rc; + NSCalendarDate *dateValue; + NSInteger offset; + + dateValue = [event recurrenceId]; + if (dateValue) + { + rc = MAPISTORE_SUCCESS; + + if ([event isAllDay]) + { + offset = -[timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + } + [dateValue setTimeZone: utcTZ]; + *data = [dateValue asFileTimeInMemCtx: memCtx]; + } + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + +- (void) _fillExceptionInfo: (struct ExceptionInfo *) exceptionInfo + andExtendedException: (struct ExtendedException *) extendedException + withException: (iCalEvent *) exceptionEvent + inMemCtx: (TALLOC_CTX *) memCtx +{ + iCalEventChanges *changes; + NSArray *changedProperties; + NSCalendarDate *dateValue; + NSInteger offset; + + changes = [iCalEventChanges changesFromEvent: event toEvent: exceptionEvent]; + + memset (exceptionInfo, 0, sizeof (struct ExceptionInfo)); + memset (extendedException, 0, sizeof (struct ExtendedException)); + extendedException->ChangeHighlight.Size = sizeof (uint32_t); + + dateValue = [exceptionEvent startDate]; + offset = [timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + exceptionInfo->StartDateTime = [dateValue asMinutesSince1601]; + extendedException->ChangeHighlight.Value = BIT_CH_START; + extendedException->StartDateTime = exceptionInfo->StartDateTime; + + dateValue = [exceptionEvent endDate]; + offset = [timeZone secondsFromGMTForDate: dateValue]; + dateValue = [dateValue dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + exceptionInfo->EndDateTime = [dateValue asMinutesSince1601]; + extendedException->ChangeHighlight.Value |= BIT_CH_END; + extendedException->EndDateTime = exceptionInfo->EndDateTime; + + dateValue = [[exceptionEvent recurrenceId] + dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: offset]; + exceptionInfo->OriginalStartDate = [dateValue asMinutesSince1601]; + extendedException->OriginalStartDate = exceptionInfo->OriginalStartDate; + + changedProperties = [changes updatedProperties]; + if ([changedProperties containsObject: @"summary"]) + { + extendedException->ChangeHighlight.Value |= BIT_CH_SUBJECT; + extendedException->Subject + = [[exceptionEvent summary] asUnicodeInMemCtx: memCtx]; + + exceptionInfo->OverrideFlags |= ARO_SUBJECT; + exceptionInfo->Subject.subjectMsg.msg + = (uint8_t *) extendedException->Subject; + /* FIXME: this will fail with non ascii chars */ + exceptionInfo->Subject.subjectMsg.msgLength2 = [[exceptionEvent summary] length]; + exceptionInfo->Subject.subjectMsg.msgLength = exceptionInfo->Subject.subjectMsg.msgLength2 + 1; + } + if ([changedProperties containsObject: @"location"]) + { + extendedException->ChangeHighlight.Value |= BIT_CH_LOCATION; + extendedException->Location + = [[exceptionEvent location] asUnicodeInMemCtx: memCtx]; + exceptionInfo->OverrideFlags |= ARO_LOCATION; + exceptionInfo->Location.locationMsg.msg + = (uint8_t *) extendedException->Location; + /* FIXME: this will fail with non ascii chars */ + exceptionInfo->Location.locationMsg.msgLength2 = [[exceptionEvent location] length]; + exceptionInfo->Location.locationMsg.msgLength = exceptionInfo->Location.locationMsg.msgLength2 + 1; + } + if ([event isAllDay] != [exceptionEvent isAllDay]) + { + exceptionInfo->OverrideFlags |= ARO_SUBTYPE; + exceptionInfo->SubType.sType = [exceptionEvent isAllDay]; + } +} + +// - (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 +1450,47 @@ _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 = 0x00003008; /* 0x3008 for compatibility with + ol2003 */ + + 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 + andExtendedException: arp->ExtendedException + count + withException: exceptionEvent + inMemCtx: arp]; + } + 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,12 +1499,100 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, else { [self errorWithFormat: @"no first occurrence found in rule: %@", rule]; - sBin = NULL; + // bin = NULL; + bin = NULL; } - return sBin; + return bin; } +/* exception 12345 + 123456 (exchange): + 81ad0102 (PT_BINARY): + named prop + guid: {00062002-0000-0000-c000-000000000046} + dispid: 0x00008216 + (163 bytes) + 04 30 04 30 0a 20 00 00 | \x04 0 \x04 0 \x0a \x00 \x00 + 00 00 00 00 00 00 a0 05 | \x00 \x00 \x00 \x00 \x00 \x00 \xa0 \x05 + 00 00 00 00 00 00 23 20 | \x00 \x00 \x00 \x00 \x00 \x00 # + 00 00 0a 00 00 00 00 00 | \x00 \x00 \x0a \x00 \x00 \x00 \x00 \x00 + 00 00 01 00 00 00 a0 c6 | \x00 \x00 \x01 \x00 \x00 \x00 \xa0 \xc6 + e6 0c 01 00 00 00 a0 c6 | \xe6 \x0c \x01 \x00 \x00 \x00 \xa0 \xc6 + e6 0c 00 c1 e6 0c df 80 | \xe6 \x0c \x00 \xc1 \xe6 \x0c \xdf \x80 + e9 5a 06 30 00 00 08 30 | \xe9 Z \x06 0 \x00 \x00 \x08 0 + 00 00 66 03 00 00 84 03 | \x00 \x00 f \x03 \x00 \x00 \x84 \x03 + 00 00 01 00 e8 c9 e6 0c | \x00 \x00 \x01 \x00 \xe8 \xc9 \xe6 \x0c + f6 ca e6 0c 06 ca e6 0c | \xf6 \xca \xe6 \x0c \x06 \xca \xe6 \x0c + 11 00 06 00 05 00 31 32 | \x11 \x00 \x06 \x00 \x05 \x00 1 2 + 33 34 35 07 00 06 00 31 | 3 4 5 \x07 \x00 \x06 \x00 1 + 32 33 34 35 36 00 00 00 | 2 3 4 5 6 \x00 \x00 \x00 + 00 00 00 00 00 e8 c9 e6 | \x00 \x00 \x00 \x00 \x00 \xe8 \xc9 \xe6 + 0c f6 ca e6 0c 06 ca e6 | \x0c \xf6 \xca \xe6 \x0c \x06 \xca \xe6 + 0c 05 00 31 00 32 00 33 | \x0c \x05 \x00 1 \x00 2 \x00 3 + 00 34 00 35 00 06 00 31 | \x00 4 \x00 5 \x00 \x06 \x00 1 + 00 32 00 33 00 34 00 35 | \x00 2 \x00 3 \x00 4 \x00 5 + 00 36 00 00 00 00 00 00 | \x00 6 \x00 \x00 \x00 \x00 \x00 \x00 + 00 00 00 | \x00 \x00 \x00 + +openchange: + 918b0102 (PT_BINARY): + named prop + guid: {00062002-0000-0000-c000-000000000046} + dispid: 0x00008216 + (167 bytes) + + +recurrence pattern + readerversion: 04 30 + writerversion: 04 30 + recurfrequency: 0a 20 (daily) + patterntype: 00 00 + calendartype: 00 00 + firstdatetime: 00 00 00 00 + period: a0 05 00 00 (1440 minutes) + slidingflag: 00 00 00 00 + patterntypespecific: (0 bytes) + endtype: 23 20 00 00 + occurrencecount: *00->0a 00 00 00 (meaningless since no enddate) + firstdow: 00 00 00 00 + deletedicount: 01 00 00 00 + deletedinstancedates: (1) + a0 c6 e6 0c + modifiedicount: 01 00 00 00 + modifiedinstancedates: (1) + a0 c6 e6 0c + startdate: 00 c1 e6 0c + enddate: df 80 e9 5a +ReaderVersion2: 06 30 00 00 +WriterVersion2: 08 30 00 00 +StartTimeOffset: 66 03 00 00 +EndTimeOffset: 84 03 00 00 +ExceptionCount: 01 00 +ExceptionInfos: (1) + StartDateTime: *e7->e8 *ca->c9 e6 0c + EndDateTime: *e6->f6 *cb->ca e6 0c + OriginalStartDate: *a0->06 *c6->ca e6 0c + OverrideFlags: 11 00 + SubjectLength2: 06 00 + SubjectLength: 05 00 + Subject: 31 32 33 34 35 + LocationLength2: 07 00 + LocationLength: 06 00 + Location: 31 32 33 34 35 36 +ReservedBlock1Size: 00 00 00 00 +ExtendedException: (1) + ReservedBlockEE1Size: 00 00 00 00 + StartDateTime: *e7->e8 *ca->c9 e6 0c + EndDateTime: *e6->f6 *cb->ca e6 0c + OriginalStartDate: *a0->06 *c6->ca e6 0c + WideCharSubjectLength *06->05 + WideCharSubject: 00 31 00 32 00 33 00 34 00 35 00 [2bytes sup: 00 00] + LocationLength: *07->06 + Location 00 31 00 32 00 33 00 34 00 35 00 36 00 00 + ReservedBlockEE2Size: 00 00 00 00 +ReservedBlockEE2Size: 00 00 00 00 +*/ + - (int) getPidLidAppointmentRecur: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -1515,4 +1972,41 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, return MAPISTORE_ERR_NOT_FOUND; } +- (int) getPidLidTimeZoneDescription: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + enum mapistore_error rc; + NSString *tzid; + + tzid = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] + value: 0 ofAttribute: @"tzid"]; + if ([tzid length] > 0) + { + *data = [tzid asUnicodeInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + +- (int) getPidLidTimeZoneStruct: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + enum mapistore_error rc; + iCalTimeZone *icalTZ; + + icalTZ = [(iCalDateTime *) [event firstChildWithTag: @"dtstart"] timeZone]; + if (icalTZ) + { + *data = [icalTZ asTimeZoneStructInMemCtx: memCtx]; + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + @end diff --git a/OpenChange/MAPIStoreAttachment.h b/OpenChange/MAPIStoreAttachment.h index f9716f7e7..c859e7c8a 100644 --- a/OpenChange/MAPIStoreAttachment.h +++ b/OpenChange/MAPIStoreAttachment.h @@ -1,6 +1,6 @@ /* MAPIStoreAttachment.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -40,10 +40,16 @@ 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; +/* move & copy operations */ +- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment; + /* subclasses */ - (MAPIStoreEmbeddedMessage *) openEmbeddedMessage; - (MAPIStoreEmbeddedMessage *) createEmbeddedMessage; diff --git a/OpenChange/MAPIStoreAttachment.m b/OpenChange/MAPIStoreAttachment.m index 59c8832df..05cdaec15 100644 --- a/OpenChange/MAPIStoreAttachment.m +++ b/OpenChange/MAPIStoreAttachment.m @@ -1,6 +1,6 @@ /* MAPIStoreAttachment.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -28,6 +28,7 @@ #import "MAPIStoreMapping.h" #import "MAPIStoreMessage.h" #import "MAPIStoreTypes.h" +#import "NSObject+MAPIStore.h" #undef DEBUG #include @@ -90,6 +91,12 @@ return MAPISTORE_SUCCESS; } +- (int) getPidTagAccessLevel: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getLongZero: data inMemCtx: memCtx]; +} + - (int) openEmbeddedMessage: (MAPIStoreEmbeddedMessage **) messagePtr withMID: (uint64_t *) mid withMAPIStoreMsg: (struct mapistore_message **) mapistoreMsgPtr @@ -103,20 +110,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); } @@ -137,6 +158,30 @@ return ULLONG_MAX; } +- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment +{ + void *attachMethod; + enum mapistore_error error; + MAPIStoreEmbeddedMessage *embeddedMessage, *newEmbeddedMessage; + + [self copyPropertiesToObject: newAttachment]; + + attachMethod = NULL; + error = [self getProperty: &attachMethod + withTag: PidTagAttachMethod + inMemCtx: NULL]; + if (error == MAPISTORE_SUCCESS && attachMethod) + { + if (*(uint32_t *) attachMethod == afEmbeddedMessage) + { + embeddedMessage = [self openEmbeddedMessage]; + newEmbeddedMessage = [newAttachment createEmbeddedMessage]; + [embeddedMessage copyToMessage: newEmbeddedMessage]; + } + talloc_free (attachMethod); + } +} + /* subclasses */ - (MAPIStoreEmbeddedMessage *) openEmbeddedMessage { diff --git a/OpenChange/MAPIStoreAttachmentTable.h b/OpenChange/MAPIStoreAttachmentTable.h index 94f57e551..d066a7b8c 100644 --- a/OpenChange/MAPIStoreAttachmentTable.h +++ b/OpenChange/MAPIStoreAttachmentTable.h @@ -1,6 +1,6 @@ /* MAPIStoreAttachmentTable.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreAttachmentTable.m b/OpenChange/MAPIStoreAttachmentTable.m index bdf8d960e..61c82dd1b 100644 --- a/OpenChange/MAPIStoreAttachmentTable.m +++ b/OpenChange/MAPIStoreAttachmentTable.m @@ -1,6 +1,6 @@ /* MAPIStoreAttachmentTable.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreAuthenticator.h b/OpenChange/MAPIStoreAuthenticator.h index 985de43b5..fc41d25d1 100644 --- a/OpenChange/MAPIStoreAuthenticator.h +++ b/OpenChange/MAPIStoreAuthenticator.h @@ -1,7 +1,7 @@ /* MAPIStoreAuthenticator.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreAuthenticator.m b/OpenChange/MAPIStoreAuthenticator.m index 023a68e83..c3174a615 100644 --- a/OpenChange/MAPIStoreAuthenticator.m +++ b/OpenChange/MAPIStoreAuthenticator.m @@ -1,6 +1,6 @@ /* MAPIStoreAuthenticator.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreCalendarAttachment.h b/OpenChange/MAPIStoreCalendarAttachment.h index d95c3f560..9dce8d17e 100644 --- a/OpenChange/MAPIStoreCalendarAttachment.h +++ b/OpenChange/MAPIStoreCalendarAttachment.h @@ -1,6 +1,6 @@ /* MAPIStoreCalendarAttachment.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..cbe63c6d7 100644 --- a/OpenChange/MAPIStoreCalendarAttachment.m +++ b/OpenChange/MAPIStoreCalendarAttachment.m @@ -1,6 +1,6 @@ /* MAPIStoreCalendarAttachment.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -20,9 +20,22 @@ * Boston, MA 02111-1307, USA. */ -#import "MAPIStoreTypes.h" +#import +#import +#import +#import -#import "MAPIStoreEmbeddedMessage.h" +#import +#import + +#import "iCalEvent+MAPIStore.h" +#import "MAPIStoreCalendarEmbeddedMessage.h" +#import "MAPIStoreTypes.h" +#import "MAPIStoreUserContext.h" +#import "NSDate+MAPIStore.h" +#import "NSData+MAPIStore.h" +#import "NSObject+MAPIStore.h" +#import "NSString+MAPIStore.h" #import "MAPIStoreCalendarAttachment.h" @@ -34,12 +47,42 @@ @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; +} + +- (NSString *) nameInContainer +{ + return [[event uniqueChildWithTag: @"recurrence-id"] + flattenedValuesForKey: @""]; +} + - (int) getPidTagAttachmentHidden: (void **) data inMemCtx: (TALLOC_CTX *) localMemCtx { - *data = MAPIBoolValue (localMemCtx, YES); - - return MAPISTORE_SUCCESS; + return [self getYes: data inMemCtx: localMemCtx]; } - (int) getPidTagAttachmentFlags: (void **) data @@ -50,34 +93,69 @@ return MAPISTORE_SUCCESS; } +- (int) getPidTagAttachmentLinkId: (void **) data + inMemCtx: (TALLOC_CTX *) localMemCtx +{ + return [self getLongZero: data inMemCtx: localMemCtx]; +} + +- (int) getPidTagAttachFlags: (void **) data + inMemCtx: (TALLOC_CTX *) localMemCtx +{ + return [self getLongZero: data inMemCtx: localMemCtx]; +} + - (int) getPidTagAttachMethod: (void **) data inMemCtx: (TALLOC_CTX *) localMemCtx { - *data = MAPILongValue (localMemCtx, 0x00000005); /* afEmbeddedMessage */ + *data = MAPILongValue (localMemCtx, afEmbeddedMessage); return MAPISTORE_SUCCESS; } -// case PidTagExceptionStartTime: -// case PidTagExceptionEndTime: +- (int) getPidTagAttachEncoding: (void **) data + inMemCtx: (TALLOC_CTX *) localMemCtx +{ + *data = [[NSData data] asBinaryInMemCtx: localMemCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagDisplayName: (void **) data + inMemCtx: (TALLOC_CTX *) localMemCtx +{ + *data = "Untitled"; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagAttachmentContactPhoto: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getNo: data inMemCtx: memCtx]; +} + // 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/MAPIStoreCalendarContext.h b/OpenChange/MAPIStoreCalendarContext.h index 96df4d1c2..e6f804805 100644 --- a/OpenChange/MAPIStoreCalendarContext.h +++ b/OpenChange/MAPIStoreCalendarContext.h @@ -1,6 +1,6 @@ /* MAPIStoreCalendarContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreCalendarContext.m b/OpenChange/MAPIStoreCalendarContext.m index 279e9a081..035741afb 100644 --- a/OpenChange/MAPIStoreCalendarContext.m +++ b/OpenChange/MAPIStoreCalendarContext.m @@ -1,6 +1,6 @@ /* MAPIStoreCalendarContext.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * 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..7fa3274c3 --- /dev/null +++ b/OpenChange/MAPIStoreCalendarEmbeddedMessage.m @@ -0,0 +1,208 @@ +/* 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) getPidTagMessageFlags: (void **) data // TODO + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = MAPILongValue (memCtx, MSGFLAG_UNMODIFIED); + + 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]; +} + +/* discarded properties */ + +- (int) getPidLidAppointmentLastSequence: (void **) + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidLidMeetingWorkspaceUrl: (void **) + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidLidContacts: (void **) + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagSensitivity: (void **) + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidLidPrivate: (void **) + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidNameKeywords: (void **) + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (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.h b/OpenChange/MAPIStoreCalendarFolder.h index 8c483f9c9..fd6c5d20f 100644 --- a/OpenChange/MAPIStoreCalendarFolder.h +++ b/OpenChange/MAPIStoreCalendarFolder.h @@ -1,6 +1,6 @@ /* MAPIStoreCalendarFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreCalendarFolder.m b/OpenChange/MAPIStoreCalendarFolder.m index 71dcddb4e..eeb5bb81e 100644 --- a/OpenChange/MAPIStoreCalendarFolder.m +++ b/OpenChange/MAPIStoreCalendarFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreCalendarFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..8b2de759d 100644 --- a/OpenChange/MAPIStoreCalendarMessage.h +++ b/OpenChange/MAPIStoreCalendarMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreCalendarMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..afdbb98b0 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreCalendarMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -33,8 +33,11 @@ #import #import #import +#import +#import #import #import +#import #import #import #import @@ -44,11 +47,13 @@ #import #import #import +#import #import #import #import #import +#import "iCalEvent+MAPIStore.h" #import "MAPIStoreAppointmentWrapper.h" #import "MAPIStoreCalendarAttachment.h" #import "MAPIStoreCalendarFolder.h" @@ -76,6 +81,8 @@ // extern void ndr_print_AppointmentRecurrencePattern(struct ndr_print *ndr, const char *name, const struct AppointmentRecurrencePattern *r); +static Class NSArrayK; + @implementation SOGoAppointmentObject (MAPIStoreExtension) - (Class) mapistoreMessageClass @@ -87,11 +94,101 @@ @implementation MAPIStoreCalendarMessage ++ (void) initialize +{ + NSArrayK = [NSArray class]; +} + ++ (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; + iCalEvent *event; + + 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]; + event = [events objectAtIndex: count]; + [attachment setEvent: event]; + newKey = [[event uniqueChildWithTag: @"recurrence-id"] + flattenedValuesForKey: @""]; + [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 +196,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 { @@ -141,106 +210,17 @@ - (int) getPidTagMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = talloc_strdup (memCtx, "IPM.Appointment"); + SOGoUser *owner; + + owner = [[self userContext] sogoUser]; + if ([masterEvent userAsAttendee: owner]) + *data = talloc_strdup (memCtx, "IPM.Schedule.Meeting.Request"); + else + *data = talloc_strdup (memCtx, "IPM.Appointment"); return MAPISTORE_SUCCESS; } -- (int) getPidLidAppointmentMessageClass: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx -{ - *data = talloc_strdup (memCtx, "IPM.Appointment"); - - 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 +231,154 @@ 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 { + static NSString *recTypes[] = {@"orig", @"to", @"cc", @"bcc"}; + static NSInteger recTypesValue[] = {MAPI_ORIG, MAPI_TO, MAPI_CC, MAPI_BCC}; struct mapistore_message *msgData; + NSDictionary *recipients, *contactInfos; + NSString *email; + NSArray *attendees; + NSDictionary *attendee; + SOGoUserManager *mgr; + struct mapistore_message_recipient *recipient; + NSUInteger nRecType, maxRecTypes, count, max, propCount; + NSObject *currentValue; [super getMessageData: &msgData inMemCtx: memCtx]; - [[self appointmentWrapper] fillMessageData: msgData - inMemCtx: memCtx]; + + /* The presence of the "recipients" meta-property means that our most recent + list of recipients has not been saved yet and that we must return that + one instead of the one stored in the event. */ + recipients = [properties objectForKey: @"recipients"]; + if (recipients) + { + mgr = [SOGoUserManager sharedUserManager]; + + /* TODO: this code might need to be moved into MAPIStoreMessage */ + msgData->columns = set_SPropTagArray (msgData, 9, + PR_OBJECT_TYPE, + PR_DISPLAY_TYPE, + PR_7BIT_DISPLAY_NAME_UNICODE, + PR_SMTP_ADDRESS_UNICODE, + PR_SEND_INTERNET_ENCODING, + PR_RECIPIENT_DISPLAY_NAME_UNICODE, + PR_RECIPIENT_FLAGS, + PR_RECIPIENT_ENTRYID, + PR_RECIPIENT_TRACKSTATUS); + + maxRecTypes = sizeof(recTypes) / sizeof(recTypes[0]); + for (nRecType = 0; nRecType < maxRecTypes; nRecType++) + { + attendees = [recipients objectForKey: recTypes[nRecType]]; + max = [attendees count]; + if (max > 0) + { + msgData->recipients_count += max; + msgData->recipients = talloc_realloc(msgData, + msgData->recipients, struct + mapistore_message_recipient, msgData->recipients_count); + recipient = msgData->recipients; + for (count = 0; count < max; count++) + { + attendee = [attendees objectAtIndex: count]; + recipient->type = recTypesValue[nRecType]; + email = [attendee objectForKey: @"email"]; + if (email) + { + contactInfos + = [mgr contactInfosForUserWithUIDorEmail: email]; + recipient->username = [[contactInfos + objectForKey: @"c_uid"] + asUnicodeInMemCtx: msgData]; + } + else + recipient->username = NULL; + + recipient->data = talloc_array(msgData, void *, + msgData->columns->cValues); + for (propCount = 0; + propCount < msgData->columns->cValues; + propCount++) + { + currentValue = [attendee objectForKey: MAPIPropertyKey (msgData->columns->aulPropTag[propCount])]; + [currentValue getValue: recipient->data + propCount + forTag: msgData->columns->aulPropTag[propCount] + inMemCtx: msgData]; + } + recipient++; + } + } + } + } + else + { + /* 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 +413,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 +422,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]; @@ -567,14 +441,61 @@ return uid; } +- (SOGoAppointmentObject *) _resurrectRecord: (NSString *) cname + fromFolder: (SOGoAppointmentFolder *) folder +{ + NSArray *records; + EOQualifier *qualifier; + EOFetchSpecification *fs; + GCSFolder *ocsFolder; + SOGoAppointmentObject *newObject; + NSMutableDictionary *newRecord; + static NSArray *childRecordFields = nil; + + if (!childRecordFields) + { + childRecordFields = [NSArray arrayWithObjects: @"c_name", + @"c_creationdate", @"c_lastmodified", + @"c_content", nil]; + [childRecordFields retain]; + } + + ocsFolder = [folder ocsFolder]; + + qualifier + = [EOQualifier qualifierWithQualifierFormat: + [NSString stringWithFormat: @"c_name='%@'", cname]]; + fs = [EOFetchSpecification fetchSpecificationWithEntityName: [ocsFolder folderName] + qualifier: qualifier + sortOrderings: nil]; + records = [ocsFolder fetchFields: childRecordFields + fetchSpecification: fs + ignoreDeleted: NO]; + if ([records isKindOfClass: NSArrayK] && [records count]) + { + newRecord = [[records objectAtIndex: 0] mutableCopy]; + [newRecord setObject: [NSNumber numberWithInt: 0] + forKey: @"c_version"]; + newObject = [SOGoAppointmentObject objectWithRecord: newRecord + inContainer: folder]; + [newRecord autorelease]; + [newObject setIsNew: NO]; + } + else + newObject = nil; + + + return newObject; +} + - (void) _fixupAppointmentObjectWithUID: (NSString *) uid { NSString *cname, *url; MAPIStoreMapping *mapping; uint64_t objectId; + WOContext *woContext; SOGoAppointmentFolder *folder; SOGoAppointmentObject *newObject; - WOContext *woContext; cname = [[container sogoObject] resourceNameForEventUID: uid]; if (cname) @@ -585,12 +506,21 @@ mapping = [self mapping]; url = [NSString stringWithFormat: @"%@%@", [container url], cname]; - folder = [container sogoObject]; + folder = [sogoObject container]; + /* reinstantiate the old sogo object and attach it to self */ woContext = [[self userContext] woContext]; if (isNew) - newObject = [SOGoAppointmentObject objectWithName: cname - inContainer: folder]; + { + /* event could have been deleted, let's try to resurrect it */ + newObject = [self _resurrectRecord: cname fromFolder: folder]; + if (!newObject) + { + newObject = [SOGoAppointmentObject objectWithName: cname + inContainer: folder]; + [newObject setIsNew: YES]; + } + } else { /* dissociate the object url from the old object's id */ @@ -613,50 +543,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 +568,39 @@ return rc; } +- (void) _updateAttachedEvents +{ + NSArray *allAttachments; + NSUInteger count, max; + NSString *uid, *summary; + iCalEvent *event; + MAPIStoreCalendarAttachment *attachment; + + /* ensure that all exception events have the same UID as the master */ + uid = [masterEvent uid]; + summary = [masterEvent summary]; + + allAttachments = [attachmentParts allValues]; + max = [allAttachments count]; + for (count = 0; count < max; count++) + { + attachment = [allAttachments objectAtIndex: count]; + event = [attachment event]; + if ([[event summary] length] == 0) + [event setSummary: summary]; + [event setUid: 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, *nameInContainer; + // iCalEvent *newEvent; // iCalPerson *userPerson; - NSUInteger responseStatus = 0; - NSInteger tzOffset; - SOGoUser *activeUser, *ownerUser; - id value; + SOGoUser *activeUser; + NSRange rangeOfDot; if (isNew) { @@ -703,397 +608,49 @@ 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]; + { + /* We create a UID from the nameInContainer, or the reverse if the + latter is already set... */ + nameInContainer = [sogoObject nameInContainer]; + if (nameInContainer) + { + rangeOfDot = [nameInContainer rangeOfString: @"." + options: NSBackwardsSearch]; + if (rangeOfDot.location == NSNotFound) + uid = nameInContainer; + else + uid = [nameInContainer substringToIndex: rangeOfDot.location]; + } + else + { + uid = [SOGoObject globallyUniqueObjectId]; + nameInContainer = [NSString stringWithFormat: @"%@.ics", uid]; + [sogoObject setNameInContainer: nameInContainer]; + } + } + [masterEvent setUid: 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]; } @@ -1107,14 +664,17 @@ MAPIStoreCalendarAttachment *newAttachment; uint32_t newAid; NSString *newKey; + iCalEvent *newEvent; newAid = [[self attachmentKeys] count]; newAttachment = [MAPIStoreCalendarAttachment - mapiStoreObjectWithSOGoObject: nil - inContainer: self]; - [newAttachment setIsNew: YES]; + mapiStoreObjectInContainer: self]; [newAttachment setAID: newAid]; + newEvent = [iCalEvent groupWithTag: @"vevent"]; + [newAttachment setEvent: newEvent]; + [calendar addToEvents: newEvent]; + newKey = [NSString stringWithFormat: @"%ul", newAid]; [attachmentParts setObject: newAttachment forKey: newKey]; diff --git a/OpenChange/MAPIStoreCalendarMessageTable.h b/OpenChange/MAPIStoreCalendarMessageTable.h index 1bed13a1b..eeccbc455 100644 --- a/OpenChange/MAPIStoreCalendarMessageTable.h +++ b/OpenChange/MAPIStoreCalendarMessageTable.h @@ -1,6 +1,6 @@ /* MAPIStoreCalendarMessageTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreCalendarMessageTable.m b/OpenChange/MAPIStoreCalendarMessageTable.m index 6d897b772..6844d8433 100644 --- a/OpenChange/MAPIStoreCalendarMessageTable.m +++ b/OpenChange/MAPIStoreCalendarMessageTable.m @@ -1,6 +1,6 @@ /* MAPIStoreCalendarMessageTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsAttachment.h b/OpenChange/MAPIStoreContactsAttachment.h index b8f0d16e3..c4a368849 100644 --- a/OpenChange/MAPIStoreContactsAttachment.h +++ b/OpenChange/MAPIStoreContactsAttachment.h @@ -1,6 +1,6 @@ /* MAPIStoreContactsAttachment.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsAttachment.m b/OpenChange/MAPIStoreContactsAttachment.m index 00fc652d6..f578dbc61 100644 --- a/OpenChange/MAPIStoreContactsAttachment.m +++ b/OpenChange/MAPIStoreContactsAttachment.m @@ -1,6 +1,6 @@ /* MAPIStoreContactsAttachment.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsContext.h b/OpenChange/MAPIStoreContactsContext.h index 9e1e45498..68120215e 100644 --- a/OpenChange/MAPIStoreContactsContext.h +++ b/OpenChange/MAPIStoreContactsContext.h @@ -1,6 +1,6 @@ /* MAPIStoreContactsContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsContext.m b/OpenChange/MAPIStoreContactsContext.m index 967b1ccd3..bfef33e27 100644 --- a/OpenChange/MAPIStoreContactsContext.m +++ b/OpenChange/MAPIStoreContactsContext.m @@ -1,6 +1,6 @@ /* MAPIStoreContactsContext.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsFolder.h b/OpenChange/MAPIStoreContactsFolder.h index c269a6cfc..2bade99f7 100644 --- a/OpenChange/MAPIStoreContactsFolder.h +++ b/OpenChange/MAPIStoreContactsFolder.h @@ -1,6 +1,6 @@ /* MAPIStoreContactsFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsFolder.m b/OpenChange/MAPIStoreContactsFolder.m index 3e7fe71c5..fc0c35840 100644 --- a/OpenChange/MAPIStoreContactsFolder.m +++ b/OpenChange/MAPIStoreContactsFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreContactsFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsMessage.h b/OpenChange/MAPIStoreContactsMessage.h index f22a077a1..48d5bafb0 100644 --- a/OpenChange/MAPIStoreContactsMessage.h +++ b/OpenChange/MAPIStoreContactsMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreContactsMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsMessage.m b/OpenChange/MAPIStoreContactsMessage.m index c8af5c05b..c02eb8cbd 100644 --- a/OpenChange/MAPIStoreContactsMessage.m +++ b/OpenChange/MAPIStoreContactsMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreContactsMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * Ludovic Marcotte @@ -35,6 +35,7 @@ #import #import +#import "MAPIStoreAttachment.h" #import "MAPIStoreContactsAttachment.h" #import "MAPIStoreContactsFolder.h" #import "MAPIStorePropertySelectors.h" @@ -109,6 +110,28 @@ return MAPISTORE_SUCCESS; } +- (int) getPidTagAlternateRecipientAllowed: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx + +{ + return [self getYes: data inMemCtx: memCtx]; +} + +- (int) getPidTagMessageFlags: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = MAPILongValue (memCtx, MSGFLAG_READ); + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagDeleteAfterSubmit: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx + +{ + return [self getNo: data inMemCtx: memCtx]; +} + - (int) getPidTagMessageClass: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -179,8 +202,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]; } @@ -188,13 +211,34 @@ - (int) getPidLidFileUnder: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidTagDisplayName: data inMemCtx: memCtx]; + NSString *surName, *givenName, *middleName; + NSMutableString *fileUnder; + CardElement *n; + + n = [[sogoObject vCard] n]; + surName = [n flattenedValueAtIndex: 0 + forKey: @""]; + fileUnder = [surName mutableCopy]; + [fileUnder autorelease]; + [fileUnder appendString: @","]; + givenName = [n flattenedValueAtIndex: 1 + forKey: @""]; + if ([givenName length] > 0) + [fileUnder appendFormat: @" %@", givenName]; + middleName = [n flattenedValueAtIndex: 2 + forKey: @""]; + if ([middleName length] > 0) + [fileUnder appendFormat: @" %@", middleName]; + + *data = [fileUnder asUnicodeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; } - (int) getPidLidFileUnderId: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = MAPILongValue (memCtx, 0xffffffff); + *data = MAPILongValue (memCtx, 0x00008017); /* what ol2003 sets */ return MAPISTORE_SUCCESS; } @@ -208,7 +252,7 @@ vCard = [sogoObject vCard]; fn = [vCard fn]; email = [vCard preferredEMail]; - *data = [[NSString stringWithFormat: @"%@ <%@>", fn, email] + *data = [[NSString stringWithFormat: @"%@ (%@)", fn, email] asUnicodeInMemCtx: memCtx]; return MAPISTORE_SUCCESS; @@ -217,7 +261,8 @@ - (int) getPidLidEmail1OriginalDisplayName: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidLidEmail1DisplayName: data inMemCtx: memCtx]; + return [self getPidLidEmail1EmailAddress: data + inMemCtx: memCtx]; } - (int) getPidLidEmail1EmailAddress: (void **) data @@ -767,8 +812,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/MAPIStoreContactsMessageTable.h b/OpenChange/MAPIStoreContactsMessageTable.h index 56a317cb0..0563f9b2e 100644 --- a/OpenChange/MAPIStoreContactsMessageTable.h +++ b/OpenChange/MAPIStoreContactsMessageTable.h @@ -1,6 +1,6 @@ /* MAPIStoreContactsMessageTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContactsMessageTable.m b/OpenChange/MAPIStoreContactsMessageTable.m index 406329bab..524ed06c3 100644 --- a/OpenChange/MAPIStoreContactsMessageTable.m +++ b/OpenChange/MAPIStoreContactsMessageTable.m @@ -1,6 +1,6 @@ /* MAPIStoreContactsMessageTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -74,10 +74,12 @@ static Class MAPIStoreContactsMessageK, NGMailAddressK, NSDataK, NSStringK; forKey: MAPIPropertyKey (PidLidEmail2EmailAddress)]; [knownProperties setObject: @"c_mail" forKey: MAPIPropertyKey (PidLidEmail3EmailAddress)]; - [knownProperties setObject: @"c_cn" - forKey: MAPIPropertyKey (PR_DISPLAY_NAME_UNICODE)]; [knownProperties setObject: @"c_cn" forKey: MAPIPropertyKey (PidLidFileUnder)]; + [knownProperties setObject: @"c_cn" + forKey: MAPIPropertyKey (PidTagDisplayName)]; + [knownProperties setObject: @"c_cn" + forKey: MAPIPropertyKey (PidTagSubject)]; } return [knownProperties objectForKey: MAPIPropertyKey (property)]; @@ -213,7 +215,11 @@ static Class MAPIStoreContactsMessageK, NGMailAddressK, NSDataK, NSStringK; [knownProperties setObject: @"c_cn" forKey: MAPIPropertyKey (PidLidFileUnder)]; [knownProperties setObject: @"c_cn" - forKey: MAPIPropertyKey (PR_DISPLAY_NAME_UNICODE)]; + forKey: MAPIPropertyKey (PidTagDisplayName)]; + [knownProperties setObject: @"c_cn" + forKey: MAPIPropertyKey (PidTagSubject)]; + [knownProperties setObject: @"c_cn" + forKey: MAPIPropertyKey (PidTagNormalizedSubject)]; } return [knownProperties objectForKey: MAPIPropertyKey (property)]; diff --git a/OpenChange/MAPIStoreContext.h b/OpenChange/MAPIStoreContext.h index fdea9bbd1..d57ffeb74 100644 --- a/OpenChange/MAPIStoreContext.h +++ b/OpenChange/MAPIStoreContext.h @@ -1,6 +1,6 @@ /* MAPIStoreContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreContext.m b/OpenChange/MAPIStoreContext.m index 17907e93b..dceed826f 100644 --- a/OpenChange/MAPIStoreContext.m +++ b/OpenChange/MAPIStoreContext.m @@ -1,6 +1,6 @@ /* MAPIStoreContext.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -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]; @@ -363,7 +366,8 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) NSString *objectURL, *url; // TDB_DATA key, dbuf; - url = [contextUrl absoluteString]; + url = [[contextUrl absoluteString] + stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; objectURL = [[userContext mapping] urlFromID: fmid]; if (objectURL) { @@ -414,39 +418,46 @@ static inline NSURL *CompleteURLFromMapistoreURI (const char *uri) MAPIStoreFolder *baseFolder; SOGoFolder *currentFolder; WOContext *woContext; - NSString *path; + NSString *path, *urlString; NSArray *pathComponents; NSUInteger count, max; mapping = [userContext mapping]; if (![mapping urlFromID: newFid]) - [mapping registerURL: [contextUrl absoluteString] - withID: newFid]; - + { + urlString = [[contextUrl absoluteString] + stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; + [mapping registerURL: urlString + withID: newFid]; + } [userContext activateWithUser: activeUser]; woContext = [userContext woContext]; [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 +466,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 59% rename from OpenChange/MAPIStoreFSFolder.m rename to OpenChange/MAPIStoreDBFolder.m index 68f57545f..cacbb2376 100644 --- a/OpenChange/MAPIStoreFSFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -1,6 +1,6 @@ -/* MAPIStoreFSFolder.m - this file is part of SOGo +/* MAPIStoreDBFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -24,28 +24,32 @@ #import #import +#import +#import #import #import #import #import +#import #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 "MAPIStoreMapping.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, MAPIStoreDBFolderK; static NSString *MAPIStoreRightReadItems = @"RightsReadItems"; static NSString *MAPIStoreRightCreateItems = @"RightsCreateItems"; @@ -57,54 +61,127 @@ static NSString *MAPIStoreRightCreateSubfolders = @"RightsCreateSubfolders"; static NSString *MAPIStoreRightFolderOwner = @"RightsFolderOwner"; static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; -@implementation MAPIStoreFSFolder +@implementation MAPIStoreDBFolder + (void) initialize { EOKeyValueQualifierK = [EOKeyValueQualifier class]; + SOGoMAPIDBFolderK = [SOGoMAPIDBFolder class]; + MAPIStoreDBFolderK = [MAPIStoreDBFolder 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; +} + +- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName + isMove: (BOOL) isMove + isRecursive: (BOOL) isRecursive +{ + enum mapistore_error rc; + NSString *path, *pathComponent, *targetPath, *newPath; + NSString *newURL; + MAPIStoreMapping *mapping; + NSRange slashRange; + + if (isMove && [targetFolder isKindOfClass: MAPIStoreDBFolderK]) + { + path = [sogoObject path]; + slashRange = [path rangeOfString: @"/" options: NSBackwardsSearch]; + if (slashRange.location == NSNotFound) + [NSException raise: @"MAPIStoreIOException" + format: @"db folder path must start with a '/'"]; + else + pathComponent = [path substringFromIndex: slashRange.location + 1]; + targetPath = [[targetFolder sogoObject] path]; + newPath = [NSString stringWithFormat: @"%@/%@", + targetPath, pathComponent]; + [dbFolder changePathTo: newPath]; + + mapping = [self mapping]; + newURL = [NSString stringWithFormat: @"%@%@/", + [targetFolder url], pathComponent]; + [mapping updateID: [self objectId] + withURL: newURL]; + + [targetFolder cleanupCaches]; + + rc = MAPISTORE_SUCCESS; + } + else + rc = [super moveCopyToFolder: targetFolder withNewName: newFolderName + isMove: isMove + isRecursive: isRecursive]; + + 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 +196,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 +209,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 +254,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 61% rename from OpenChange/MAPIStoreFSMessage.m rename to OpenChange/MAPIStoreDBMessage.m index 7b7939884..2e535c7bc 100644 --- a/OpenChange/MAPIStoreFSMessage.m +++ b/OpenChange/MAPIStoreDBMessage.m @@ -1,6 +1,6 @@ -/* MAPIStoreFSMessage.m - this file is part of SOGo +/* MAPIStoreDBMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..4ef65f261 100644 --- a/OpenChange/MAPIStoreEmbeddedMessage.h +++ b/OpenChange/MAPIStoreEmbeddedMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreEmbeddedMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..562d581de 100644 --- a/OpenChange/MAPIStoreEmbeddedMessage.m +++ b/OpenChange/MAPIStoreEmbeddedMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreEmbeddedMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -23,9 +23,13 @@ #import #import "MAPIStoreAttachment.h" +#import "MAPIStoreFolder.h" +#import "NSObject+MAPIStore.h" #import "MAPIStoreEmbeddedMessage.h" +#include + static Class MAPIStoreAttachmentK; @implementation MAPIStoreEmbeddedMessage @@ -35,30 +39,116 @@ static Class MAPIStoreAttachmentK; MAPIStoreAttachmentK = [MAPIStoreAttachment class]; } -+ (id) embeddedMessageWithAttachment: (id) newAttachment +- (uint64_t) objectId { - MAPIStoreEmbeddedMessage *newMessage; + NSString *objectKey; + MAPIStoreMessage *grandParent; - newMessage = [[self alloc] initWithAttachment: newAttachment]; - [newMessage autorelease]; + grandParent = (MAPIStoreMessage *) [container container]; - return newMessage; + /* FIXME: this is a hack */ + objectKey = [NSString stringWithFormat: @"%@/%@/as-message", + [grandParent nameInContainer], + [container nameInContainer], + [self nameInContainer]]; + + return [(MAPIStoreFolder *) [grandParent container] + idForObjectWithKey: objectKey]; } -- (id) initWithAttachment: (id) newAttachment +- (int) getPidTagAccessLevel: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx { - if ((self = [self init])) - { - if ([newAttachment isKindOfClass: MAPIStoreAttachmentK]) - ASSIGN (container, newAttachment); - } - - return self; + return [self getLongZero: data inMemCtx: memCtx]; } +/* disabled properties */ +- (int) getPidTagFolderId: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagChangeKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagSourceKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (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; +} + +- (int) getPidTagInstID: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagInstanceNum: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagRowType: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagDepth: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagIconIndex: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagGenerateExchangeViews: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +- (int) getPidTagOriginalMessageClass: (void **) dataa + inMemCtx: (TALLOC_CTX *) memCtx +{ + return MAPISTORE_ERR_NOT_FOUND; +} + +/* common methods */ - (NSString *) nameInContainer { 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..509bd37be 100644 --- a/OpenChange/MAPIStoreFAIMessage.h +++ b/OpenChange/MAPIStoreFAIMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreFAIMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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/MAPIStoreFAIMessage.m b/OpenChange/MAPIStoreFAIMessage.m index ef30a9b59..99ab23c85 100644 --- a/OpenChange/MAPIStoreFAIMessage.m +++ b/OpenChange/MAPIStoreFAIMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreFAIMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreFAIMessageTable.h b/OpenChange/MAPIStoreFAIMessageTable.h index 70e12f43f..c12f20f99 100644 --- a/OpenChange/MAPIStoreFAIMessageTable.h +++ b/OpenChange/MAPIStoreFAIMessageTable.h @@ -1,6 +1,6 @@ /* MAPIStoreFAIMessageTable.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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/MAPIStoreFAIMessageTable.m b/OpenChange/MAPIStoreFAIMessageTable.m index fb7b6df1f..531299868 100644 --- a/OpenChange/MAPIStoreFAIMessageTable.m +++ b/OpenChange/MAPIStoreFAIMessageTable.m @@ -1,6 +1,6 @@ /* MAPIStoreFAIMessageTable.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * 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..a6a2707ab 100644 --- a/OpenChange/MAPIStoreFallbackContext.h +++ b/OpenChange/MAPIStoreFallbackContext.h @@ -1,6 +1,6 @@ /* MAPIStoreFallbackContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -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..ea6fa7ff3 100644 --- a/OpenChange/MAPIStoreFallbackContext.m +++ b/OpenChange/MAPIStoreFallbackContext.m @@ -1,6 +1,6 @@ /* MAPIStoreFallbackContext.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc. + * Copyright (C) 2011-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -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..262334dfc 100644 --- a/OpenChange/MAPIStoreFolder.h +++ b/OpenChange/MAPIStoreFolder.h @@ -1,6 +1,6 @@ /* MAPIStoreFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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; @@ -118,6 +123,11 @@ andChangeKeys: (struct Binary_r **) targetChangeKeys wantCopy: (uint8_t) want_copy; +- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName + isMove: (BOOL) isMove + isRecursive: (BOOL) isRecursive; + - (int) getDeletedFMIDs: (struct I8Array_r **) fmidsPtr andCN: (uint64_t *) cnPtr fromChangeNumber: (uint64_t) changeNum diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index 3e480f11d..8cb57b5ac 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -23,7 +23,9 @@ /* TODO: main key arrays must be initialized */ #import +#import #import +#import #import #import #import @@ -45,11 +47,12 @@ #import "MAPIStoreSamDBUtils.h" #import "MAPIStoreTypes.h" #import "MAPIStoreUserContext.h" +#import "NSData+MAPIStore.h" #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 +82,69 @@ 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, *escapedURL, *folderName; + NSArray *parts; + NSUInteger lastPartIdx; + MAPIStoreUserContext *userContext; + + escapedURL = [[self url] + stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; + folderURL = [NSURL URLWithString: escapedURL]; + 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 +158,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe inContainer: newContainer]) && newContainer) { - [self _setupAuxiliaryObjects]; + [self setupAuxiliaryObjects]; } return self; @@ -129,13 +168,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 +184,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 +216,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 +227,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 +308,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]; @@ -360,7 +404,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe baseURL = [self url]; if (![baseURL hasSuffix: @"/"]) baseURL = [NSString stringWithFormat: @"%@/", baseURL]; - childURL = [NSString stringWithFormat: @"%@%@", + childURL = [NSString stringWithFormat: @"%@%@/", baseURL, folderKey]; [mapping registerURL: childURL withID: fid]; childFolder = [self lookupFolder: folderKey]; @@ -383,9 +427,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (int) deleteFolder { - [propsMessage delete]; - [propsFolder delete]; - [faiFolder delete]; + // [propsMessage delete]; + [dbFolder delete]; [self cleanupCaches]; @@ -615,13 +658,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe int rc; MAPIStoreMessage *sourceMsg, *destMsg; TALLOC_CTX *memCtx; - struct SPropTagArray *availableProps; - bool *exclusions; - NSUInteger count; - enum MAPITAGS propTag; - struct SRow *aRow; - int error; - void *data; + struct SRow aRow; + struct SPropValue property; memCtx = talloc_zero (NULL, TALLOC_CTX); rc = [sourceFolder openMessage: &sourceMsg @@ -631,56 +669,23 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe if (rc != MAPISTORE_SUCCESS) goto end; - rc = [sourceMsg getAvailableProperties: &availableProps - inMemCtx: memCtx]; - if (rc != MAPISTORE_SUCCESS) - goto end; - - exclusions = talloc_array(NULL, bool, 65536); - exclusions[PR_ROW_TYPE >> 16] = true; - exclusions[PR_INSTANCE_KEY >> 16] = true; - exclusions[PR_INSTANCE_NUM >> 16] = true; - exclusions[PR_INST_ID >> 16] = true; - exclusions[PR_FID >> 16] = true; - exclusions[PR_MID >> 16] = true; - exclusions[PR_SOURCE_KEY >> 16] = true; - exclusions[PR_PARENT_SOURCE_KEY >> 16] = true; - exclusions[PR_PARENT_FID >> 16] = true; - exclusions[PR_CHANGE_KEY >> 16] = true; - exclusions[PR_PREDECESSOR_CHANGE_LIST >> 16] = true; - - aRow = talloc_zero (memCtx, struct SRow); - aRow->lpProps = talloc_array (aRow, struct SPropValue, 65535); - - for (count = 0; count < availableProps->cValues; count++) - { - propTag = availableProps->aulPropTag[count]; - if (!exclusions[propTag >> 16]) - { - error = [sourceMsg getProperty: &data - withTag: propTag - inMemCtx: aRow]; - if (error == MAPISTORE_SUCCESS && data) - { - set_SPropValue_proptag(&aRow->lpProps[aRow->cValues], propTag, data); - aRow->cValues++; - } - } - } - - if (targetChangeKey) - { - set_SPropValue_proptag(&aRow->lpProps[aRow->cValues], PR_CHANGE_KEY, targetChangeKey); - aRow->cValues++; - } - rc = [self createMessage: &destMsg withMID: targetMid isAssociated: [sourceMsg isKindOfClass: MAPIStoreFAIMessageK]]; if (rc != MAPISTORE_SUCCESS) goto end; - rc = [destMsg addPropertiesFromRow: aRow]; - if (rc != MAPISTORE_SUCCESS) - goto end; + + [sourceMsg copyToMessage: destMsg]; + + if (targetChangeKey) + { + property.ulPropTag = PidTagChangeKey; + property.value.bin = *targetChangeKey; + aRow.cValues = 1; + aRow.lpProps = &property; + rc = [destMsg addPropertiesFromRow: &aRow]; + if (rc != MAPISTORE_SUCCESS) + goto end; + } [destMsg save]; if (!wantCopy) rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: 0]; @@ -757,6 +762,122 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe return rc; } +- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName + isMove: (BOOL) isMove + isRecursive: (BOOL) isRecursive +{ + enum mapistore_error rc; + NSAutoreleasePool *pool; + struct SRow folderRow; + struct SPropValue nameProperty; + MAPIStoreFolder *subFolder, *newFolder; + NSArray *children; + MAPIStoreMapping *mapping; + MAPIStoreMessage *message, *targetMessage; + NSUInteger count, max; + NSString *childKey; + uint64_t fmid; + + /* TODO: one possible issue with this algorithm is that moved messages will + lack a version number and will all be assigned a new one, even though + they have not changed. This also means that they will be transferred + again to the client during a sync operation. */ + + if ([targetFolder supportsSubFolders]) + { + mapping = [self mapping]; + + if (!newFolderName) + newFolderName = [sogoObject displayName]; + nameProperty.ulPropTag = PidTagDisplayName; + nameProperty.value.lpszW = [newFolderName UTF8String]; + folderRow.lpProps = &nameProperty; + folderRow.cValues = 1; + rc = [targetFolder createFolder: &folderRow + withFID: [self objectId] + andKey: &childKey]; + if (rc == MAPISTORE_SUCCESS) + { + newFolder = [targetFolder lookupFolder: childKey]; + [self copyPropertiesToObject: newFolder]; + + pool = [NSAutoreleasePool new]; + children = [self messageKeys]; + max = [children count]; + for (count = 0; count < max; count++) + { + childKey = [children objectAtIndex: count]; + message = [self lookupMessage: childKey]; + targetMessage = [newFolder createMessage: NO]; + [targetMessage setIsNew: YES]; + [message copyToMessage: targetMessage]; + if (isMove) + { + fmid = [mapping idFromURL: [message url]]; + [self deleteMessageWithMID: fmid andFlags: 0]; + [mapping registerURL: [targetMessage url] + withID: fmid]; + } + [targetMessage save]; + } + [pool release]; + + pool = [NSAutoreleasePool new]; + children = [self faiMessageKeys]; + max = [children count]; + for (count = 0; count < max; count++) + { + childKey = [children objectAtIndex: count]; + message = [self lookupFAIMessage: childKey]; + targetMessage = [newFolder createMessage: YES]; + [targetMessage setIsNew: YES]; + [message copyToMessage: targetMessage]; + if (isMove) + { + fmid = [mapping idFromURL: [message url]]; + [self deleteMessageWithMID: fmid andFlags: 0]; + [mapping registerURL: [targetMessage url] + withID: fmid]; + } + [targetMessage save]; + } + [pool release]; + + if (isRecursive) + { + pool = [NSAutoreleasePool new]; + children = [self folderKeys]; + max = [children count]; + for (count = 0; count < max; count++) + { + childKey = [children objectAtIndex: count]; + subFolder = [self lookupFolder: childKey]; + [subFolder moveCopyToFolder: newFolder withNewName: nil + isMove: isMove + isRecursive: isRecursive]; + } + [pool release]; + } + + if (isMove) + { + fmid = [mapping idFromURL: [self url]]; + [mapping unregisterURLWithID: fmid]; + [self deleteFolder]; + [mapping registerURL: [newFolder url] + withID: fmid]; + } + [targetFolder cleanupCaches]; + } + [self cleanupCaches]; + } + else + rc = MAPISTORE_ERR_DENIED; + + return rc; +} + - (SOGoFolder *) aclFolder { [self subclassResponsibility: _cmd]; @@ -1004,7 +1125,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 +1137,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe currentProp++; } - [propsMessage appendProperties: propsCopy]; - [propsMessage save]; - [propsCopy release]; + [properties addEntriesFromDictionary: propsCopy]; + [dbFolder save]; } - (NSArray *) messageKeys @@ -1039,9 +1163,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 @@ -1192,7 +1317,51 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (int) getPidTagAccessLevel: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = MAPILongValue (memCtx, 0x01); + SOGoUser *ownerUser; + BOOL userIsOwner; + + ownerUser = [[self userContext] sogoUser]; + + userIsOwner = [[context activeUser] isEqual: ownerUser]; + + *data = MAPILongValue (memCtx, (userIsOwner) ? 0x01 : 0x00); + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagRights: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + uint32_t rights = 0; + SOGoUser *ownerUser; + BOOL userIsOwner; + + ownerUser = [[self userContext] sogoUser]; + + userIsOwner = [[context activeUser] isEqual: ownerUser]; + if (userIsOwner || [self subscriberCanReadMessages]) + rights |= RightsReadItems; + if (userIsOwner || [self subscriberCanCreateMessages]) + rights |= RightsCreateItems; + if (userIsOwner || [self subscriberCanModifyMessages]) + rights |= RightsEditOwn | RightsEditAll; + if (userIsOwner || [self subscriberCanDeleteMessages]) + rights |= RightsDeleteOwn | RightsDeleteAll; + if ((userIsOwner || [self subscriberCanCreateSubFolders]) + && [self supportsSubFolders]) + rights |= RightsCreateSubfolders; + if (userIsOwner) + rights |= RightsFolderOwner | RightsFolderContact; + + *data = MAPILongValue (memCtx, rights); + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagAccessControlListData: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = [[NSData data] asBinaryInMemCtx: memCtx]; return MAPISTORE_SUCCESS; } @@ -1287,6 +1456,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 +1476,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 +1488,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 +1511,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; } @@ -1354,7 +1543,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe url = [NSString stringWithFormat: @"%@/", [super url]]; else { - url = [[context url] absoluteString]; + url = [[[context url] absoluteString] + stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; if (![url hasSuffix: @"/"]) url = [NSString stringWithFormat: @"%@/", url]; } @@ -1581,9 +1771,14 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe - (uint64_t) objectId { uint64_t objectId; + NSString *folderKey; if (container) - objectId = [super objectId]; + { + folderKey = [NSString stringWithFormat: @"%@/", + [sogoObject nameInContainer]]; + objectId = [container idForObjectWithKey: folderKey]; + } else objectId = [self idForObjectWithKey: nil]; @@ -1598,12 +1793,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/MAPIStoreFolderTable.h b/OpenChange/MAPIStoreFolderTable.h index f8c2b24d0..b584c6084 100644 --- a/OpenChange/MAPIStoreFolderTable.h +++ b/OpenChange/MAPIStoreFolderTable.h @@ -1,6 +1,6 @@ /* MAPIStoreFolderTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreFolderTable.m b/OpenChange/MAPIStoreFolderTable.m index c0beed517..d76c9890e 100644 --- a/OpenChange/MAPIStoreFolderTable.m +++ b/OpenChange/MAPIStoreFolderTable.m @@ -1,6 +1,6 @@ /* MAPIStoreFolderTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreGCSBaseContext.h b/OpenChange/MAPIStoreGCSBaseContext.h index 76fba3602..8d9e57f5d 100644 --- a/OpenChange/MAPIStoreGCSBaseContext.h +++ b/OpenChange/MAPIStoreGCSBaseContext.h @@ -1,6 +1,6 @@ /* MAPIStoreGCSBaseContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreGCSBaseContext.m b/OpenChange/MAPIStoreGCSBaseContext.m index 296479251..4da73b349 100644 --- a/OpenChange/MAPIStoreGCSBaseContext.m +++ b/OpenChange/MAPIStoreGCSBaseContext.m @@ -1,6 +1,6 @@ /* MAPIStoreGCSBaseContext.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreGCSFolder.h b/OpenChange/MAPIStoreGCSFolder.h index 0d0c1e6df..1f48e034a 100644 --- a/OpenChange/MAPIStoreGCSFolder.h +++ b/OpenChange/MAPIStoreGCSFolder.h @@ -1,6 +1,6 @@ /* MAPIStoreGCSFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -34,7 +34,7 @@ @interface MAPIStoreGCSFolder : MAPIStoreFolder { - SOGoMAPIFSMessage *versionsMessage; + SOGoMAPIDBMessage *versionsMessage; NSArray *activeUserRoles; EOQualifier *componentQualifier; } @@ -45,11 +45,8 @@ withChangeKey: (NSData *) newChangeKey; - (NSNumber *) lastModifiedFromMessageChangeNumber: (NSNumber *) changeNum; - (NSNumber *) changeNumberForMessageWithKey: (NSString *) messageKey; - - (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey; - (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey; -- (void) setChangeKey: (NSData *) changeKey - forMessageWithKey: (NSString *) messageKey; - (NSArray *) activeUserRoles; diff --git a/OpenChange/MAPIStoreGCSFolder.m b/OpenChange/MAPIStoreGCSFolder.m index e5f6bbd65..a5702131f 100644 --- a/OpenChange/MAPIStoreGCSFolder.m +++ b/OpenChange/MAPIStoreGCSFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreGCSFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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 @@ -260,6 +261,7 @@ static Class NSNumberK; - (void) _setChangeKey: (NSData *) changeKey forMessageEntry: (NSMutableDictionary *) messageEntry + inChangeListOnly: (BOOL) inChangeListOnly { struct XID *xid; NSString *guid; @@ -272,12 +274,15 @@ static Class NSNumberK; globCnt = [NSData dataWithBytes: xid->Data length: xid->Size]; talloc_free (xid); - /* 1. set change key association */ - changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys: - guid, @"GUID", - globCnt, @"LocalId", - nil]; - [messageEntry setObject: changeKeyDict forKey: @"ChangeKey"]; + if (!inChangeListOnly) + { + /* 1. set change key association */ + changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys: + guid, @"GUID", + globCnt, @"LocalId", + nil]; + [messageEntry setObject: changeKeyDict forKey: @"ChangeKey"]; + } /* 2. append/update predecessor change list */ changeList = [messageEntry objectForKey: @"PredecessorChangeList"]; @@ -285,7 +290,7 @@ static Class NSNumberK; { changeList = [NSMutableDictionary new]; [messageEntry setObject: changeList - forKey: @"PredecessorChangeList"]; + forKey: @"PredecessorChangeList"]; [changeList release]; } [changeList setObject: globCnt forKey: guid]; @@ -349,6 +354,7 @@ static Class NSNumberK; [sortOrdering retain]; } + [versionsMessage reloadIfNeeded]; currentProperties = [versionsMessage properties]; lastModificationDate = [currentProperties objectForKey: @"SyncLastModificationDate"]; @@ -430,7 +436,8 @@ static Class NSNumberK; [messageEntry setObject: changeNumber forKey: @"version"]; changeKey = [self getReplicaKeyFromGlobCnt: newChangeNum >> 16]; - [self _setChangeKey: changeKey forMessageEntry: messageEntry]; + [self _setChangeKey: changeKey forMessageEntry: messageEntry + inChangeListOnly: NO]; [mapping setObject: cLastModified forKey: changeNumber]; @@ -451,7 +458,6 @@ static Class NSNumberK; forKey: @"SyncLastSynchronisationDate"]; [currentProperties setObject: lastModificationDate forKey: @"SyncLastModificationDate"]; - [versionsMessage appendProperties: currentProperties]; [versionsMessage save]; } } @@ -462,10 +468,21 @@ static Class NSNumberK; - (void) updateVersionsForMessageWithKey: (NSString *) messageKey withChangeKey: (NSData *) newChangeKey { - [self synchroniseCache]; + NSMutableDictionary *messages, *messageEntry; + [self synchroniseCache]; if (newChangeKey) - [self setChangeKey: newChangeKey forMessageWithKey: messageKey]; + { + messages = [[versionsMessage properties] objectForKey: @"Messages"]; + messageEntry = [messages objectForKey: messageKey]; + if (!messageEntry) + [NSException raise: @"MAPIStoreIOException" + format: @"no version record found for message '%@'", + messageKey]; + [self _setChangeKey: newChangeKey forMessageEntry: messageEntry + inChangeListOnly: YES]; + [versionsMessage save]; + } } - (NSNumber *) lastModifiedFromMessageChangeNumber: (NSNumber *) changeNum @@ -491,26 +508,6 @@ static Class NSNumberK; return changeNumber; } -- (void) setChangeKey: (NSData *) changeKey - forMessageWithKey: (NSString *) messageKey -{ - NSMutableDictionary *messages; - NSMutableDictionary *messageEntry; - - messages = [[versionsMessage properties] objectForKey: @"Messages"]; - messageEntry = [messages objectForKey: messageKey]; - if (!messageEntry) - { - [self synchroniseCache]; - messageEntry = [messages objectForKey: messageKey]; - if (!messageEntry) - abort (); - } - [self _setChangeKey: changeKey forMessageEntry: messageEntry]; - - [versionsMessage save]; -} - - (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey { NSDictionary *messages, *changeKeyDict; diff --git a/OpenChange/MAPIStoreGCSMessage.h b/OpenChange/MAPIStoreGCSMessage.h index 5ada9290b..cac182874 100644 --- a/OpenChange/MAPIStoreGCSMessage.h +++ b/OpenChange/MAPIStoreGCSMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreGCSMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreGCSMessage.m b/OpenChange/MAPIStoreGCSMessage.m index 95c004430..143f9ef19 100644 --- a/OpenChange/MAPIStoreGCSMessage.m +++ b/OpenChange/MAPIStoreGCSMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreGCSMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreGCSMessageTable.h b/OpenChange/MAPIStoreGCSMessageTable.h index 00b03cded..72190c221 100644 --- a/OpenChange/MAPIStoreGCSMessageTable.h +++ b/OpenChange/MAPIStoreGCSMessageTable.h @@ -1,6 +1,6 @@ /* MAPIStoreGCSMessageTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreGCSMessageTable.m b/OpenChange/MAPIStoreGCSMessageTable.m index ef4006394..74d9d3151 100644 --- a/OpenChange/MAPIStoreGCSMessageTable.m +++ b/OpenChange/MAPIStoreGCSMessageTable.m @@ -1,6 +1,6 @@ /* MAPIStoreGCSMessageTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMIME.h b/OpenChange/MAPIStoreMIME.h index 427868fca..eb2d2a6b2 100644 --- a/OpenChange/MAPIStoreMIME.h +++ b/OpenChange/MAPIStoreMIME.h @@ -1,6 +1,6 @@ /* MAPIStoreMIME.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMIME.m b/OpenChange/MAPIStoreMIME.m index b23f660e2..712cc88bc 100644 --- a/OpenChange/MAPIStoreMIME.m +++ b/OpenChange/MAPIStoreMIME.m @@ -1,6 +1,6 @@ /* MAPIStoreMIME.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMailAttachment.h b/OpenChange/MAPIStoreMailAttachment.h index 5fded594c..b04b197ab 100644 --- a/OpenChange/MAPIStoreMailAttachment.h +++ b/OpenChange/MAPIStoreMailAttachment.h @@ -1,6 +1,6 @@ /* MAPIStoreMailAttachment.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..e62250549 100644 --- a/OpenChange/MAPIStoreMailAttachment.m +++ b/OpenChange/MAPIStoreMailAttachment.m @@ -1,6 +1,6 @@ /* MAPIStoreMailAttachment.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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/MAPIStoreMailContext.h b/OpenChange/MAPIStoreMailContext.h index ab176cd1a..9e8371714 100644 --- a/OpenChange/MAPIStoreMailContext.h +++ b/OpenChange/MAPIStoreMailContext.h @@ -1,6 +1,6 @@ /* MAPIStoreMailContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -26,6 +26,9 @@ #import "MAPIStoreContext.h" @interface MAPIStoreMailContext : MAPIStoreContext + +- (void) updateURLWithFolderName: (NSString *) newFolderName; + @end @interface MAPIStoreOutboxContext : MAPIStoreMailContext diff --git a/OpenChange/MAPIStoreMailContext.m b/OpenChange/MAPIStoreMailContext.m index d91d76514..43212e513 100644 --- a/OpenChange/MAPIStoreMailContext.m +++ b/OpenChange/MAPIStoreMailContext.m @@ -1,6 +1,6 @@ /* MAPIStoreMailContext.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -23,7 +23,8 @@ #import #import #import - +#import +#import #import #import @@ -203,6 +204,34 @@ MakeDisplayFolderName (NSString *folderName) return [[userContext rootFolders] objectForKey: @"mail"]; } +- (void) updateURLWithFolderName: (NSString *) newFolderName +{ + NSString *urlString, *escapedName; + NSMutableArray *pathComponents; + BOOL hasSlash; + NSUInteger max, folderNameIdx; + NSURL *newURL; + + /* we do not need to unescape the url here as it will be reassembled later + in the method */ + urlString = [contextUrl absoluteString]; + hasSlash = [urlString hasSuffix: @"/"]; + pathComponents = [[urlString componentsSeparatedByString: @"/"] + mutableCopy]; + [pathComponents autorelease]; + max = [pathComponents count]; + if (hasSlash) + folderNameIdx = max - 2; + else + folderNameIdx = max - 1; + escapedName = [newFolderName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; + [pathComponents replaceObjectAtIndex: folderNameIdx + withObject: escapedName]; + urlString = [pathComponents componentsJoinedByString: @"/"]; + newURL = [NSURL URLWithString: urlString]; + ASSIGN (contextUrl, newURL); +} + @end @implementation MAPIStoreOutboxContext diff --git a/OpenChange/MAPIStoreMailFolder.h b/OpenChange/MAPIStoreMailFolder.h index 7e47e8c09..ad1c2dfdb 100644 --- a/OpenChange/MAPIStoreMailFolder.h +++ b/OpenChange/MAPIStoreMailFolder.h @@ -1,6 +1,6 @@ /* MAPIStoreMailFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..9bbaede63 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreMailFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -49,19 +49,20 @@ #import "MAPIStoreAppointmentWrapper.h" #import "MAPIStoreContext.h" #import "MAPIStoreFAIMessage.h" +#import "MAPIStoreMailContext.h" #import "MAPIStoreMailMessageTable.h" #import "MAPIStoreMapping.h" #import "MAPIStoreTypes.h" #import "NSData+MAPIStore.h" #import "NSString+MAPIStore.h" -#import "SOGoMAPIFSMessage.h" +#import "SOGoMAPIDBMessage.h" +#import "SOGoMAPIDBFolder.h" -#import "SOGoMAPIVolatileMessage.h" #import "MAPIStoreMailVolatileMessage.h" #import "MAPIStoreMailFolder.h" -static Class SOGoMailFolderK, MAPIStoreOutboxFolderK; +static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; #undef DEBUG #include @@ -74,6 +75,7 @@ static Class SOGoMailFolderK, MAPIStoreOutboxFolderK; + (void) initialize { SOGoMailFolderK = [SOGoMailFolder class]; + MAPIStoreMailFolderK = [MAPIStoreMailFolder class]; MAPIStoreOutboxFolderK = [MAPIStoreOutboxFolder class]; [MAPIStoreAppointmentWrapper class]; } @@ -97,8 +99,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 @@ -108,9 +111,10 @@ static Class SOGoMailFolderK, MAPIStoreOutboxFolderK; - (void) addProperties: (NSDictionary *) newProperties { - NSString *newDisplayName; + NSString *newDisplayName, *newNameInContainer; NSMutableDictionary *propsCopy; NSNumber *key; + uint64_t fid; key = MAPIPropertyKey (PR_DISPLAY_NAME_UNICODE); newDisplayName = [newProperties objectForKey: key]; @@ -119,7 +123,16 @@ static Class SOGoMailFolderK, MAPIStoreOutboxFolderK; && ![[(SOGoMailFolder *) sogoObject displayName] isEqualToString: newDisplayName]) { + fid = [self objectId]; [(SOGoMailFolder *) sogoObject renameTo: newDisplayName]; + newNameInContainer = [sogoObject nameInContainer]; + if (!container) + [(MAPIStoreMailContext *) context + updateURLWithFolderName: newNameInContainer]; + [[self mapping] updateID: fid withURL: [self url]]; + [dbFolder setNameInContainer: newNameInContainer]; + [self cleanupCaches]; + propsCopy = [newProperties mutableCopy]; [propsCopy removeObjectForKey: key]; [propsCopy autorelease]; @@ -202,7 +215,7 @@ static Class SOGoMailFolderK, MAPIStoreOutboxFolderK; } - (int) getPidTagContentUnreadCount: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { EOQualifier *searchQualifier; uint32_t longValue; @@ -393,6 +406,11 @@ static Class SOGoMailFolderK, MAPIStoreOutboxFolderK; return permissionEntries; } +- (BOOL) supportsSubFolders +{ + return YES; +} + /* synchronisation */ /* Tree: @@ -489,10 +507,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 +629,6 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) ti = [NSNumber numberWithDouble: [now timeIntervalSince1970]]; [currentProperties setObject: ti forKey: @"SyncLastSynchronisationDate"]; - [versionsMessage appendProperties: currentProperties]; [versionsMessage save]; } @@ -978,14 +993,17 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) } /* Update the change keys */ - [self synchroniseCache]; - for (count = 0; count < midCount; count++) + if (targetChangeKeys) { - changeKey = [NSData dataWithBinary: targetChangeKeys[count]]; - messageKey = [NSString stringWithFormat: @"%@.eml", - [destUIDs objectAtIndex: count]]; - [self setChangeKey: changeKey - forMessageWithKey: messageKey]; + [self synchroniseCache]; + for (count = 0; count < midCount; count++) + { + changeKey = [NSData dataWithBinary: targetChangeKeys[count]]; + messageKey = [NSString stringWithFormat: @"%@.eml", + [destUIDs objectAtIndex: count]]; + [self setChangeKey: changeKey + forMessageWithKey: messageKey]; + } } [self postNotificationsForMoveCopyMessagesWithMIDs: srcMids @@ -1002,21 +1020,133 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) return MAPISTORE_SUCCESS; } -- (MAPIStoreMessage *) createMessage +- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName + isMove: (BOOL) isMove + isRecursive: (BOOL) isRecursive { - MAPIStoreMailVolatileMessage *newMessage; - SOGoMAPIVolatileMessage *newObject; + enum mapistore_error rc; + NSURL *folderURL, *newFolderURL; + struct SRow folderRow; + struct SPropValue nameProperty; + MAPIStoreMailFolder *newFolder; + SOGoMailFolder *targetSOGoFolder; + NSMutableArray *uids; + NSArray *childKeys; + NSUInteger count, max; + NGImap4Connection *connection; + NGImap4Client *client; + NSString *newURL, *parentDBFolderPath, *childKey, *folderIMAPName, *newFolderIMAPName; + NSException *error; + MAPIStoreMapping *mapping; + NSDictionary *result; - newObject = [SOGoMAPIVolatileMessage - objectWithName: [SOGoObject globallyUniqueObjectId] - inContainer: sogoObject]; - newMessage - = [MAPIStoreMailVolatileMessage mapiStoreObjectWithSOGoObject: newObject - inContainer: self]; - - return newMessage; + if ([targetFolder isKindOfClass: MAPIStoreMailFolderK]) + { + folderURL = [sogoObject imap4URL]; + if (!newFolderName) + newFolderName = [sogoObject displayName]; + targetSOGoFolder = [targetFolder sogoObject]; + if (isMove) + { + newFolderURL = [NSURL + URLWithString: [newFolderName stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding] + relativeToURL: [targetSOGoFolder imap4URL]]; + error = [[sogoObject imap4Connection] + moveMailboxAtURL: folderURL + toURL: newFolderURL]; + if (error) + rc = MAPISTORE_ERR_DENIED; + else + { + rc = MAPISTORE_SUCCESS; + mapping = [self mapping]; + newURL = [NSString stringWithFormat: @"%@folder%@/", + [targetFolder url], newFolderName]; + [mapping updateID: [self objectId] withURL: newURL]; + parentDBFolderPath = [[targetFolder dbFolder] path]; + if (!parentDBFolderPath) + parentDBFolderPath = @""; + [dbFolder changePathTo: [NSString stringWithFormat: + @"%@/folder%@", + parentDBFolderPath, + newFolderName]]; + } + } + else + { + nameProperty.ulPropTag = PidTagDisplayName; + nameProperty.value.lpszW = [newFolderName UTF8String]; + folderRow.lpProps = &nameProperty; + folderRow.cValues = 1; + rc = [targetFolder createFolder: &folderRow + withFID: -1 + andKey: &childKey]; + if (rc == MAPISTORE_SUCCESS) + { + newFolder = [targetFolder lookupFolder: childKey]; + + connection = [sogoObject imap4Connection]; + folderIMAPName = [connection + imap4FolderNameForURL: [sogoObject imap4URL]]; + newFolderIMAPName = [connection + imap4FolderNameForURL: [[newFolder sogoObject] imap4URL]]; + client = [connection client]; + [client select: folderIMAPName]; + + childKeys = [self messageKeys]; + max = [childKeys count]; + uids = [NSMutableArray arrayWithCapacity: max]; + for (count = 0; count < max; count++) + { + childKey = [childKeys objectAtIndex: count]; + [uids addObject: [self messageUIDFromMessageKey: childKey]]; + } + + result = [client copyUids: uids + toFolder: newFolderIMAPName]; + if ([[result objectForKey: @"result"] boolValue]) + { + if (isRecursive) + { + childKeys = [self folderKeys]; + max = [childKeys count]; + for (count = 0; count < max; count++) + { + childKey = [childKeys objectAtIndex: count]; + [[self lookupFolder: childKey] + moveCopyToFolder: newFolder + withNewName: nil + isMove: NO + isRecursive: YES]; + } + } + } + else + rc = MAPISTORE_ERROR; + } + } + [targetFolder cleanupCaches]; + } + else + rc = [super moveCopyToFolder: targetFolder withNewName: newFolderName + isMove: isMove + isRecursive: isRecursive]; + + return rc; } +- (MAPIStoreMessage *) createMessage +{ + SOGoMAPIObject *childObject; + + childObject = [SOGoMAPIObject objectWithName: [SOGoMAPIObject + globallyUniqueObjectId] + inContainer: sogoObject]; + return [MAPIStoreMailVolatileMessage + mapiStoreObjectWithSOGoObject: childObject + inContainer: self]; +} - (NSArray *) rolesForExchangeRights: (uint32_t) rights { @@ -1043,8 +1173,6 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) [roles addObject: SOGoRole_ObjectViewer]; if (rights & RightsCreateSubfolders) [roles addObject: SOGoRole_FolderCreator]; - if (rights & RightsCreateSubfolders) - [roles addObject: SOGoRole_FolderCreator]; // [self logWithFormat: @"roles for rights %.8x = (%@)", rights, roles]; @@ -1069,8 +1197,6 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) rights |= RightsReadItems; if ([roles containsObject: SOGoRole_FolderCreator]) rights |= RightsCreateSubfolders; - if ([roles containsObject: SOGoRole_FolderCreator]) - rights |= RightsCreateSubfolders; if (rights != 0) rights |= RoleNone; /* actually "folder visible" */ diff --git a/OpenChange/MAPIStoreMailMessage.h b/OpenChange/MAPIStoreMailMessage.h index 378d8e490..76b7a3258 100644 --- a/OpenChange/MAPIStoreMailMessage.h +++ b/OpenChange/MAPIStoreMailMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreMailMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 85081c2db..a88e5bc04 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreMailMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * Ludovic Marcotte @@ -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 { @@ -1013,12 +1000,6 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) return [self getNo: data inMemCtx: memCtx]; } -- (int) getPidTagDeleteAfterSubmit: (void **) data // TODO - inMemCtx: (TALLOC_CTX *) memCtx -{ - return [self getNo: data inMemCtx: memCtx]; -} - - (int) getPidLidGlobalObjectId: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -1529,8 +1510,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.h b/OpenChange/MAPIStoreMailMessageTable.h index 1a5f1f8c4..8efa43c16 100644 --- a/OpenChange/MAPIStoreMailMessageTable.h +++ b/OpenChange/MAPIStoreMailMessageTable.h @@ -1,6 +1,6 @@ /* MAPIStoreMailMessageTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreMailMessageTable.m b/OpenChange/MAPIStoreMailMessageTable.m index 62dc406fd..3933b62db 100644 --- a/OpenChange/MAPIStoreMailMessageTable.m +++ b/OpenChange/MAPIStoreMailMessageTable.m @@ -1,6 +1,6 @@ /* MAPIStoreMailMessageTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..212226abf 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.h +++ b/OpenChange/MAPIStoreMailVolatileMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreMailVolatileMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..fa12130cf 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreMailVolatileMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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,85 @@ 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; +} + +- (NSDate *) creationTime +{ + return [sogoObject creationDate]; +} + +- (NSDate *) lastModificationTime +{ + return [sogoObject lastModified]; +} + +- (id) lookupAttachment: (NSString *) childKey +{ + return [attachmentParts objectForKey: childKey]; +} + - (void) getMessageData: (struct mapistore_message **) dataPtr inMemCtx: (TALLOC_CTX *) memCtx { @@ -258,9 +340,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,9 +744,11 @@ 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, NSDictionary *attachmentParts, NSString **contentType) { id messageBody, textBody; NSString *textContentType; @@ -707,22 +793,19 @@ 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, attachmentParts, &contentType); if (messageBody) { [headers setObject: contentType forKey: @"content-type"]; @@ -775,7 +858,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, - (int) submitWithFlags: (enum SubmitFlags) flags { - NSDictionary *mailProperties, *recipients; + NSDictionary *recipients; NSData *messageData; NSMutableArray *recipientEmails; NSArray *list; @@ -785,19 +868,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 +900,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,7 +915,7 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, - (void) save { - NSString *folderName, *flag, *newIdString; + NSString *folderName, *flag, *newIdString, *messageKey; NSData *changeKey, *messageData; NGImap4Connection *connection; NGImap4Client *client; @@ -858,23 +939,27 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, responseResult = [[result objectForKey: @"RawResponse"] objectForKey: @"ResponseResult"]; flag = [responseResult objectForKey: @"flag"]; + newIdString = [[flag componentsSeparatedByString: @" "] objectAtIndex: 2]; - mid = [self objectId]; mapping = [self mapping]; + mid = [self objectId]; [mapping unregisterURLWithID: mid]; - [sogoObject setNameInContainer: [NSString stringWithFormat: @"%@.eml", newIdString]]; - [mapping registerURL: [self url] withID: mid]; - } + // [sogoObject setNameInContainer: ]; - /* 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]]; + messageKey = [NSString stringWithFormat: @"%@.eml", newIdString]; + [sogoObject setNameInContainer: messageKey]; + [mapping registerURL: [self url] withID: mid]; + + /* 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/MAPIStoreMapping.h b/OpenChange/MAPIStoreMapping.h index 484c74da3..22ba052d3 100644 --- a/OpenChange/MAPIStoreMapping.h +++ b/OpenChange/MAPIStoreMapping.h @@ -1,6 +1,6 @@ /* MAPIStoreMapping.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -54,6 +54,8 @@ - (BOOL) registerURL: (NSString *) urlString withID: (uint64_t) idNbr; - (void) unregisterURLWithID: (uint64_t) idNbr; +- (void) updateID: (uint64_t) idNbr + withURL: (NSString *) urlString; @end diff --git a/OpenChange/MAPIStoreMapping.m b/OpenChange/MAPIStoreMapping.m index c1a4b1f6b..e5e762127 100644 --- a/OpenChange/MAPIStoreMapping.m +++ b/OpenChange/MAPIStoreMapping.m @@ -1,6 +1,6 @@ /* MAPIStoreMapping.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -30,6 +30,8 @@ #import +#import + #import "MAPIStoreTypes.h" #import "MAPIStoreMapping.h" @@ -204,6 +206,91 @@ MAPIStoreMappingTDBTraverse (TDB_CONTEXT *ctx, TDB_DATA data1, TDB_DATA data2, return idNbr; } +- (void) _updateFolderWithURL: (NSString *) oldURL + withURL: (NSString *) urlString +{ + NSArray *allKeys; + NSUInteger count, max; + NSString *currentKey, *newKey; + NSNumber *idKey; + TDB_DATA key, dbuf; + + [oldURL retain]; + + allKeys = [reverseMapping allKeys]; + max = [allKeys count]; + for (count = 0; count < max; count++) + { + currentKey = [allKeys objectAtIndex: count]; + if ([currentKey hasPrefix: oldURL]) + { + newKey = [currentKey stringByReplacingPrefix: oldURL + withPrefix: urlString]; + + idKey = [reverseMapping objectForKey: currentKey]; + [mapping setObject: newKey forKey: idKey]; + [reverseMapping setObject: idKey forKey: newKey]; + [reverseMapping removeObjectForKey: currentKey]; + + /* update the record in the indexing database */ + key.dptr = (unsigned char *) talloc_asprintf (NULL, "0x%.16"PRIx64, + (uint64_t) [idKey unsignedLongLongValue]); + key.dsize = strlen ((const char *) key.dptr); + + dbuf.dptr = (unsigned char *) talloc_strdup (NULL, + [newKey UTF8String]); + dbuf.dsize = strlen ((const char *) dbuf.dptr); + tdb_store (indexing->tdb, key, dbuf, TDB_MODIFY); + talloc_free (key.dptr); + talloc_free (dbuf.dptr); + } + } + + [oldURL release]; +} + +- (void) updateID: (uint64_t) idNbr + withURL: (NSString *) urlString +{ + NSString *oldURL; + NSNumber *idKey; + TDB_DATA key, dbuf; + + idKey = [NSNumber numberWithUnsignedLongLong: idNbr]; + oldURL = [mapping objectForKey: idKey]; + if (oldURL) + { + if ([oldURL hasSuffix: @"/"]) /* is container ? */ + { + if (![urlString hasSuffix: @"/"]) + [NSException raise: NSInvalidArgumentException + format: @"a container url must have an ending '/'"]; + tdb_transaction_start (indexing->tdb); + [self _updateFolderWithURL: oldURL withURL: urlString]; + tdb_transaction_commit (indexing->tdb); + } + else + { + if ([urlString hasSuffix: @"/"]) + [NSException raise: NSInvalidArgumentException + format: @"a leaf url must not have an ending '/'"]; + [mapping setObject: urlString forKey: idKey]; + [reverseMapping setObject: idKey forKey: urlString]; + [reverseMapping removeObjectForKey: oldURL]; + + /* update the record in the indexing database */ + key.dptr = (unsigned char *) talloc_asprintf(NULL, "0x%.16"PRIx64, idNbr); + key.dsize = strlen((const char *) key.dptr); + + dbuf.dptr = (unsigned char *) talloc_strdup (NULL, [urlString UTF8String]); + dbuf.dsize = strlen((const char *) dbuf.dptr); + tdb_store (indexing->tdb, key, dbuf, TDB_MODIFY); + talloc_free (key.dptr); + talloc_free (dbuf.dptr); + } + } +} + - (BOOL) registerURL: (NSString *) urlString withID: (uint64_t) idNbr { diff --git a/OpenChange/MAPIStoreMessage.h b/OpenChange/MAPIStoreMessage.h index d1494c060..c782cb0d6 100644 --- a/OpenChange/MAPIStoreMessage.h +++ b/OpenChange/MAPIStoreMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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,13 +66,13 @@ - (int) setReadFlag: (uint8_t) flag; - (enum mapistore_error) saveMessage; -/* helper getters */ -- (int) getSMTPAddrType: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx; - (NSArray *) activeContainerMessageTables; - (NSArray *) activeUserRoles; +/* move & copy internal ops */ +- (void) copyToMessage: (MAPIStoreMessage *) newMessage; + /* subclasses */ - (void) save; diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index 35ea1036d..325757b81 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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 @@ -424,6 +425,41 @@ rtf2html (NSData *compressedRTF) andType: MAPISTORE_MESSAGE_TABLE]; } +- (void) copyToMessage: (MAPIStoreMessage *) newMessage + +{ + TALLOC_CTX *memCtx; + struct mapistore_message *messageData; + NSArray *keys; + NSUInteger count, max; + NSString *key; + MAPIStoreAttachment *attachment, *newAttachment; + + memCtx = talloc_zero (NULL, TALLOC_CTX); + + /* message headers and recipients */ + [self getMessageData: &messageData inMemCtx: memCtx]; + [newMessage modifyRecipientsWithRecipients: messageData->recipients + andCount: messageData->recipients_count + andColumns: messageData->columns]; + + /* properties */ + [self copyPropertiesToObject: newMessage]; + + /* attachments */ + keys = [self attachmentKeys]; + max = [keys count]; + for (count = 0; count < max; count++) + { + key = [keys objectAtIndex: count]; + attachment = [self lookupAttachment: key]; + newAttachment = [newMessage createAttachment]; + [attachment copyToAttachment: newAttachment]; + } + + talloc_free (memCtx); +} + - (enum mapistore_error) saveMessage { enum mapistore_error rc; @@ -443,62 +479,73 @@ 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]; + /* We make sure that any change-related properties are removes from the + properties dictionary, to make sure that related methods will be + invoked the next time they are requested. */ + [properties removeObjectForKey: MAPIPropertyKey (PidTagChangeKey)]; + [properties removeObjectForKey: MAPIPropertyKey (PidTagChangeNumber)]; - /* 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 +554,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 @@ -615,7 +654,8 @@ rtf2html (NSData *compressedRTF) - (int) getPidLidCurrentVersion: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = MAPILongValue (memCtx, 115608); // Outlook 11.5608 + // *data = MAPILongValue (memCtx, 115608); // Outlook 11.5608 + *data = MAPILongValue (memCtx, 0x1ce3a); // Outlook 11.8330 return MAPISTORE_SUCCESS; } @@ -655,9 +695,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 +758,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 @@ -737,6 +801,12 @@ rtf2html (NSData *compressedRTF) return [self getEmptyString: data inMemCtx: memCtx]; } +- (int) getPidTagDeleteAfterSubmit: (void **) data // TODO + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getNo: data inMemCtx: memCtx]; +} + - (int) getPidTagDisplayTo: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -792,7 +862,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..9b1473325 100644 --- a/OpenChange/MAPIStoreMessageTable.h +++ b/OpenChange/MAPIStoreMessageTable.h @@ -1,6 +1,6 @@ /* MAPIStoreMessageTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..75d5adab9 100644 --- a/OpenChange/MAPIStoreMessageTable.m +++ b/OpenChange/MAPIStoreMessageTable.m @@ -1,6 +1,6 @@ /* MAPIStoreMessageTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -27,7 +27,9 @@ #import #import +#import "MAPIStoreContext.h" #import "MAPIStoreFolder.h" +#import "MAPIStoreMessage.h" #import "MAPIStoreTypes.h" #import "NSData+MAPIStore.h" #import "NSString+MAPIStore.h" @@ -83,4 +85,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..0c2f58261 100644 --- a/OpenChange/MAPIStoreNotesContext.h +++ b/OpenChange/MAPIStoreNotesContext.h @@ -1,6 +1,6 @@ /* MAPIStoreNotesContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -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/MAPIStoreNotesContext.m b/OpenChange/MAPIStoreNotesContext.m index b73a4032a..36d6804b9 100644 --- a/OpenChange/MAPIStoreNotesContext.m +++ b/OpenChange/MAPIStoreNotesContext.m @@ -1,6 +1,6 @@ /* MAPIStoreNotesContext.m - this file is part of SOGo * - * Copyright (C) 2010-2011 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreNotesFolder.h b/OpenChange/MAPIStoreNotesFolder.h index de2eb2748..4f049fb4f 100644 --- a/OpenChange/MAPIStoreNotesFolder.h +++ b/OpenChange/MAPIStoreNotesFolder.h @@ -1,6 +1,6 @@ /* MAPIStoreNotesFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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/MAPIStoreNotesFolder.m b/OpenChange/MAPIStoreNotesFolder.m index bac783bd2..ae2652d88 100644 --- a/OpenChange/MAPIStoreNotesFolder.m +++ b/OpenChange/MAPIStoreNotesFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreNotesFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreNotesMessage.h b/OpenChange/MAPIStoreNotesMessage.h index 81adfc0dc..08c1223d0 100644 --- a/OpenChange/MAPIStoreNotesMessage.h +++ b/OpenChange/MAPIStoreNotesMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreNotesMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..52712277b 100644 --- a/OpenChange/MAPIStoreNotesMessage.m +++ b/OpenChange/MAPIStoreNotesMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreNotesMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..d7aa989de 100644 --- a/OpenChange/MAPIStoreObject.h +++ b/OpenChange/MAPIStoreObject.h @@ -1,6 +1,6 @@ /* MAPIStoreObject.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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,16 @@ 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; +/* move and copy operations */ +- (void) copyPropertiesToObject: (MAPIStoreObject *) newObject; + /* subclasses */ -- (uint64_t) objectVersion; +- (NSString *) nameInContainer; - (NSDate *) creationTime; - (NSDate *) lastModificationTime; diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index e3d379d6b..185f19286 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -1,6 +1,6 @@ /* MAPIStoreObject.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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,102 @@ 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; +} + +/* move and copy operations */ +- (void) copyPropertiesToObject: (MAPIStoreObject *) newObject +{ + TALLOC_CTX *memCtx; + struct SPropTagArray *availableProps; + struct SRow row; + enum MAPITAGS propTag; + bool *exclusions; + NSUInteger count; + enum mapistore_error error; + void *data; + + memCtx = talloc_zero (NULL, TALLOC_CTX); + + [self getAvailableProperties: &availableProps inMemCtx: memCtx]; + + /* We exclude identity and versioning properties to facilitate copy + operations. If they need to be set (move operations), the caller will need + to take care of them. */ + exclusions = talloc_array (memCtx, bool, 65536); + exclusions[PidTagRowType >> 16] = true; + exclusions[PidTagInstanceKey >> 16] = true; + exclusions[PidTagInstanceNum >> 16] = true; + exclusions[PidTagInstID >> 16] = true; + exclusions[PidTagAttachNumber >> 16] = true; + exclusions[PidTagFolderId >> 16] = true; + exclusions[PidTagMid >> 16] = true; + exclusions[PidTagSourceKey >> 16] = true; + exclusions[PidTagParentSourceKey >> 16] = true; + exclusions[PidTagParentFolderId >> 16] = true; + exclusions[PidTagChangeKey >> 16] = true; + exclusions[PidTagChangeNumber >> 16] = true; + exclusions[PidTagPredecessorChangeList >> 16] = true; + + row.cValues = 0; + row.lpProps = talloc_array (memCtx, struct SPropValue, 65535); + + for (count = 0; count < availableProps->cValues; count++) + { + propTag = availableProps->aulPropTag[count]; + if (!exclusions[propTag >> 16]) + { + error = [self getProperty: &data withTag: propTag inMemCtx: memCtx]; + if (error == MAPISTORE_SUCCESS && data) + { + set_SPropValue_proptag (row.lpProps + row.cValues, propTag, data); + row.cValues++; + } + } + } + [newObject addPropertiesFromRow: &row]; + + talloc_free (memCtx); + +} + /* 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.h b/OpenChange/MAPIStorePermissionsTable.h index ef490d8b3..3f951f50c 100644 --- a/OpenChange/MAPIStorePermissionsTable.h +++ b/OpenChange/MAPIStorePermissionsTable.h @@ -1,6 +1,6 @@ /* MAPIStorePermissionsTable.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStorePermissionsTable.m b/OpenChange/MAPIStorePermissionsTable.m index 6d4c57c55..3dba53d79 100644 --- a/OpenChange/MAPIStorePermissionsTable.m +++ b/OpenChange/MAPIStorePermissionsTable.m @@ -1,6 +1,6 @@ /* MAPIStorePermissionsTable.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -23,7 +23,6 @@ #import #import #import - #import #import #import @@ -50,7 +49,7 @@ MAPIStorePermissionEntry *newEntry; newEntry = [[self alloc] initWithUserId: newUserId andMemberId: newMemberId - forFolder: newFolder]; + forFolder: newFolder]; [newEntry autorelease]; return newEntry; @@ -60,7 +59,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; @@ -103,7 +102,7 @@ entryId = [NSData data]; else { - connInfo = [[container context] connectionInfo]; + connInfo = [(MAPIStoreContext *) [container context] connectionInfo]; entryId = MAPIStoreInternalEntryId (connInfo->sam_ctx, userId); } *data = [entryId asBinaryInMemCtx: memCtx]; diff --git a/OpenChange/MAPIStoreRecurrenceUtils.h b/OpenChange/MAPIStoreRecurrenceUtils.h index 4fdf8c54e..68c84361e 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.h +++ b/OpenChange/MAPIStoreRecurrenceUtils.h @@ -1,6 +1,6 @@ /* MAPIStoreRecurrenceUtils.h - this file is part of $PROJECT_NAME_HERE$ * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..ebf588000 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.m +++ b/OpenChange/MAPIStoreRecurrenceUtils.m @@ -1,6 +1,6 @@ /* MAPIStoreRecurrenceUtils.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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; @@ -244,6 +293,7 @@ else { rp->EndDate = 0x5ae980df; + rp->OccurrenceCount = 0xa; rp->EndType = END_NEVER_END; } } @@ -370,6 +420,43 @@ [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]; + if (startDate) + [modifiedDates addObject: startDate]; + else + [self errorWithFormat: @"missing recurrence-id for event %d", count]; + } + 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..09921b9b6 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -1,6 +1,6 @@ /* MAPIStoreSOGo.m - this file is part of SOGo * - * Copyright (C) 2010, 2011 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -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]; @@ -608,6 +608,92 @@ sogo_folder_move_copy_messages(void *folder_object, return rc; } +static enum mapistore_error +sogo_folder_move_folder(void *folder_object, void *target_folder_object, + const char *new_folder_name) +{ + NSAutoreleasePool *pool; + MAPIStoreFolder *moveFolder, *targetFolder; + NSString *newFolderName; + struct MAPIStoreTallocWrapper *wrapper; + int rc; + + DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + + if (folder_object) + { + wrapper = folder_object; + moveFolder = wrapper->instance; + + wrapper = target_folder_object; + if (wrapper) + targetFolder = wrapper->instance; + else + targetFolder = nil; + + GSRegisterCurrentThread (); + pool = [NSAutoreleasePool new]; + + if (new_folder_name) + newFolderName = [NSString stringWithUTF8String: new_folder_name]; + else + newFolderName = nil; + + rc = [moveFolder moveCopyToFolder: targetFolder + withNewName: newFolderName + isMove: YES + isRecursive: YES]; + [pool release]; + GSUnregisterCurrentThread (); + } + else + { + rc = sogo_backend_unexpected_error(); + } + + return rc; +} + +static enum mapistore_error +sogo_folder_copy_folder(void *folder_object, void *target_folder_object, + bool recursive, const char *new_folder_name) +{ + NSAutoreleasePool *pool; + MAPIStoreFolder *copyFolder, *targetFolder; + NSString *newFolderName; + struct MAPIStoreTallocWrapper *wrapper; + int rc; + + DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + + if (folder_object) + { + wrapper = folder_object; + copyFolder = wrapper->instance; + + wrapper = target_folder_object; + targetFolder = wrapper->instance; + + GSRegisterCurrentThread (); + pool = [NSAutoreleasePool new]; + + newFolderName = [NSString stringWithUTF8String: new_folder_name]; + + rc = [copyFolder moveCopyToFolder: targetFolder + withNewName: newFolderName + isMove: NO + isRecursive: recursive]; + [pool release]; + GSUnregisterCurrentThread (); + } + else + { + rc = sogo_backend_unexpected_error(); + } + + return rc; +} + static enum mapistore_error sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx, enum mapistore_table_type table_type, uint64_t change_num, @@ -623,7 +709,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 +744,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 +779,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 +811,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 +842,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 +875,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 +907,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 +942,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 +973,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 +1002,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 +1031,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 +1048,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 +1065,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 +1085,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 +1134,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 +1162,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 +1191,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 +1222,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 +1255,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 +1286,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 +1315,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 +1345,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 +1376,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 +1406,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]; @@ -1378,6 +1500,8 @@ int mapistore_init_backend(void) backend.folder.create_message = sogo_folder_create_message; backend.folder.delete_message = sogo_folder_delete_message; backend.folder.move_copy_messages = sogo_folder_move_copy_messages; + backend.folder.move_folder = sogo_folder_move_folder; + backend.folder.copy_folder = sogo_folder_copy_folder; backend.folder.get_deleted_fmids = sogo_folder_get_deleted_fmids; backend.folder.get_child_count = sogo_folder_get_child_count; backend.folder.open_table = sogo_folder_open_table; @@ -1386,6 +1510,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..411736718 --- /dev/null +++ b/OpenChange/MAPIStoreSOGoObject.h @@ -0,0 +1,86 @@ +/* MAPIStoreObject.h - this file is part of SOGo + * + * Copyright (C) 2011-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 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..008083192 --- /dev/null +++ b/OpenChange/MAPIStoreSOGoObject.m @@ -0,0 +1,230 @@ +/* MAPIStoreObject.m - this file is part of SOGo + * + * Copyright (C) 2011-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 "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 +{ + return [container idForObjectWithKey: [sogoObject nameInContainer]]; +} + +/* getters */ +- (int) getPidTagDisplayName: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + *data = [[sogoObject displayName] asUnicodeInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagSearchKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + NSString *stringValue; + + stringValue = [sogoObject nameInContainer]; + *data = [[stringValue dataUsingEncoding: NSASCIIStringEncoding] + asBinaryInMemCtx: memCtx]; + + return MAPISTORE_SUCCESS; +} + +- (int) getPidTagGenerateExchangeViews: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getNo: data inMemCtx: memCtx]; +} + +- (int) getPidTagParentSourceKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getReplicaKey: data fromGlobCnt: [container objectId] >> 16 + inMemCtx: memCtx]; +} + +- (int) getPidTagSourceKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + return [self getReplicaKey: data fromGlobCnt: [self objectId] >> 16 + inMemCtx: memCtx]; +} + +/* helper getters */ +- (int) getPidTagChangeKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + int rc; + uint64_t obVersion; + + obVersion = [self objectVersion]; + if (obVersion == ULLONG_MAX) + rc = MAPISTORE_ERR_NOT_FOUND; + else + rc = [self getReplicaKey: data fromGlobCnt: obVersion + inMemCtx: memCtx]; + + return rc; +} + +- (int) getPidTagChangeNumber: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + int rc; + uint64_t obVersion; + + obVersion = [self objectVersion]; + if (obVersion == ULLONG_MAX) + rc = MAPISTORE_ERR_NOT_FOUND; + else + { + *data = MAPILongLongValue (memCtx, ((obVersion << 16) + | 0x0001)); + rc = MAPISTORE_SUCCESS; + } + + return rc; +} + +/* subclasses */ +- (uint64_t) objectVersion +{ + [self subclassResponsibility: _cmd]; + + return ULLONG_MAX; +} + +/* logging */ +- (NSString *) loggingPrefix +{ + return [NSString stringWithFormat:@"<%@:%p:%@>", + NSStringFromClass (isa), self, [self nameInContainer]]; +} + +@end diff --git a/OpenChange/MAPIStoreSamDBUtils.h b/OpenChange/MAPIStoreSamDBUtils.h index c58a12686..25ee5e4eb 100644 --- a/OpenChange/MAPIStoreSamDBUtils.h +++ b/OpenChange/MAPIStoreSamDBUtils.h @@ -1,6 +1,6 @@ /* MAPIStoreSamDBUtils.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreSamDBUtils.m b/OpenChange/MAPIStoreSamDBUtils.m index 4d7caff63..e1f3fff44 100644 --- a/OpenChange/MAPIStoreSamDBUtils.m +++ b/OpenChange/MAPIStoreSamDBUtils.m @@ -1,6 +1,6 @@ /* MAPIStoreSamDBUtils.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTable.h b/OpenChange/MAPIStoreTable.h index fbf13a680..8c4b4718a 100644 --- a/OpenChange/MAPIStoreTable.h +++ b/OpenChange/MAPIStoreTable.h @@ -1,6 +1,6 @@ /* MAPIStoreTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..04dcdf717 100644 --- a/OpenChange/MAPIStoreTable.m +++ b/OpenChange/MAPIStoreTable.m @@ -1,6 +1,6 @@ /* MAPIStoreTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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/MAPIStoreTasksContext.h b/OpenChange/MAPIStoreTasksContext.h index b26b580cc..70d416130 100644 --- a/OpenChange/MAPIStoreTasksContext.h +++ b/OpenChange/MAPIStoreTasksContext.h @@ -1,6 +1,6 @@ /* MAPIStoreTasksContext.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTasksContext.m b/OpenChange/MAPIStoreTasksContext.m index 2726a2a62..096ca3711 100644 --- a/OpenChange/MAPIStoreTasksContext.m +++ b/OpenChange/MAPIStoreTasksContext.m @@ -1,6 +1,6 @@ /* MAPIStoreTasksContext.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTasksFolder.h b/OpenChange/MAPIStoreTasksFolder.h index 5f30c77b4..dc9b6791a 100644 --- a/OpenChange/MAPIStoreTasksFolder.h +++ b/OpenChange/MAPIStoreTasksFolder.h @@ -1,6 +1,6 @@ /* MAPIStoreTasksFolder.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTasksFolder.m b/OpenChange/MAPIStoreTasksFolder.m index bfc0698e8..7b8990fc8 100644 --- a/OpenChange/MAPIStoreTasksFolder.m +++ b/OpenChange/MAPIStoreTasksFolder.m @@ -1,6 +1,6 @@ /* MAPIStoreTasksFolder.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTasksMessage.h b/OpenChange/MAPIStoreTasksMessage.h index 273cde7cb..3130b72a5 100644 --- a/OpenChange/MAPIStoreTasksMessage.h +++ b/OpenChange/MAPIStoreTasksMessage.h @@ -1,6 +1,6 @@ /* MAPIStoreTasksMessage.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTasksMessage.m b/OpenChange/MAPIStoreTasksMessage.m index e1a5a9df4..93d73cfd6 100644 --- a/OpenChange/MAPIStoreTasksMessage.m +++ b/OpenChange/MAPIStoreTasksMessage.m @@ -1,6 +1,6 @@ /* MAPIStoreTasksMessage.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * Ludovic Marcotte @@ -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/MAPIStoreTasksMessageTable.h b/OpenChange/MAPIStoreTasksMessageTable.h index 2180dd9ec..4be570027 100644 --- a/OpenChange/MAPIStoreTasksMessageTable.h +++ b/OpenChange/MAPIStoreTasksMessageTable.h @@ -1,6 +1,6 @@ /* MAPIStoreTasksMessageTable.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTasksMessageTable.m b/OpenChange/MAPIStoreTasksMessageTable.m index 9f6e5ad28..2948177b0 100644 --- a/OpenChange/MAPIStoreTasksMessageTable.m +++ b/OpenChange/MAPIStoreTasksMessageTable.m @@ -1,6 +1,6 @@ /* MAPIStoreTasksMessageTable.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc + * Copyright (C) 2010-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTypes.h b/OpenChange/MAPIStoreTypes.h index 8e2fb7d46..a556bb26f 100644 --- a/OpenChange/MAPIStoreTypes.h +++ b/OpenChange/MAPIStoreTypes.h @@ -1,6 +1,6 @@ /* MAPIStoreTypes.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/MAPIStoreTypes.m b/OpenChange/MAPIStoreTypes.m index b13585e66..43fa048ee 100644 --- a/OpenChange/MAPIStoreTypes.m +++ b/OpenChange/MAPIStoreTypes.m @@ -1,6 +1,6 @@ /* MAPIStoreTypes.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * 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..9489eba44 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,27 @@ * Boston, MA 02111-1307, USA. */ +#import #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 +87,9 @@ static NSMapTable *contextsTable = nil; mapping = nil; + userDbTableExists = NO; + folderTableURL = nil; + authenticator = nil; woContext = [WOContext contextWithRequest: nil]; [woContext retain]; @@ -88,9 +98,33 @@ static NSMapTable *contextsTable = nil; return self; } +- (NSString *) _readUserPassword: (NSString *) newUsername +{ + NSString *password, *path; + NSData *content; + + password = nil; + + path = [NSString stringWithFormat: SAMBA_PRIVATE_DIR + @"/mapistore/%@/password", newUsername]; + + content = [NSData dataWithContentsOfFile: path]; + + if (content) + { + password = [[NSString alloc] initWithData: content + encoding: NSUTF8StringEncoding]; + [password autorelease]; + } + + 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 +136,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 +154,8 @@ static NSMapTable *contextsTable = nil; [authenticator release]; [mapping release]; + [folderTableURL release]; + [sogoUser release]; [contextsTable removeObjectForKey: username]; @@ -213,6 +252,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/NSArray+MAPIStore.m b/OpenChange/NSArray+MAPIStore.m index 7a41245d4..9ed20130a 100644 --- a/OpenChange/NSArray+MAPIStore.m +++ b/OpenChange/NSArray+MAPIStore.m @@ -1,6 +1,6 @@ /* NSArray+MAPIStore.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSData+MAPIStore.h b/OpenChange/NSData+MAPIStore.h index 20409c1ac..5715b9128 100644 --- a/OpenChange/NSData+MAPIStore.h +++ b/OpenChange/NSData+MAPIStore.h @@ -45,6 +45,8 @@ + (id) dataWithChangeKeyGUID: (NSString *) guidString andCnt: (NSData *) globCnt; +- (void) hexDumpWithLineSize: (NSUInteger) lineSize; + @end @interface NSMutableData (MAPIStoreDataTypes) diff --git a/OpenChange/NSData+MAPIStore.m b/OpenChange/NSData+MAPIStore.m index b0143dc1b..b1200c5f4 100644 --- a/OpenChange/NSData+MAPIStore.m +++ b/OpenChange/NSData+MAPIStore.m @@ -1,6 +1,6 @@ /* NSData+MAPIStore.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -20,6 +20,8 @@ * Boston, MA 02111-1307, USA. */ +#import + #import "NSString+MAPIStore.h" #import "NSData+MAPIStore.h" @@ -185,6 +187,36 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID * return changeKey; } +- (void) hexDumpWithLineSize: (NSUInteger) lineSize +{ + const char *bytes; + NSUInteger lineCount, count, max, charCount, charMax; + NSMutableString *line; + + bytes = [self bytes]; + max = [self length]; + + lineCount = 0; + for (count = 0; count < max; count++) + { + line = [NSMutableString stringWithFormat: @"%d: ", lineCount]; + if (lineSize) + { + if ((max - count) > lineSize) + charMax = lineSize; + else + charMax = max - count; + } + else + charMax = max; + for (charCount = 0; charCount < charMax; charCount++) + [line appendFormat: @" %.2x", *(bytes + count + charCount)]; + [self logWithFormat: @" %@", line]; + count += charMax; + lineCount++; + } +} + @end @implementation NSMutableData (MAPIStoreDataTypes) diff --git a/OpenChange/NSDate+MAPIStore.h b/OpenChange/NSDate+MAPIStore.h index 3c7809f79..0e417d21f 100644 --- a/OpenChange/NSDate+MAPIStore.h +++ b/OpenChange/NSDate+MAPIStore.h @@ -1,6 +1,6 @@ /* NSDate+MAPIStore.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -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..b96812adf 100644 --- a/OpenChange/NSDate+MAPIStore.m +++ b/OpenChange/NSDate+MAPIStore.m @@ -1,6 +1,6 @@ /* NSDate+MAPIStore.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -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..ff5bed57d 100644 --- a/OpenChange/NSObject+MAPIStore.h +++ b/OpenChange/NSObject+MAPIStore.h @@ -1,6 +1,6 @@ /* NSObject+MAPIStore.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..1829b59f3 100644 --- a/OpenChange/NSObject+MAPIStore.m +++ b/OpenChange/NSObject+MAPIStore.m @@ -1,6 +1,6 @@ /* NSObject+MAPIStore.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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..37861ed0f --- /dev/null +++ b/OpenChange/NSObject+PropertyList.m @@ -0,0 +1,182 @@ +/* dbmsgdump.m - this file is part of SOGo + * + * Copyright (C) 2011-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 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/NSString+MAPIStore.h b/OpenChange/NSString+MAPIStore.h index 26addcbdf..6db35543c 100644 --- a/OpenChange/NSString+MAPIStore.h +++ b/OpenChange/NSString+MAPIStore.h @@ -1,6 +1,6 @@ /* NSString+MAPIStore.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSString+MAPIStore.m b/OpenChange/NSString+MAPIStore.m index a4a894b6a..186c30e46 100644 --- a/OpenChange/NSString+MAPIStore.m +++ b/OpenChange/NSString+MAPIStore.m @@ -1,6 +1,6 @@ /* NSString+MAPIStore.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSValue+MAPIStore.h b/OpenChange/NSValue+MAPIStore.h index 6352b9a4c..da0b2aa41 100644 --- a/OpenChange/NSValue+MAPIStore.h +++ b/OpenChange/NSValue+MAPIStore.h @@ -1,6 +1,6 @@ /* NSValue+MAPIStore.h - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/NSValue+MAPIStore.m b/OpenChange/NSValue+MAPIStore.m index 83d583e33..a3301ce00 100644 --- a/OpenChange/NSValue+MAPIStore.m +++ b/OpenChange/NSValue+MAPIStore.m @@ -1,6 +1,6 @@ /* NSValue+MAPIStore.m - this file is part of SOGo * - * Copyright (C) 2010 Inverse inc. + * Copyright (C) 2010-2012 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/SOGoMAPIFSFolder.h b/OpenChange/SOGoMAPIDBFolder.h similarity index 51% rename from OpenChange/SOGoMAPIFSFolder.h rename to OpenChange/SOGoMAPIDBFolder.h index 244094129..d055291bc 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,40 @@ * 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 *) childKeysOfType: (MAPIDBObjectType) type + includeDeleted: (BOOL) includeDeleted + matchingQualifier: (EOQualifier *) qualifier + andSortOrderings: (NSArray *) sortOrderings; -- (NSArray *) toOneRelationshipKeysMatchingQualifier: (EOQualifier *) qualifier - andSortOrderings: (NSArray *) sortOrderings; +- (void) changePathTo: (NSString *) newPath; @end -#endif /* SOGOMAPIFSFOLDER_H */ +#endif /* SOGOMAPIDBFOLDER_H */ diff --git a/OpenChange/SOGoMAPIDBFolder.m b/OpenChange/SOGoMAPIDBFolder.m new file mode 100644 index 000000000..1ed8d23ff --- /dev/null +++ b/OpenChange/SOGoMAPIDBFolder.m @@ -0,0 +1,482 @@ +/* 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 +#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]; + [whereClause addObject: [NSString stringWithFormat: @"c_parent_path = '%@'", + [self path]]]; + [whereClause addObject: [NSString stringWithFormat: @"c_type = %d", type]]; + if (!includeDeleted) + [whereClause addObject: @"c_deleted = 0"]; + + [sql appendFormat: @" WHERE %@", + [whereClause componentsJoinedByString: @" AND "]]; + + childPathPrefix = [NSString stringWithFormat: @"%@/", [self path]]; + + /* results */ + records = [self performSQLQuery: sql]; + if (records) + { + max = [records count]; + childKeys = [NSMutableArray arrayWithCapacity: max]; + childPathPrefixLen = [childPathPrefix length]; + for (count = 0; count < max; count++) + { + record = [records objectAtIndex: count]; + childPath = [record objectForKey: @"c_path"]; + childKey = [childPath substringFromIndex: childPathPrefixLen]; + if ([childKey rangeOfString: @"/"].location == NSNotFound) + { + if (qualifier) + { + currentChild = [SOGoMAPIDBObject objectWithName: childKey + inContainer: self]; + [currentChild setupFromRecord: record]; + if ([qualifier evaluateSOGoMAPIDBObject: currentChild]) + [childKeys addObject: childKey]; + } + else + [childKeys addObject: childKey]; + } + } + } + else + childKeys = nil; + + return childKeys; +} + +- (NSArray *) toManyRelationshipKeys +{ + return [self childKeysOfType: MAPIDBObjectTypeFolder + includeDeleted: NO + matchingQualifier: nil + andSortOrderings: nil]; +} + +- (NSArray *) toOneRelationshipKeys +{ + return [self childKeysOfType: MAPIDBObjectTypeMessage + includeDeleted: NO + matchingQualifier: nil + andSortOrderings: nil]; +} + +- (void) setNameInContainer: (NSString *) newName +{ + NSMutableString *sql; + NSString *oldPath, *newPath, *path, *parentPath; + NSMutableArray *queries; + NSArray *records; + NSDictionary *record; + NSUInteger count, max; + + /* change the paths in children records */ + if (nameInContainer) + oldPath = [self path]; + + [super setNameInContainer: newName]; + + if (nameInContainer) + { + newPath = [self path]; + + sql = [NSMutableString stringWithFormat: + @"SELECT c_path, c_parent_path FROM %@" + @" WHERE c_path LIKE '%@/%%'", + [self tableName], oldPath]; + records = [self performSQLQuery: sql]; + max = [records count]; + queries = [NSMutableArray arrayWithCapacity: max + 1]; + if (max > 0) + { + for (count = 0; count < max; count++) + { + record = [records objectAtIndex: count]; + path = [record objectForKey: @"c_path"]; + sql = [NSMutableString stringWithFormat: @"UPDATE %@" + @" SET c_path = '%@'", + [self tableName], + [path stringByReplacingPrefix: oldPath + withPrefix: newPath]]; + parentPath = [record objectForKey: @"c_parent_path"]; + if ([parentPath isNotNull]) + [sql appendFormat: @", c_parent_path = '%@'", + [parentPath stringByReplacingPrefix: oldPath + withPrefix: newPath]]; + [sql appendFormat: @" WHERE c_path = '%@'", path]; + [queries addObject: sql]; + } + [self performBatchSQLQueries: queries]; + } + } +} + +- (void) changePathTo: (NSString *) newPath +{ + NSMutableString *sql// , *qualifierClause + ; + NSString *oldPath, *oldPathAsPrefix, *path, *parentPath; + NSMutableArray *queries; + NSArray *records; + NSDictionary *record; + NSUInteger count, max; + + /* change the paths in children records */ + oldPath = [self path]; + oldPathAsPrefix = [NSString stringWithFormat: @"%@/", oldPath]; + + sql = [NSMutableString stringWithFormat: + @"SELECT c_path, c_parent_path FROM %@" + @" WHERE c_path LIKE '%@%%'", + [self tableName], oldPathAsPrefix]; + records = [self performSQLQuery: sql]; + max = [records count]; + queries = [NSMutableArray arrayWithCapacity: max + 1]; + if (max > 0) + { + for (count = 0; count < max; count++) + { + record = [records objectAtIndex: count]; + path = [record objectForKey: @"c_path"]; + sql = [NSMutableString stringWithFormat: @"UPDATE %@" + @" SET c_path = '%@'", + [self tableName], + [path stringByReplacingPrefix: oldPath + withPrefix: newPath]]; + parentPath = [record objectForKey: @"c_parent_path"]; + if ([parentPath isNotNull]) + [sql appendFormat: @", c_parent_path = '%@'", + [parentPath stringByReplacingPrefix: oldPath + withPrefix: newPath]]; + [sql appendFormat: @" WHERE c_path = '%@'", path]; + [queries addObject: sql]; + } + [self performBatchSQLQueries: queries]; + } + + /* change the path in this folder record */ + [super changePathTo: newPath]; +} + +// - (NSArray *) toOneRelationshipKeysMatchingQualifier: (EOQualifier *) qualifier +// andSortOrderings: (NSArray *) sortOrderings +// { +// NSArray *allKeys; +// NSMutableArray *keys; +// NSUInteger count, max; +// NSString *messageKey; +// SOGoMAPIDBMessage *message; + +// if (sortOrderings) +// [self warnWithFormat: @"sorting is not handled yet"]; + +// allKeys = [self toOneRelationshipKeys]; +// if (qualifier) +// { +// [self logWithFormat: @"%s: getting restricted FAI keys", __PRETTY_FUNCTION__]; +// max = [allKeys count]; +// keys = [NSMutableArray arrayWithCapacity: max]; +// for (count = 0; count < max; count++) +// { +// messageKey = [allKeys objectAtIndex: count]; +// message = [self lookupName: messageKey +// inContext: nil +// acquire: NO]; +// if ([qualifier evaluateMAPIVolatileMessage: message]) +// [keys addObject: messageKey]; +// } +// } +// else +// keys = (NSMutableArray *) allKeys; + +// return keys; +// } + +- (id) lookupName: (NSString *) childName + inContext: (WOContext *) woContext + acquire: (BOOL) acquire +{ + id object; + Class objectClass; + NSString *childPath; + NSDictionary *record; + + childPath = [self pathForChild: childName]; + record = [self lookupRecord: childPath newerThanVersion: -1]; + if (record) + { + if ([[record objectForKey: @"c_type"] intValue] == 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]; +// } + +/* 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..6bf1750bb --- /dev/null +++ b/OpenChange/SOGoMAPIDBObject.h @@ -0,0 +1,85 @@ +/* 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; + +- (void) changePathTo: (NSString *) newPath; + +/* db helpers */ +- (EOAdaptor *) tableChannelAdaptor; +- (NSArray *) performSQLQuery: (NSString *) sql; +- (BOOL) performBatchSQLQueries: (NSArray *) queries; + +@end + +#endif /* SOGOMAPIDBOBJECT_H */ diff --git a/OpenChange/SOGoMAPIDBObject.m b/OpenChange/SOGoMAPIDBObject.m new file mode 100644 index 000000000..0b75270af --- /dev/null +++ b/OpenChange/SOGoMAPIDBObject.m @@ -0,0 +1,569 @@ +/* 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 */ +- (void) setNameInContainer: (NSString *) newNameInContainer +{ + NSMutableString *sql; + NSString *oldPath, *newPath; + + if (nameInContainer) + oldPath = [self path]; + + [super setNameInContainer: newNameInContainer]; + + if (nameInContainer) + { + newPath = [self path]; + + sql = [NSMutableString stringWithFormat: @"UPDATE %@" + @" SET c_path = '%@'", + [self tableName], + newPath]; + [sql appendFormat: @" WHERE c_path = '%@'", oldPath]; + [self performBatchSQLQueries: [NSArray arrayWithObject: sql]]; + } +} + +- (void) changePathTo: (NSString *) newPath +{ + NSMutableString *sql; + NSString *oldPath, *newParentPath; + NSRange slashRange; + + oldPath = [self path]; + + slashRange = [newPath rangeOfString: @"/" + options: NSBackwardsSearch]; + if (slashRange.location != NSNotFound) + newParentPath = [newPath substringToIndex: slashRange.location]; + else + newParentPath = NULL; + + sql = [NSMutableString stringWithFormat: @"UPDATE %@" + @" SET c_path = '%@'", + [self tableName], + newPath]; + if (newParentPath) + [sql appendFormat: @", c_parent_path = '%@'", newParentPath]; + else + [sql appendString: @", c_parent_path = NULL"]; + [sql appendFormat: @" WHERE c_path = '%@'", oldPath]; + [self performBatchSQLQueries: [NSArray arrayWithObject: sql]]; +} + +- (EOAdaptor *) tableChannelAdaptor +{ + GCSChannelManager *cm; + EOAdaptor *adaptor; + EOAdaptorChannel *channel; + + cm = [GCSChannelManager defaultChannelManager]; + channel = [cm acquireOpenChannelForURL: [self tableUrl]]; + adaptor = [[channel adaptorContext] adaptor]; + [cm releaseChannel: channel]; + + return adaptor; +} + +- (NSArray *) performSQLQuery: (NSString *) sql +{ + NSMutableArray *records; + GCSChannelManager *cm; + EOAdaptorChannel *channel; + NSException *error; + NSArray *attrs; + NSDictionary *record; + + cm = [GCSChannelManager defaultChannelManager]; + channel = [cm acquireOpenChannelForURL: [self tableUrl]]; + + error = [channel evaluateExpressionX: sql]; + if (error) + { + records = nil; + [self logWithFormat: + @"an exception occurred when executing query '%@'", + sql]; + [self logWithFormat: @"exception is '%@'", error]; + } + else + { + records = [NSMutableArray arrayWithCapacity: 256]; + attrs = [channel describeResults: NO]; + while ((record = [channel fetchAttributes: attrs withZone: NULL])) + [records addObject: record]; + } + [cm releaseChannel: channel]; + + return records; +} + +- (BOOL) performBatchSQLQueries: (NSArray *) queries +{ + GCSChannelManager *cm; + EOAdaptorChannel *channel; + EOAdaptorContext *dbContext; + NSException *error; + NSUInteger count, max; + NSString *sql; + + cm = [GCSChannelManager defaultChannelManager]; + channel = [cm acquireOpenChannelForURL: [self tableUrl]]; + dbContext = [channel adaptorContext]; + + [dbContext beginTransaction]; + + error = nil; + + max = [queries count]; + for (count = 0; error == nil && count < max; count++) + { + sql = [queries objectAtIndex: count]; + error = [channel evaluateExpressionX: sql]; + if (error) + [dbContext rollbackTransaction]; + } + if (!error) + [dbContext commitTransaction]; + [cm releaseChannel: channel]; + + return (error == nil); +} + +- (NSDictionary *) lookupRecord: (NSString *) path + newerThanVersion: (NSInteger) startVersion +{ + NSDictionary *record; + NSArray *records; + NSString *tableName, *pathValue; + NSMutableString *sql; + EOAdaptor *adaptor; + + if ([path hasSuffix: @"/"]) + [NSException raise: @"MAPIStoreIOException" + format: @"path ends with a slash: %@", path]; + + tableName = [self tableName]; + adaptor = [self tableChannelAdaptor]; + pathValue = [adaptor formatValue: path + forAttribute: textColumn]; + + /* query */ + sql = [NSMutableString stringWithFormat: + @"SELECT * FROM %@ WHERE c_path = %@", + tableName, pathValue]; + if (startVersion > -1) + [sql appendFormat: @" AND c_version > %d", startVersion]; + + /* execution */ + records = [self performSQLQuery: sql]; + if ([records count] > 0) + record = [records objectAtIndex: 0]; + else + record = nil; + + return record; +} + +- (void) reloadIfNeeded +{ + /* if object is uninitialized: reload without condition, otherwise, load if + c_version > :version */ + NSDictionary *record; + + if (initialized) + { + if (!isNew) + { + record = [self lookupRecord: [self path] + newerThanVersion: version]; + if (record) + [self setupFromRecord: record]; + } + } + else + { + record = [self lookupRecord: [self path] + newerThanVersion: -1]; + if (record) + { + [self setupFromRecord: record]; + isNew = NO; + } + else + isNew = YES; + initialized = YES; + } +} + +- (NSException *) delete +{ + deleted = YES; + [properties removeAllObjects]; + [self save]; + + return nil; +} + +- (void) save +{ + NSString *sql; + NSData *content; + NSCalendarDate *now; + GCSChannelManager *cm; + EOAdaptor *adaptor; + EOAdaptorChannel *channel; + NSInteger creationDateValue, lastModifiedValue, deletedValue; + NSString *tableName, *pathValue, *parentPathValue, *propsValue; + NSException *result; + + if (!initialized) + [NSException raise: @"MAPIStoreIOException" + format: @"record has not been initialized: %@", self]; + + cm = [GCSChannelManager defaultChannelManager]; + + channel = [cm acquireOpenChannelForURL: [self tableUrl]]; + + tableName = [self tableName]; + + now = [NSCalendarDate date]; + ASSIGN (lastModified, now); + + /* +- (NSException *)insertRowX:(NSDictionary *)_row forEntity:(EOEntity *)_entity; +- (NSException *)updateRowX:(NSDictionary*)aRow + describedByQualifier:(EOSQLQualifier*)aQualifier; + */ + + adaptor = [[channel adaptorContext] adaptor]; + pathValue = [adaptor formatValue: [self path] + forAttribute: textColumn]; + + lastModifiedValue = (NSInteger) [lastModified timeIntervalSince1970]; + + if (objectType == -1) + [NSException raise: @"MAPIStoreIOException" + format: @"object type has not been set for object '%@'", + self]; + + if ([properties count] > 0) + { + content = [NSPropertyListSerialization + dataFromPropertyList: properties + format: NSPropertyListGNUstepBinaryFormat + errorDescription: NULL]; + propsValue = [adaptor formatValue: [content stringByEncodingBase64] + forAttribute: textColumn]; + } + else + propsValue = @"NULL"; + + if (isNew) + { + ASSIGN (creationDate, now); + creationDateValue = (NSInteger) [creationDate timeIntervalSince1970]; + parentPathValue = [adaptor formatValue: [container path] + forAttribute: textColumn]; + if (!parentPathValue) + parentPathValue = @"NULL"; + sql = [NSString stringWithFormat: + (@"INSERT INTO %@" + @" (c_path, c_parent_path, c_type, c_creationdate, c_lastmodified," + @" c_deleted, c_version, c_content)" + @" VALUES (%@, %@, %d, %d, %d, 0, 0, %@" + @")"), + tableName, + pathValue, parentPathValue, objectType, + creationDateValue, lastModifiedValue, + propsValue]; + isNew = NO; + } + else + { + version++; + deletedValue = (deleted ? 1 : 0); + sql = [NSString stringWithFormat: + (@"UPDATE %@" + @" SET c_lastmodified = %d, c_deleted = %d," + @" c_version = %d, c_content = %@" + @" WHERE c_path = %@"), + tableName, + lastModifiedValue, deletedValue, version, propsValue, + pathValue]; + } + + result = [channel evaluateExpressionX: sql]; + if (result) + [self errorWithFormat: @"could not insert/update record for record %@" + @" in %@: %@", pathValue, tableName, result]; + // @" c_path VARCHAR(255) PRIMARY KEY," + // @" c_type SMALLINT NOT NULL," + // @" c_creationdate INT4 NOT NULL," + // @" c_lastmodified INT4 NOT NULL," + // @" c_deleted SMALLINT NOT NULL DEFAULT 0," + // @" c_content BLOB"); + + [cm releaseChannel: channel]; +} + +@end 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..178202963 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 * @@ -21,16 +21,21 @@ */ #import +#import -#import "SOGoMAPIVolatileMessage.h" +#import "SOGoMAPIObject.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 +43,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/code-MAPIStorePropertySelectors.h b/OpenChange/code-MAPIStorePropertySelectors.h index cceb2b751..f338ebe62 100644 --- a/OpenChange/code-MAPIStorePropertySelectors.h +++ b/OpenChange/code-MAPIStorePropertySelectors.h @@ -1,6 +1,6 @@ /* code-MAPIStorePropertySelectors.h - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/code-MAPIStorePropertySelectors.m b/OpenChange/code-MAPIStorePropertySelectors.m index aae4f0489..86ac76f20 100644 --- a/OpenChange/code-MAPIStorePropertySelectors.m +++ b/OpenChange/code-MAPIStorePropertySelectors.m @@ -1,6 +1,6 @@ /* code-MAPIStorePropertySelectors.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * diff --git a/OpenChange/dbmsgreader.m b/OpenChange/dbmsgreader.m new file mode 100644 index 000000000..0119a00c9 --- /dev/null +++ b/OpenChange/dbmsgreader.m @@ -0,0 +1,109 @@ +/* dbmsgreader.m - this file is part of SOGo + * + * Copyright (C) 2011-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 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/gen-property-selectors.py b/OpenChange/gen-property-selectors.py index 8c728bb99..f009d6864 100755 --- a/OpenChange/gen-property-selectors.py +++ b/OpenChange/gen-property-selectors.py @@ -7,27 +7,7 @@ output = "-" import os import sys -m_template = """/* %(filename)s (auto-generated) - 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. - */ +m_template = """/* %(filename)s (auto-generated) */ #include #include @@ -53,27 +33,7 @@ static const SEL MAPIStorePropertyGetterSelectors[] = { #include "code-%(filename)s" """ -h_template = """/* %(filename)s (auto-generated) - 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. - */ +h_template = """/* %(filename)s (auto-generated) */ #ifndef %(h_exclusion)s #define %(h_exclusion)s 1 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/iCalTimeZone+MAPIStore.h b/OpenChange/iCalTimeZone+MAPIStore.h new file mode 100644 index 000000000..d476869c5 --- /dev/null +++ b/OpenChange/iCalTimeZone+MAPIStore.h @@ -0,0 +1,35 @@ +/* iCalTimeZone+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 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 ICALTIMEZONE_MAPISTORE_H +#define ICALTIMEZONE_MAPISTORE_H + +#import + +@interface iCalTimeZone (MAPIStoreProperties) + +- (struct Binary_r *) asTimeZoneStructInMemCtx: (TALLOC_CTX *) memCtx; + +@end + + +#endif /* ICALTIMEZONE_MAPISTORE_H */ diff --git a/OpenChange/iCalTimeZone+MAPIStore.m b/OpenChange/iCalTimeZone+MAPIStore.m new file mode 100644 index 000000000..d15447233 --- /dev/null +++ b/OpenChange/iCalTimeZone+MAPIStore.m @@ -0,0 +1,115 @@ +/* iCalTimeZone+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 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 + +#include +#include +#include +#undef DEBUG +#include + +#import "iCalTimeZone+MAPIStore.h" + +@interface iCalTimeZonePeriod (MAPIStorePropertiesPrivate) + +- (void) _fillTZDate: (struct SYSTEMTIME *) tzData; + +@end + +@implementation iCalTimeZonePeriod (MAPIStorePropertiesPrivate) + +- (void) _fillTZDate: (struct SYSTEMTIME *) tzData +{ + iCalRecurrenceRule *rrule; + NSArray *byMonth; + iCalByDayMask *mask; + NSCalendarDate *dateValue; + + rrule = [self recurrenceRule]; + byMonth = [rrule byMonth]; + if ([byMonth count] > 0) + { + tzData->wMonth = [[byMonth objectAtIndex: 0] intValue]; + mask = [rrule byDayMask]; + tzData->wDayOfWeek = [mask firstDay]; + tzData->wDay = [mask firstOccurrence]; + + dateValue = [self startDate]; + tzData->wHour = [dateValue hourOfDay]; + tzData->wMinute = [dateValue minuteOfHour]; + tzData->wSecond = [dateValue secondOfMinute]; + } +} + +@end + +@implementation iCalTimeZone (MAPIStoreProperties) + +- (iCalTimeZonePeriod *) _mostRecentPeriodWithName: (NSString *) periodName +{ + NSArray *periods; + iCalTimeZonePeriod *period; + NSUInteger max; + + periods = [self childrenWithTag: periodName]; + max = [periods count]; + if (max > 0) + { + periods = [periods sortedArrayUsingSelector: @selector (compare:)]; + period = (iCalTimeZonePeriod *) [periods objectAtIndex: (max - 1)]; + } + else + period = nil; + + return period; +} + +- (struct Binary_r *) asTimeZoneStructInMemCtx: (TALLOC_CTX *) memCtx +{ + iCalTimeZonePeriod *period; + struct TimeZoneStruct tz; + int lBias, dlBias; + + memset (&tz, 0, sizeof (struct TimeZoneStruct)); + period = [self _mostRecentPeriodWithName: @"STANDARD"]; + lBias = -[period secondsOffsetFromGMT] / 60; + tz.lBias = (uint32_t) lBias; + [period _fillTZDate: &tz.stStandardDate]; + period = [self _mostRecentPeriodWithName: @"DAYLIGHT"]; + if (!period) + tz.stStandardDate.wMonth = 0; + dlBias = -([period secondsOffsetFromGMT] / 60) - lBias; + tz.lDaylightBias = (uint32_t) (dlBias); + [period _fillTZDate: &tz.stDaylightDate]; + tz.wStandardYear = tz.stStandardDate.wYear; + tz.wDaylightYear = tz.stDaylightDate.wYear; + + return set_TimeZoneStruct (memCtx, &tz); +} + +@end diff --git a/OpenChange/plreader.m b/OpenChange/plreader.m index 68c7a81e5..f6ee15672 100644 --- a/OpenChange/plreader.m +++ b/OpenChange/plreader.m @@ -1,6 +1,6 @@ /* plreader.m - this file is part of SOGo * - * Copyright (C) 2011 Inverse inc + * Copyright (C) 2011-2012 Inverse inc * * Author: Wolfgang Sourdeau * @@ -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/OpenChange/unrtf-0.21.2.diff b/OpenChange/unrtf-0.21.2.diff index 466c2d16a..339480ac4 100644 --- a/OpenChange/unrtf-0.21.2.diff +++ b/OpenChange/unrtf-0.21.2.diff @@ -1,6 +1,6 @@ diff -durpN unrtf-0.21.2.old/outputs/html.conf unrtf-0.21.2/outputs/html.conf --- unrtf-0.21.2.old/outputs/html.conf 2010-08-15 08:44:09.000000000 -0400 -+++ unrtf-0.21.2/outputs/html.conf 2012-03-13 16:38:53.295941363 -0400 ++++ unrtf-0.21.2/outputs/html.conf 2012-08-21 13:33:44.761682724 -0400 @@ -5,7 +5,7 @@ comment_end --> @@ -21,7 +21,7 @@ diff -durpN unrtf-0.21.2.old/outputs/html.conf unrtf-0.21.2/outputs/html.conf diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c --- unrtf-0.21.2.old/src/attr.c 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/attr.c 2012-03-13 16:38:41.323940752 -0400 ++++ unrtf-0.21.2/src/attr.c 2012-08-21 13:38:56.717688715 -0400 @@ -1,23 +1,23 @@ /*============================================================================= - GNU UnRTF, a command-line program to convert RTF documents to other formats. @@ -504,7 +504,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + ++stack->tos; + stack->attr_stack[stack->tos] = attr; + if (param) -+ stack->attr_stack_params[stack->tos] = my_strdup(oc->conversion, param); ++ stack->attr_stack_params[stack->tos] = unrtf_strdup(oc->conversion, param); + else + stack->attr_stack_params[stack->tos] = NULL; @@ -641,7 +641,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + AttrStack *new_stack; - prev_stack = stack_of_stacks_top; -+ new_stack = (AttrStack*) my_malloc (sizeof (AttrStack)); ++ new_stack = (AttrStack*) unrtf_malloc (sizeof (AttrStack)); + memset ((void*) new_stack, 0, sizeof (AttrStack)); + new_stack->tos = -1; @@ -691,7 +691,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + attr_express_end (attr, param, oc); - if (param) my_free(param); -+ if (param) my_free(param); ++ if (param) unrtf_free(param); + stack->attr_stack_params[stack->tos] = NULL; - stack->tos--; @@ -769,7 +769,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + while (stack->tos>=0) + { + char *param=stack->attr_stack_params[stack->tos]; -+ if (param) my_free(param); ++ if (param) unrtf_free(param); + stack->attr_stack_params[stack->tos] = NULL; + stack->tos--; + } @@ -826,7 +826,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + } + } + -+ my_free ((void*) stack); ++ unrtf_free ((void*) stack); } /*======================================================================== @@ -859,7 +859,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + int attr=stack->attr_stack[stack->tos]; + char *param=stack->attr_stack_params[stack->tos]; + attr_express_end (attr,param, oc); -+ if (param) my_free(param); ++ if (param) unrtf_free(param); + stack->attr_stack_params[stack->tos] = NULL; + stack->tos--; + } @@ -1102,7 +1102,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + if (string == NULL) + return NULL; + else { -+ s = my_malloc(strlen(string) + 1 + 12/* Number of characters that can be in int type (including '\0') - AF */); ++ s = unrtf_malloc(strlen(string) + 1 + 12/* Number of characters that can be in int type (including '\0') - AF */); + while(string[i] != '\0' && (string[i] != '%' || (string[i] == '%' && (i != 0 && string[i-1] == '\\')))) { + if (string[i] != '\\' || string[i+1] != '%') { + s[j] = string[i]; @@ -1183,7 +1183,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c - c->text = text; + if (col == NULL) + { -+ col = (Collection *)my_malloc(sizeof(Collection)); ++ col = (Collection *)unrtf_malloc(sizeof(Collection)); + col->nr = nr; + col->text = strdup(text); + col->next = NULL; @@ -1195,7 +1195,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + if (c->nr == nr) + { + /* Here is a memory leak but not heavy. Do we need to care about this? -+ my_free(a->alias.text); ++ unrtf_free(a->alias.text); + */ + c->text = strdup(text); @@ -1214,7 +1214,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c - c->next->text = text; - c->next->next = NULL; - } -+ c->next = (Collection *)my_malloc(sizeof(Collection)); ++ c->next = (Collection *)unrtf_malloc(sizeof(Collection)); + c->next->nr = nr; + c->next->text = strdup(text); + c->next->next = NULL; @@ -1265,16 +1265,16 @@ diff -durpN unrtf-0.21.2.old/src/attr.c unrtf-0.21.2/src/attr.c + { + c2 = c->next; + if (c->text) { -+ my_free((void *)c->text); ++ unrtf_free((void *)c->text); + } -+ my_free((void *)c); ++ unrtf_free((void *)c); + c = c2; + } } - diff -durpN unrtf-0.21.2.old/src/attr.h unrtf-0.21.2/src/attr.h --- unrtf-0.21.2.old/src/attr.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/attr.h 2012-03-13 16:38:41.323940752 -0400 ++++ unrtf-0.21.2/src/attr.h 2012-08-21 13:33:44.785682699 -0400 @@ -1,23 +1,23 @@ /*============================================================================= - GNU UnRTF, a command-line program to convert RTF documents to other formats. @@ -1424,7 +1424,7 @@ diff -durpN unrtf-0.21.2.old/src/attr.h unrtf-0.21.2/src/attr.h +#endif /* ATTR_H */ diff -durpN unrtf-0.21.2.old/src/convert.c unrtf-0.21.2/src/convert.c --- unrtf-0.21.2.old/src/convert.c 2011-06-07 08:00:23.000000000 -0400 -+++ unrtf-0.21.2/src/convert.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/convert.c 2012-08-21 13:38:56.721688436 -0400 @@ -1,24 +1,24 @@ /*=========================================================================== @@ -2697,7 +2697,7 @@ diff -durpN unrtf-0.21.2.old/src/convert.c unrtf-0.21.2/src/convert.c - w=w->next; - } + oc->conversion->font_table[oc->conversion->total_fonts].num=num; -+ oc->conversion->font_table[oc->conversion->total_fonts].name=my_strdup(oc->conversion, name); ++ oc->conversion->font_table[oc->conversion->total_fonts].name=unrtf_strdup(oc->conversion, name); + if (safe_printf(device, 0, assemble_string(oc->personality->fonttable_fontnr, num))) fprintf(stderr, TOO_MANY_ARGS, "fonttable_fontnr"); + if (safe_printf(device, 1, oc->personality->fonttable_fontname, name)) fprintf(stderr, TOO_MANY_ARGS, "fonttable_fontname"); + oc->conversion->total_fonts++; @@ -2747,7 +2747,7 @@ diff -durpN unrtf-0.21.2.old/src/convert.c unrtf-0.21.2/src/convert.c + + for (i = 0; i < cc->total_fonts; i++) { + if (cc->font_table[i].name) { -+ my_free(cc->font_table[i].name); ++ unrtf_free(cc->font_table[i].name); + cc->font_table[i].name = NULL; + } + } @@ -3596,7 +3596,7 @@ diff -durpN unrtf-0.21.2.old/src/convert.c unrtf-0.21.2/src/convert.c + } else { + if (oc->personality->fonttable_begin != NULL) + { -+ name = my_malloc(12); ++ name = unrtf_malloc(12); + sprintf(name, "%d", num); + } #if 1 /* daved 0.21.1 */ @@ -6503,7 +6503,7 @@ diff -durpN unrtf-0.21.2.old/src/convert.c unrtf-0.21.2/src/convert.c - *doublet = (int)ch; - *(doublet+1) = (int)ch2; - *(doublet+2) = 0; -+ doublet = (int *)my_malloc(12); ++ doublet = (int *)unrtf_malloc(12); + *doublet = (int)ch; + *(doublet+1) = (int)ch2; + *(doublet+2) = 0; @@ -7058,7 +7058,7 @@ diff -durpN unrtf-0.21.2.old/src/convert.c unrtf-0.21.2/src/convert.c + + hash_free(&cc); + if (cc.input_str) -+ my_free(cc.input_str); ++ unrtf_free(cc.input_str); + word_free(word); + fonttable_free(oc.conversion); + if (my_iconv_is_valid(oc.conversion->desc)) @@ -7120,7 +7120,7 @@ diff -durpN unrtf-0.21.2.old/src/convert.c unrtf-0.21.2/src/convert.c } diff -durpN unrtf-0.21.2.old/src/convert.h unrtf-0.21.2/src/convert.h --- unrtf-0.21.2.old/src/convert.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/convert.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/convert.h 2012-08-21 13:33:44.793682720 -0400 @@ -36,18 +36,135 @@ #ifndef _CONVERT @@ -7264,7 +7264,7 @@ diff -durpN unrtf-0.21.2.old/src/convert.h unrtf-0.21.2/src/convert.h diff -durpN unrtf-0.21.2.old/src/defs.h unrtf-0.21.2/src/defs.h --- unrtf-0.21.2.old/src/defs.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/defs.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/defs.h 2012-08-21 13:33:44.817682703 -0400 @@ -64,9 +64,6 @@ #define SKIP_ONE_WORD 2 #endif @@ -7284,7 +7284,7 @@ diff -durpN unrtf-0.21.2.old/src/defs.h unrtf-0.21.2/src/defs.h +#define DEFAULT_OUTPUT "html" diff -durpN unrtf-0.21.2.old/src/error.c unrtf-0.21.2/src/error.c --- unrtf-0.21.2.old/src/error.c 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/error.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/error.c 2012-08-21 13:38:56.729687967 -0400 @@ -51,27 +51,11 @@ #include #endif @@ -7329,7 +7329,7 @@ diff -durpN unrtf-0.21.2.old/src/error.c unrtf-0.21.2/src/error.c #endif diff -durpN unrtf-0.21.2.old/src/error.h unrtf-0.21.2/src/error.h --- unrtf-0.21.2.old/src/error.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/error.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/error.h 2012-08-21 13:33:44.817682703 -0400 @@ -37,9 +37,10 @@ #define CHECK_MALLOC_SUCCESS(XX) { if ((XX)==NULL) { fprintf (stderr, "internal error: cannot allocate memory in %s at %d\n", __FILE__, __LINE__); exit (1); }} @@ -7344,7 +7344,7 @@ diff -durpN unrtf-0.21.2.old/src/error.h unrtf-0.21.2/src/error.h diff -durpN unrtf-0.21.2.old/src/hash.c unrtf-0.21.2/src/hash.c --- unrtf-0.21.2.old/src/hash.c 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/hash.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/hash.c 2012-08-21 13:38:56.733687861 -0400 @@ -53,24 +53,16 @@ #include #endif @@ -7442,12 +7442,12 @@ diff -durpN unrtf-0.21.2.old/src/hash.c unrtf-0.21.2/src/hash.c - i <<= 24; - hi->value = i | (hash_value++ & 0xffffff); - hi->next = NULL; -+ hi=(HashItem*) my_malloc(sizeof(HashItem)); ++ hi=(HashItem*) unrtf_malloc(sizeof(HashItem)); + if (!hi) + error_handler(cc, "Out of memory"); + memset ((void*)hi, 0, sizeof (HashItem)); + -+ hi->str = my_strdup(cc, str); ++ hi->str = unrtf_strdup(cc, str); + + i = *str; + if (i=='\\') i=str[1]; @@ -7529,7 +7529,7 @@ diff -durpN unrtf-0.21.2.old/src/hash.c unrtf-0.21.2/src/hash.c +{ + HashItem *next = item->next; + -+ my_free (item->str); ++ unrtf_free (item->str); + free (item); + if (next) + hashitem_free(next); @@ -7549,7 +7549,7 @@ diff -durpN unrtf-0.21.2.old/src/hash.c unrtf-0.21.2/src/hash.c +} diff -durpN unrtf-0.21.2.old/src/hash.h unrtf-0.21.2/src/hash.h --- unrtf-0.21.2.old/src/hash.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/hash.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/hash.h 2012-08-21 13:33:44.817682703 -0400 @@ -32,11 +32,15 @@ * 16 Dec 07, daved@physiol.usyd.edu.au: updated to GPL v3 *--------------------------------------------------------------------*/ @@ -7573,7 +7573,7 @@ diff -durpN unrtf-0.21.2.old/src/hash.h unrtf-0.21.2/src/hash.h +#endif /* HASH_H */ diff -durpN unrtf-0.21.2.old/src/main.c unrtf-0.21.2/src/main.c --- unrtf-0.21.2.old/src/main.c 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/main.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/main.c 2012-08-21 13:38:56.737687716 -0400 @@ -1,23 +1,23 @@ /*============================================================================= - GNU UnRTF, a command-line program to convert RTF documents to other formats. @@ -7995,7 +7995,7 @@ diff -durpN unrtf-0.21.2.old/src/main.c unrtf-0.21.2/src/main.c - diff -durpN unrtf-0.21.2.old/src/main.h unrtf-0.21.2/src/main.h --- unrtf-0.21.2.old/src/main.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/main.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/main.h 2012-08-21 13:33:44.821682709 -0400 @@ -35,21 +35,8 @@ * 17 Jan 10, daved@physiol.usyd.edu.au: change CONFIG_DIR to drop outputs/ *--------------------------------------------------------------------*/ @@ -8021,7 +8021,7 @@ diff -durpN unrtf-0.21.2.old/src/main.h unrtf-0.21.2/src/main.h +#define USAGE "unrtf [--version] [--verbose] [--help] [--nopict|-n] [--noremap] [--html] [--text] [--vt] [--latex] [--rtf] [-P config_search_path] [-t )] " diff -durpN unrtf-0.21.2.old/src/Makefile.am unrtf-0.21.2/src/Makefile.am --- unrtf-0.21.2.old/src/Makefile.am 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/Makefile.am 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/Makefile.am 2012-08-21 13:33:44.821682709 -0400 @@ -13,7 +13,6 @@ unrtf_SOURCES = attr.c attr.h \ malloc.c malloc.h \ output.c output.h \ @@ -8032,15 +8032,100 @@ diff -durpN unrtf-0.21.2.old/src/Makefile.am unrtf-0.21.2/src/Makefile.am util.c util.h \ diff -durpN unrtf-0.21.2.old/src/malloc.c unrtf-0.21.2/src/malloc.c --- unrtf-0.21.2.old/src/malloc.c 2010-07-09 01:13:05.000000000 -0400 -+++ unrtf-0.21.2/src/malloc.c 2012-03-13 16:38:41.327940973 -0400 -@@ -135,19 +135,19 @@ total_malloced (void) { ++++ unrtf-0.21.2/src/malloc.c 2012-08-21 13:39:15.329687813 -0400 +@@ -28,6 +28,8 @@ + * much memory is being used. + *---------------------------------------------------------------------- + * Changes: ++ * 21 Aug 12, wsourdeau@inverse.ca: renamed "my_*" to "unrtf_*", to ++ * avoid symbol classes with other libraries + * 14 Aug 01, tuorfa@yahoo.com: added Turbo C support. + * 16 Aug 01, Lars Unger : added Amiga/GCC support. + * 22 Sep 01, tuorfa@yahoo.com: added function-level comment blocks +@@ -35,7 +37,7 @@ + * 08 Oct 03, daved@physiol.usyd.edu.au: added stdlib.h for linux + * 29 Mar 05, daved@physiol.usyd.edu.au: changes requested by ZT Smith + * 16 Dec 07, daved@physiol.usyd.edu.au: updated to GPL v3 +- * 09 Nov 08, arkadiusz.firus@gmail.com: added my_realloc ++ * 09 Nov 08, arkadiusz.firus@gmail.com: added unrtf_realloc + *--------------------------------------------------------------------*/ + + #ifdef HAVE_CONFIG_H +@@ -60,14 +62,14 @@ + static unsigned long count=0; + + /*======================================================================== +- * Name: my_malloc ++ * Name: unrtf_malloc + * Purpose: Internal version of malloc necessary for record keeping. + * Args: Amount. + * Returns: Pointer. + *=======================================================================*/ + + char * +-my_malloc (unsigned long size) { ++unrtf_malloc (unsigned long size) { + char *ptr; + + ptr = malloc (size); +@@ -78,14 +80,14 @@ my_malloc (unsigned long size) { + } + + /*======================================================================== +- * Name: my_free ++ * Name: unrtf_free + * Purpose: Internal version of free necessary for record keeping. + * Args: Pointer. + * Returns: None. + *=======================================================================*/ + + void +-my_free (char* ptr) { ++unrtf_free (char* ptr) { + CHECK_PARAM_NOT_NULL(ptr); + + free (ptr); +@@ -93,20 +95,20 @@ my_free (char* ptr) { + + #if 1 /* AK3 - AF */ + /*======================================================================== +- * Name: my_realloc ++ * Name: unrtf_realloc + * Purpose: Internal version of realloc necessary for record keeping. + * Args: Pointer. + * Returns: None. + *=======================================================================*/ + char * +-my_realloc(char *ptr, unsigned long old_size, unsigned long new_size) ++unrtf_realloc(char *ptr, unsigned long old_size, unsigned long new_size) + { +- char *new_ptr = my_malloc(new_size); ++ char *new_ptr = unrtf_malloc(new_size); + + if (new_ptr != NULL) + memcpy(new_ptr, ptr, old_size); + +- my_free(ptr); ++ unrtf_free(ptr); + + return new_ptr; + } +@@ -128,26 +130,26 @@ total_malloced (void) { + + + /*======================================================================== +- * Name: my_strdup ++ * Name: unrtf_strdup + * Purpose: Internal version of strdup necessary for record keeping. + * Args: String. + * Returns: String. *=======================================================================*/ char * -my_strdup (char *src) { - unsigned long len; - char *ptr; -+my_strdup (struct ConversionContext *cc, char *src) { ++unrtf_strdup (struct ConversionContext *cc, char *src) { + unsigned long len; + char *ptr; @@ -8052,7 +8137,7 @@ diff -durpN unrtf-0.21.2.old/src/malloc.c unrtf-0.21.2/src/malloc.c - if (!ptr) - error_handler ("out of memory in strdup()"); + len = strlen(src); -+ ptr = my_malloc (len+1); ++ ptr = unrtf_malloc (len+1); + if (!ptr) + error_handler (cc, "out of memory in strdup()"); @@ -8063,32 +8148,253 @@ diff -durpN unrtf-0.21.2.old/src/malloc.c unrtf-0.21.2/src/malloc.c } /* added by daved */ #include -@@ -163,5 +163,5 @@ rpl_malloc (size_t n) +@@ -163,5 +165,5 @@ rpl_malloc (size_t n) { if (n == 0) n = 1; -return malloc (n); + return malloc (n); } +diff -durpN unrtf-0.21.2.old/src/malloc.c~ unrtf-0.21.2/src/malloc.c~ +--- unrtf-0.21.2.old/src/malloc.c~ 1969-12-31 19:00:00.000000000 -0500 ++++ unrtf-0.21.2/src/malloc.c~ 2012-08-21 13:38:56.745687548 -0400 +@@ -0,0 +1,169 @@ ++/*============================================================================= ++ GNU UnRTF, a command-line program to convert RTF documents to other formats. ++ Copyright (C) 2000,2001,2004 by Zachary Smith ++ ++ This program 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 of the License, or ++ (at your option) any later version. ++ ++ This program 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; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ ++ The maintainer is reachable by electronic mail at daved@physiol.usyd.edu.au ++=============================================================================*/ ++ ++ ++/*---------------------------------------------------------------------- ++ * Module name: malloc ++ * Author name: Zachary Smith ++ * Create date: 01 Aug 01 ++ * Purpose: Memory management. Allows us to keep track of how ++ * much memory is being used. ++ *---------------------------------------------------------------------- ++ * Changes: ++ * 21 Aug 12, wsourdeau@inverse.ca: rename "my_malloc" to "unrtf_malloc", to ++ * avoid symbol classes with other libraries ++ * 14 Aug 01, tuorfa@yahoo.com: added Turbo C support. ++ * 16 Aug 01, Lars Unger : added Amiga/GCC support. ++ * 22 Sep 01, tuorfa@yahoo.com: added function-level comment blocks ++ * 28 Sep 01, tuorfa@yahoo.com: removed Turbo C support. ++ * 08 Oct 03, daved@physiol.usyd.edu.au: added stdlib.h for linux ++ * 29 Mar 05, daved@physiol.usyd.edu.au: changes requested by ZT Smith ++ * 16 Dec 07, daved@physiol.usyd.edu.au: updated to GPL v3 ++ * 09 Nov 08, arkadiusz.firus@gmail.com: added unrtf_realloc ++ *--------------------------------------------------------------------*/ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#ifdef HAVE_STDIO_H ++#include ++#endif ++ ++#ifdef HAVE_STDLIB_H ++#include ++#endif ++ ++#ifdef HAVE_STRING_H ++#include ++#endif ++ ++#include "error.h" ++#include "malloc.h" ++ ++static unsigned long count=0; ++ ++/*======================================================================== ++ * Name: unrtf_malloc ++ * Purpose: Internal version of malloc necessary for record keeping. ++ * Args: Amount. ++ * Returns: Pointer. ++ *=======================================================================*/ ++ ++char * ++unrtf_malloc (unsigned long size) { ++ char *ptr; ++ ++ ptr = malloc (size); ++ if (ptr) ++ count += size; ++ ++ return ptr; ++} ++ ++/*======================================================================== ++ * Name: unrtf_free ++ * Purpose: Internal version of free necessary for record keeping. ++ * Args: Pointer. ++ * Returns: None. ++ *=======================================================================*/ ++ ++void ++unrtf_free (char* ptr) { ++ CHECK_PARAM_NOT_NULL(ptr); ++ ++ free (ptr); ++} ++ ++#if 1 /* AK3 - AF */ ++/*======================================================================== ++ * Name: unrtf_realloc ++ * Purpose: Internal version of realloc necessary for record keeping. ++ * Args: Pointer. ++ * Returns: None. ++ *=======================================================================*/ ++char * ++unrtf_realloc(char *ptr, unsigned long old_size, unsigned long new_size) ++{ ++ char *new_ptr = unrtf_malloc(new_size); ++ ++ if (new_ptr != NULL) ++ memcpy(new_ptr, ptr, old_size); ++ ++ unrtf_free(ptr); ++ ++ return new_ptr; ++} ++#endif ++ ++/*======================================================================== ++ * Name: total_malloced ++ * Purpose: Returns total amount of memory thus far allocated. Called at ++ * the end of main() when in debug mode. ++ * Args: None. ++ * Returns: Amount. ++ *=======================================================================*/ ++ ++unsigned long ++total_malloced (void) { ++ return count; ++} ++ ++ ++ ++/*======================================================================== ++ * Name: unrtf_strdup ++ * Purpose: Internal version of strdup necessary for record keeping. ++ * Args: String. ++ * Returns: String. ++ *=======================================================================*/ ++ ++char * ++unrtf_strdup (struct ConversionContext *cc, char *src) { ++ unsigned long len; ++ char *ptr; ++ ++ CHECK_PARAM_NOT_NULL(src); ++ ++ len = strlen(src); ++ ptr = unrtf_malloc (len+1); ++ if (!ptr) ++ error_handler (cc, "out of memory in strdup()"); ++ ++ sprintf (ptr, "%s", src); ++ return ptr; ++} ++/* added by daved */ ++#include ++#undef malloc ++ ++void *malloc (); ++ ++/* Allocate an N-byte block of memory from the heap. ++If N is zero, allocate a 1-byte block. */ ++ ++void * ++rpl_malloc (size_t n) ++{ ++ if (n == 0) ++ n = 1; ++ return malloc (n); ++} diff -durpN unrtf-0.21.2.old/src/malloc.h unrtf-0.21.2/src/malloc.h --- unrtf-0.21.2.old/src/malloc.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/malloc.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/malloc.h 2012-08-21 13:38:32.385687262 -0400 @@ -32,9 +32,10 @@ * 09 Nov 08, arkadiusz.firus@gmail.com: added my_realloc *--------------------------------------------------------------------*/ +-extern char * my_malloc (unsigned long); +-extern void my_free (char*); +-extern char * my_realloc(char*, unsigned long, unsigned long); +-extern unsigned long total_malloced (void); +-extern char * my_strdup (char*); ++struct ConversionContext; + ++extern char * unrtf_malloc (unsigned long); ++extern void unrtf_free (char*); ++extern char * unrtf_realloc(char*, unsigned long, unsigned long); ++extern unsigned long total_malloced (void); ++extern char * unrtf_strdup (struct ConversionContext *, char*); +diff -durpN unrtf-0.21.2.old/src/malloc.h~ unrtf-0.21.2/src/malloc.h~ +--- unrtf-0.21.2.old/src/malloc.h~ 1969-12-31 19:00:00.000000000 -0500 ++++ unrtf-0.21.2/src/malloc.h~ 2012-08-21 13:33:44.825682713 -0400 +@@ -0,0 +1,41 @@ ++/*============================================================================= ++ GNU UnRTF, a command-line program to convert RTF documents to other formats. ++ Copyright (C) 2000,2001,2004 by Zachary Smith ++ ++ This program 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 of the License, or ++ (at your option) any later version. ++ ++ This program 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; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ ++ The maintainer is reachable by electronic mail at daved@physiol.usyd.edu.au ++=============================================================================*/ ++ ++ ++/*---------------------------------------------------------------------- ++ * Module name: malloc ++ * Author name: Zachary Smith ++ * Create date: 1 Aug 2001 ++ * Purpose: Definitions for memory management. ++ *---------------------------------------------------------------------- ++ * Changes: ++ * 29 Mar 05, daved@physiol.usyd.edu.au: changes requested by ZT Smith ++ * 16 Dec 07, daved@physiol.usyd.edu.au: updated to GPL v3 ++ * 09 Nov 08, arkadiusz.firus@gmail.com: added my_realloc ++ *--------------------------------------------------------------------*/ ++ +struct ConversionContext; + - extern char * my_malloc (unsigned long); - extern void my_free (char*); - extern char * my_realloc(char*, unsigned long, unsigned long); - extern unsigned long total_malloced (void); --extern char * my_strdup (char*); -- ++extern char * my_malloc (unsigned long); ++extern void my_free (char*); ++extern char * my_realloc(char*, unsigned long, unsigned long); ++extern unsigned long total_malloced (void); +extern char * my_strdup (struct ConversionContext *, char*); diff -durpN unrtf-0.21.2.old/src/my_iconv.c unrtf-0.21.2/src/my_iconv.c --- unrtf-0.21.2.old/src/my_iconv.c 2010-08-16 00:12:43.000000000 -0400 -+++ unrtf-0.21.2/src/my_iconv.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/my_iconv.c 2012-08-21 13:38:56.753687604 -0400 @@ -12,154 +12,133 @@ #include #include @@ -8157,7 +8463,7 @@ diff -durpN unrtf-0.21.2.old/src/my_iconv.c unrtf-0.21.2/src/my_iconv.c -#endif + if ((cd.desc = iconv_open(tocode, fromcode)) == (iconv_t) -1) + { -+ path = my_malloc((strlen(cc->options->config_directory) + strlen(fromcode) + 10) * sizeof(char)); ++ path = unrtf_malloc((strlen(cc->options->config_directory) + strlen(fromcode) + 10) * sizeof(char)); + sprintf (path, "%s/%s.charmap", cc->options->config_directory, fromcode); - if (f != NULL) @@ -8176,7 +8482,7 @@ diff -durpN unrtf-0.21.2.old/src/my_iconv.c unrtf-0.21.2/src/my_iconv.c - } + if (f != NULL) + { -+ cd.char_table = (char **)my_malloc(char_table_size * sizeof(char *)); ++ cd.char_table = (char **)unrtf_malloc(char_table_size * sizeof(char *)); + c = fgetc(f); - fclose(f); @@ -8195,7 +8501,7 @@ diff -durpN unrtf-0.21.2.old/src/my_iconv.c unrtf-0.21.2/src/my_iconv.c + } - return cd; -+ my_free(path); ++ unrtf_free(path); + } + + return cd; @@ -8282,13 +8588,13 @@ diff -durpN unrtf-0.21.2.old/src/my_iconv.c unrtf-0.21.2/src/my_iconv.c + { + for (i = 0; i < char_table_size; i++) + { -+ my_free(cd.char_table[i]); ++ unrtf_free(cd.char_table[i]); + } - my_free((void *)cd.char_table); - cd.char_table = NULL; - } -+ my_free((void *)cd.char_table); ++ unrtf_free((void *)cd.char_table); + cd.char_table = NULL; + } @@ -8330,7 +8636,7 @@ diff -durpN unrtf-0.21.2.old/src/my_iconv.c unrtf-0.21.2/src/my_iconv.c diff -durpN unrtf-0.21.2.old/src/my_iconv.h unrtf-0.21.2/src/my_iconv.h --- unrtf-0.21.2.old/src/my_iconv.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/my_iconv.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/my_iconv.h 2012-08-21 13:33:44.825682713 -0400 @@ -5,6 +5,9 @@ * Purpose: my_conv definitions *--------------------------------------------------------------------*/ @@ -8360,7 +8666,7 @@ diff -durpN unrtf-0.21.2.old/src/my_iconv.h unrtf-0.21.2/src/my_iconv.h +#endif /* _MY_ICONV */ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c --- unrtf-0.21.2.old/src/output.c 2011-06-07 08:04:38.000000000 -0400 -+++ unrtf-0.21.2/src/output.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/output.c 2012-08-21 13:38:56.753687604 -0400 @@ -1,23 +1,23 @@ /*============================================================================= - GNU UnRTF, a command-line program to convert RTF documents to other formats. @@ -8432,7 +8738,7 @@ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c - new_op = (OutputPersonality*) my_malloc (sizeof(OutputPersonality)); - if (!new_op) - error_handler ("cannot allocate output personality"); -+ new_op = (OutputPersonality*) my_malloc (sizeof(OutputPersonality)); ++ new_op = (OutputPersonality*) unrtf_malloc (sizeof(OutputPersonality)); + if (!new_op) + error_handler (cc, "cannot allocate output personality"); @@ -8458,7 +8764,7 @@ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c + if (op->aliases) + free_collection(op->aliases); -+ my_free ((void*) op); ++ unrtf_free ((void*) op); +} /*======================================================================== @@ -8502,8 +8808,8 @@ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c + else + if (result == NULL) + { -+ originbuf = inbuf = my_malloc(inbytes + 1); -+ origoutbuf = outbuf = my_malloc(outbytes + 1); ++ originbuf = inbuf = unrtf_malloc(inbytes + 1); ++ origoutbuf = outbuf = unrtf_malloc(outbytes + 1); - for (i = inbytes - 1; ch > 255; i--) - { @@ -8712,12 +9018,12 @@ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c - *(inbuf+2) = 0; - fprintf(stderr, "inbuf = %o %o\n", *inbuf, *(inbuf+1)); - outbuf = my_malloc(outbytes + 1); -+ inbuf = (char *) my_malloc(inbytes + 1); ++ inbuf = (char *) unrtf_malloc(inbytes + 1); + *inbuf = *doublet; + *(inbuf+1) = (unsigned char *) *(doublet+1); + *(inbuf+2) = 0; + fprintf(stderr, "inbuf = %o %o\n", *inbuf, *(inbuf+1)); -+ outbuf = my_malloc(outbytes + 1); ++ outbuf = unrtf_malloc(outbytes + 1); #if 0 @@ -8925,7 +9231,7 @@ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c + else + if (result == NULL) + { -+ inbuf = (char *) my_malloc(inbytes + 1); ++ inbuf = (char *) unrtf_malloc(inbytes + 1); + *inbuf = ch1; + *(inbuf+1) = ch2; + *(inbuf+2) = 0; @@ -8934,7 +9240,7 @@ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c + fprintf(stderr, "inbuf = %o %o\n", *inbuf, *(inbuf+1)); #endif - outbuf = my_malloc(outbytes + 1); -+ outbuf = my_malloc(outbytes + 1); ++ outbuf = unrtf_malloc(outbytes + 1); - i = outbytes; - if (!my_iconv_is_valid(cd)) @@ -9544,7 +9850,7 @@ diff -durpN unrtf-0.21.2.old/src/output.c unrtf-0.21.2/src/output.c - diff -durpN unrtf-0.21.2.old/src/output.h unrtf-0.21.2/src/output.h --- unrtf-0.21.2.old/src/output.h 2010-08-11 21:09:02.000000000 -0400 -+++ unrtf-0.21.2/src/output.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/output.h 2012-08-21 13:33:44.829682714 -0400 @@ -44,227 +44,228 @@ typedef Collection Aliases; @@ -9932,7 +10238,7 @@ diff -durpN unrtf-0.21.2.old/src/output.h unrtf-0.21.2/src/output.h - diff -durpN unrtf-0.21.2.old/src/parse.c unrtf-0.21.2/src/parse.c --- unrtf-0.21.2.old/src/parse.c 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/parse.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/parse.c 2012-08-21 13:38:56.765687661 -0400 @@ -1,23 +1,23 @@ /*============================================================================= - GNU UnRTF, a command-line program to convert RTF documents to other formats. @@ -10172,7 +10478,7 @@ diff -durpN unrtf-0.21.2.old/src/parse.c unrtf-0.21.2/src/parse.c + error_handler(cc, "No input buffer allocated"); + old_length = cc->current_max_length; + cc->current_max_length *= 2; -+ new_ptr = my_malloc (cc->current_max_length); ++ new_ptr = unrtf_malloc (cc->current_max_length); + if (!new_ptr) + error_handler(cc, "Out of memory while resizing buffer"); @@ -10181,7 +10487,7 @@ diff -durpN unrtf-0.21.2.old/src/parse.c unrtf-0.21.2/src/parse.c - input_str = new_ptr; - return TRUE; + memcpy (new_ptr, cc->input_str, old_length); -+ my_free(cc->input_str); ++ unrtf_free(cc->input_str); + cc->input_str = new_ptr; + return TRUE; } @@ -10220,9 +10526,9 @@ diff -durpN unrtf-0.21.2.old/src/parse.c unrtf-0.21.2/src/parse.c + /* Get some storage for a word. + */ + if (cc->input_str) { -+ my_free(cc->input_str); ++ unrtf_free(cc->input_str); + } -+ cc->input_str = my_malloc (cc->current_max_length); ++ cc->input_str = unrtf_malloc (cc->current_max_length); + if (!cc->input_str) + error_handler(cc, "Cannot allocate word storage"); @@ -10600,13 +10906,13 @@ diff -durpN unrtf-0.21.2.old/src/parse.c unrtf-0.21.2/src/parse.c - input_str = NULL; - } while (1); + /* Free up the memory allocated by read_word. */ -+ my_free(cc->input_str); ++ unrtf_free(cc->input_str); + cc->input_str = NULL; + } while (1); } diff -durpN unrtf-0.21.2.old/src/parse.h unrtf-0.21.2/src/parse.h --- unrtf-0.21.2.old/src/parse.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/parse.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/parse.h 2012-08-21 13:33:44.829682714 -0400 @@ -38,8 +38,6 @@ #include "word.h" #endif @@ -10697,9 +11003,81 @@ diff -durpN unrtf-0.21.2.old/src/path.h unrtf-0.21.2/src/path.h - -int check_dirs(); -void show_dirs(); +diff -durpN unrtf-0.21.2.old/src/unicode.c unrtf-0.21.2/src/unicode.c +--- unrtf-0.21.2.old/src/unicode.c 2011-06-07 08:06:43.000000000 -0400 ++++ unrtf-0.21.2/src/unicode.c 2012-08-21 13:38:56.765687661 -0400 +@@ -55,20 +55,20 @@ unicode_to_string(int uc) + + if (uc < 0x7f) + { +- string = my_malloc(2 * sizeof(char)); ++ string = unrtf_malloc(2 * sizeof(char)); + string[0] = (unsigned char) uc; + string[1] = '\0'; + } + else if (uc < 0x7ff) + { +- string = my_malloc(3 * sizeof(char)); ++ string = unrtf_malloc(3 * sizeof(char)); + string[0] = (unsigned char) 192 + (uc / 64); + string[1] = (unsigned char) 128 + (uc % 64); + string[2] = '\0'; + } + else if (uc < 0xffff) + { +- string = my_malloc(4 * sizeof(char)); ++ string = unrtf_malloc(4 * sizeof(char)); + string[0] = (unsigned char) 224 + (uc / (64 * 64)); + string[1] = (unsigned char) 128 + ((uc / 64) % 64); + string[2] = (unsigned char) 128 + (uc % 64); +@@ -76,7 +76,7 @@ unicode_to_string(int uc) + } + else if (uc < 0x1FFFFF) + { +- string = my_malloc(5 * sizeof(char)); ++ string = unrtf_malloc(5 * sizeof(char)); + string[0] = (unsigned char) 240 + (uc / (64 * 64 * 64)); + string[1] = (unsigned char) 128 + ((uc / (64 * 64)) % 64); + string[2] = (unsigned char) 128 + ((uc / 64) % 64); +@@ -85,7 +85,7 @@ unicode_to_string(int uc) + } + else if (uc < 0x3FFFFFF) + { +- string = my_malloc(6 * sizeof(char)); ++ string = unrtf_malloc(6 * sizeof(char)); + string[0] = (unsigned char) 248 + (uc / (64 * 64 * 64 * 64)); + string[1] = (unsigned char) 128 + ((uc / (64 * 64 * 64)) % 64); + string[2] = (unsigned char) 128 + ((uc / (64 * 64)) % 64); +@@ -95,7 +95,7 @@ unicode_to_string(int uc) + } + else if (uc < 0x7FFFFFFF) + { +- string = my_malloc(7 * sizeof(char)); ++ string = unrtf_malloc(7 * sizeof(char)); + string[0] = (unsigned char) 252 + (uc / (64 * 64 * 64 * 64 * 64)); + string[1] = (unsigned char) 128 + ((uc / (64 * 64 * 64 * 64)) % 64); + string[2] = (unsigned char) 128 + ((uc / (64 * 64 * 64)) % 64); +@@ -122,7 +122,7 @@ char * + get_unicode_char(FILE *file) + { + int allocated = 5, len = 0, uc; +- char c, *unicode_number = my_malloc(allocated * sizeof(char)); ++ char c, *unicode_number = unrtf_malloc(allocated * sizeof(char)); + + c = fgetc(file); + +@@ -139,7 +139,7 @@ get_unicode_char(FILE *file) + if (len == allocated) + { + allocated *= 2; +- unicode_number = my_realloc(unicode_number, allocated / 2, allocated); ++ unicode_number = unrtf_realloc(unicode_number, allocated / 2, allocated); + } + } + diff -durpN unrtf-0.21.2.old/src/unrtf.h unrtf-0.21.2/src/unrtf.h --- unrtf-0.21.2.old/src/unrtf.h 1969-12-31 19:00:00.000000000 -0500 -+++ unrtf-0.21.2/src/unrtf.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/unrtf.h 2012-08-21 13:33:44.833682714 -0400 @@ -0,0 +1,55 @@ +/*=========================================================================== + GNU UnRTF, a command-line program to convert RTF documents to other formats. @@ -10758,7 +11136,7 @@ diff -durpN unrtf-0.21.2.old/src/unrtf.h unrtf-0.21.2/src/unrtf.h +#endif /* UNRTF_H */ diff -durpN unrtf-0.21.2.old/src/user.c unrtf-0.21.2/src/user.c --- unrtf-0.21.2.old/src/user.c 2011-06-07 08:08:17.000000000 -0400 -+++ unrtf-0.21.2/src/user.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/user.c 2012-08-21 13:38:56.773687616 -0400 @@ -7,7 +7,7 @@ *---------------------------------------------------------------------- * Changes: @@ -10790,7 +11168,7 @@ diff -durpN unrtf-0.21.2.old/src/user.c unrtf-0.21.2/src/user.c - if ((f->file = fopen(file_name, "r")) == NULL || (f->name = my_malloc((strlen(file_name) + 1) * sizeof(char))) == NULL) - return NULL; -+ if ((f->file = fopen(file_name, "r")) == NULL || (f->name = my_malloc((strlen(file_name) + 1) * sizeof(char))) == NULL) ++ if ((f->file = fopen(file_name, "r")) == NULL || (f->name = unrtf_malloc((strlen(file_name) + 1) * sizeof(char))) == NULL) + return NULL; - f->line_nr = 1; @@ -10810,7 +11188,7 @@ diff -durpN unrtf-0.21.2.old/src/user.c unrtf-0.21.2/src/user.c - fclose(f->file); - my_free(f->name); + fclose(f->file); -+ my_free(f->name); ++ unrtf_free(f->name); } /*======================================================================== @@ -10833,7 +11211,7 @@ diff -durpN unrtf-0.21.2.old/src/user.c unrtf-0.21.2/src/user.c +#define ADD_CHAR(char) \ + if (def_buffer_length == chars_nr) \ + { \ -+ if ((def = my_realloc(def, def_buffer_length, def_buffer_length * 2)) == NULL) \ ++ if ((def = unrtf_realloc(def, def_buffer_length, def_buffer_length * 2)) == NULL) \ + { \ + perror("Cannot allocate memory."); \ + return NULL; \ @@ -10855,7 +11233,7 @@ diff -durpN unrtf-0.21.2.old/src/user.c unrtf-0.21.2/src/user.c - if ((def = my_malloc(def_buffer_length)) == NULL) - return NULL; -+ if ((def = my_malloc(def_buffer_length)) == NULL) ++ if ((def = unrtf_malloc(def_buffer_length)) == NULL) + return NULL; - c = fgetc(file->file); @@ -11060,11 +11438,11 @@ diff -durpN unrtf-0.21.2.old/src/user.c unrtf-0.21.2/src/user.c + add_alias(op, get_unicode(&name[2]), def); + else + { -+ my_free (def); ++ unrtf_free (def); + fprintf(stderr, "unrtf: unknown name \"%s\" in line %d of \"%s\"\n", name, file->line_nr, file->name); + return 1; + } -+ my_free (def); ++ unrtf_free (def); + } + else + if ((*defs[i].variable = give_definition(file)) == NULL) @@ -11188,7 +11566,7 @@ diff -durpN unrtf-0.21.2.old/src/user.c unrtf-0.21.2/src/user.c diff -durpN unrtf-0.21.2.old/src/user.h unrtf-0.21.2/src/user.h --- unrtf-0.21.2.old/src/user.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/user.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/user.h 2012-08-21 13:33:44.833682714 -0400 @@ -151,9 +151,10 @@ #ifndef _USER @@ -11202,9 +11580,21 @@ diff -durpN unrtf-0.21.2.old/src/user.h unrtf-0.21.2/src/user.h #define _USER #endif +diff -durpN unrtf-0.21.2.old/src/util.c unrtf-0.21.2/src/util.c +--- unrtf-0.21.2.old/src/util.c 2010-08-09 08:05:30.000000000 -0400 ++++ unrtf-0.21.2/src/util.c 2012-08-21 13:38:56.777687600 -0400 +@@ -110,7 +110,7 @@ concatenate (const char *s1, const char + { + char *result; + +- result = my_malloc((strlen(s1) + strlen(s2) + 1) * sizeof(char)); ++ result = unrtf_malloc((strlen(s1) + strlen(s2) + 1) * sizeof(char)); + strcpy(result, s1); + strcat(result, s2); + diff -durpN unrtf-0.21.2.old/src/word.c unrtf-0.21.2/src/word.c --- unrtf-0.21.2.old/src/word.c 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/word.c 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/word.c 2012-08-21 13:38:56.781687591 -0400 @@ -1,23 +1,23 @@ /*============================================================================= - GNU UnRTF, a command-line program to convert RTF documents to other formats. @@ -11298,7 +11688,7 @@ diff -durpN unrtf-0.21.2.old/src/word.c unrtf-0.21.2/src/word.c - error_handler ("out of memory"); - memset ((void*) w, 0, sizeof(Word)); - if (!w) error_handler ("cannot allocate a Word"); -+ w = (Word *) my_malloc(sizeof(Word)); ++ w = (Word *) unrtf_malloc(sizeof(Word)); + if (!w) + error_handler (cc, "out of memory"); + memset ((void*) w, 0, sizeof(Word)); @@ -11346,7 +11736,7 @@ diff -durpN unrtf-0.21.2.old/src/word.c unrtf-0.21.2/src/word.c - } + prev = w; + w = w->next; -+ my_free((char*) prev); ++ unrtf_free((char*) prev); + } } @@ -11501,7 +11891,7 @@ diff -durpN unrtf-0.21.2.old/src/word.c unrtf-0.21.2/src/word.c + if (s != NULL && s1 != NULL && !strcmp(s1, s)) + { + w2->next = w->next; -+ my_free((char *)w); ++ unrtf_free((char *)w); + w = w2; + } + else @@ -11529,7 +11919,7 @@ diff -durpN unrtf-0.21.2.old/src/word.c unrtf-0.21.2/src/word.c diff -durpN unrtf-0.21.2.old/src/word.h unrtf-0.21.2/src/word.h --- unrtf-0.21.2.old/src/word.h 2010-07-03 22:30:58.000000000 -0400 -+++ unrtf-0.21.2/src/word.h 2012-03-13 16:38:41.327940973 -0400 ++++ unrtf-0.21.2/src/word.h 2012-08-21 13:33:44.833682714 -0400 @@ -41,14 +41,15 @@ typedef struct _w { struct _w * child; } Word; 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/SOPE/NGCards/ChangeLog b/SOPE/NGCards/ChangeLog index e5922829f..2dca4e482 100644 --- a/SOPE/NGCards/ChangeLog +++ b/SOPE/NGCards/ChangeLog @@ -9,6 +9,15 @@ * iCalRepeatableEntityObject.m (-exceptionDatesWithTimeZone:): we now consider the timezone of the EXDATE, if defined. +2012-07-26 Wolfgang Sourdeau + + * iCalTimeZonePeriod.m (-recurrenceRule): new accessor for the + "rrule" element. + (-startDate): made method public. + (-compare:): new method that compare two periods based on their + startDate, for timezone definitions which have a "standard" or + "daylight" period for more that one year. + 2012-05-30 Francis Lachapelle * iCalRepeatableEntityObject.m (-exceptionDatesWithTimeZone:) diff --git a/SOPE/NGCards/iCalTimeZonePeriod.h b/SOPE/NGCards/iCalTimeZonePeriod.h index a710630df..838176804 100644 --- a/SOPE/NGCards/iCalTimeZonePeriod.h +++ b/SOPE/NGCards/iCalTimeZonePeriod.h @@ -25,11 +25,20 @@ #import "CardGroup.h" +@class NSCalendarDate; + +@class iCalRecurrenceRule; + @interface iCalTimeZonePeriod : CardGroup +- (NSCalendarDate *) startDate; +- (iCalRecurrenceRule *) recurrenceRule; + - (NSCalendarDate *) occurenceForDate: (NSCalendarDate *) refDate; - (int) secondsOffsetFromGMT; +- (NSComparisonResult) compare: (iCalTimeZonePeriod *) otherPeriod; + @end #endif /* ICALTIMEZONEPERIOD_H */ diff --git a/SOPE/NGCards/iCalTimeZonePeriod.m b/SOPE/NGCards/iCalTimeZonePeriod.m index b161f55ab..f3613ee68 100644 --- a/SOPE/NGCards/iCalTimeZonePeriod.m +++ b/SOPE/NGCards/iCalTimeZonePeriod.m @@ -109,6 +109,11 @@ dateTime]; } +- (iCalRecurrenceRule *) recurrenceRule +{ + return (iCalRecurrenceRule *) [self firstChildWithTag: @"rrule"]; +} + /** * This method returns the date corresponding for to the start of the period * in the year of the reference date. @@ -184,4 +189,9 @@ return [self _secondsOfOffset: @"tzoffsetto"]; } +- (NSComparisonResult) compare: (iCalTimeZonePeriod *) otherPeriod +{ + return [[self startDate] compare: [otherPeriod startDate]]; +} + @end diff --git a/SoObjects/Mailer/SOGoMailFolder.m b/SoObjects/Mailer/SOGoMailFolder.m index 1bf4c6a30..5e6348bde 100644 --- a/SoObjects/Mailer/SOGoMailFolder.m +++ b/SoObjects/Mailer/SOGoMailFolder.m @@ -1171,6 +1171,9 @@ static NSString *defaultUserID = @"anyone"; NSEnumerator *usernames; NSString *username; + if ([mailboxACL isKindOfClass: [NSException class]]) + return; + newIMAPAcls = [NSMutableDictionary new]; usernames = [[mailboxACL allKeys] objectEnumerator]; @@ -1193,6 +1196,9 @@ static NSString *defaultUserID = @"anyone"; NSString *newUsername; NSString *imapPrefix; + if ([mailboxACL isKindOfClass: [NSException class]]) + return; + imapPrefix = [[[context activeUser] domainDefaults] imapAclGroupIdPrefix]; newIMAPAcls = [[NSMutableDictionary alloc] init]; diff --git a/SoObjects/SOGo/NSString+Utilities.h b/SoObjects/SOGo/NSString+Utilities.h index a94e48ce6..df82535e2 100644 --- a/SoObjects/SOGo/NSString+Utilities.h +++ b/SoObjects/SOGo/NSString+Utilities.h @@ -31,6 +31,7 @@ @interface NSString (SOGoURLExtension) +/* URL handling */ - (NSString *) composeURLWithAction: (NSString *) action parameters: (NSDictionary *) urlParameters andHash: (BOOL) useHash; @@ -40,13 +41,21 @@ - (NSString *) stringByDetectingURLs; +/* escaping */ - (NSString *) doubleQuotedString; -- (NSString *) jsonRepresentation; - +/* CSS and URL safety */ - (NSString *) asCSSIdentifier; - (NSString *) fromCSSIdentifier; +/* SQL safety */ +- (NSString *) asSafeSQLString; + +/* JSON */ +- (NSString *) jsonRepresentation; +- (BOOL) isJSONString; +- (id) objectFromJSONString; + /* bare email addresses */ - (NSString *) pureEMailAddress; @@ -54,6 +63,7 @@ - (NSRange) _rangeOfURLInRange: (NSRange) refRange; +/* LDAP */ - (BOOL) caseInsensitiveMatches: (NSString *) match; #ifndef GNUSTEP_BASE_LIBRARY @@ -62,14 +72,10 @@ - (int) timeValue; -- (BOOL) isJSONString; - -- (id) objectFromJSONString; - -- (NSString *) asSafeSQLString; - +/* substrings */ - (NSUInteger) countOccurrencesOfString: (NSString *) substring; - +- (NSString *) stringByReplacingPrefix: (NSString *) oldPrefix + withPrefix: (NSString *) newPrefix; /* Those methods provide symmetric enc-/decryption via a XOR operation */ - (NSString *) encryptWithKey: (NSString *) theKey; diff --git a/SoObjects/SOGo/NSString+Utilities.m b/SoObjects/SOGo/NSString+Utilities.m index ec04b9795..da5a69993 100644 --- a/SoObjects/SOGo/NSString+Utilities.m +++ b/SoObjects/SOGo/NSString+Utilities.m @@ -560,6 +560,24 @@ static int cssEscapingCount; return count; } +- (NSString *) stringByReplacingPrefix: (NSString *) oldPrefix + withPrefix: (NSString *) newPrefix +{ + NSUInteger oldPrefixLength; + NSString *newString; + + if (![self hasPrefix: oldPrefix]) + [NSException raise: NSInvalidArgumentException + format: @"string does not have the specified prefix"]; + + oldPrefixLength = [oldPrefix length]; + newString = [NSString stringWithFormat: @"%@%@", + newPrefix, + [self substringFromIndex: oldPrefixLength]]; + + return newString; +} + - (NSString *) encryptWithKey: (NSString *) theKey { NSMutableData *encryptedPassword; 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 abd556b9e..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=18 +MAJOR_VERSION=2 +MINOR_VERSION=0 +SUBMINOR_VERSION=0 diff --git a/packaging/debian-multiarch/control b/packaging/debian-multiarch/control index 0f1790b3e..1f861a83f 100644 --- a/packaging/debian-multiarch/control +++ b/packaging/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/packaging/debian-multiarch/rules b/packaging/debian-multiarch/rules index edfc67f6f..6f06fb1ac 100755 --- a/packaging/debian-multiarch/rules +++ b/packaging/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/packaging/debian-multiarch/sogo-openchange.install b/packaging/debian-multiarch/sogo-openchange.install new file mode 100644 index 000000000..d3f119d33 --- /dev/null +++ b/packaging/debian-multiarch/sogo-openchange.install @@ -0,0 +1,2 @@ +usr/lib/*/mapistore_backends/* +usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore diff --git a/packaging/debian-multiarch/sogo.docs b/packaging/debian-multiarch/sogo.docs index e789c21d8..ded20965f 100644 --- a/packaging/debian-multiarch/sogo.docs +++ b/packaging/debian-multiarch/sogo.docs @@ -1,4 +1,5 @@ NEWS TODO Scripts/*.sh +Scripts/*.py Scripts/updates.php diff --git a/packaging/debian/rules b/packaging/debian/rules index 4f2ffd513..b3b41ce65 100755 --- a/packaging/debian/rules +++ b/packaging/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 diff --git a/packaging/debian/sogo-openchange.install b/packaging/debian/sogo-openchange.install new file mode 100644 index 000000000..dcae5f4e2 --- /dev/null +++ b/packaging/debian/sogo-openchange.install @@ -0,0 +1,2 @@ +usr/lib/mapistore_backends/* +usr/lib/GNUstep/SOGo/SOGoBackend.MAPIStore diff --git a/packaging/debian/sogo.docs b/packaging/debian/sogo.docs index e789c21d8..ded20965f 100644 --- a/packaging/debian/sogo.docs +++ b/packaging/debian/sogo.docs @@ -1,4 +1,5 @@ NEWS TODO Scripts/*.sh +Scripts/*.py Scripts/updates.php diff --git a/packaging/rhel/sogo.spec b/packaging/rhel/sogo.spec index 70c939781..91d055fe2 100644 --- a/packaging/rhel/sogo.spec +++ b/packaging/rhel/sogo.spec @@ -3,6 +3,8 @@ %global oc_build_depends samba4 openchange %endif +%{!?python_sys_pyver: %global python_sys_pyver %(/usr/bin/python -c "import sys; print sys.hexversion")} + Summary: SOGo Name: sogo Version: %{sogo_version} @@ -17,7 +19,7 @@ Prefix: /usr AutoReqProv: off Requires: gnustep-base >= 1.23, sope%{sope_major_version}%{sope_minor_version}-core, httpd, sope%{sope_major_version}%{sope_minor_version}-core, sope%{sope_major_version}%{sope_minor_version}-appserver, sope%{sope_major_version}%{sope_minor_version}-ldap, sope%{sope_major_version}%{sope_minor_version}-cards >= %{sogo_version}, sope%{sope_major_version}%{sope_minor_version}-gdl1-contentstore >= %{sogo_version}, sope%{sope_major_version}%{sope_minor_version}-sbjson, libmemcached BuildRoot: %{_tmppath}/%{name}-%{version}-%{release} -BuildRequires: gcc-objc gnustep-base gnustep-make sope%{sope_major_version}%{sope_minor_version}-appserver-devel sope%{sope_major_version}%{sope_minor_version}-core-devel sope%{sope_major_version}%{sope_minor_version}-ldap-devel sope%{sope_major_version}%{sope_minor_version}-mime-devel sope%{sope_major_version}%{sope_minor_version}-xml-devel sope%{sope_major_version}%{sope_minor_version}-gdl1-devel sope%{sope_major_version}%{sope_minor_version}-sbjson-devel libmemcached-devel %{?oc_build_depends} +BuildRequires: gcc-objc gnustep-base gnustep-make sope%{sope_major_version}%{sope_minor_version}-appserver-devel sope%{sope_major_version}%{sope_minor_version}-core-devel sope%{sope_major_version}%{sope_minor_version}-ldap-devel sope%{sope_major_version}%{sope_minor_version}-mime-devel sope%{sope_major_version}%{sope_minor_version}-xml-devel sope%{sope_major_version}%{sope_minor_version}-gdl1-devel sope%{sope_major_version}%{sope_minor_version}-sbjson-devel libmemcached-devel sed %{?oc_build_depends} # Required by MS Exchange freebusy lookups @@ -133,6 +135,14 @@ SOGo backend for OpenChange rm -fr ${RPM_BUILD_ROOT} %setup -q -n SOGo-%{sogo_version} + +# small tweak to the python script for RHEL5 +# if hex(sys.hexversion) < 0x02060000 +%if %{python_sys_pyver} < 33947648 + sed -i 's!/usr/bin/env python!/usr/bin/env python2.6!' Scripts/openchange_cleanup.py +%endif + + # ****************************** build ******************************** %build . /usr/share/GNUstep/Makefiles/GNUstep.sh @@ -234,7 +244,7 @@ rm -fr ${RPM_BUILD_ROOT} %config(noreplace) %{_sysconfdir}/cron.d/sogo %config(noreplace) %{_sysconfdir}/httpd/conf.d/SOGo.conf %config(noreplace) %{_sysconfdir}/sysconfig/sogo -%doc ChangeLog NEWS Scripts/*sh Scripts/updates.php +%doc ChangeLog NEWS Scripts/*sh Scripts/*py Scripts/updates.php %files -n sogo-tool %{_sbindir}/sogo-tool @@ -312,6 +322,9 @@ fi # ********************************* changelog ************************* %changelog +* Tue Aug 28 2012 Jean Raby +- Add openchange_cleanup.py and tweak it to work on RHEL5 + * Tue Jul 31 2012 Jean Raby - treat logrotate file as a config file