diff --git a/ActiveSync/SOGoActiveSyncDispatcher+Sync.m b/ActiveSync/SOGoActiveSyncDispatcher+Sync.m
index 730936132..86a2e5c89 100644
--- a/ActiveSync/SOGoActiveSyncDispatcher+Sync.m
+++ b/ActiveSync/SOGoActiveSyncDispatcher+Sync.m
@@ -505,7 +505,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
softdelete_count = 0;
- folderMetadata = [self _folderMetadataForKey: [theCollection nameInContainer]];
+ folderMetadata = [self _folderMetadataForKey: [[[theCollection mailAccountFolder] imapFolderGUIDs] objectForKey: [theCollection nameInContainer]]];
+
dateCache = [folderMetadata objectForKey: @"DateCache"];
syncCache = [folderMetadata objectForKey: @"SyncCache"];
@@ -529,7 +530,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (softdelete_count >= theWindowSize)
{
[folderMetadata setObject: [NSNumber numberWithBool: YES] forKey: @"MoreAvailable"];
- [self _setFolderMetadata: folderMetadata forKey: [theCollection nameInContainer]];
+ [self _setFolderMetadata: folderMetadata forKey: [[[theCollection mailAccountFolder] imapFolderGUIDs] objectForKey: [theCollection nameInContainer]]];
more_available = YES;
*theLastServerKey = theSyncKey;
@@ -541,7 +542,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
[folderMetadata removeObjectForKey: @"MoreAvailable"];
- [self _setFolderMetadata: folderMetadata forKey: [theCollection nameInContainer]];
+ [self _setFolderMetadata: folderMetadata forKey: [[[theCollection mailAccountFolder] imapFolderGUIDs] objectForKey: [theCollection nameInContainer]]];
}
//
@@ -695,23 +696,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
// If it's a new Sync operation, DateCache and SyncCache need to be deleted
- // but GUID stored by folderSync shouldn't be touched
- folderMetadata = [self _folderMetadataForKey: [theCollection nameInContainer]];
+ folderMetadata = [self _folderMetadataForKey: [[[theCollection mailAccountFolder] imapFolderGUIDs] objectForKey: [theCollection nameInContainer]]];
+
if ([theSyncKey isEqualToString: @"-1"])
{
[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:
- [NSString stringWithFormat: @"folder%@", [self globallyUniqueIDToIMAPFolderName: [folderMetadata objectForKey: @"GUID"] type: theFolderType]]]))
- {
- NSLog(@"GUID mismatch don't sync now!");
- return;
- }
-
syncCache = [folderMetadata objectForKey: @"SyncCache"];
dateCache = [folderMetadata objectForKey: @"DateCache"];
@@ -859,7 +851,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
[self _setFolderMetadata: folderMetadata
- forKey: [theCollection nameInContainer]];
+ forKey: [[[theCollection mailAccountFolder] imapFolderGUIDs] objectForKey: [theCollection nameInContainer]]];
} // default:
break;
} // switch (folderType) ...
@@ -958,7 +950,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
inBuffer: (NSMutableString *) theBuffer
changeDetected: (BOOL *) changeDetected
{
- NSString *collectionId, *realCollectionId, *syncKey, *davCollectionTag, *bodyPreferenceType, *lastServerKey;
+ NSString *collectionId, *realCollectionId, *syncKey, *davCollectionTag, *bodyPreferenceType, *lastServerKey, *nameInCache;
SOGoMicrosoftActiveSyncFolderType folderType;
id collection, value;
@@ -975,6 +967,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
collection = [self collectionFromId: realCollectionId type: folderType];
syncKey = davCollectionTag = [[(id)[theDocumentElement getElementsByTagName: @"SyncKey"] lastObject] textValue];
+
+ if (collection == nil)
+ {
+ // Collection not found - next folderSync will do the cleanup
+ //NSLog(@"Sync Collection not found %@ %@", collectionId, realCollectionId);
+ [theBuffer appendString: @""];
+ [theBuffer appendFormat: @"%@", syncKey];
+ [theBuffer appendFormat: @"%@", collectionId];
+ [theBuffer appendFormat: @"%d", 8];
+ [theBuffer appendString: @""];
+
+ return;
+ }
// We check for a window size, default to 100 if not specfied or out of bounds
windowSize = [[[(id)[theDocumentElement getElementsByTagName: @"WindowSize"] lastObject] textValue] intValue];
@@ -1059,9 +1064,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
if (lastServerKey)
davCollectionTag = lastServerKey;
- else if (![[self _folderMetadataForKey: [collection nameInContainer]] objectForKey: @"MoreAvailable"])
- davCollectionTag = [collection davCollectionTag];
-
+ else
+ {
+ if (folderType == ActiveSyncMailFolder)
+ nameInCache = [[[collection mailAccountFolder] imapFolderGUIDs] objectForKey: [collection nameInContainer]];
+ else
+ nameInCache = [collection nameInContainer];
+
+ if (![[self _folderMetadataForKey: nameInCache] objectForKey: @"MoreAvailable"])
+ davCollectionTag = [collection davCollectionTag];
+ }
+
*changeDetected = YES;
}
else
diff --git a/ActiveSync/SOGoActiveSyncDispatcher.m b/ActiveSync/SOGoActiveSyncDispatcher.m
index 0d5287a8a..083829b22 100644
--- a/ActiveSync/SOGoActiveSyncDispatcher.m
+++ b/ActiveSync/SOGoActiveSyncDispatcher.m
@@ -36,6 +36,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import
#import
+#import
+#import
#import
#import
#import
@@ -89,6 +91,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import
#import
#import
+#import
#import
#import
@@ -186,7 +189,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (theFilter)
{
- o = [SOGoCacheGCSObject objectWithName: [NSString stringWithFormat: @"%@+folder%@", [context objectForKey: @"DeviceId"], theCollectionId] inContainer: nil];
+ o = [SOGoCacheGCSObject objectWithName: [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], theCollectionId] inContainer: nil];
[o setObjectType: ActiveSyncGlobalCacheObject];
[o setTableUrl: [self folderTableURL]];
[o reloadIfNeeded];
@@ -223,7 +226,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Get the GUID of the IMAP folder
imapGUIDs = [accountFolder imapFolderGUIDs];
- return [[imapGUIDs allKeysForObject: theIdToTranslate] objectAtIndex: 0];
+ //return [[imapGUIDs allKeysForObject: theIdToTranslate] objectAtIndex: 0];
+ return [[[imapGUIDs allKeysForObject: [NSString stringWithFormat: @"folder%@", theIdToTranslate]] objectAtIndex: 0] substringFromIndex: 6] ;
}
return theIdToTranslate;
@@ -244,13 +248,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
case ActiveSyncContactFolder:
{
- collection = [[context activeUser] personalContactsFolderInContext: context];
+ collection = [[[[context activeUser] homeFolderInContext: context] lookupName: @"Contacts" inContext: context acquire: NO] lookupName: theCollectionId inContext: context acquire: NO];
+ if (!collection || ([collection isKindOfClass: [NSException class]]))
+ collection = nil;
+
}
break;
case ActiveSyncEventFolder:
case ActiveSyncTaskFolder:
{
- collection = [[context activeUser] personalCalendarFolderInContext: context];
+ collection = [[[[context activeUser] homeFolderInContext: context] lookupName: @"Calendar" inContext: context acquire: NO] lookupName: theCollectionId inContext: context acquire: NO];
+ if (!collection || ([collection isKindOfClass: [NSException class]]))
+ collection = nil;
}
break;
case ActiveSyncMailFolder:
@@ -267,6 +276,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
collection = [currentFolder lookupName: [NSString stringWithFormat: @"folder%@", theCollectionId]
inContext: context
acquire: NO];
+ if (![(SOGoMailFolder *)collection exists])
+ collection = nil;
}
}
@@ -335,27 +346,20 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
NSString *key;
nameInContainer = [newFolder nameInContainer];
-
- // We strip the "folder" prefix
- nameInContainer = [nameInContainer substringFromIndex: 6];
- // save new guid into cache
accountFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
-
- // update GUID in cache
imapGUIDs = [accountFolder imapFolderGUIDs];
+ nameInContainer =[imapGUIDs objectForKey: nameInContainer];
- key = [NSString stringWithFormat: @"%@+folder%@", [context objectForKey: @"DeviceId"], nameInContainer ];
+ key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], nameInContainer ];
o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
[o setObjectType: ActiveSyncFolderCacheObject];
[o setTableUrl: [self folderTableURL]];
[o reloadIfNeeded];
- nameInContainer =[imapGUIDs objectForKey: nameInContainer];
-
- [[o properties ] setObject: nameInContainer forKey: @"GUID"];
+ [[o properties ] setObject: [[newFolder nameInContainer] substringFromIndex: 6] forKey: @"displayName"];
[o save];
- nameInContainer = [[NSString stringWithFormat: @"mail/%@", nameInContainer] stringByEscapingURL];
+ nameInContainer = [[NSString stringWithFormat: @"mail/%@", [nameInContainer substringFromIndex: 6]] stringByEscapingURL];
}
else
{
@@ -369,7 +373,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
case 15:
{
SOGoAppointmentFolders *appointmentFolders;
-
+ SOGoCacheGCSObject *o;
+ NSString *key;
+
+ nameInContainer = nil;
+
appointmentFolders = [userFolder privateCalendars: @"Calendar" inContext: context];
[appointmentFolders newFolderWithName: displayName
nameInContainer: &nameInContainer];
@@ -377,16 +385,36 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nameInContainer = [NSString stringWithFormat: @"vevent/%@", nameInContainer];
else
nameInContainer = [NSString stringWithFormat: @"vtodo/%@", nameInContainer];
+
+ key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], nameInContainer ];
+ o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
+ [o setObjectType: ActiveSyncFolderCacheObject];
+ [o setTableUrl: [self folderTableURL]];
+ [o reloadIfNeeded];
+ [[o properties ] setObject: displayName forKey: @"displayName"];
+ [o save];
}
break;
case 14:
{
SOGoContactFolders *contactFolders;
+ SOGoCacheGCSObject *o;
+ NSString *key;
+
+ nameInContainer = nil;
contactFolders = [userFolder privateContacts: @"Contacts" inContext: context];
[contactFolders newFolderWithName: displayName
nameInContainer: &nameInContainer];
nameInContainer = [NSString stringWithFormat: @"vcard/%@", nameInContainer];
+
+ key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], nameInContainer ];
+ o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
+ [o setObjectType: ActiveSyncFolderCacheObject];
+ [o setTableUrl: [self folderTableURL]];
+ [o reloadIfNeeded];
+ [[o properties ] setObject: displayName forKey: @"displayName"];
+ [o save];
}
break;
default:
@@ -428,66 +456,87 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
inResponse: (WOResponse *) theResponse
{
SOGoMailAccounts *accountsFolder;
- SOGoMailFolder *folderToDelete;
SOGoUserFolder *userFolder;
- id currentFolder;
- NSException *error;
- NSString *serverId;
-
+ id currentFolder, folderToDelete;
+ NSString *serverId, *nameInCache, *key, *syncKey;
+ SOGoCacheGCSObject *o;
+ NSMutableString *s;
+ NSData *d;
+
SOGoMicrosoftActiveSyncFolderType folderType;
-
+
serverId = [[[(id)[theDocumentElement getElementsByTagName: @"ServerId"] lastObject] textValue] realCollectionIdWithFolderType: &folderType];
+ nameInCache = serverId;
serverId = [self globallyUniqueIDToIMAPFolderName: serverId type: folderType];
-
userFolder = [[context activeUser] homeFolderInContext: context];
- accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
- currentFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
- folderToDelete = [currentFolder lookupName: [NSString stringWithFormat: @"folder%@", serverId]
- inContext: context
- acquire: NO];
-
- error = [folderToDelete delete];
-
- if (!error)
+ switch (folderType)
{
- NSString *syncKey, *key;
- SOGoCacheGCSObject *o;
- NSMutableString *s;
- NSData *d;
+ case ActiveSyncMailFolder:
+ {
+ nameInCache = [NSString stringWithFormat: @"folder%@", nameInCache];
+ accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
+ currentFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
+
+ folderToDelete = [currentFolder lookupName: [NSString stringWithFormat: @"folder%@", serverId]
+ inContext: context
+ acquire: NO];
+ }
+ break;
+ case ActiveSyncEventFolder:
+ case ActiveSyncTaskFolder:
+ {
+ SOGoAppointmentFolders *appointmentFolders;
- //
- // We destroy the cache object
- //
- key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], [folderToDelete nameInContainer]];
- o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
- [o setTableUrl: [self folderTableURL]];
- [o destroy];
-
- //
- // We update the FolderSync's synckey
- //
- syncKey = [[NSProcessInfo processInfo] globallyUniqueString];
-
- [self _setFolderSyncKey: syncKey];
-
- s = [NSMutableString string];
- [s appendString: @""];
- [s appendString: @""];
- [s appendString: @""];
- [s appendFormat: @"%d", 1];
- [s appendFormat: @"%@", syncKey];
- [s appendString: @""];
-
- d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
-
- [theResponse setContent: d];
- }
- else
- {
- [theResponse setStatus: 500];
- [theResponse appendContentString: @"Unable to delete folder."];
+ if (folderType == ActiveSyncEventFolder)
+ nameInCache = [NSString stringWithFormat: @"vevent/%@", serverId];
+ else
+ nameInCache = [NSString stringWithFormat: @"vtodo/%@", serverId];
+
+ appointmentFolders = [userFolder privateCalendars: @"Calendar" inContext: context];
+
+ folderToDelete = [appointmentFolders lookupName: [NSString stringWithFormat: @"%@", serverId]
+ inContext: context
+ acquire: NO];
+ }
+ break;
+ default:
+ {
+ [theResponse setStatus: 500];
+ [theResponse appendContentString: @"Unsupported folder type during creation."];
+ return;
+ }
}
+
+ // FIXME: we should handle exception here
+ [folderToDelete delete];
+
+ //
+ // We destroy the cache object
+ //
+ key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], nameInCache];
+ o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
+ [o setTableUrl: [self folderTableURL]];
+ [o destroy];
+
+
+ //
+ // We update the FolderSync's synckey
+ //
+ syncKey = [[NSProcessInfo processInfo] globallyUniqueString];
+
+ [self _setFolderSyncKey: syncKey];
+
+ s = [NSMutableString string];
+ [s appendString: @""];
+ [s appendString: @""];
+ [s appendString: @""];
+ [s appendFormat: @"%d", 1];
+ [s appendFormat: @"%@", syncKey];
+ [s appendString: @""];
+
+ d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
+ [theResponse setContent: d];
}
//
@@ -496,89 +545,127 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (void) processFolderUpdate: (id ) theDocumentElement
inResponse: (WOResponse *) theResponse
{
- NSString *serverId, *parentId, *displayName;
- SOGoMailAccounts *accountsFolder;
+ NSString *serverId, *parentId, *displayName, *newName, *nameInCache, *syncKey, *key;
SOGoUserFolder *userFolder;
- SOGoMailFolder *folderToUpdate;
+ SOGoCacheGCSObject *o;
+ NSMutableString *s;
id currentFolder;
- NSException *error;
+ NSData *d;
SOGoMicrosoftActiveSyncFolderType folderType;
- int status;
serverId = [[[(id)[theDocumentElement getElementsByTagName: @"ServerId"] lastObject] textValue] realCollectionIdWithFolderType: &folderType];
+
+ nameInCache = [NSString stringWithFormat: @"folder%@", serverId];
+
serverId = [self globallyUniqueIDToIMAPFolderName: serverId type: folderType];
parentId = [[(id)[theDocumentElement getElementsByTagName: @"ParentId"] lastObject] textValue];
displayName = [[(id)[theDocumentElement getElementsByTagName: @"DisplayName"] lastObject] textValue];
userFolder = [[context activeUser] homeFolderInContext: context];
- accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
- currentFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
+
+
+ switch (folderType)
+ {
+ case ActiveSyncMailFolder:
+ {
+ SOGoMailAccounts *accountsFolder;
+ SOGoMailFolder *folderToUpdate;
+
+ accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
+ currentFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
- folderToUpdate = [currentFolder lookupName: [NSString stringWithFormat: @"folder%@", serverId]
- inContext: context
- acquire: NO];
+ folderToUpdate = [currentFolder lookupName: [NSString stringWithFormat: @"folder%@", serverId]
+ inContext: context
+ acquire: NO];
- // If parent is 0 or displayname is not changed it is either a rename of a folder in 0 or a move to 0
- if ([parentId isEqualToString: @"0"] ||
- ([serverId hasSuffix: [NSString stringWithFormat: @"/%@", displayName]] && [parentId isEqualToString: @"0"]))
- {
- error = [folderToUpdate renameTo: [NSString stringWithFormat: @"/%@", [displayName stringByEncodingImap4FolderName]]];
- }
- else
- {
- parentId = [self globallyUniqueIDToIMAPFolderName: [[parentId stringByUnescapingURL] substringFromIndex: 5] type: folderType];
- error = [folderToUpdate renameTo: [NSString stringWithFormat: @"%@/%@", [parentId stringByEncodingImap4FolderName],
- [displayName stringByEncodingImap4FolderName]]];
+ // If parent is 0 or displayname is not changed it is either a rename of a folder in 0 or a move to 0
+ if ([parentId isEqualToString: @"0"] ||
+ ([serverId hasSuffix: [NSString stringWithFormat: @"/%@", displayName]] && [parentId isEqualToString: @"0"]))
+ {
+ newName = [NSString stringWithFormat: @"%@", [displayName stringByEncodingImap4FolderName]];
+
+ // FIXME: handle exception here
+ [folderToUpdate renameTo: [NSString stringWithFormat: @"/%@", [displayName stringByEncodingImap4FolderName]]];
+ }
+ else
+ {
+ parentId = [self globallyUniqueIDToIMAPFolderName: [[parentId stringByUnescapingURL] substringFromIndex: 5] type: folderType];
+ newName = [NSString stringWithFormat: @"%@/%@", [parentId stringByEncodingImap4FolderName], [displayName stringByEncodingImap4FolderName]];
+
+ // FIXME: handle exception here
+ [folderToUpdate renameTo: newName];
+ }
+
+
+ //
+ // We update our cache
+ //
+ key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], nameInCache];
+ o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
+ [o setObjectType: ActiveSyncFolderCacheObject];
+ [o setTableUrl: [self folderTableURL]];
+ [o reloadIfNeeded];
+ [[o properties ] setObject: newName forKey: @"displayName"];
+ [o save];
+ }
+ break;
+ case ActiveSyncEventFolder:
+ case ActiveSyncTaskFolder:
+ {
+ SOGoAppointmentFolders *appointmentFolders;
+ SOGoAppointmentFolder *folderToUpdate;
+ NSString *nameInCache;
+
+ appointmentFolders = [userFolder privateCalendars: @"Calendar" inContext: context];
+
+ folderToUpdate = [appointmentFolders lookupName: [NSString stringWithFormat: @"%@", serverId]
+ inContext: context
+ acquire: NO];
+
+ // update the cache anyway regardless of any error; if the rename fails next folderSync will to the cleanup
+ [folderToUpdate renameTo: [NSString stringWithFormat: @"%@", [displayName stringByEncodingImap4FolderName]]];
+
+ if (folderType == ActiveSyncEventFolder)
+ nameInCache = [NSString stringWithFormat: @"vevent/%@", serverId];
+ else
+ nameInCache = [NSString stringWithFormat: @"vtodo/%@",serverId];
+
+ key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], nameInCache ];
+ o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
+ [o setObjectType: ActiveSyncFolderCacheObject];
+ [o setTableUrl: [self folderTableURL]];
+ [o reloadIfNeeded];
+ [[o properties ] setObject: displayName forKey: @"displayName"];
+ [o save];
+ }
+ break;
+ default:
+ {
+ [theResponse setStatus: 500];
+ [theResponse appendContentString: @"Unsupported folder type during creation."];
+ return;
+ }
}
- // Handle new name exist
- if (!error)
- {
- NSString *syncKey, *key;
- SOGoCacheGCSObject *o;
- NSMutableString *s;
- NSData *d;
-
- //
- // We update our cache
- //
- key = [NSString stringWithFormat: @"%@+folder%@", [context objectForKey: @"DeviceId"], serverId];
- o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
- [o setTableUrl: [self folderTableURL]];
- [o reloadIfNeeded];
-
- key = [NSString stringWithFormat: @"/%@+%@", [context objectForKey: @"DeviceId"], [folderToUpdate nameInContainer]];
- [o changePathTo: key];
+ //
+ // We update the FolderSync's synckey
+ //
+ syncKey = [[NSProcessInfo processInfo] globallyUniqueString];
- //
- // We update the FolderSync's synckey
- //
- syncKey = [[NSProcessInfo processInfo] globallyUniqueString];
+ [self _setFolderSyncKey: syncKey];
- // See http://msdn.microsoft.com/en-us/library/gg675615(v=exchg.80).aspx
- // we return '9' - we force a FolderSync
- status = 1;
-
- [self _setFolderSyncKey: syncKey];
-
- s = [NSMutableString string];
- [s appendString: @""];
- [s appendString: @""];
- [s appendString: @""];
- [s appendFormat: @"%d", status];
- [s appendFormat: @"%@", syncKey];
- [s appendString: @""];
+ s = [NSMutableString string];
+ [s appendString: @""];
+ [s appendString: @""];
+ [s appendString: @""];
+ [s appendFormat: @"%d", 1];
+ [s appendFormat: @"%@", syncKey];
+ [s appendString: @""];
+
+ d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
- d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
-
- [theResponse setContent: d];
- }
- else
- {
- [theResponse setStatus: 500];
- [theResponse appendContentString: @"Unable to update folder."];
- }
+ [theResponse setContent: d];
}
@@ -592,21 +679,36 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (void) processFolderSync: (id ) theDocumentElement
inResponse: (WOResponse *) theResponse
{
-
- NSMutableDictionary *metadata;
- NSMutableString *s;
- NSString *syncKey;
+ NSString *key, *cKey, *nkey, *name, *serverId, *parentId, *nameInCache, *personalFolderName, *syncKey, *folderType;
+ NSDictionary *folderMetadata, *imapGUIDs;
+ NSArray *allFoldersMetadata, *allKeys;
+ NSMutableDictionary *cachedGUIDs, *metadata;
+ SOGoMailAccounts *accountsFolder;
+ SOGoMailAccount *accountFolder;
+ NSMutableString *s, *commands;
+ SOGoUserFolder *userFolder;
+ NSMutableArray *folders;
+ SoSecurityManager *sm;
+ SOGoCacheGCSObject *o;
+ id currentFolder;
NSData *d;
-
- BOOL first_sync;
- int status;
+ int status, command_count, i, type, fi, count;
+
+ BOOL first_sync;
+
+ sm = [SoSecurityManager sharedSecurityManager];
metadata = [self _globalMetadataForDevice];
syncKey = [[(id)[theDocumentElement getElementsByTagName: @"SyncKey"] lastObject] textValue];
s = [NSMutableString string];
first_sync = NO;
status = 1;
+ command_count = 0;
+ commands = [NSMutableString string];
+
+ [s appendString: @""];
+ [s appendString: @""];
if ([syncKey isEqualToString: @"0"])
{
@@ -616,215 +718,296 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
else if (![syncKey isEqualToString: [metadata objectForKey: @"FolderSyncKey"]])
{
// Synchronization key mismatch or invalid synchronization key
- status = 9;
+ //NSLog(@"FolderSync syncKey mismatch %@ <> %@", syncKey, metadata);
+ [s appendFormat: @"9"];
+
+ d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
+ [theResponse setContent: d];
+ return;
}
- [self _setFolderSyncKey: syncKey];
+ userFolder = [[context activeUser] homeFolderInContext: context];
+ accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
+ accountFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
- [s appendString: @""];
- [s appendString: @""];
- [s appendFormat: @"%d%@", status, syncKey];
-
- if (status == 1)
- {
- SOGoMailAccounts *accountsFolder;
- SOGoMailAccount *accountFolder;
- SOGoUserFolder *userFolder;
- id currentFolder;
-
- NSString *key, *cKey, *nkey, *name, *serverId, *parentId;
- NSDictionary *folderMetadata, *imapGUIDs;
- NSArray *allFoldersMetadata, *allKeys;
- NSMutableDictionary *cachedGUIDs;
- NSMutableString *commands;
- SOGoCacheGCSObject *o;
-
- int i, type, command_count;
-
- userFolder = [[context activeUser] homeFolderInContext: context];
- accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
- accountFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
-
- allFoldersMetadata = [accountFolder allFoldersMetadata];
+ allFoldersMetadata = [accountFolder allFoldersMetadata];
- // Get GUIDs of folder (IMAP)
- // e.g. {INBOX = "sogo_73c_192bd57b_d8"
- imapGUIDs = [accountFolder imapFolderGUIDs];
+ // Get GUIDs of folder (IMAP)
+ // e.g. {folderINBOX = folder6b93c528176f1151c7260000aef6df92}
+ imapGUIDs = [accountFolder imapFolderGUIDs];
- cachedGUIDs = [NSMutableDictionary dictionary];
+ cachedGUIDs = [NSMutableDictionary dictionary];
- // No need to read cached folder infos during first sync. Otherwise, pull it from the database.
- // e.g. {"sogo_73c_192bd57b_d8" = INBOX} - guid = foldername for easy reverse lookup with imapGUIDs
- if (!first_sync)
- {
- NSArray *foldersInCache;
- NSString *folderName;
+ // No need to read cached folder infos during first sync. Otherwise, pull it from the database.
+ // e.g. {folder6b93c528176f1151c7260000aef6df92 = folderINBOX} - guid = foldername for easy reverse lookup with imapGUIDs
+ if (!first_sync)
+ {
+ NSArray *foldersInCache;
- // get the list of folder stored in cache
- key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], @"0"];
- o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
- [o setObjectType: ActiveSyncFolderCacheObject];
- [o setTableUrl: [self folderTableURL]];
- [o reloadIfNeeded];
- foldersInCache = [o folderList: [context objectForKey: @"DeviceId"] newerThanVersion: -1];
-
- // get guids of folders stored in cache
- for (i = 0; i < [foldersInCache count]; i++)
- {
- folderName = [foldersInCache objectAtIndex: i];
- key = [folderName substringFromIndex: 1];
-
- o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
- [o setObjectType: ActiveSyncFolderCacheObject];
- [o setTableUrl: [self folderTableURL]];
- [o reloadIfNeeded];
-
- if ([[o properties ] objectForKey: @"GUID"])
- [cachedGUIDs setObject: [key substringFromIndex: [key rangeOfString: @"+"].location+7]
- forKey: [[o properties] objectForKey: @"GUID"]];
- }
- }
+ o = [SOGoCacheGCSObject objectWithName: @"0" inContainer: nil];
+ [o setObjectType: ActiveSyncFolderCacheObject];
+ [o setTableUrl: folderTableURL];
+
+ foldersInCache = [o cacheEntriesForDeviceId: [context objectForKey: @"DeviceId"] newerThanVersion: -1];
+
+ // get guids of folders stored in cache
+ for (i = 0; i < [foldersInCache count]; i++)
+ {
+ key = [[foldersInCache objectAtIndex: i] substringFromIndex: 1];
+ o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
+ [o setObjectType: ActiveSyncFolderCacheObject];
+ [o setTableUrl: [self folderTableURL]];
+ [o reloadIfNeeded];
+
+ // When the GUID entry exists the name of the entry has to be changed to new name
+ if ([[o properties] objectForKey: @"GUID"])
+ {
+ //NSLog(@"Old cacheEntry: %@ displayName: %@ GUID: %@", key, [[o properties] objectForKey: @"displayName"], [[o properties] objectForKey: @"GUID"]);
+ key = [NSString stringWithFormat: @"%@+folder%@", [context objectForKey: @"DeviceId"], [[o properties] objectForKey: @"GUID"]];
+ //NSLog(@"New cacheEntry: %@", key);
+ [[o properties] removeObjectForKey: @"GUID"];
+ [[o properties ] setObject: @"updateMe" forKey: @"displayName"];
+ [o save];
+ [o changePathTo: [NSString stringWithFormat: @"%@", key]];
+ }
+
+ // no dispalay Name
+ if (![[o properties] objectForKey: @"displayName"])
+ continue;
+
+ if ([key rangeOfString: @"+folder" options: NSCaseInsensitiveSearch].location != NSNotFound)
+ [cachedGUIDs setObject: [NSString stringWithFormat: @"folder%@", [[o properties] objectForKey: @"displayName"]] // e.g. CDB648DDBC5040F8AC90792383DBBBAA+folderINBOX
+ forKey: [key substringFromIndex: [key rangeOfString: @"+"].location+1]];
+ else
+ [cachedGUIDs setObject: [key substringFromIndex: [key rangeOfString: @"+"].location+1] // e.g. CDB648DDBC5040F8AC90792383DBBBAA+vcard/personal
+ forKey: [key substringFromIndex: [key rangeOfString: @"+"].location+1]];
+ }
+ }
- // Handle folders that have been deleted over IMAP
- command_count = 0;
- commands = [NSMutableString string];
- allKeys = [cachedGUIDs allKeys];
+ // Handle folders that have been deleted on server
+ allKeys = [cachedGUIDs allKeys];
- for (i = 0; i < [allKeys count]; i++)
- {
- cKey = [allKeys objectAtIndex: i];
+ for (i = 0; i < [allKeys count]; i++)
+ {
+ cKey = [allKeys objectAtIndex: i];
- if (![imapGUIDs allKeysForObject: cKey])
- {
- // Destroy folders cache content to avoid stale data if a new folder gets created with the same name
- key = [NSString stringWithFormat: @"%@+folder%@", [context objectForKey: @"DeviceId"], [cachedGUIDs objectForKey: cKey]];
- o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
- [o setObjectType: ActiveSyncFolderCacheObject];
- [o setTableUrl: [self folderTableURL]];
- [o reloadIfNeeded];
-
- // Only send a delete command if GUID is found
- if ([[o properties] objectForKey: @"GUID"])
+ // ignore invalid folder in cache caused by fs code bugs
+ if ([cKey isEqualToString:@"(null)"])
+ continue;
+
+ // if a cache entry is not found in imapGUIDs its either an imap which has been deleted or its an other folder type which can be checked via lookupName.
+ if (![imapGUIDs allKeysForObject: cKey])
+ {
+ // Destroy folders cache content to avoid stale data if a new folder gets created with the same name
+ key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], cKey];
+ o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
+ [o setObjectType: ActiveSyncFolderCacheObject];
+ [o setTableUrl: [self folderTableURL]];
+ [o reloadIfNeeded];
+
+ if ([cKey hasPrefix: @"folder"])
+ {
+ [commands appendFormat: @"%@", [[NSString stringWithFormat: @"mail/%@", [cKey substringFromIndex: 6]] stringByEscapingURL]] ;
+ command_count++;
+
+ [o destroy];
+ }
+ else
+ {
+ if ([cKey rangeOfString: @"vevent" options: NSCaseInsensitiveSearch].location != NSNotFound ||
+ [cKey rangeOfString: @"vtodo" options: NSCaseInsensitiveSearch].location != NSNotFound)
+ folderType = @"Calendar";
+ else
+ folderType = @"Contacts";
+
+ if ([ cKey rangeOfString: @"/"].location != NSNotFound)
+ currentFolder = [[[[context activeUser] homeFolderInContext: context] lookupName: folderType inContext: context acquire: NO]
+ lookupName: [cKey substringFromIndex: [cKey rangeOfString: @"/"].location+1] inContext: context acquire: NO];
+
+ // remove the folder from device if it doesn't exists or it has not the proper permissions
+ if (!currentFolder ||
+ [sm validatePermission: SoPerm_DeleteObjects
+ onObject: currentFolder
+ inContext: context] ||
+ [sm validatePermission: SoPerm_AddDocumentsImagesAndFiles
+ onObject: currentFolder
+ inContext: context])
{
- [commands appendFormat: @"%@", [[NSString stringWithFormat: @"mail/%@", [[o properties ] objectForKey: @"GUID"]] stringByEscapingURL] ];
+ [commands appendFormat: @"%@", [cKey stringByEscapingURL] ];
command_count++;
- }
-
- [o destroy];
- }
- }
-
- // Handle addition and changes
- for (i = 0; i < [allFoldersMetadata count]; i++)
- {
- folderMetadata = [allFoldersMetadata objectAtIndex: i];
-
- // No GUID -> no sync
- if (!([imapGUIDs objectForKey: [[folderMetadata objectForKey: @"path"] substringFromIndex: 1]]))
- continue;
-
- serverId = [NSString stringWithFormat: @"mail/%@", [imapGUIDs objectForKey: [[folderMetadata objectForKey: @"path"] substringFromIndex: 1]]];
- name = [folderMetadata objectForKey: @"displayName"];
-
- if ([name hasPrefix: @"/"])
- name = [name substringFromIndex: 1];
-
- if ([name hasSuffix: @"/"])
- name = [name substringToIndex: [name length]-1];
-
- type = [[folderMetadata objectForKey: @"type"] activeSyncFolderType];
- parentId = @"0";
-
- if ([folderMetadata objectForKey: @"parent"])
- {
- parentId = [NSString stringWithFormat: @"mail/%@", [imapGUIDs objectForKey: [[folderMetadata objectForKey: @"parent"] substringFromIndex: 1]]];
- name = [[name pathComponents] lastObject];
- }
-
- // Decide between add and change
- if ([cachedGUIDs objectForKey: [imapGUIDs objectForKey: [[folderMetadata objectForKey: @"path"] substringFromIndex: 1]]])
- {
- // Search GUID to check name change in cache (diff between IMAP and cache)
- if ((![[[folderMetadata objectForKey: @"path"] substringFromIndex: 1] isEqualToString: [imapGUIDs objectForKey: [cachedGUIDs objectForKey:
- [[folderMetadata objectForKey: @"path"] substringFromIndex: 1]]]]))
- {
- key = [NSString stringWithFormat: @"%@+folder%@", [context objectForKey: @"DeviceId"], [cachedGUIDs objectForKey:
- [imapGUIDs objectForKey: [[folderMetadata objectForKey: @"path"] substringFromIndex: 1]]]];
- nkey = [NSString stringWithFormat: @"%@+folder%@", [context objectForKey: @"DeviceId"], [[folderMetadata objectForKey: @"path"] substringFromIndex: 1] ];
-
- if (![key isEqualToString: nkey])
- {
- [commands appendFormat: @"%@%@%d%@",
- [serverId stringByEscapingURL],
- [parentId stringByEscapingURL],
- type,
- [name activeSyncRepresentationInContext: context]];
-
-
- // Change path in cache
- o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
- [o setObjectType: ActiveSyncFolderCacheObject];
- [o setTableUrl: [self folderTableURL]];
- [o reloadIfNeeded];
- [o changePathTo: [NSString stringWithFormat: @"/%@", nkey]]; // ?? why is '/' prefix needed - problem in changePathTo?
-
- command_count++;
- }
+ [o destroy];
}
}
- else
- {
- [commands appendFormat: @"%@%@%d%@",
+ }
+ }
+
+ // Handle addition and changes
+ for (i = 0; i < [allFoldersMetadata count]; i++)
+ {
+ folderMetadata = [allFoldersMetadata objectAtIndex: i];
+
+ nameInCache = [NSString stringWithFormat: @"folder%@", [[folderMetadata objectForKey: @"path"] substringFromIndex: 1]];
+ serverId = [NSString stringWithFormat: @"mail/%@", [[imapGUIDs objectForKey: nameInCache] substringFromIndex: 6]];
+ name = [folderMetadata objectForKey: @"displayName"];
+
+ if ([name hasPrefix: @"/"])
+ name = [name substringFromIndex: 1];
+
+ if ([name hasSuffix: @"/"])
+ name = [name substringToIndex: [name length]-1];
+
+ type = [[folderMetadata objectForKey: @"type"] activeSyncFolderType];
+ parentId = @"0";
+
+ if ([folderMetadata objectForKey: @"parent"])
+ {
+ parentId = [NSString stringWithFormat: @"mail/%@", [[imapGUIDs objectForKey: [NSString stringWithFormat: @"folder%@", [[folderMetadata objectForKey: @"parent"] substringFromIndex: 1]]] substringFromIndex: 6]];
+ name = [[name pathComponents] lastObject];
+ }
+
+ // Decide between add and change
+ if ([cachedGUIDs objectForKey: [imapGUIDs objectForKey: nameInCache]])
+ {
+ // Search GUID to check name change in cache (diff between IMAP and cache)
+ key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], [cachedGUIDs objectForKey: [imapGUIDs objectForKey: nameInCache ]]];
+ nkey = [NSString stringWithFormat: @"%@+folder%@", [context objectForKey: @"DeviceId"], [[folderMetadata objectForKey: @"path"] substringFromIndex: 1] ];
+
+ if (![key isEqualToString: nkey])
+ {
+ [commands appendFormat: @"%@%@%@%d",
+ [serverId stringByEscapingURL],
+ [parentId stringByEscapingURL],
+ [name activeSyncRepresentationInContext: context], type];
+
+ // Change path in cache
+ o = [SOGoCacheGCSObject objectWithName: [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], [imapGUIDs objectForKey: nameInCache ]] inContainer: nil];
+ [o setObjectType: ActiveSyncFolderCacheObject];
+ [o setTableUrl: [self folderTableURL]];
+ [o reloadIfNeeded];
+
+ [[o properties ] setObject: [[folderMetadata objectForKey: @"path"] substringFromIndex: 1] forKey: @"displayName"];
+ [o save];
+
+ command_count++;
+ }
+ }
+ else
+ {
+ [commands appendFormat: @"%@%@%@%d",
[serverId stringByEscapingURL],
[parentId stringByEscapingURL],
- type,
- [name activeSyncRepresentationInContext: context]];
+ [name activeSyncRepresentationInContext: context], type];
- // Store folder's GUID in cache
- key = [NSString stringWithFormat: @"%@+folder%@", [context objectForKey: @"DeviceId"], [[folderMetadata objectForKey: @"path"] substringFromIndex: 1]];
- o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
- [o setObjectType: ActiveSyncFolderCacheObject];
- [o setTableUrl: [self folderTableURL]];
- [o reloadIfNeeded];
+ // Store folder's displayName in cache
+ key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], [imapGUIDs objectForKey: nameInCache ]];
+ o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
+ [o setObjectType: ActiveSyncFolderCacheObject];
+ [o setTableUrl: [self folderTableURL]];
+ [o reloadIfNeeded];
- [[o properties ] setObject: [imapGUIDs objectForKey: [[folderMetadata objectForKey: @"path"] substringFromIndex: 1]] forKey: @"GUID"];
- [o save];
+ [[o properties ] setObject: [[folderMetadata objectForKey: @"path"] substringFromIndex: 1] forKey: @"displayName"];
+ [o save];
- command_count++;
- }
- }
-
- if (first_sync)
- [s appendFormat: @"%d", command_count+3];
- else
- [s appendFormat: @"%d", command_count];
-
- if (command_count > 0)
- [s appendFormat: @"%@", commands];
-
- if (first_sync)
- {
- // We add the personal calendar - events
- // FIXME: add all calendars
- currentFolder = [[context activeUser] personalCalendarFolderInContext: context];
- name = [NSString stringWithFormat: @"vevent/%@", [currentFolder nameInContainer]];
- [s appendFormat: @"%@%@%d%@", name, @"0", 8, [[currentFolder displayName] activeSyncRepresentationInContext: context]];
-
- // We add the personal calendar - tasks
- // FIXME: add all calendars
- currentFolder = [[context activeUser] personalCalendarFolderInContext: context];
- name = [NSString stringWithFormat: @"vtodo/%@", [currentFolder nameInContainer]];
- [s appendFormat: @"%@%@%d%@", name, @"0", 7, [[currentFolder displayName] activeSyncRepresentationInContext: context]];
-
- // We add the personal address book
- // FIXME: add all address books
- currentFolder = [[context activeUser] personalContactsFolderInContext: context];
- name = [NSString stringWithFormat: @"vcard/%@", [currentFolder nameInContainer]];
- [s appendFormat: @"%@%@%d%@", name, @"0", 9, [[currentFolder displayName] activeSyncRepresentationInContext: context]];
- }
+ command_count++;
+ }
}
+
+ personalFolderName = [[[context activeUser] personalCalendarFolderInContext: context] nameInContainer];
+ folders = [[[[[context activeUser] homeFolderInContext: context] lookupName: @"Calendar" inContext: context acquire: NO] subFolders] mutableCopy];
+ [folders addObjectsFromArray: [[[[context activeUser] homeFolderInContext: context] lookupName: @"Contacts" inContext: context acquire: NO] subFolders]];
+
+ // Inside this loop we remove all the folder without write/delete permissions
+ count = [folders count]-1;
+ for (; count >= 0; count--)
+ {
+ if ([sm validatePermission: SoPerm_DeleteObjects
+ onObject: [folders objectAtIndex: count]
+ inContext: context] ||
+ [sm validatePermission: SoPerm_AddDocumentsImagesAndFiles
+ onObject: [folders objectAtIndex: count]
+ inContext: context])
+ {
+ [folders removeObjectAtIndex: count];
+ }
+ }
+
+ count = [folders count]-1;
+ NSString *operation;
+
+ for (fi = 0; fi <= count ; fi++)
+ {
+ if ([[folders objectAtIndex:fi] isKindOfClass: [SOGoAppointmentFolder class]])
+ name = [NSString stringWithFormat: @"vevent/%@", [[folders objectAtIndex:fi] nameInContainer]];
+ else
+ name = [NSString stringWithFormat: @"vcard/%@", [[folders objectAtIndex:fi] nameInContainer]];
+
+ key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], name];
+ o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
+ [o setObjectType: ActiveSyncFolderCacheObject];
+ [o setTableUrl: [self folderTableURL]];
+ [o reloadIfNeeded];
+
+ // Decide between add and change
+ if (![[o properties ] objectForKey: @"displayName"] || first_sync)
+ operation = @"Add";
+ else if (![[[o properties ] objectForKey: @"displayName"] isEqualToString: [[folders objectAtIndex:fi] displayName]])
+ operation = @"Update";
+ else
+ operation = nil;
+
+ if (operation)
+ {
+ if ([[folders objectAtIndex:fi] isKindOfClass: [SOGoAppointmentFolder class]])
+ {
+ type = ([[[folders objectAtIndex:fi] nameInContainer] isEqualToString: personalFolderName] ? 8 : 13);
+ [commands appendFormat: @"<%@>%@%@%@%d%@>", operation,
+ [name stringByEscapingURL], @"0", [[[folders objectAtIndex:fi] displayName] activeSyncRepresentationInContext: context], type, operation];
+
+ command_count++;
+
+ [[o properties ] setObject: [[folders objectAtIndex:fi] displayName] forKey: @"displayName"];
+ [o save];
+
+ name = [NSString stringWithFormat: @"vtodo/%@", [[folders objectAtIndex:fi] nameInContainer]];
+ type = ([[[folders objectAtIndex:fi] nameInContainer] isEqualToString: personalFolderName] ? 7 : 15);
+ [commands appendFormat: @"<%@>%@%@%@%d%@>", operation,
+ [name stringByEscapingURL], @"0", [[[folders objectAtIndex:fi] displayName] activeSyncRepresentationInContext: context], type, operation];
+
+ command_count++;
+ key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], name];
+
+ o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
+ [o setObjectType: ActiveSyncFolderCacheObject];
+ [o setTableUrl: [self folderTableURL]];
+ [o reloadIfNeeded];
+ [[o properties ] setObject: [[folders objectAtIndex:fi] displayName] forKey: @"displayName"];
+ [o save];
+ }
+ else
+ {
+ type = ([[[folders objectAtIndex:fi] nameInContainer] isEqualToString: personalFolderName] ? 9 : 14);
+ [commands appendFormat: @"<%@>%@%@%@%d%@>", operation,
+ [name stringByEscapingURL], @"0", [[[folders objectAtIndex:fi] displayName] activeSyncRepresentationInContext: context], type, operation];
+
+ command_count++;
+
+ [[o properties ] setObject: [[folders objectAtIndex:fi] displayName] forKey: @"displayName"];
+ [o save];
+ }
+ }
+ }
+
- [s appendString: @""];
+ // set a new syncKey if there are folder changes
+ if (command_count > 0)
+ {
+ syncKey = [[NSProcessInfo processInfo] globallyUniqueString];
+ [self _setFolderSyncKey: syncKey];
+ }
+
+
+ [s appendFormat: @"%d", status];
+ [s appendFormat: @"%@%d%@", syncKey, command_count, commands];
d = [[s dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
@@ -906,7 +1089,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- (void) processGetItemEstimate: (id ) theDocumentElement
inResponse: (WOResponse *) theResponse
{
- NSString *collectionId, *realCollectionId;
+ NSString *collectionId, *realCollectionId, *nameInCache;
id currentCollection;
NSMutableString *s;
NSData *d;
@@ -920,7 +1103,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
collectionId = [[(id)[theDocumentElement getElementsByTagName: @"CollectionId"] lastObject] textValue];
realCollectionId = [collectionId realCollectionIdWithFolderType: &folderType];
+
+ if (folderType == ActiveSyncMailFolder)
+ nameInCache = [NSString stringWithFormat: @"folder%@", realCollectionId];
+ else
+ nameInCache = collectionId;
+
realCollectionId = [self globallyUniqueIDToIMAPFolderName: realCollectionId type: folderType];
+
currentCollection = [self collectionFromId: realCollectionId type: folderType];
//
@@ -955,7 +1145,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
count = [uids count];
// Add the number of UIDs expected to "soft delete"
- count += [self _softDeleteCountWithFilter: filter collectionId: realCollectionId];
+ count += [self _softDeleteCountWithFilter: filter collectionId: nameInCache];
}
else
@@ -1211,6 +1401,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
SOGoMicrosoftActiveSyncFolderType srcFolderType, dstFolderType;
id aMoveOperation;
NSArray *moveOperations;
+ SoSecurityManager *sm;
NSMutableString *s;
NSData *d;
int i;
@@ -1233,8 +1424,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[s appendString: @""];
- // FIXME - we should support moving events between calendars, for example, or
- // or contacts between address books.
if (srcFolderType == ActiveSyncMailFolder && dstFolderType == ActiveSyncMailFolder)
{
NGImap4Client *client;
@@ -1309,13 +1498,66 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
else
{
- // Non-mail move operations - unsupported for now.
- [s appendFormat: @"%d", 1];
+ id srcCollection, dstCollection, srcSogoObject, dstSogoObject;
+ NSArray *elements;
+ NSString *newUID;
+ NSException *ex;
+
+ unsigned int count, max;
+
+ srcCollection = [self collectionFromId: srcFolderId type: srcFolderType];
+ dstCollection = [self collectionFromId: dstFolderId type: srcFolderType];
+
+ srcSogoObject = [srcCollection lookupName: [srcMessageId sanitizedServerIdWithType: srcFolderType]
+ inContext: context
+ acquire: NO];
+
+ sm = [SoSecurityManager sharedSecurityManager];
+ if (![sm validatePermission: SoPerm_DeleteObjects
+ onObject: srcCollection
+ inContext: context])
+ {
+ if (![sm validatePermission: SoPerm_AddDocumentsImagesAndFiles
+ onObject: dstCollection
+ inContext: context])
+ {
+ newUID = [srcSogoObject globallyUniqueObjectId];
+ dstSogoObject = [[SOGoAppointmentObject alloc] initWithName: [newUID sanitizedServerIdWithType: srcFolderType]
+ inContainer: dstCollection];
+ elements = [[srcSogoObject calendar: NO secure: NO] allObjects];
+ max = [elements count];
+ for (count = 0; count < max; count++)
+ [[elements objectAtIndex: count] setUid: newUID];
+
+ ex = [dstSogoObject saveCalendar: [srcSogoObject calendar: NO secure: NO]];
+ if (!ex)
+ {
+ ex = [srcSogoObject delete];
+ [s appendFormat: @"%@", srcMessageId];
+ [s appendFormat: @"%@", newUID];
+ [s appendFormat: @"%d", 3];
+ }
+ else
+ {
+ [s appendFormat: @"%@", srcMessageId];
+ [s appendFormat: @"%d", 1];
+ }
+ }
+ else
+ {
+ [s appendFormat: @"%@", srcMessageId];
+ [s appendFormat: @"%d", 2];
+ }
+ }
+ else
+ {
+ [s appendFormat: @"%@", srcMessageId];
+ [s appendFormat: @"%d", 1];
+ }
}
[s appendString: @""];
}
-
[s appendString: @""];
@@ -1421,7 +1663,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
allValues = [[accountFolder imapFolderGUIDs] allValues];
for (i = 0; i < [allValues count]; i++)
- [allFoldersID addObject: [NSString stringWithFormat: @"mail/%@", [allValues objectAtIndex: i]]];
+ [allFoldersID addObject: [NSString stringWithFormat: @"mail/%@", [[allValues objectAtIndex: i] substringFromIndex: 6]]];
// FIXME: handle multiple GCS collecitons
@@ -1449,22 +1691,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
collectionId = [allFoldersID objectAtIndex: j];
realCollectionId = [collectionId realCollectionIdWithFolderType: &folderType];
realCollectionId = [self globallyUniqueIDToIMAPFolderName: realCollectionId type: folderType];
+
+ if (folderType == ActiveSyncMailFolder)
+ folderMetadata = [self _folderMetadataForKey: [NSString stringWithFormat: @"folder%@", [[collectionId stringByUnescapingURL] substringFromIndex:5]]];
+ else
+ folderMetadata = [self _folderMetadataForKey: [collectionId stringByUnescapingURL]];
+
collection = [self collectionFromId: realCollectionId type: folderType];
-
- switch (folderType)
- {
- case ActiveSyncContactFolder:
- folderMetadata = [self _folderMetadataForKey: [NSString stringWithFormat: @"vcard/%@", [collection nameInContainer]]];
- break;
- case ActiveSyncEventFolder:
- folderMetadata = [self _folderMetadataForKey: [NSString stringWithFormat: @"vevent/%@", [collection nameInContainer]]];
- break;
- case ActiveSyncTaskFolder:
- folderMetadata = [self _folderMetadataForKey: [NSString stringWithFormat: @"vtodo/%@", [collection nameInContainer]]];
- break;
- default:
- folderMetadata = [self _folderMetadataForKey: [collection nameInContainer]];
- }
+
+ // if collection doesn't exists skip it - next foldersync will do the cleanup
+ if (!collection)
+ continue;
syncKey = [folderMetadata objectForKey: @"SyncKey"];
@@ -2142,7 +2379,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{
d = [[theRequest content] wbxml2xml];
}
-
documentElement = nil;
if (!d)
diff --git a/SoObjects/Mailer/SOGoMailAccount.m b/SoObjects/Mailer/SOGoMailAccount.m
index 5bc3ff2ae..ab6021f07 100644
--- a/SoObjects/Mailer/SOGoMailAccount.m
+++ b/SoObjects/Mailer/SOGoMailAccount.m
@@ -710,7 +710,8 @@ static NSString *inboxFolderName = @"INBOX";
}
}
- [folders setObject: guid forKey: [object substringFromIndex: 1]];
+ [folders setObject: [NSString stringWithFormat: @"folder%@", guid] forKey: [NSString stringWithFormat: @"folder%@", [object substringFromIndex: 1]]];
+
}
return folders;
diff --git a/SoObjects/SOGo/SOGoCacheGCSObject.h b/SoObjects/SOGo/SOGoCacheGCSObject.h
index 90f7d1ba1..b456c1775 100644
--- a/SoObjects/SOGo/SOGoCacheGCSObject.h
+++ b/SoObjects/SOGo/SOGoCacheGCSObject.h
@@ -67,8 +67,8 @@ typedef enum {
- (NSDictionary *) lookupRecord: (NSString *) path
newerThanVersion: (NSInteger) startVersion;
-- (NSArray *) folderList: (NSString *) deviceId
- newerThanVersion: (NSInteger) startVersion;
+- (NSArray *) cacheEntriesForDeviceId: (NSString *) deviceId
+ newerThanVersion: (NSInteger) startVersion;
- (void) setObjectType: (SOGoCacheObjectType) newObjectType;
- (SOGoCacheObjectType) objectType; /* message, fai, folder */
diff --git a/SoObjects/SOGo/SOGoCacheGCSObject.m b/SoObjects/SOGo/SOGoCacheGCSObject.m
index 0b3ba25e8..1f83f8ed2 100644
--- a/SoObjects/SOGo/SOGoCacheGCSObject.m
+++ b/SoObjects/SOGo/SOGoCacheGCSObject.m
@@ -250,7 +250,7 @@ static EOAttribute *textColumn = nil;
newParentPath = NULL;
sql = [NSMutableString stringWithFormat: @"UPDATE %@"
- @" SET c_path = '%@'",
+ @" SET c_path = '/%@'",
[self tableName],
newPath];
if (newParentPath)
@@ -375,9 +375,8 @@ static EOAttribute *textColumn = nil;
return record;
}
-// get a list of all folders
-- (NSArray *) folderList: (NSString *) deviceId
- newerThanVersion: (NSInteger) startVersion
+- (NSArray *) cacheEntriesForDeviceId: (NSString *) deviceId
+ newerThanVersion: (NSInteger) startVersion
{
NSMutableArray *recordsOut;
NSArray *records;
@@ -392,16 +391,22 @@ static EOAttribute *textColumn = nil;
tableName = [self tableName];
adaptor = [self tableChannelAdaptor];
- pathValue = [adaptor formatValue: [NSString stringWithFormat: @"/%@+folder%", deviceId]
+ pathValue = [adaptor formatValue: [NSString stringWithFormat: @"/%@", deviceId]
forAttribute: textColumn];
/* query */
sql = [NSMutableString stringWithFormat:
- @"SELECT * FROM %@ WHERE c_path LIKE %@ AND c_deleted <> 1",
- tableName, pathValue];
+ @"SELECT * FROM %@ WHERE c_type = %d AND c_deleted <> 1", tableName, objectType];
+
if (startVersion > -1)
[sql appendFormat: @" AND c_version > %d", startVersion];
+ if (deviceId) {
+ pathValue = [adaptor formatValue: [NSString stringWithFormat: @"/%@%", deviceId]
+ forAttribute: textColumn];
+ [sql appendFormat: @" AND c_path like %@", pathValue];
+ }
+
/* execution */
records = [self performSQLQuery: sql];