diff --git a/ActiveSync/SOGoActiveSyncDispatcher+Sync.m b/ActiveSync/SOGoActiveSyncDispatcher+Sync.m
index 8c206baaf..024b2a2a7 100644
--- a/ActiveSync/SOGoActiveSyncDispatcher+Sync.m
+++ b/ActiveSync/SOGoActiveSyncDispatcher+Sync.m
@@ -126,6 +126,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[[o properties] removeObjectForKey: @"SyncKey"];
[[o properties] removeObjectForKey: @"SyncCache"];
[[o properties] removeObjectForKey: @"DateCache"];
+ [[o properties] removeObjectForKey: @"MoreAvailable"];
[[o properties] addEntriesFromDictionary: theFolderMetadata];
[o save];
@@ -477,21 +478,70 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
lastServerKey: (NSString **) theLastServerKey
{
- NSMutableDictionary *folderMetadata;
+ NSMutableDictionary *folderMetadata, *dateCache, *syncCache;
NSMutableString *s;
BOOL more_available;
int i, max;
+ s = [NSMutableString string];
+
+ more_available = NO;
+
+ if (theFolderType == ActiveSyncMailFolder && !([theSyncKey isEqualToString: @"-1"]) && theFilterType)
+ {
+ NSArray *allKeys;
+ NSString *key;
+ int softdelete_count;
+
+ softdelete_count = 0;
+
+ folderMetadata = [self _folderMetadataForKey: [theCollection nameInContainer]];
+ dateCache = [folderMetadata objectForKey: @"DateCache"];
+ syncCache = [folderMetadata objectForKey: @"SyncCache"];
+
+ allKeys = [dateCache allKeys];
+ for (i = 0; i < [allKeys count]; i++)
+ {
+ key = [allKeys objectAtIndex: i];
+
+ if ([[dateCache objectForKey:key] compare: theFilterType] == NSOrderedAscending)
+ {
+ [s appendString: @""];
+ [s appendFormat: @"%@", key];
+ [s appendString: @""];
+
+ [syncCache removeObjectForKey: key];
+ [dateCache removeObjectForKey: key];
+
+ softdelete_count++;
+ }
+
+ if (softdelete_count >= theWindowSize)
+ {
+ [folderMetadata setObject: [NSNumber numberWithBool: YES] forKey: @"MoreAvailable"];
+ [self _setFolderMetadata: folderMetadata forKey: [theCollection nameInContainer]];
+
+ more_available = YES;
+ *theLastServerKey = theSyncKey;
+
+ // Since WindowSize is reached don't even try to add more to the response, let's just
+ // jump to the end and return the response immediately
+ goto return_response;
+ }
+ }
+
+ [folderMetadata removeObjectForKey: @"MoreAvailable"];
+ [self _setFolderMetadata: folderMetadata forKey: [theCollection nameInContainer]];
+ }
+
//
// No changes in the collection - 2.2.2.19.1.1 Empty Sync Request.
// We check this and we don't generate any commands if we don't have to.
//
- if ([theSyncKey isEqualToString: [theCollection davCollectionTag]])
+ if ([theSyncKey isEqualToString: [theCollection davCollectionTag]] && !([s length]))
return;
- s = [NSMutableString string];
-
more_available = NO;
switch (theFolderType)
@@ -614,7 +664,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
case ActiveSyncMailFolder:
default:
{
- NSMutableDictionary *syncCache, *dateCache;
SOGoSyncCacheObject *lastCacheObject, *aCacheObject;
NSMutableArray *allCacheObjects, *sortedBySequence;
@@ -644,6 +693,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[folderMetadata setObject: [NSMutableDictionary dictionary] forKey: @"SyncCache"];
[folderMetadata setObject: [NSMutableDictionary dictionary] forKey: @"DateCache"];
}
+
// Check whether GUID in cache is equal to the GUID from imap - this is to avoid cache corruptions if a folder has been renamed and a new folder
// with the same name has been created but folderSync has not yet updated the cache
if (!([[theCollection nameInContainer] isEqualToString:
@@ -805,6 +855,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
break;
} // switch (folderType) ...
+ return_response:
+
if ([s length])
{
[theBuffer appendString: @""];
@@ -1008,7 +1060,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
davCollectionTag = [collection davCollectionTag];
}
-
// Generate the response buffer
[theBuffer appendString: @""];
diff --git a/ActiveSync/SOGoActiveSyncDispatcher.m b/ActiveSync/SOGoActiveSyncDispatcher.m
index b98ce3bd2..82c1868fc 100644
--- a/ActiveSync/SOGoActiveSyncDispatcher.m
+++ b/ActiveSync/SOGoActiveSyncDispatcher.m
@@ -64,6 +64,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import
#import
#import
+#import
#import
#import
#import
@@ -170,6 +171,41 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
return [o properties];
}
+- (unsigned int) _softDeleteCountWithFilter: (NSCalendarDate *) theFilter
+ collectionId: (NSString *) theCollectionId
+{
+ NSMutableDictionary *dateCache;
+ NSMutableArray *sdUids;
+ SOGoCacheGCSObject *o;
+ NSArray *allKeys;
+ NSString *key;
+
+ int i;
+
+ sdUids = [NSMutableArray array];
+
+ if (theFilter)
+ {
+ o = [SOGoCacheGCSObject objectWithName: [NSString stringWithFormat: @"%@+folder%@", [context objectForKey: @"DeviceId"], theCollectionId] inContainer: nil];
+ [o setObjectType: ActiveSyncGlobalCacheObject];
+ [o setTableUrl: [self folderTableURL]];
+ [o reloadIfNeeded];
+
+ dateCache = [[o properties] objectForKey: @"DateCache"];
+ allKeys = [dateCache allKeys];
+
+ for (i = 0; i < [allKeys count]; i++)
+ {
+ key = [allKeys objectAtIndex: i];
+
+ if ([[dateCache objectForKey:key] compare: theFilter ] == NSOrderedAscending)
+ [sdUids addObject: [dateCache objectForKey:key]];
+ }
+ }
+
+ return [sdUids count];
+}
+
- (id) globallyUniqueIDToIMAPFolderName: (NSString *) theIdToTranslate
type: (SOGoMicrosoftActiveSyncFolderType) theFolderType
{
@@ -919,6 +955,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
sortOrdering: @"REVERSE ARRIVAL"
threaded: NO];
count = [uids count];
+
+ // Add the number of UIDs expected to "soft delete"
+ count += [self _softDeleteCountWithFilter: filter collectionId: realCollectionId];
+
}
else
{
diff --git a/NEWS b/NEWS
index 42cc196d5..46be9433c 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ Enhancements
- contacts photos are now synchronized using ActiveSync (#2807)
- implemented the GetAttachment ActiveSync command (#2808)
- implemented the Ping ActiveSync command
+ - added "soft deletes" support for ActiveSync (#2734)
Bug fixes
- better handling of empty "Flag" messages over ActiveSync (#2806)