From ed176ec946cd7955105298cfbb3c59ad69befa62 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 20 Sep 2011 19:37:03 +0000 Subject: [PATCH] Monotone-Parent: fde0ef781cb60652a47fc1c5edcece9225aafa07 Monotone-Revision: 07cb9d1891b96efc9f2a3c78eacb86dadf65aaa2 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2011-09-20T19:37:03 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 26 +++++ OpenChange/MAPIStoreCalendarMessage.m | 6 +- OpenChange/MAPIStoreContactsMessage.m | 6 +- OpenChange/MAPIStoreGCSFolder.h | 10 +- OpenChange/MAPIStoreGCSFolder.m | 148 ++++++++++++++++++++++---- OpenChange/MAPIStoreMailFolder.h | 4 + OpenChange/MAPIStoreMailFolder.m | 126 ++++++++++++++++++++++ OpenChange/MAPIStoreMailMessage.m | 40 +++++++ OpenChange/MAPIStoreTasksMessage.m | 4 + 9 files changed, 342 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index cd9e7dc73..5aac26f70 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,31 @@ 2011-09-20 Wolfgang Sourdeau + * OpenChange/MAPIStoreContactsMessage.m (-save): same as below. + + * OpenChange/MAPIStoreTasksMessage.m (-save): same as below. + + * OpenChange/MAPIStoreCalendarMessage.m (-save): set the + PR_CHANGE_KEY to the value passed by the client after the version + cache has been updated a first time. + + * OpenChange/MAPIStoreMailMessage.m (-getPrChangeKey:inMemCtx:, + (-getPrPredecessorChangeList:inMemCtx:): same as below. + + * OpenChange/MAPIStoreGCSMessage.m (-getPrChangeKey:inMemCtx:, + (-getPrPredecessorChangeList:inMemCtx:): wrapper accessors around + the getters defined in MAPIStoreGCSFolder below. + + * OpenChange/MAPIStoreMailFolder.m + (-setChangeKey:forMessageWithKey:, -changeKeyForMessageWithKey:) + (-predecessorChangeListForMessageWithKey:): same as below. + + * OpenChange/MAPIStoreGCSFolder.m (-changeKeyForMessageWithKey:) + (-predecessorChangeListForMessageWithKey:) + (-setChangeKey:forMessageWithKey: (NSString *) messageKey): new + methods for retrieving or setting the PR_CHANGE_KEY for the + specified record. The PR_PREDECESSOR_CHANGE_LIST is also handled, + albeit set automatically. + * OpenChange/NSString+MAPIStore.m (+stringWithGUID:) (-extractGUID:): new wrapper methods around the GUID utility functions in libndr. diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index c88b59260..1ded32e41 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -518,7 +518,7 @@ [person setEmail: [dict objectForKey: @"email"]]; [person setParticipationStatus: iCalPersonPartStatNeedsAction]; [person setRsvp: @"TRUE"]; - [person setRole: @"REQ-PARTICIPANT"]; + [person setRole: @"REQ-PARTICIPANT"]; // FIXME: We must NOT always rely on this if (![newEvent isAttendee: [person rfc822Email]]) @@ -531,6 +531,10 @@ [sogoObject saveComponent: newEvent]; } [(MAPIStoreCalendarFolder *) container synchroniseCache]; + value = [newProperties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)]; + if (value) + [(MAPIStoreCalendarFolder *) container + setChangeKey: value forMessageWithKey: [self nameInContainer]]; } - (id) lookupAttachment: (NSString *) childKey diff --git a/OpenChange/MAPIStoreContactsMessage.m b/OpenChange/MAPIStoreContactsMessage.m index 2d569cbae..ab03c8410 100644 --- a/OpenChange/MAPIStoreContactsMessage.m +++ b/OpenChange/MAPIStoreContactsMessage.m @@ -919,13 +919,17 @@ [[newCard uniqueChildWithTag: @"x-aim"] setValue: 0 to: value]; - } + } // // we save the new/modified card // [sogoObject saveContentString: [newCard versitString]]; [(MAPIStoreContactsFolder *) container synchroniseCache]; + value = [newProperties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)]; + if (value) + [(MAPIStoreContactsFolder *) container + setChangeKey: value forMessageWithKey: [self nameInContainer]]; } @end diff --git a/OpenChange/MAPIStoreGCSFolder.h b/OpenChange/MAPIStoreGCSFolder.h index d61c7cdd4..84ff6fcce 100644 --- a/OpenChange/MAPIStoreGCSFolder.h +++ b/OpenChange/MAPIStoreGCSFolder.h @@ -26,6 +26,7 @@ #import "MAPIStoreFolder.h" @class NSCalendarDate; +@class NSData; @class NSMutableDictionary; @class NSNumber; @class NSString; @@ -33,7 +34,6 @@ @interface MAPIStoreGCSFolder : MAPIStoreFolder { SOGoMAPIFSMessage *versionsMessage; - NSMutableDictionary *initialVersions; } /* synchronisation */ @@ -41,12 +41,14 @@ - (NSNumber *) lastModifiedFromMessageChangeNumber: (NSNumber *) changeNum; - (NSNumber *) changeNumberForMessageWithKey: (NSString *) messageKey; +- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey; +- (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey; +- (void) setChangeKey: (NSData *) changeKey + forMessageWithKey: (NSString *) messageKey; + /* subclasses */ - (EOQualifier *) componentQualifier; -- (void) setInitialVersion: (uint64_t) version - forMessage: (NSString *) theMessage; - @end #endif /* MAPISTOREGCSFOLDER_H */ diff --git a/OpenChange/MAPIStoreGCSFolder.m b/OpenChange/MAPIStoreGCSFolder.m index bcde67941..a114874b4 100644 --- a/OpenChange/MAPIStoreGCSFolder.m +++ b/OpenChange/MAPIStoreGCSFolder.m @@ -32,7 +32,9 @@ #import "MAPIStoreContext.h" #import "MAPIStoreTypes.h" +#import "NSData+MAPIStore.h" #import "NSDate+MAPIStore.h" +#import "NSString+MAPIStore.h" #import "SOGoMAPIFSMessage.h" #import "MAPIStoreGCSFolder.h" @@ -51,8 +53,6 @@ ASSIGN (versionsMessage, [SOGoMAPIFSMessage objectWithName: @"versions.plist" inContainer: propsFolder]); - - initialVersions = [[NSMutableDictionary alloc] init]; } return self; @@ -66,8 +66,6 @@ ASSIGN (versionsMessage, [SOGoMAPIFSMessage objectWithName: @"versions.plist" inContainer: propsFolder]); - - initialVersions = [[NSMutableDictionary alloc] init]; } return self; @@ -76,7 +74,6 @@ - (void) dealloc { [versionsMessage release]; - [initialVersions release]; [super dealloc]; } @@ -138,7 +135,7 @@ /* synchronisation */ -/* Tree: +/* Tree { SyncLastModseq = x; SyncLastSynchronisationDate = x; ** not updated until something changed @@ -147,6 +144,8 @@ Version = x; Modseq = x; Deleted = b; + ChangeKey = d; + PredecessorChangeList = { guid1 = globcnt1, guid2 ... }; }; ... }; @@ -155,12 +154,47 @@ ... } } -*/ + */ + +- (void) _setChangeKey: (NSData *) changeKey + forMessageEntry: (NSMutableDictionary *) messageEntry +{ + struct XID *xid; + NSString *guid; + NSData *globCnt; + NSDictionary *changeKeyDict; + NSMutableDictionary *changeList; + + xid = [changeKey asXIDInMemCtx: NULL]; + guid = [NSString stringWithGUID: &xid->GUID]; + globCnt = [NSData dataWithBytes: xid->Data length: xid->Size]; + talloc_free (xid); + + changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys: + guid, @"GUID", + globCnt, @"LocalId", + nil]; + + /* 1. set change key association */ + [messageEntry setObject: changeKeyDict forKey: @"ChangeKey"]; + + /* 2. append/update predecessor change list */ + changeList = [messageEntry objectForKey: @"PredecessorChangeList"]; + if (!changeList) + { + changeList = [NSMutableDictionary new]; + [messageEntry setObject: changeList + forKey: @"PredecessorChangeList"]; + [changeList release]; + } + [changeList setObject: globCnt forKey: guid]; +} - (BOOL) synchroniseCache { BOOL rc = YES, foundChange = NO; uint64_t newChangeNum; + NSData *changeKey; NSNumber *ti, *changeNumber, *lastModificationDate, *cName, *cVersion, *cLastModified; EOFetchSpecification *fs; EOQualifier *searchQualifier, *fetchQualifier; @@ -252,20 +286,16 @@ { foundChange = YES; - //if ([[messageEntry objectForKey: @"c_version"] intValue] == 0) - // newChangeNum = [[initialVersions objectForKey: cName] unsignedLongLongValue]; - //else - { - newChangeNum = [[self context] getNewChangeNumber]; - [initialVersions removeObjectForKey: cName]; - } - + newChangeNum = [[self context] getNewChangeNumber]; changeNumber = [NSNumber numberWithUnsignedLongLong: newChangeNum]; [messageEntry setObject: cLastModified forKey: @"c_lastmodified"]; [messageEntry setObject: cVersion forKey: @"c_version"]; [messageEntry setObject: changeNumber forKey: @"version"]; + changeKey = [self getReplicaKeyFromGlobCnt: newChangeNum >> 16]; + [self _setChangeKey: changeKey forMessageEntry: messageEntry]; + [mapping setObject: cLastModified forKey: changeNumber]; if (!lastModificationDate @@ -315,6 +345,87 @@ return changeNumber; } +- (void) setChangeKey: (NSData *) changeKey + forMessageWithKey: (NSString *) messageKey +{ + NSMutableDictionary *messages; + NSMutableDictionary *messageEntry; + + messages = [[versionsMessage properties] objectForKey: @"Messages"]; + messageEntry = [messages objectForKey: messageKey]; + if (!messageEntry) + abort (); + [self _setChangeKey: changeKey forMessageEntry: messageEntry]; + + [versionsMessage save]; +} + +- (NSData *) _dataFromChangeKeyGUID: (NSString *) guidString + andCnt: (NSData *) globCnt +{ + NSMutableData *changeKey; + struct GUID guid; + + changeKey = [NSMutableData dataWithCapacity: 16 + [globCnt length]]; + + [guidString extractGUID: &guid]; + [changeKey appendData: [NSData dataWithGUID: &guid]]; + [changeKey appendData: globCnt]; + + return changeKey; +} + +- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey +{ + NSDictionary *messages, *changeKeyDict; + NSString *guid; + NSData *globCnt, *changeKey = nil; + + messages = [[versionsMessage properties] objectForKey: @"Messages"]; + changeKeyDict = [[messages objectForKey: messageKey] + objectForKey: @"ChangeKey"]; + if (changeKeyDict) + { + guid = [changeKeyDict objectForKey: @"GUID"]; + globCnt = [changeKeyDict objectForKey: @"LocalId"]; + changeKey = [self _dataFromChangeKeyGUID: guid andCnt: globCnt]; + } + + return changeKey; +} + +- (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey +{ + NSMutableData *changeKeys = nil; + NSDictionary *messages, *changeListDict; + NSArray *keys; + NSUInteger count, max; + NSData *changeKey; + NSString *guid; + NSData *globCnt; + + messages = [[versionsMessage properties] objectForKey: @"Messages"]; + changeListDict = [[messages objectForKey: messageKey] + objectForKey: @"PredecessorChangeList"]; + if (changeListDict) + { + changeKeys = [NSMutableData data]; + keys = [changeListDict allKeys]; + max = [keys count]; + + for (count = 0; count < max; count++) + { + guid = [keys objectAtIndex: count]; + globCnt = [changeListDict objectForKey: guid]; + changeKey = [self _dataFromChangeKeyGUID: guid andCnt: globCnt]; + [changeKeys appendUInt8: [changeKey length]]; + [changeKeys appendData: changeKey]; + } + } + + return changeKeys; +} + - (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum andCN: (NSNumber **) cnNbr inTableType: (uint8_t) tableType @@ -410,11 +521,4 @@ return nil; } -- (void) setInitialVersion: (uint64_t) version - forMessage: (NSString *) theMessage -{ - [initialVersions setObject: [NSNumber numberWithUnsignedLongLong: version] - forKey: theMessage]; -} - @end diff --git a/OpenChange/MAPIStoreMailFolder.h b/OpenChange/MAPIStoreMailFolder.h index 2fec15d3d..3d8bad3f2 100644 --- a/OpenChange/MAPIStoreMailFolder.h +++ b/OpenChange/MAPIStoreMailFolder.h @@ -49,6 +49,10 @@ - (NSNumber *) modseqFromMessageChangeNumber: (NSNumber *) changeNum; - (NSNumber *) messageUIDFromMessageKey: (NSString *) messageKey; - (NSNumber *) changeNumberForMessageUID: (NSNumber *) messageUid; +- (void) setChangeKey: (NSData *) changeKey + forMessageWithKey: (NSString *) messageKey; +- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey; +- (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey; @end diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 236395433..7476c5a2c 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -53,6 +53,7 @@ #import "MAPIStoreMailMessageTable.h" #import "MAPIStoreMapping.h" #import "MAPIStoreTypes.h" +#import "NSData+MAPIStore.h" #import "NSString+MAPIStore.h" #import "SOGoMAPIFSMessage.h" @@ -436,6 +437,40 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) return [modseq1 compare: modseq2]; } +- (void) _setChangeKey: (NSData *) changeKey + forMessageEntry: (NSMutableDictionary *) messageEntry +{ + struct XID *xid; + NSString *guid; + NSData *globCnt; + NSDictionary *changeKeyDict; + NSMutableDictionary *changeList; + + xid = [changeKey asXIDInMemCtx: NULL]; + guid = [NSString stringWithGUID: &xid->GUID]; + globCnt = [NSData dataWithBytes: xid->Data length: xid->Size]; + talloc_free (xid); + + changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys: + guid, @"GUID", + globCnt, @"LocalId", + nil]; + + /* 1. set change key association */ + [messageEntry setObject: changeKeyDict forKey: @"ChangeKey"]; + + /* 2. append/update predecessor change list */ + changeList = [messageEntry objectForKey: @"PredecessorChangeList"]; + if (!changeList) + { + changeList = [NSMutableDictionary new]; + [messageEntry setObject: changeList + forKey: @"PredecessorChangeList"]; + [changeList release]; + } + [changeList setObject: globCnt forKey: guid]; +} + - (BOOL) synchroniseCache { BOOL rc = YES; @@ -446,6 +481,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) NSUInteger count, max; NSArray *fetchResults; NSDictionary *result; + NSData *changeKey; NSMutableDictionary *currentProperties, *messages, *mapping, *messageEntry; NSCalendarDate *now; @@ -519,6 +555,9 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) [messageEntry setObject: modseq forKey: @"modseq"]; [messageEntry setObject: changeNumber forKey: @"version"]; + changeKey = [self getReplicaKeyFromGlobCnt: newChangeNum >> 16]; + [self _setChangeKey: changeKey forMessageEntry: messageEntry]; + [mapping setObject: modseq forKey: changeNumber]; if (!lastModseq @@ -580,6 +619,93 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) return changeNumber; } +- (void) setChangeKey: (NSData *) changeKey + forMessageWithKey: (NSString *) messageKey +{ + NSMutableDictionary *messages; + NSMutableDictionary *messageEntry; + NSNumber *messageUid; + + messageUid = [self messageUIDFromMessageKey: messageKey]; + messages = [[versionsMessage properties] objectForKey: @"Messages"]; + messageEntry = [messages objectForKey: messageUid]; + if (!messageEntry) + abort (); + [self _setChangeKey: changeKey forMessageEntry: messageEntry]; + + [versionsMessage save]; +} + +- (NSData *) _dataFromChangeKeyGUID: (NSString *) guidString + andCnt: (NSData *) globCnt +{ + NSMutableData *changeKey; + struct GUID guid; + + changeKey = [NSMutableData dataWithCapacity: 16 + [globCnt length]]; + + [guidString extractGUID: &guid]; + [changeKey appendData: [NSData dataWithGUID: &guid]]; + [changeKey appendData: globCnt]; + + return changeKey; +} + +- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey +{ + NSDictionary *messages, *changeKeyDict; + NSString *guid; + NSNumber *messageUid; + NSData *globCnt, *changeKey = nil; + + messageUid = [self messageUIDFromMessageKey: messageKey]; + messages = [[versionsMessage properties] objectForKey: @"Messages"]; + changeKeyDict = [[messages objectForKey: messageUid] + objectForKey: @"ChangeKey"]; + if (changeKeyDict) + { + guid = [changeKeyDict objectForKey: @"GUID"]; + globCnt = [changeKeyDict objectForKey: @"LocalId"]; + changeKey = [self _dataFromChangeKeyGUID: guid andCnt: globCnt]; + } + + return changeKey; +} + +- (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey +{ + NSMutableData *changeKeys = nil; + NSDictionary *messages, *changeListDict; + NSArray *keys; + NSUInteger count, max; + NSData *changeKey; + NSString *guid; + NSNumber *messageUid; + NSData *globCnt; + + messageUid = [self messageUIDFromMessageKey: messageKey]; + messages = [[versionsMessage properties] objectForKey: @"Messages"]; + changeListDict = [[messages objectForKey: messageUid] + objectForKey: @"PredecessorChangeList"]; + if (changeListDict) + { + changeKeys = [NSMutableData data]; + keys = [changeListDict allKeys]; + max = [keys count]; + + for (count = 0; count < max; count++) + { + guid = [keys objectAtIndex: count]; + globCnt = [changeListDict objectForKey: guid]; + changeKey = [self _dataFromChangeKeyGUID: guid andCnt: globCnt]; + [changeKeys appendUInt8: [changeKey length]]; + [changeKeys appendData: changeKey]; + } + } + + return changeKeys; +} + - (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum andCN: (NSNumber **) cnNbr inTableType: (uint8_t) tableType diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index c4a344467..6bc2e56ef 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -270,6 +270,46 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) return appointmentWrapper; } +- (int) getPrChangeKey: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + int rc = MAPISTORE_SUCCESS; + NSData *changeKey; + + if (isNew) + rc = MAPISTORE_ERR_NOT_FOUND; + else + { + changeKey = [(MAPIStoreMailFolder *)[self container] + changeKeyForMessageWithKey: [self nameInContainer]]; + if (!changeKey) + abort (); + *data = [changeKey asBinaryInMemCtx: memCtx]; + } + + return rc; +} + +- (int) getPrPredecessorChangeList: (void **) data + inMemCtx: (TALLOC_CTX *) memCtx +{ + int rc = MAPISTORE_SUCCESS; + NSData *changeList; + + if (isNew) + rc = MAPISTORE_ERR_NOT_FOUND; + else + { + changeList = [(MAPIStoreMailFolder *)[self container] + predecessorChangeListForMessageWithKey: [self nameInContainer]]; + if (!changeList) + abort (); + *data = [changeList asBinaryInMemCtx: memCtx]; + } + + return rc; +} + - (uint64_t) objectVersion { uint64_t version = 0xffffffffffffffffLL; diff --git a/OpenChange/MAPIStoreTasksMessage.m b/OpenChange/MAPIStoreTasksMessage.m index 863ba04ef..f5fcd02ee 100644 --- a/OpenChange/MAPIStoreTasksMessage.m +++ b/OpenChange/MAPIStoreTasksMessage.m @@ -425,6 +425,10 @@ [sogoObject saveContentString: [vCalendar versitString]]; [(MAPIStoreTasksFolder *) container synchroniseCache]; + value = [newProperties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)]; + if (value) + [(MAPIStoreTasksFolder *) container + setChangeKey: value forMessageWithKey: [self nameInContainer]]; } @end