From 31ace947cbf1fbbfa93a92ed0f028e5a56b8b0d1 Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Thu, 6 Mar 2014 14:16:08 -0500 Subject: [PATCH] Fixed race condition when syncing huge amount of deleted messages using AS --- ActiveSync/SOGoActiveSyncDispatcher+Sync.m | 77 ++++++++++++++-------- NEWS | 1 + SoObjects/Mailer/SOGoMailFolder.m | 14 ++-- 3 files changed, 62 insertions(+), 30 deletions(-) diff --git a/ActiveSync/SOGoActiveSyncDispatcher+Sync.m b/ActiveSync/SOGoActiveSyncDispatcher+Sync.m index dfa0b3110..551551e8d 100644 --- a/ActiveSync/SOGoActiveSyncDispatcher+Sync.m +++ b/ActiveSync/SOGoActiveSyncDispatcher+Sync.m @@ -571,24 +571,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. case ActiveSyncMailFolder: default: { + NSMutableArray *addedOrChangedMessages; SOGoMailObject *mailObject; NSString *uid, *command; NSDictionary *aMessage; NSArray *allMessages; - + int deleted_count; + allMessages = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType]; - + addedOrChangedMessages = [NSMutableArray array]; + deleted_count = 0; + // Check for the WindowSize. // FIXME: we should eventually check for modseq and slice the maximum // amount of messages returned to ensure we don't have the same // modseq accross contiguous boundaries max = [allMessages count]; - if (max > theWindowSize) - { - max = theWindowSize; - more_available = YES; - } + // We first check the number of deleted messages we have + // We do NOT honor the window size here as it seems to be + // impossible to get the modseq of an expunged message so + // we can't iterate in the list of deleted messages. for (i = 0; i < max; i++) { aMessage = [allMessages objectAtIndex: i]; @@ -601,31 +604,53 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [s appendString: @""]; [s appendFormat: @"%@", uid]; [s appendString: @""]; + deleted_count++; } else { - if ([command isEqualToString: @"added"]) - [s appendString: @""]; - else - [s appendString: @""]; - - mailObject = [theCollection lookupName: uid - inContext: context - acquire: 0]; - - [s appendFormat: @"%@", uid]; - [s appendString: @""]; - [s appendString: [mailObject activeSyncRepresentationInContext: context]]; - [s appendString: @""]; - - if ([command isEqualToString: @"added"]) - [s appendString: @""]; - else - [s appendString: @""]; - + [addedOrChangedMessages addObject: aMessage]; } } + // We then "pad" with our added/changed messages. We ALWAYS + // at least return one if available + max = [addedOrChangedMessages count]; + + for (i = 0; i < max; i++) + { + aMessage = [addedOrChangedMessages objectAtIndex: i]; + + uid = [[[aMessage allKeys] lastObject] stringValue]; + command = [[aMessage allValues] lastObject]; + + if ([command isEqualToString: @"added"]) + [s appendString: @""]; + else + [s appendString: @""]; + + mailObject = [theCollection lookupName: uid + inContext: context + acquire: 0]; + + [s appendFormat: @"%@", uid]; + [s appendString: @""]; + [s appendString: [mailObject activeSyncRepresentationInContext: context]]; + [s appendString: @""]; + + if ([command isEqualToString: @"added"]) + [s appendString: @""]; + else + [s appendString: @""]; + + + // We check if we must stop padding + if (i+1+deleted_count > theWindowSize) + { + more_available = YES; + break; + } + } + // if (more_available) { diff --git a/NEWS b/NEWS index 09a3bb241..4a3a731b5 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ Bug fixes - fixed encoding of mail folder name when creating a subfolder (#2637) - fixed returned date format for email messages in Active Sync - fixed missing 'name part' in address for email messages in Active Sync + - fixed race condition when syncing huge amount of deleted messages over Active Sync 2.2.0 (2014-02-24) ------------------ diff --git a/SoObjects/Mailer/SOGoMailFolder.m b/SoObjects/Mailer/SOGoMailFolder.m index abf4bf100..7f45ec814 100644 --- a/SoObjects/Mailer/SOGoMailFolder.m +++ b/SoObjects/Mailer/SOGoMailFolder.m @@ -1940,8 +1940,11 @@ static NSString *defaultUserID = @"anyone"; uid = [theId intValue]; result = [[imap4 client] fetchModseqForUid: uid]; modseq = [[[[result objectForKey: @"RawResponse"] objectForKey: @"fetch"] objectForKey: @"modseq"] intValue]; - - tag = [NSString stringWithFormat: @"%d-%d", uid, modseq-1]; + + if (modseq < 1) + modseq = 1; + + tag = [NSString stringWithFormat: @"%d-%d", uid, modseq]; } return tag; @@ -1999,7 +2002,7 @@ static NSString *defaultUserID = @"anyone"; // Check updated items // // -// . uid fetch 1:* (FLAGS) (changedsince 171) +// . uid fetch 1:* (UID) (changedsince 171) // // To get the modseq of a specific message: // @@ -2101,11 +2104,14 @@ static NSString *defaultUserID = @"anyone"; // We fetch deleted ones if (highestmodseq > 0) { + id uid; + uids = [self fetchUIDsOfVanishedItems: highestmodseq]; for (i = 0; i < [uids count]; i++) { - d = [NSDictionary dictionaryWithObject: @"deleted" forKey: [uids objectAtIndex: i]]; + uid = [uids objectAtIndex: i]; + d = [NSDictionary dictionaryWithObject: @"deleted" forKey: uid]; [allTokens addObject: d]; } }