Improved modseq code

pull/39/head
Ludovic Marcotte 2014-05-15 14:44:53 -04:00
parent c8860dc92b
commit c08c3e27d5
2 changed files with 82 additions and 25 deletions

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2009-2011 Inverse inc.
Copyright (C) 2009-2014 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of SOGo
@ -94,7 +94,6 @@
- (NSCalendarDate *) mostRecentMessageDate;
- (NSString *) davCollectionTagFromId: (NSString *) theId;
- (NSString *) davCollectionTag;
- (NSArray *) syncTokenFieldsWithProperties: (NSDictionary *) properties

View File

@ -72,6 +72,28 @@
static NSString *defaultUserID = @"anyone";
static NSComparisonResult
_compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
{
static NSNumber *zeroNumber = nil;
NSNumber *modseq1, *modseq2;
if (!zeroNumber)
{
zeroNumber = [NSNumber numberWithUnsignedLongLong: 0];
[zeroNumber retain];
}
modseq1 = [entry1 objectForKey: @"modseq"];
if (!modseq1)
modseq1 = zeroNumber;
modseq2 = [entry2 objectForKey: @"modseq"];
if (!modseq2)
modseq2 = zeroNumber;
return [modseq1 compare: modseq2];
}
@interface NGImap4Connection (PrivateMethods)
- (NSString *) imap4FolderNameForURL: (NSURL *) url;
@ -808,8 +830,9 @@ static NSString *defaultUserID = @"anyone";
- (NSArray *) fetchUIDs: (NSArray *) _uids
parts: (NSArray *) _parts
{
return [[self imap4Connection] fetchUIDs: _uids inURL: [self imap4URL]
parts: _parts];
return [[self imap4Connection] fetchUIDs: _uids
inURL: [self imap4URL]
parts: _parts];
}
- (NSArray *) fetchUIDsOfVanishedItems: (uint64_t) modseq
@ -835,7 +858,7 @@ static NSString *defaultUserID = @"anyone";
toFolderURL: [self imap4URL]];
return [NSException exceptionWithHTTPStatus: 502 /* Bad Gateway */
reason: [NSString stringWithFormat: @"%@ is not an IMAP4 folder", [self relativeImap4Name]]];
reason: [NSString stringWithFormat: @"%@ is not an IMAP4 folder", [self relativeImap4Name]]];
}
- (NSException *) expunge
@ -2013,16 +2036,45 @@ static NSString *defaultUserID = @"anyone";
//
// Check updated items
//
// . UID FETCH 1:* (UID) (CHANGEDSINCE 1)
// * 1 FETCH (UID 542 MODSEQ (7))
// * 2 FETCH (UID 553 MODSEQ (14))
// * 3 FETCH (UID 554 MODSEQ (16))
// * 4 FETCH (UID 555 MODSEQ (15))
// * 5 FETCH (UID 559 MODSEQ (17))
// * 6 FETCH (UID 560 MODSEQ (18))
// * 7 FETCH (UID 561 MODSEQ (19))
//
// . uid fetch 1:* (UID) (changedsince 171)
// SORT + MODSEQ: http://www.watersprings.org/pub/id/draft-melnikov-condstore-sort-00.txt
// With date, not modseq
// . UID SORT (DATE) UTF-8 (NOT DELETED) (SINCE "15-Mar-2014")
// * SORT 553 542 555 554 601 559 560 561 565 602 603 605 611 610 612 613 614 615 616 617 618 621 619 620 622 623
//
// . UID SORT (DATE) UTF-8 ((MODSEQ 64) (NOT DELETED)) (SINCE "15-Mar-2014")
// * SORT 623 624 (MODSEQ 65)
// . OK Completed (2 msgs in 0.000 secs)
//
// ".. the server MUST also append (to the end of the untagged SORT response) the highest mod-sequence for all messages being returned."
//
// To get the modseq of a specific message:
//
// . uid fetch 124569:124569 uid (changedsince 1)
// . UID FETCH 124569:124569 (UID MODSEQ)
// * 4900 FETCH (UID 124569 MODSEQ (2))
//
//
// Deleted: "UID FETCH 1:* (UID) (CHANGEDSINCE 171 VANISHED)"
// To get deleted messages
//
// . UID FETCH 1:* (UID) (CHANGEDSINCE 1 VANISHED)
// * VANISHED (EARLIER) 1:541,543:552,556:558,562:564,566:600,604,606:609
// * 1 FETCH (UID 542 MODSEQ (7))
// * 2 FETCH (UID 553 MODSEQ (14))
// * 3 FETCH (UID 554 MODSEQ (16))
// * 4 FETCH (UID 555 MODSEQ (15))
// * 5 FETCH (UID 559 MODSEQ (17))
// * 6 FETCH (UID 560 MODSEQ (18))
// * 7 FETCH (UID 561 MODSEQ (19))
//
// fetchUIDsOfVanishedItems ..
//
// . uid fetch 1:* (FLAGS) (changedsince 176 vanished)
@ -2039,6 +2091,7 @@ static NSString *defaultUserID = @"anyone";
NSMutableArray *allTokens;
NSArray *a, *uids;
NSDictionary *d;
id fetchResults;
int uidnext, highestmodseq, i;
@ -2065,7 +2118,7 @@ static NSString *defaultUserID = @"anyone";
EOKeyValueQualifier *kvQualifier;
NSNumber *nextModseq;
nextModseq = [NSNumber numberWithUnsignedLongLong: highestmodseq + 1];
nextModseq = [NSNumber numberWithUnsignedLongLong: highestmodseq];
kvQualifier = [[EOKeyValueQualifier alloc]
initWithKey: @"modseq"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
@ -2083,9 +2136,10 @@ static NSString *defaultUserID = @"anyone";
if (theStartDate)
{
EOQualifier *sinceDateQualifier = [EOQualifier qualifierWithQualifierFormat:
@"(DATE >= %@)", theStartDate];
EOQualifier *sinceDateQualifier;
sinceDateQualifier = [EOQualifier qualifierWithQualifierFormat:
@"(DATE >= %@)", theStartDate];
searchQualifier = [[EOAndQualifier alloc] initWithQualifiers: searchQualifier, sinceDateQualifier,
nil];
[searchQualifier autorelease];
@ -2096,24 +2150,28 @@ static NSString *defaultUserID = @"anyone";
uids = [self fetchUIDsMatchingQualifier: searchQualifier
sortOrdering: nil];
for (i = 0; i < [uids count]; i++)
{
// New messages
if ([[uids objectAtIndex: i] intValue] >= uidnext)
{
d = [NSDictionary dictionaryWithObject: @"added" forKey: [uids objectAtIndex: i]];
}
// Changed messages
else
{
d = [NSDictionary dictionaryWithObject: @"changed" forKey: [uids objectAtIndex: i]];
}
fetchResults = [(NSDictionary *)[self fetchUIDs: uids
parts: [NSArray arrayWithObject: @"modseq"]]
objectForKey: @"fetch"];
/* NOTE: we sort items manually because Cyrus does not properly sort
entries with a MODSEQ of 0 */
fetchResults
= [fetchResults sortedArrayUsingFunction: _compareFetchResultsByMODSEQ
context: NULL];
for (i = 0; i < [fetchResults count]; i++)
{
d = [NSDictionary dictionaryWithObject: [[fetchResults objectAtIndex: i] objectForKey: @"modseq"]
forKey: [[[fetchResults objectAtIndex: i] objectForKey: @"uid"] stringValue]];
[allTokens addObject: d];
}
// We fetch deleted ones
if (highestmodseq == 0)
highestmodseq = 1;
if (highestmodseq > 0)
{
id uid;
@ -2122,8 +2180,8 @@ static NSString *defaultUserID = @"anyone";
for (i = 0; i < [uids count]; i++)
{
uid = [uids objectAtIndex: i];
d = [NSDictionary dictionaryWithObject: @"deleted" forKey: uid];
uid = [[uids objectAtIndex: i] stringValue];
d = [NSDictionary dictionaryWithObject: [NSNull null] forKey: uid];
[allTokens addObject: d];
}
}