From 017ebb901c26ee3e99d55be9a284671260466a57 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 5 Aug 2011 23:38:18 +0000 Subject: [PATCH] Monotone-Parent: 79e96bad18e27c8d142f04fe18be100bc2a7e975 Monotone-Revision: d63c864a1b3540c00d2825cbeb4a8cdb0a698ea6 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2011-08-05T23:38:18 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 + OpenChange/MAPIStoreAppointmentWrapper.h | 2 + OpenChange/MAPIStoreAppointmentWrapper.m | 245 +++++++++++++++++++---- 3 files changed, 215 insertions(+), 37 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9ab9dfea0..ab3d02f3b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2011-08-05 Wolfgang Sourdeau + * OpenChange/MAPIStoreAppointmentWrapper.m + (-getPidLidGlobalObjectId:inMemCtx:) + (-getPidLidCleanGlobalObjectId:inMemCtx:): reimplemented methods + by following the spec carefully (MS-OXICAL: 2.1.3.1.1.20.26). + * OpenChange/NSString+MAPIStore.m (-convertHexStringToBytes): new method that returns an NSData from a string of hex values represented as text. diff --git a/OpenChange/MAPIStoreAppointmentWrapper.h b/OpenChange/MAPIStoreAppointmentWrapper.h index 313bb2143..7df6d5f1b 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.h +++ b/OpenChange/MAPIStoreAppointmentWrapper.h @@ -37,6 +37,8 @@ extern NSTimeZone *utcTZ; iCalCalendar *calendar; iCalEvent *event; NSTimeZone *timeZone; + NSData *globalObjectId; + NSData *cleanGlobalObjectId; } + (id) wrapperWithICalEvent: (iCalEvent *) newEvent diff --git a/OpenChange/MAPIStoreAppointmentWrapper.m b/OpenChange/MAPIStoreAppointmentWrapper.m index e72621e97..544e80078 100644 --- a/OpenChange/MAPIStoreAppointmentWrapper.m +++ b/OpenChange/MAPIStoreAppointmentWrapper.m @@ -22,6 +22,7 @@ #import #import +#import #import #import #import @@ -41,9 +42,11 @@ #import "MAPIStoreAppointmentWrapper.h" #undef DEBUG +#include #include #include #include +#include #include #include #include @@ -51,12 +54,19 @@ NSTimeZone *utcTZ; +static NSCharacterSet *hexCharacterSet = nil; + @implementation MAPIStoreAppointmentWrapper + (void) initialize { utcTZ = [NSTimeZone timeZoneWithName: @"UTC"]; [utcTZ retain]; + if (!hexCharacterSet) + { + hexCharacterSet = [NSCharacterSet characterSetWithCharactersInString: @"1234567890abcdefABCDEF"]; + [hexCharacterSet retain]; + } } + (id) wrapperWithICalEvent: (iCalEvent *) newEvent @@ -71,6 +81,20 @@ NSTimeZone *utcTZ; return wrapper; } +- (id) init +{ + if ((self = [super init])) + { + calendar = nil; + event = nil; + timeZone = nil; + globalObjectId = nil; + cleanGlobalObjectId = nil; + } + + return self; +} + - (id) initWithICalEvent: (iCalEvent *) newEvent inTimeZone: (NSTimeZone *) newTimeZone { @@ -88,6 +112,9 @@ NSTimeZone *utcTZ; { [calendar release]; [event release]; + [timeZone release]; + [globalObjectId release]; + [cleanGlobalObjectId release]; [super dealloc]; } @@ -375,53 +402,197 @@ _fillAppointmentRecurrencePattern (struct AppointmentRecurrencePattern *arp, return rc; } +// - (int) getPidLidGlobalObjectId: (void **) data +// inMemCtx: (TALLOC_CTX *) memCtx +// { +// static char byteArrayId[] = {0x04, 0x00, 0x00, 0x00, 0x82, 0x00, 0xE0, +// 0x00, 0x74, 0xC5, 0xB7, 0x10, 0x1A, 0x82, +// 0xE0, 0x08}; +// static char X[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +// NSMutableData *nsData; +// NSData *uidData; +// NSCalendarDate *creationTime; +// struct FILETIME *creationFileTime; +// uint32_t uidDataLength; + +// nsData = [NSMutableData dataWithCapacity: 256]; +// [nsData appendBytes: byteArrayId length: 16]; + +// /* FIXME TODO */ +// [nsData appendBytes: X length: 4]; +// /* /FIXME */ + +// creationTime = [event created]; +// if (!creationTime) +// { +// [self logWithFormat: @"" __location__ ": event has no 'CREATED' tag -> inventing one"]; +// creationTime = [event lastModified]; +// if (!creationTime) +// creationTime = [NSCalendarDate date]; +// } +// creationFileTime = [creationTime asFileTimeInMemCtx: NULL]; +// [nsData appendBytes: &creationFileTime->dwLowDateTime length: 4]; +// [nsData appendBytes: &creationFileTime->dwHighDateTime length: 4]; +// talloc_free (creationFileTime); + +// uidData = [[event uid] dataUsingEncoding: NSUTF8StringEncoding]; +// uidDataLength = [uidData length]; +// [nsData appendBytes: &uidDataLength length: 4]; +// [nsData appendData: uidData]; +// *data = [nsData asBinaryInMemCtx: memCtx]; + +// return MAPISTORE_SUCCESS; +// } + +- (void) _setInstanceDate: (struct GlobalObjectId *) newGlobalId + fromDate: (NSCalendarDate *) instanceDate; +{ + uint16_t year; + + if (instanceDate) + { + [instanceDate setTimeZone: timeZone]; + year = [instanceDate yearOfCommonEra]; + newGlobalId->YH = year >> 8; + newGlobalId->YL = year & 0xff; + newGlobalId->Month = [instanceDate monthOfYear]; + newGlobalId->D = [instanceDate dayOfMonth]; + } +} + +/* note: returns a retained object */ +- (NSData *) _objectIdAsNSData: (const struct GlobalObjectId *) newGlobalId +{ + NSData *nsData; + TALLOC_CTX *localMemCtx; + struct ndr_push *ndr; + + localMemCtx = talloc_zero (NULL, TALLOC_CTX); + ndr = ndr_push_init_ctx (localMemCtx); + ndr_push_GlobalObjectId (ndr, NDR_SCALARS, newGlobalId); + nsData = [[NSData alloc] initWithBytes: ndr->data + length: ndr->offset]; + talloc_free (localMemCtx); + + return nsData; +} + +- (void) _computeGlobalObjectIds +{ + static NSString *prefix = @"040000008200e00074c5b7101a82e008"; + static uint8_t dataPrefix[] = { 0x76, 0x43, 0x61, 0x6c, 0x2d, 0x55, 0x69, + 0x64, 0x01, 0x00, 0x00, 0x00 }; + NSString *uid; + const char *uidAsUTF8; + NSUInteger uidLength; + NSData *encodedGlobalIdData; + struct Binary_r *encodedGlobalIdBinary; + struct GlobalObjectId *encodedGlobalId; + struct GlobalObjectId newGlobalId; + uint16_t year; + NSData *binPrefix; + TALLOC_CTX *localMemCtx; + + localMemCtx = talloc_zero (NULL, TALLOC_CTX); + + memset (&newGlobalId, 0, sizeof (struct GlobalObjectId)); + + uid = [event uid]; + uidLength = [uid length]; + if (uidLength >= 82 && (uidLength % 2) == 0 && [uid hasPrefix: prefix] + && [[uid stringByTrimmingCharactersInSet: hexCharacterSet] length] == 0) + { + encodedGlobalIdData = [uid convertHexStringToBytes]; + if (encodedGlobalIdData) + { + encodedGlobalIdBinary + = [encodedGlobalIdData asBinaryInMemCtx: localMemCtx]; + encodedGlobalId = get_GlobalObjectId (localMemCtx, + encodedGlobalIdBinary); + if (encodedGlobalId) + { + memcpy (newGlobalId.ByteArrayID, + encodedGlobalId->ByteArrayID, + 16); + year = ((uint16_t) encodedGlobalId->YH << 8) | encodedGlobalId->YL; + if (year >= 1601 && year <= 4500 + && encodedGlobalId->Month > 0 && encodedGlobalId->Month < 13 + && encodedGlobalId->D > 0 && encodedGlobalId->D < 31) + { + newGlobalId.YH = encodedGlobalId->YH; + newGlobalId.YL = encodedGlobalId->YL; + newGlobalId.Month = encodedGlobalId->Month; + newGlobalId.D = encodedGlobalId->D; + } + else + [self _setInstanceDate: &newGlobalId + fromDate: [event recurrenceId]]; + newGlobalId.CreationTime = encodedGlobalId->CreationTime; + memcpy (newGlobalId.X, encodedGlobalId->X, 8); + newGlobalId.Size = encodedGlobalId->Size; + newGlobalId.Data = encodedGlobalId->Data; + } + else + abort (); + } + else + abort (); + } + else + { + binPrefix = [prefix convertHexStringToBytes]; + [binPrefix getBytes: &newGlobalId.ByteArrayID]; + [self _setInstanceDate: &newGlobalId + fromDate: [event recurrenceId]]; + uidAsUTF8 = [uid UTF8String]; + newGlobalId.Size = 0x0c + strlen (uidAsUTF8); + newGlobalId.Data = talloc_array (localMemCtx, uint8_t, + newGlobalId.Size); + memcpy (newGlobalId.Data, dataPrefix, 0x0c); + memcpy (newGlobalId.Data + 0x0c, uidAsUTF8, newGlobalId.Size - 0x0c); + } + + globalObjectId = [self _objectIdAsNSData: &newGlobalId]; + + newGlobalId.YH = 0; + newGlobalId.YL = 0; + newGlobalId.Month = 0; + newGlobalId.D = 0; + cleanGlobalObjectId = [self _objectIdAsNSData: &newGlobalId]; + + talloc_free (localMemCtx); +} + - (int) getPidLidGlobalObjectId: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - static char byteArrayId[] = {0x04, 0x00, 0x00, 0x00, 0x82, 0x00, 0xE0, - 0x00, 0x74, 0xC5, 0xB7, 0x10, 0x1A, 0x82, - 0xE0, 0x08}; - static char X[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - NSMutableData *nsData; - NSData *uidData; - NSCalendarDate *creationTime; - struct FILETIME *creationFileTime; - uint32_t uidDataLength; + int rc = MAPISTORE_SUCCESS; - nsData = [NSMutableData dataWithCapacity: 256]; - [nsData appendBytes: byteArrayId length: 16]; + if (!globalObjectId) + [self _computeGlobalObjectIds]; - /* FIXME TODO */ - [nsData appendBytes: X length: 4]; - /* /FIXME */ - - creationTime = [event created]; - if (!creationTime) - { - [self logWithFormat: @"" __location__ ": event has no 'CREATED' tag -> inventing one"]; - creationTime = [event lastModified]; - if (!creationTime) - creationTime = [NSCalendarDate date]; - } - creationFileTime = [creationTime asFileTimeInMemCtx: NULL]; - [nsData appendBytes: &creationFileTime->dwLowDateTime length: 4]; - [nsData appendBytes: &creationFileTime->dwHighDateTime length: 4]; - talloc_free (creationFileTime); - - uidData = [[event uid] dataUsingEncoding: NSUTF8StringEncoding]; - uidDataLength = [uidData length]; - [nsData appendBytes: &uidDataLength length: 4]; - [nsData appendData: uidData]; - *data = [nsData asBinaryInMemCtx: memCtx]; - - return MAPISTORE_SUCCESS; + if (globalObjectId) + *data = [globalObjectId asBinaryInMemCtx: memCtx]; + else + abort (); + + return rc; } - (int) getPidLidCleanGlobalObjectId: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - return [self getPidLidGlobalObjectId: data - inMemCtx: memCtx]; + int rc = MAPISTORE_SUCCESS; + + if (!cleanGlobalObjectId) + [self _computeGlobalObjectIds]; + + if (cleanGlobalObjectId) + *data = [cleanGlobalObjectId asBinaryInMemCtx: memCtx]; + else + abort (); + + return rc; } @end