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)); }
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 static bool IsExchangeSyncResultValid(ExchangeSyncResult exchangeSyncResult) { return(exchangeSyncResult != null && exchangeSyncResult.AuthorizationResult != null && exchangeSyncResult.AuthorizationResult.AuthorizationStatus == ExchangeAuthorizationStatus.OK); }
private async Task <ExchangeSyncResult> EnsureAutoDiscover(ExchangeConnectionInfo connectionInfo) { var success = new ExchangeSyncResult { AuthorizationResult = new ExchangeAuthorizationResult { AuthorizationStatus = ExchangeAuthorizationStatus.OK, IsOperationSuccess = true }, OperationResult = new ServiceOperationResult { IsOperationSuccess = true }, }; // check Office 365 server uri is correct (ie. https://outlook.office365.com/EWS/Exchange.asmx) if (connectionInfo.ServerUri != null) { string uri = connectionInfo.ServerUri.ToString().ToLowerInvariant(); if (uri.Contains("outlook.office365.com") && !uri.EndsWith("/ews/exchange.asmx")) { connectionInfo.ServerUri = SafeUri.Get("https://outlook.office365.com/EWS/Exchange.asmx"); } if (uri.Contains("/ews/exchange.asmx/ews/exchange.asmx")) { connectionInfo.ServerUri = SafeUri.Get(uri.Replace("/ews/exchange.asmx/ews/exchange.asmx", "/EWS/Exchange.asmx")); } // check if the server uri looks correct, if it doesn't, run autodiscover var server = new EwsSyncServer(connectionInfo.CreateEwsSettings()); try { var identifiers = await server.GetRootFolderIdentifiersAsync(useCache : false); if (identifiers != null) { return(success); } } catch (Exception ex) { if (connectionInfo.ServerUri != null && !connectionInfo.ServerUri.ToString().EndsWith("/ews/exchange.asmx", StringComparison.OrdinalIgnoreCase)) { // one more try with the /ews/exchange.asmx path connectionInfo.ServerUri = SafeUri.Get(uri.TrimEnd('/') + "/ews/exchange.asmx"); var secondResult = await this.EnsureAutoDiscover(connectionInfo); if (IsExchangeSyncResultValid(secondResult)) { return(success); } } LogService.Log("EwsSyncService", $"Server uri is {connectionInfo.ServerUri} but GetRootFolderIds failed ({ex.Message}), fallbacking to classic autodiscover"); } } LogService.Log("EwsSyncService", "Server uri is empty, performing auto discover"); var engine = new AutoDiscoverEngine(); var autoDiscoverResult = await engine.AutoDiscoverAsync(connectionInfo.Email, connectionInfo.Username, connectionInfo.Password, connectionInfo.Version); if (autoDiscoverResult != null) { if (autoDiscoverResult.ServerUri != null) { LogService.Log("EwsSyncService", "Now using server uri: " + autoDiscoverResult.ServerUri); connectionInfo.ServerUri = autoDiscoverResult.ServerUri; } if (!string.IsNullOrWhiteSpace(autoDiscoverResult.RedirectEmail)) { LogService.Log("EwsSyncService", "Now using email redirect: " + autoDiscoverResult.RedirectEmail); connectionInfo.Email = autoDiscoverResult.RedirectEmail; } return(success); } LogService.Log("EwsSyncService", "Auto discovery failed"); return(new ExchangeSyncResult { AuthorizationResult = new ExchangeAuthorizationResult { AuthorizationStatus = ExchangeAuthorizationStatus.AutodiscoveryServiceNotFound, ErrorMessage = "Check credentials are valid and/or try to specify manually a valid server address" } }); }
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); }
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); }