From 8e7f6d1aec1ebf05afe3330447cea4cf6797d3a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Fri, 23 Jan 2015 18:15:44 +0100 Subject: [PATCH 1/4] oc: avoid change number leaking when refreshing folder. Everytime a folder where its last operation was delete some email was requesting change numbers that were not used. --- OpenChange/MAPIStoreMailFolder.m | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 57679c1f1..3d85f3e62 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -637,16 +637,18 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) fetchResults = [(SOGoMailFolder *) sogoObject fetchUIDsOfVanishedItems: lastModseqNbr]; max = [fetchResults count]; - changeNumbers = [[self context] getNewChangeNumbers: max]; + changeNumber = nil; for (count = 0; count < max; count++) { uid = [[fetchResults objectAtIndex: count] stringValue]; if ([messages objectForKey: uid]) { - newChangeNum = [[changeNumbers objectAtIndex: count] - unsignedLongLongValue]; - changeNumber = [NSString stringWithUnsignedLongLong: newChangeNum]; + if (!changeNumber) + { + newChangeNum = [[self context] getNewChangeNumber]; + changeNumber = [NSString stringWithUnsignedLongLong: newChangeNum]; + } [messages removeObjectForKey: uid]; [self logWithFormat: @"Removed message entry for UID %@", uid]; } From 34efcfee4e4bc593d01efe64c0db2b7e20b1a994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Fri, 23 Jan 2015 18:17:45 +0100 Subject: [PATCH 2/4] oc: synchroniseCache store modseq for last delete change number. This will be the more frequent change number used to obtain updates on the folder related with deleted messages --- OpenChange/MAPIStoreMailFolder.m | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 3d85f3e62..11af956b2 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -661,6 +661,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) { [currentProperties setObject: changeNumber forKey: @"SyncLastDeleteChangeNumber"]; + [mapping setObject: lastModseq forKey: changeNumber]; foundChange = YES; } } From 47be392d4f92c6afb1954244fe52cc4344c2ae1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Fri, 23 Jan 2015 18:18:25 +0100 Subject: [PATCH 3/4] oc: avoid request change number until necessary Minor changenumber leak, but avoid it anyway --- OpenChange/MAPIStoreMailFolder.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 11af956b2..38e54b7af 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -762,7 +762,6 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) messageEntry = [messages objectForKey: messageUID]; if (!messageEntry) { - changeNumber = [[self context] getNewChangeNumber]; fetchResults = [(NSDictionary *) [sogoObject fetchUIDs: [NSArray arrayWithObject: messageUID] parts: [NSArray arrayWithObject: @"modseq"]] objectForKey: @"fetch"]; @@ -770,6 +769,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) { result = [fetchResults objectAtIndex: 0]; modseq = [result objectForKey: @"modseq"]; + changeNumber = [[self context] getNewChangeNumber]; changeNumberStr = [NSString stringWithUnsignedLongLong: changeNumber]; /* Create new message entry in Messages dict */ From 312084243b664932f55457738b30bc345457f5a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Garc=C3=ADa=20S=C3=A1ez?= Date: Fri, 23 Jan 2015 18:19:24 +0100 Subject: [PATCH 4/4] oc: improve modseqFromMessageChangeNumber to return an approximation. Only for scenarios where we hadn't store the cn <-> modseq relationship --- OpenChange/MAPIStoreMailFolder.m | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 38e54b7af..8c3983f7e 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -802,13 +802,43 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) return YES; } + - (NSNumber *) modseqFromMessageChangeNumber: (NSString *) changeNum { NSDictionary *mapping; NSNumber *modseq; + NSEnumerator *enumerator; + id key; + uint64_t found, target, current, replica_id, current_cn; + NSString *closestChangeNum; mapping = [[versionsMessage properties] objectForKey: @"VersionMapping"]; modseq = [mapping objectForKey: changeNum]; + if (modseq) return modseq; + + // Not found from stored change numbers for this folder. + // Get the closest modseq for the change number given. + // O(n) cost but will be unusual behaviour. + target = exchange_globcnt([changeNum unsignedLongLongValue] >> 16); + replica_id = [changeNum unsignedLongLongValue] & 0xFFFF; + found = 0; + enumerator = [mapping keyEnumerator]; + while ((key = [enumerator nextObject])) + { + current_cn = [(NSString *)key unsignedLongLongValue]; + if ((current_cn & 0xFFFF) != replica_id) + continue; + current = exchange_globcnt(current_cn >> 16); + if (current < target && current > found) + found = current; + } + + if (found) + { + closestChangeNum = [NSString stringWithUnsignedLongLong: + (exchange_globcnt(found) << 16 | replica_id)]; + modseq = [mapping objectForKey: closestChangeNum]; + } return modseq; }