oc: Update predecessor change list on saving

There were cases where only the change key was updated (GCS) or
others were the change key was updated with wrong info.

This changeset has as goal to update the predecessor change list
and, change key if required, on saving taking into account the latest information
given by the client in high level ROPs such as ImportMessageMove
or SetProperties, and merge it with information provided by the server
backend (IMAP server, SOGo DB) using `synchroniseCache`.

For more details about `PidTagChangeKey` and `PidTagPredecessorChangeList`
property values check [MS-OXCFXICS] Section 2.2.1.2
This commit is contained in:
Enrique J. Hernández Blasco
2015-07-20 11:17:00 +02:00
parent 8d9b54815c
commit 321672e2c3
8 changed files with 292 additions and 32 deletions
+82 -16
View File
@@ -261,7 +261,6 @@ static Class NSNumberK;
*/
- (void) _setChangeKey: (NSData *) changeKey
forMessageEntry: (NSMutableDictionary *) messageEntry
inChangeListOnly: (BOOL) inChangeListOnly
{
struct XID *xid;
NSString *guid;
@@ -274,15 +273,11 @@ static Class NSNumberK;
globCnt = [NSData dataWithBytes: xid->LocalId.data length: xid->LocalId.length];
talloc_free (xid);
if (!inChangeListOnly)
{
/* 1. set change key association */
changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys:
guid, @"GUID",
globCnt, @"LocalId",
nil];
[messageEntry setObject: changeKeyDict forKey: @"ChangeKey"];
}
/* 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"];
@@ -296,6 +291,77 @@ static Class NSNumberK;
[changeList setObject: globCnt forKey: guid];
}
- (void) _updatePredecessorChangeList: (NSData *) predecessorChangeList
forMessageEntry: (NSMutableDictionary *) messageEntry
withOldChangeKey: (NSData *) oldChangeKey
{
NSData *globCnt, *oldGlobCnt;
NSDictionary *changeKeyDict;
NSString *guid;
NSMutableDictionary *changeList;
struct SizedXid *sizedXIDList;
struct XID xid, *givenChangeKey;
TALLOC_CTX *localMemCtx;
uint32_t i, length;
localMemCtx = talloc_new (NULL);
if (!localMemCtx)
{
[self errorWithFormat: @"No more memory"];
return;
}
if (predecessorChangeList)
{
sizedXIDList = [predecessorChangeList asSizedXidArrayInMemCtx: localMemCtx with: &length];
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
if (!changeList)
{
changeList = [NSMutableDictionary new];
[messageEntry setObject: changeList
forKey: @"PredecessorChangeList"];
[changeList release];
}
if (sizedXIDList) {
for (i = 0; i < length; i++)
{
xid = sizedXIDList[i].XID;
guid = [NSString stringWithGUID: &xid.NameSpaceGuid];
globCnt = [NSData dataWithBytes: xid.LocalId.data length: xid.LocalId.length];
oldGlobCnt = [changeList objectForKey: guid];
if (!oldGlobCnt || ([globCnt compare: oldGlobCnt] == NSOrderedDescending))
[changeList setObject: globCnt forKey: guid];
}
}
}
if (oldChangeKey)
{
givenChangeKey = [oldChangeKey asXIDInMemCtx: localMemCtx];
if (givenChangeKey) {
guid = [NSString stringWithGUID: &givenChangeKey->NameSpaceGuid];
globCnt = [NSData dataWithBytes: givenChangeKey->LocalId.data length: givenChangeKey->LocalId.length];
changeKeyDict = [messageEntry objectForKey: @"ChangeKey"];
if (!changeKeyDict ||
([guid isEqualToString: [changeKeyDict objectForKey: @"GUID"]]
&& ([globCnt compare: [changeKeyDict objectForKey: @"LocalId"]] == NSOrderedDescending)))
{
/* The given change key is greater than current one stored in
metadata or it does not exist */
[messageEntry setObject: [NSDictionary dictionaryWithObjectsAndKeys: guid, @"GUID",
globCnt, @"LocalId",
nil]
forKey: @"ChangeKey"];
}
}
}
talloc_free (localMemCtx);
}
- (EOQualifier *) componentQualifier
{
if (!componentQualifier)
@@ -465,8 +531,7 @@ static Class NSNumberK;
// A GLOBCNT structure is a 6-byte global namespace counter,
// we strip the first 2 bytes. The first two bytes is the ReplicaId
changeKey = [self getReplicaKeyFromGlobCnt: newChangeNum >> 16];
[self _setChangeKey: changeKey forMessageEntry: messageEntry
inChangeListOnly: NO];
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
}
now = [NSCalendarDate date];
@@ -483,12 +548,13 @@ static Class NSNumberK;
}
- (void) updateVersionsForMessageWithKey: (NSString *) messageKey
withChangeKey: (NSData *) newChangeKey
withChangeKey: (NSData *) oldChangeKey
andPredecessorChangeList: (NSData *) pcl
{
NSMutableDictionary *messages, *messageEntry;
[self synchroniseCache];
if (newChangeKey)
if (oldChangeKey || pcl)
{
messages = [[versionsMessage properties] objectForKey: @"Messages"];
messageEntry = [messages objectForKey: messageKey];
@@ -496,8 +562,8 @@ static Class NSNumberK;
[NSException raise: @"MAPIStoreIOException"
format: @"no version record found for message '%@'",
messageKey];
[self _setChangeKey: newChangeKey forMessageEntry: messageEntry
inChangeListOnly: YES];
[self _updatePredecessorChangeList: pcl forMessageEntry: messageEntry
withOldChangeKey: oldChangeKey];
[versionsMessage save];
}
}