public async Task <SyncCommandResult> Sync(string syncKey, string folderId, ExchangeChangeSet changeset) { if (string.IsNullOrEmpty(syncKey)) { throw new ArgumentNullException(nameof(syncKey)); } if (string.IsNullOrEmpty(folderId)) { throw new ArgumentNullException(nameof(folderId)); } if (changeset == null) { throw new ArgumentNullException(nameof(changeset)); } LogService.Log("ActiveSyncServer", string.Format("Syncing key: {0} folder id: {1}", syncKey.TakeLast(5), folderId != null ? folderId.TakeLast(5) : "<none>")); SyncCommand command = new SyncCommand(new SyncCommandParameter(syncKey, folderId, changeset), this.settings); ResponseResult <SyncCommandResult> result = await command.Execute(); if (ActiveSyncErrorHelper.IsStatusProvisioningError(result.Data?.Status, result?.Error)) { await this.TryDoProvisioning(); result = await command.Execute(); } if (result.Error != null) { throw result.Error; } return(result.Data); }
public async Task Task_in_default_exchange_folder_have_no_category_in_exchange() { // add a single task without any category var changeSet = new ExchangeChangeSet(); changeSet.AddedTasks.Add(new ExchangeTask { Subject = "task", Properties = ExchangeTaskProperties.Title }); var result1 = await this.Provider.ExchangeService.ExecuteFirstSyncAsync(this.Runner.GetConnectionInfo(), changeSet); Assert.IsTrue(result1.AuthorizationResult.IsOperationSuccess); // perform a full sync, that will create the default Exchange folder await this.SyncFull(); AssertEx.ContainsFolders(this.Workbook, this.Manager.ActiveProvider.DefaultFolderName); AssertEx.ContainsTasks(this.Workbook, "task"); // create a new task in the default Exchange folder this.CreateTask("task 2", this.Workbook.Folders[0]); // send this new task in Exchange await this.SyncDelta(); this.Workbook.RemoveAll(); // fetch all tasks from Exchange, make sure both have no categories set var result2 = await this.Provider.ExchangeService.ExecuteFirstSyncAsync(this.Runner.GetConnectionInfo(), new ExchangeChangeSet()); Assert.IsTrue(result2.AuthorizationResult.IsOperationSuccess); Assert.AreEqual(2, result2.ChangeSet.AddedTasks.Count); Assert.IsTrue(string.IsNullOrEmpty(result2.ChangeSet.AddedTasks[0].Category)); Assert.IsTrue(string.IsNullOrEmpty(result2.ChangeSet.AddedTasks[1].Category)); }
public async Task Task_renamed_in_exchange() { // add a single task without any category var changeSet = new ExchangeChangeSet(); changeSet.AddedTasks.Add(new ExchangeTask { Subject = "task", Properties = ExchangeTaskProperties.Title }); var result1 = await this.Provider.ExchangeService.ExecuteFirstSyncAsync(this.Runner.GetConnectionInfo(), changeSet); Assert.IsTrue(result1.AuthorizationResult.IsOperationSuccess); await this.SyncFull(); AssertEx.ContainsTasks(this.Workbook, "task"); var task = this.Workbook.Tasks[0]; Assert.IsNotNull(task.SyncId); // rename the task in Exchange changeSet = new ExchangeChangeSet(); changeSet.ModifiedTasks.Add(new ExchangeTask { Subject = "new subject", Id = task.SyncId, Properties = ExchangeTaskProperties.Title }); await this.Provider.ExchangeService.ExecuteFirstSyncAsync(this.Runner.GetConnectionInfo(), changeSet); await this.SyncFull(); AssertEx.ContainsTasks(this.Workbook, "new subject"); }
private async Task <List <EwsItemIdentifier> > ApplyRemoteChanges(ExchangeChangeSet changeSet, EwsSyncServer server, List <ExchangeMapId> mapId, EwsFolderIdentifier folderIdentifier, EwsItemType ewsItemType) { // enumerate remote content var remoteIdentifiers = await server.EnumerateFolderContentAsync(folderIdentifier, ewsItemType); var editedItems = new List <EwsItemIdentifier>(); var newItems = new List <EwsItemIdentifier>(); // check for remote identifiers that have a new change key (ie. updated elements in Exchange) foreach (var task in this.workbook.Tasks.Where(t => t.SyncId != null)) { // check if we can find this task that exists in the workbook in the remote identifiers var remoteId = remoteIdentifiers.FirstOrDefault(i => i.Id == task.SyncId.GetId()); // we find this task in the remote identifiers, check if the change key has changed since last sync if (remoteId != null && remoteId.ChangeKey != task.SyncId.GetEwsItemIdentifier().ChangeKey) { // local item found on server with a different ChangeKey because it was updated => update editedItems.Add(new EwsItemIdentifier(remoteId.Id, remoteId.ChangeKey)); } } // check for remote identifiers that we don't have in the workbook and that were not added during this sync operation foreach (var identifier in remoteIdentifiers.Where(i => mapId.All(id => id.ExchangeId != null && id.ExchangeId.GetId() != i.Id))) { var task = this.workbook.Tasks.Where(t => t.SyncId != null).FirstOrDefault(t => t.SyncId.GetId() == identifier.Id); if (task == null) { // item found on server but not locally => new item newItems.Add(identifier); } } var items = new List <EwsItemIdentifier>(); items.AddRange(editedItems); items.AddRange(newItems); var ewsTasks = await server.DownloadFolderContentAsync(items, ewsItemType); foreach (var ewsTask in ewsTasks) { if (editedItems.Any(i => i.Id == ewsTask.Id)) { changeSet.ModifiedTasks.Add(ewsTask.BuildExchangeTask()); } else if (newItems.Any(i => i.Id == ewsTask.Id)) { changeSet.AddedTasks.Add(ewsTask.BuildExchangeTask()); } else { throw new NotSupportedException(); } } return(remoteIdentifiers); }
private ExchangeChangeSet GetChangeSet(IEnumerable <ExchangeTask> deleted) { var changeset = new ExchangeChangeSet(); foreach (var exchangeTask in deleted) { changeset.DeletedTasks.Add(new ServerDeletedAsset(exchangeTask.Id)); } return(changeset); }
private async Task PushLocalChanges(ExchangeChangeSet changeSet, EwsSyncServer server, List <ExchangeMapId> mapId, EwsFolderIdentifier folder) { // send local add content if (changeSet.AddedTasks.Count > 0) { var ewsTasks = changeSet.AddedTasks.Select(exchangeTask => exchangeTask.BuildEwsTask()).ToList(); var createItemResult = await server.CreateItemAsync(ewsTasks, folder); if (changeSet.AddedTasks.Count == createItemResult.Identifiers.Count) { for (int i = 0; i < createItemResult.Identifiers.Count; i++) { var identifier = createItemResult.Identifiers[i]; if (identifier.IsValid) { mapId.Add(new ExchangeMapId { LocalId = changeSet.AddedTasks[i].LocalId, ExchangeId = identifier.GetFullId() }); } else { LogService.Log("EwsSyncService", "Error while creating task: " + changeSet.AddedTasks[i].Subject + " error: " + identifier.ErrorMessage); } } } else { LogService.Log("EwsSyncService", string.Format("Request to create {0} items but result only has {1} items", changeSet.AddedTasks.Count, createItemResult.Identifiers.Count)); } } // send local modification content if (changeSet.ModifiedTasks.Count > 0) { var ewsTasks = changeSet.ModifiedTasks.Select(exchangeTask => exchangeTask.BuildEwsTask()).ToList(); var updateItemResult = await server.UpdateItemsAsync(ewsTasks); // todo ews: we don't update change key here... not optimal because then we're going to ask // the server to enumerate items, we will find different change keys for update items and so // we're going to download them again from the server } // send local delete content if (changeSet.DeletedTasks.Count > 0) { var ewsIdentifiers = new List <EwsItemIdentifier>(); foreach (var deletedAsset in changeSet.DeletedTasks) { ewsIdentifiers.Add(deletedAsset.Id.GetEwsItemIdentifier()); } await server.DeleteItemsAsync(ewsIdentifiers); } }
private async Task <ExchangeSyncResult> Sync(ExchangeConnectionInfo connectionInfo, ExchangeChangeSet changeSet = null) { if (changeSet == null) { changeSet = new ExchangeChangeSet(); } var data = await this.service.ExecuteFirstSyncAsync(connectionInfo, changeSet); string message = string.Format("Operation success: {0} status: {1}", data.AuthorizationResult.IsOperationSuccess, data.AuthorizationResult.AuthorizationStatus); Assert.IsTrue(data.AuthorizationResult.IsOperationSuccess, message); Assert.AreEqual(ExchangeAuthorizationStatus.OK, data.AuthorizationResult.AuthorizationStatus, message); return(data); }
private ExchangeChangeSet BuildChangeSetFromMetadata() { var changeSet = new ExchangeChangeSet(); foreach (var id in this.Metadata.AddedTasks) { var task = this.Workbook.Tasks.FirstOrDefault(t => t.Id == id); if (task != null) { changeSet.AddedTasks.Add(this.CreateExchangeTask(task, TaskProperties.All)); } } foreach (var deletedEntry in this.Metadata.DeletedTasks) { if (!string.IsNullOrEmpty(deletedEntry.SyncId)) { changeSet.DeletedTasks.Add(new ServerDeletedAsset(deletedEntry.SyncId)); } } foreach (var editedEntry in this.Metadata.EditedTasks) { var task = this.Workbook.Tasks.FirstOrDefault(t => t.Id == editedEntry.Key); if (task != null) { // the task is marked edited, make sure it has a sync id if (!string.IsNullOrEmpty(task.SyncId)) { changeSet.ModifiedTasks.Add(this.CreateExchangeTask(task, editedEntry.Value)); } else { // otherwise, process it has an "added" task changeSet.AddedTasks.Add(this.CreateExchangeTask(task, TaskProperties.All)); } } } LogService.LogFormat("ExchangeSync", "Performing sync, sending changeset with {0} added tasks {1} deleted tasks and {2} edited tasks", changeSet.AddedTasks.Count, changeSet.DeletedTasks.Count, changeSet.ModifiedTasks.Count); return(changeSet); }
private async Task FirstSync(ExchangeInfoBuild exchangeInfo) { this.OnSynchronizationProgressChanged(StringResources.SyncProgress_SyncInProgress); var changeSet = new ExchangeChangeSet(); // start by sending an empty change set to get all existing task on the service LogService.LogFormat("ExchangeSync", "Performing first sync, step 1, sending empty changeset"); var result = await this.SyncService.ExecuteFirstSyncAsync(exchangeInfo.ConnectionInfo, changeSet); var completedTasks = result.ChangeSet.AddedTasks.Where(t => t.Completed.HasValue).ToList(); if (completedTasks.Count > 100) { // takes only 100 completed tasks, prevent bringing more in 2Day to prevent weird issue like having 3k tasks in the app var tasks = new List <ExchangeTask>(); tasks.AddRange(result.ChangeSet.AddedTasks.Where(t => !t.Completed.HasValue)); // add all non completed tasks tasks.AddRange(result.ChangeSet.AddedTasks.Where(t => t.Completed.HasValue).Take(100)); // add first 100 completed tasks result.ChangeSet.AddedTasks.Clear(); result.ChangeSet.AddedTasks.AddRange(tasks); } this.ProcessSyncResult(changeSet, result, sendCompletedNotification: false); this.OnSynchronizationProgressChanged(StringResources.SyncProgress_UpdatingTasks); // send a changeset for all tasks that does not have a sync id changeSet.AddedTasks.AddRange(this.Workbook.Tasks.Where(t => !t.IsCompleted && string.IsNullOrEmpty(t.SyncId)).Select(t => t.ToExchangeTask(setCategory: true, properties: TaskProperties.All))); LogService.LogFormat("ExchangeSync", "Performing first sync, step 2, sending changeset with {0} added tasks", changeSet.AddedTasks.Count); if (changeSet.AddedTasks.Count > 0) { result = await this.SyncService.ExecuteFirstSyncAsync(exchangeInfo.ConnectionInfo, changeSet); this.ProcessSyncResult(changeSet, result); } else { this.OnSynchronizationCompleted("Exchange"); } this.FolderId = this.SyncService.TaskFolderId; }
private static void EncodingTest(string input, string output = null) { // setup var changeset = new ExchangeChangeSet(); changeset.AddedTasks.Add(new ExchangeTask { Subject = input }); // act var parameter = new SyncCommandParameter("syncKey", "folderId", changeset); string xml = parameter.BuildXml("command"); // check const string subjectFormat = "<tasks:Subject>{0}</tasks:Subject>"; string subject = string.Format(subjectFormat, output ?? input); Assert.IsTrue(xml.Contains(subject)); }
private ExchangeChangeSet GetChangeSet(ExchangeTask added = null, ExchangeTask modified = null, IEnumerable <string> deleted = null) { var changeset = new ExchangeChangeSet(); if (added != null) { changeset.AddedTasks.Add(added); } if (modified != null) { changeset.ModifiedTasks.Add(modified); } if (deleted != null) { deleted.ForEach(d => changeset.DeletedTasks.Add(new ServerDeletedAsset(d))); } return(changeset); }
public void Handle_special_character() { // setup var changeset = new ExchangeChangeSet(); changeset.AddedTasks.Add(new ExchangeTask { Subject = "title /{ test" }); changeset.AddedTasks.Add(new ExchangeTask { Subject = "title {} test" }); changeset.AddedTasks.Add(new ExchangeTask { Subject = "title #d.3 test" }); // act var parameter = new SyncCommandParameter("syncKey", "folderId", changeset); string xml = parameter.BuildXml("command"); // check Assert.IsFalse(string.IsNullOrWhiteSpace(xml)); }
public SyncCommandParameter(string syncKey, string folderId, ExchangeChangeSet changeset) { if (string.IsNullOrEmpty(syncKey)) { throw new ArgumentNullException("syncKey"); } if (string.IsNullOrEmpty(folderId)) { throw new ArgumentNullException("folderId"); } if (changeset == null) { throw new ArgumentNullException("changeset"); } this.SyncKey = syncKey; this.FolderId = folderId; this.AddedTasks = changeset.AddedTasks; this.ModifiedTasks = changeset.ModifiedTasks; this.DeletedTasks = changeset.DeletedTasks; }
public void Escape_invalid_xml_character() { // non-reg test for the following exception (Windows 8 only apparently) // ActiveSync: System.ArgumentException: ' ', hexadecimal value 0x0B, is an invalid character. // at System.Xml.XmlEncodedRawTextWriter.InvalidXmlChar(Int32 ch, Char* pDst, Boolean entitize) // ... // at Chartreuse.Today.Exchange.ActiveSync.Commands.SyncCommandParameter.CreateTaskXml(ExchangeTask task, StringBuilder builder, Boolean isAdd) // at Chartreuse.Today.Exchange.ActiveSync.Commands.SyncCommandParameter.AppendAddedTasks(StringBuilder xmlBuilder) at // setup var changeset = new ExchangeChangeSet(); changeset.AddedTasks.Add(new ExchangeTask { Subject = "hello " + (char)0x0B + "world !" }); // act var parameter = new SyncCommandParameter("syncKey", "folderId", changeset); string xml = parameter.BuildXml("command"); // check Assert.IsFalse(string.IsNullOrWhiteSpace(xml)); Assert.IsTrue(xml.Contains("hello world !")); }
public async Task <ExchangeSyncResult> ExecuteSyncAsync(ExchangeConnectionInfo connectionInfo, ExchangeChangeSet changeSet, string syncState, string folderId) { return(await this.ExecuteSyncAsync(connectionInfo, changeSet, syncState, folderId, false)); }
public async Task <ExchangeSyncResult> ExecuteFirstSyncAsync(ExchangeConnectionInfo connectionInfo, ExchangeChangeSet changeSet) { ExchangeSyncResult loginResult = await this.EnsureLoginAsync(this.taskFolderId, connectionInfo); if (loginResult != null) { return(loginResult); } ActiveSyncServer server = CreateExchangeServer(connectionInfo); // Start sync with sync state = 0 // In this case we only obtain a non ero syncKey to use with future queries SyncCommandResult syncCommandResult = await server.Sync(InitialSyncKey, this.taskFolderId, new ExchangeChangeSet()); connectionInfo.PolicyKey = server.PolicyKey; if (syncCommandResult.Status != StatusOk) { var result = new ExchangeSyncResult { AuthorizationResult = this.GetFailedAuthResult("ExecuteFirstSync", syncCommandResult) }; return(result); } // As it is first sync, we have just picked a new SyncId // We have to re-sync with this new SyncId return(await this.ExecuteSyncAsync(connectionInfo, changeSet, syncCommandResult.SyncKey, this.taskFolderId, true)); }
public async Task <ExchangeSyncResult> ExecuteFirstSyncAsync(ExchangeConnectionInfo connectionInfo, ExchangeChangeSet changeSet) { return(await this.ExecuteSyncAsync(connectionInfo, changeSet, null, null)); }
public async Task <ExchangeSyncResult> ExecuteSyncAsync(ExchangeConnectionInfo connectionInfo, ExchangeChangeSet changeSet, string syncState, string folderId) { var syncRequest = new ExchangeSyncRequest { ConnectionInfo = connectionInfo, ChangeSet = changeSet, SyncState = syncState }; var content = await this.requestBuilder.PostJsonAsync <ExchangeSyncRequest, ExchangeSyncResult>(this.serverUri + "/Api/Sync/Sync", syncRequest); this.taskFolderName = content.FolderName; return(content); }
private void ProcessSyncResult(ExchangeChangeSet sourceChangeSet, ExchangeSyncResult result, bool sendCompletedNotification = true) { if (this.isCanceled) { throw new OperationCanceledException(); } if (result.AuthorizationResult.IsOperationSuccess) { this.Metadata.Reset(); var changeSet = result.ChangeSet; this.Changes.WebAdd = result.TaskAddedCount; this.Changes.WebEdit = result.TaskEditedCount; this.Changes.WebDelete = result.TaskDeletedCount; // update task sent in the sourceChangeSet foreach (var exchangeTask in sourceChangeSet.AddedTasks) { // find the task in the workbook var task = this.Workbook.Tasks.FirstOrDefault(t => t.Id == exchangeTask.LocalId); if (task != null) { var map = result.MapId.FirstOrDefault(m => m.LocalId == task.Id); if (map != null) { this.PrepareTaskUpdate(task); task.SyncId = map.ExchangeId; } } } LogService.LogFormat( "ExchangeSync", "Processing result sent by server changeset with {0} added tasks {1} deleted tasks and {2} edited tasks", changeSet.AddedTasks.Count, changeSet.DeletedTasks.Count, changeSet.ModifiedTasks.Count); foreach (var exchangeTask in changeSet.AddedTasks.Where(t => !string.IsNullOrEmpty(t.Subject))) { // find the target folder by looking using its name var folder = this.GetFolderForExchangeTask(exchangeTask); var candidate = folder.Tasks.FirstOrDefault(t => t.SyncId == exchangeTask.Id); if (candidate == null) { // check that we don't have already the "same" task candidate = this.FindTask(folder.Tasks, exchangeTask.Subject, exchangeTask.Due); if (candidate == null) { // create the task and add it to its folder var task = exchangeTask.ToTask(this.Workbook); this.AttachTaskToFolder(task, folder); this.Changes.LocalAdd++; } else if (string.IsNullOrEmpty(candidate.SyncId)) { candidate.SyncId = exchangeTask.Id; } } } foreach (var deletedAsset in changeSet.DeletedTasks) { var task = this.Workbook.Tasks.FirstOrDefault(t => t.SyncId == deletedAsset.Id); if (task != null) { this.DeleteTask(task); this.Changes.LocalDelete++; } } foreach (var exchangeTask in changeSet.ModifiedTasks) { var task = this.Workbook.Tasks.FirstOrDefault(t => this.HaveSameId(t, exchangeTask)); if (task != null) { this.PrepareTaskUpdate(task); task.UpdateFromExchange(exchangeTask); var requiredFolder = this.GetFolderForExchangeTask(exchangeTask); if (task.Folder != requiredFolder) { task.Folder = requiredFolder; } this.Changes.LocalEdit++; } else { LogService.LogFormat("ExchangeSync", "Task {0} has been modified on the server but cannot be found in the workbook", exchangeTask.Subject); } } if (result.OperationResult.IsOperationSuccess) { this.SyncState = result.SyncState; if (sendCompletedNotification) { this.OnSynchronizationCompleted("Exchange"); } } else { this.OnSynchronizationFailed(string.Format(ExchangeResources.Exchange_SyncErrorFormat, result.OperationResult.ErrorMessage)); } } else { if (result.AuthorizationResult.Status != null && result.AuthorizationResult.Status.Equals("3", StringComparison.OrdinalIgnoreCase)) { this.OnSynchronizationFailed(StringResources.Exchange_InvalidSyncKeyWorkaround); } else { this.OnSynchronizationFailed(string.Format(ExchangeResources.Exchange_AuthProblemFormat, result.AuthorizationResult.AuthorizationStatus, result.AuthorizationResult.ErrorMessage)); } } }
private async Task <ExchangeSyncResult> ExecuteSyncAsync(ExchangeConnectionInfo connectionInfo, ExchangeChangeSet changeSet, string syncState, string folderId, bool isFirstSync) { if (connectionInfo == null) { throw new ArgumentNullException("connectionInfo"); } if (changeSet == null) { throw new ArgumentNullException("changeSet"); } if (string.IsNullOrEmpty(syncState)) { throw new ArgumentNullException("syncState"); } if (string.IsNullOrEmpty(folderId) || connectionInfo.ServerUri == null || string.IsNullOrWhiteSpace(connectionInfo.ServerUri.ToString())) { ExchangeSyncResult loginResult = await this.EnsureLoginAsync(folderId, connectionInfo); if (loginResult != null) { return(loginResult); } } else { this.taskFolderId = folderId; } ActiveSyncServer server = CreateExchangeServer(connectionInfo); ExchangeSyncResult returnValue = new ExchangeSyncResult { SyncState = syncState, ChangeSet = new ExchangeChangeSet() }; bool mustSync = true; while (mustSync) { SyncCommandResult result = await server.Sync(returnValue.SyncState, this.taskFolderId, changeSet); if (result.Status != StatusOk) { returnValue.AuthorizationResult = this.GetFailedAuthResult("Sync", result); mustSync = false; } else { returnValue.AuthorizationResult = new ExchangeAuthorizationResult { AuthorizationStatus = ExchangeAuthorizationStatus.OK, IsOperationSuccess = true, ServerUri = connectionInfo.ServerUri }; if (result.SyncKey != null) { returnValue.SyncState = result.SyncKey; } connectionInfo.PolicyKey = server.PolicyKey; // If we don't have any syncstate (nothing has changed) we return the old one returnValue.OperationResult.IsOperationSuccess = true; returnValue.ChangeSet.AddedTasks.AddRange(result.AddedTasks); returnValue.ChangeSet.ModifiedTasks.AddRange(result.ModifiedTasks); returnValue.ChangeSet.DeletedTasks.AddRange(result.DeletedTasks); returnValue.TaskAddedCount += result.ServerAddedTasks; returnValue.TaskEditedCount += result.ServerModifiedTasks; foreach (var map in result.ClientServerMapIds) { returnValue.AddMap(map.Key, map.Value); } returnValue.TaskDeletedCount += changeSet.DeletedTasks.Count; mustSync = result.MoreAvailable; changeSet = new ExchangeChangeSet(); // changeSet has been pushed to server, reset it ! } } return(returnValue); }
public async Task <ExchangeSyncResult> ExecuteSyncAsync(ExchangeConnectionInfo connectionInfo, ExchangeChangeSet changeSet, string syncState, string folderId) { if (connectionInfo == null) { throw new ArgumentNullException(nameof(connectionInfo)); } if (changeSet == null) { throw new ArgumentNullException(nameof(changeSet)); } var outChangeSet = new ExchangeChangeSet(); var autoDiscoverResult = await this.EnsureAutoDiscover(connectionInfo); if (!IsExchangeSyncResultValid(autoDiscoverResult)) { return(autoDiscoverResult); } var server = new EwsSyncServer(connectionInfo.CreateEwsSettings()); var identifiers = await server.GetRootFolderIdentifiersAsync(); //var subFolders = await server.GetSubFoldersAsync(identifiers.TaskFolderIdentifier); //var flaggedItemFolders = await this.EnsureSearchFolder(server); /* * var a = await server.EnumerateFolderContentAsync(flaggedItemFolders); * var d = await server.DownloadFolderContentAsync(a); */ var mapId = new List <ExchangeMapId>(); await this.PushLocalChanges(changeSet, server, mapId, identifiers.TaskFolderIdentifier); var remoteIdentifiers = await this.ApplyRemoteChanges(outChangeSet, server, mapId, identifiers.TaskFolderIdentifier, EwsItemType.Task); /*foreach (var subFolder in subFolders.Folders) * { * await this.ApplyRemoteChanges(outChangeSet, server, mapId, subFolder); * }*/ if (connectionInfo.SyncFlaggedItems) { try { var identifier = await this.EnsureSearchFolderAsync(server); var otherRemoteIdentifiers = await this.ApplyRemoteChanges(outChangeSet, server, mapId, identifier, EwsItemType.Item); remoteIdentifiers.AddRange(otherRemoteIdentifiers); } catch (Exception ex) { LogService.Log("EwsSyncService", $"Exception while syncing flagged items: {ex}"); TrackingManagerHelper.Exception(ex, "Exception while syncing flagged items"); } } // check for deleted items foreach (var task in this.workbook.Tasks.Where(t => t.SyncId != null)) { var remoteId = remoteIdentifiers.FirstOrDefault(i => i.Id == task.SyncId.GetId()); if (remoteId == null) { // local item not found on server because it was deleted => delete outChangeSet.DeletedTasks.Add(new ServerDeletedAsset(task.SyncId)); } } var result = new ExchangeSyncResult { AuthorizationResult = new ExchangeAuthorizationResult { Status = "OK", AuthorizationStatus = ExchangeAuthorizationStatus.OK, IsOperationSuccess = true, ServerUri = connectionInfo.ServerUri }, ChangeSet = outChangeSet, MapId = mapId, SyncState = identifiers.TaskFolderIdentifier.ChangeKey, OperationResult = new ServiceOperationResult { IsOperationSuccess = true } }; return(result); }