/// <summary> /// Provides in-place (destructive) processing of the <see cref="Update"/>. /// </summary> /// <param name="update">The update instance.</param> /// <param name="file"> /// A KmlFile containing the <c>Update</c> and the update targets. /// </param> /// <exception cref="ArgumentNullException">file is null.</exception> public static void Process(this Update update, KmlFile file) { if (file == null) { throw new ArgumentNullException("file"); } foreach (var child in update.Updates) { ChangeCollection change = child as ChangeCollection; if (change != null) { ProcessChange(change, file); continue; } CreateCollection create = child as CreateCollection; if (create != null) { ProcessCreate(create, file); continue; } DeleteCollection delete = child as DeleteCollection; if (delete != null) { ProcessDelete(delete, file); } } }
/// <summary> /// Sync folder hierarchy. /// </summary> /// <param name="exchangeService">Exchange service.</param> /// <returns></returns> public static async Task SyncFolderHierarchy(ExchangeService exchangeService) { ChangeCollection <MailFolderChange> folderChange = null; string syncState = null; do { folderChange = await exchangeService.SyncFolderHierarchy(null, syncState); syncState = folderChange.SyncState; foreach (MailFolderChange mailFolderChange in folderChange.Items) { Assert.AreEqual( ChangeType.Created, mailFolderChange.ChangeType); } } while (folderChange.MoreAvailable); SearchFilter inbox = new SearchFilter.IsEqualTo(MailFolderObjectSchema.DisplayName, "Inbox"); FindMailFolderResults result = await exchangeService.FindFolders(WellKnownFolderName.MsgFolderRoot, inbox, new MailFolderView()); MailFolder mf = new MailFolder(exchangeService); mf.DisplayName = "kakakoko"; await mf.SaveAsync(result.MailFolders[0]); do { folderChange = await exchangeService.SyncFolderHierarchy(null, syncState); syncState = folderChange.SyncState; Assert.AreEqual( 1, folderChange.TotalCount); Assert.AreEqual( ChangeType.Created, folderChange.Items[0].ChangeType); } while (folderChange.MoreAvailable); await mf.DeleteAsync(); do { folderChange = await exchangeService.SyncFolderHierarchy(null, syncState); syncState = folderChange.SyncState; Assert.AreEqual( 1, folderChange.TotalCount); Assert.AreEqual( ChangeType.Deleted, folderChange.Items[0].ChangeType); } while (folderChange.MoreAvailable); }
private List <Change> GetUniqueChanges(ChangeCollection changes) { return(changes .GroupBy(i => ((ChangeItem)i).ItemId, (key, g) => g.OrderByDescending(e => e.Time).First()).OrderByDescending(c => c.Time) .ToList()); }
// Get the folder changes in the root folder. static void ProcessFolders(ChangeCollection <FolderChange> fcc) { // Create a variable for all the new folders in the FolderChange ChangeCollection. var newFolders = from fc in fcc where fc.ChangeType == ChangeType.Create select fc.FolderId; // Get the properties for each folder, so that they can be created on the client. foreach (var item in newFolders) { Folder newFolder = new Folder(service); newFolder = Folder.Bind(service, item); newFolder.Load(); Console.WriteLine("New folder, all properties loaded"); Console.WriteLine("Display name: {0}", newFolder.DisplayName); Console.WriteLine("Parent Folder Id: {0}", newFolder.ParentFolderId); Console.WriteLine("--------"); // TODO: Create the folder on the client by using the properties // returned from Load. // Call SyncContents and SetStreamingNotifications on the new child folders. string ccSyncState = SyncContents(service, null, newFolder.Id); SetStreamingNotifications(service, ccSyncState, newFolder.Id); } // Create a variable for all the deleted folders in the FolderChange ChangeCollection. var deleteFolders = from fc in fcc where fc.ChangeType == ChangeType.Delete select fc.FolderId; // Display the FolderIds to be deleted on the client. foreach (var item in deleteFolders) { Console.WriteLine("Delete FolderId: {0}", item); Console.WriteLine("--------"); // TODO: Delete messages on the client by using the FolderIds in deleteFolders. } // Create a variable for all the updated folders in the FolderChange ChangeCollection. var updateFolders = from fc in fcc where fc.ChangeType == ChangeType.Update select fc.Folder; // Display the display name for each updated folder. foreach (var item in updateFolders) { Folder folder = Folder.Bind(service, item.Id); folder.Load(); Console.WriteLine("Updated folder, all properties loaded."); Console.WriteLine("Parent Folder Id: {0}", item.ParentFolderId); Console.WriteLine("Display name: {0}", item.DisplayName); Console.WriteLine("--------"); // TODO: Compare the properties retrieved from Load to the // properties on the client and update the client properties accordingly. } }
private void RenameCollectionButton_Click(object sender, EventArgs e) { Collection collection = collections[CollectionsListBox.SelectedIndex]; ChangeCollection form = new ChangeCollection(collection); form.ShowDialog(); InterplayForServer.UpdateCollection(collection); FindCollections(); }
private void AddCollectionButton_Click(object sender, EventArgs e) { Collection collection = new Collection(); ChangeCollection form = new ChangeCollection(collection); form.ShowDialog(); InterplayForServer.CreateCollection(collection.Name); FindCollections(); }
static void Main(string[] args) { ClientContext ctx = ContextHelper.GetSPContext("https://folkuniversitetetsp2016.sharepoint.com/").Result; List list = ctx.Web.GetListByTitle("CustomList"); string currentChangeTokenstr = list.GetPropertyBagValueString("customlistchangetoken", null); ChangeToken currentChangeToken = null; if (currentChangeTokenstr != null) { currentChangeToken = new ChangeToken(); currentChangeToken.StringValue = currentChangeTokenstr; } ChangeQuery q = new ChangeQuery(false, false); q.Update = true; q.Add = true; q.Item = true; q.DeleteObject = true; q.ChangeTokenStart = currentChangeToken; q.ChangeTokenEnd = list.CurrentChangeToken; ChangeCollection changes = list.GetChanges(q); ctx.Load(changes); ctx.ExecuteQueryRetry(); foreach (var change in changes) { if (change.ChangeType == ChangeType.Add) { ChangeItem itemChange = change as ChangeItem; Console.WriteLine("Item was added id = " + itemChange.ItemId); } if (change.ChangeType == ChangeType.DeleteObject) { ChangeItem itemChange = change as ChangeItem; Console.WriteLine("Item was deleted id = " + itemChange.ItemId); } if (change.ChangeType == ChangeType.Update) { ChangeItem itemChange = change as ChangeItem; Console.WriteLine("Item was updated id = " + itemChange.ItemId); } } list.SetPropertyBagValue("customlistchangetoken", q.ChangeTokenEnd.StringValue); Console.WriteLine("done"); Console.ReadLine(); }
/// <summary> /// Creates a <see cref="System.Collections.Generic.List<T>"/> from an <see cref="ChangeCollection"/>. /// </summary> /// <typeparam name="T">The type of the elements of source.</typeparam> /// <param name="collection">Extended collection of changes.</param> /// <returns>A <see cref="System.Collections.Generic.List<T>"/> that contains elements from the input sequence</returns> public static List <T> ToChangeList <T>(this ChangeCollection collection) { List <T> changes = new List <T>(); foreach (Change change in collection) { changes.Add((T)(object)change); } return(changes); }
public void TestChangeCoordinates() { // Create the target var point = new Point { Coordinate = new Vector(38.38, -122.122) }; var placemark = new Placemark { Id = "placemark123", Geometry = point, Name = "placemark name" }; var file = KmlFile.Create(placemark, false); // Now create the Update const double latitude = -38.38; const double longitude = 122.122; point = new Point { Coordinate = new Vector(latitude, longitude) }; placemark = new Placemark { Geometry = point, TargetId = "placemark123" }; var change = new ChangeCollection { placemark }; var update = new Update(); update.AddUpdate(change); // Now test the update worked update.Process(file); placemark = file.Root as Placemark; Assert.That(placemark, Is.Not.Null); Assert.That(placemark.Id, Is.EqualTo("placemark123")); Assert.That(placemark.Name, Is.EqualTo("placemark name")); point = placemark.Geometry as Point; Assert.That(point, Is.Not.Null); Assert.That(point.Coordinate.Latitude, Is.EqualTo(latitude)); Assert.That(point.Coordinate.Longitude, Is.EqualTo(longitude)); }
private void SyncContacts(ExchangeService service) { // Initialize the flag that will indicate when there are no more changes. bool isEndOfChanges = false; // Call SyncFolderItems repeatedly until no more changes are available. // sSyncState represents the sync state value that was returned in the prior synchronization response. do { ChangeCollection <ItemChange> icc = service.SyncFolderItems(new FolderId(WellKnownFolderName.Contacts), PropertySet.FirstClassProperties, null, 512, SyncFolderItemsScope.NormalItems, sSyncState); if (icc.Count == 0) { Console.WriteLine("There are no item changes to synchronize."); } else { foreach (ItemChange ic in icc) { if (ic.ChangeType == ChangeType.Create) { Contact contacts = Contact.Bind(service, ic.ItemId); contact.AddContact(contacts); contact.PushUpdatesToAuditTable("Added the record", contacts); } else if (ic.ChangeType == ChangeType.Update) { Contact contacts = Contact.Bind(service, ic.ItemId); contact.UpdateContact(contacts); contact.PushUpdatesToAuditTable("Updated the record", contacts); } else if (ic.ChangeType == ChangeType.Delete) { contact.PushUpdatesToAuditTable("Deleted the record", ic.ItemId); contact.DeleteContact(ic.ItemId); } else if (ic.ChangeType == ChangeType.Delete) { //TODO: Update the item's read flag on the client. } } } // Save the sync state for use in future SyncFolderHierarchy calls. sSyncState = icc.SyncState; WriteSyncState(); if (!icc.MoreChangesAvailable) { isEndOfChanges = false; } } while (isEndOfChanges); }
// Synchronize the folders in the specified root folder. static string SyncFolders(ExchangeService service, string FolderSyncState, FolderId rootSyncFolder) { Console.WriteLine("Starting folder sync on the following folder"); Console.WriteLine("FolderId: {0}", rootSyncFolder); Console.WriteLine("--------"); // Get a list of all folders under the rootSyncFolder by calling SyncFolderHierarchy. // The folderId parameter is the root folder to synchronize. // The propertySet parameter is set to IdOnly to reduce calls to the Exchange database, // because any additional properties result in another call to the Exchange database. // The syncState parameter is set to the folder sync state. When this method is called // on a new or empty mailbox, the value is null. If the method has been called before, // the FolderSyncState value contains the value previously returned by the server. FolderChangeCollection = service.SyncFolderHierarchy(rootSyncFolder, PropertySet.IdOnly, FolderSyncState); // Save the sync state for use in future SyncFolderItems requests. // The sync state is used by the server to determine what changes to report // to the client. FolderSyncState = FolderChangeCollection.SyncState; // If the count of changes is zero, there are no changes to synchronize. if (FolderChangeCollection.Count == 0) { Console.WriteLine("There are no new folders to synchronize."); Console.WriteLine("--------"); } // Otherwise, write all the changes included in the response // to the console. // For the initial synchronization, all the changes will be of type // ChangeType.Create. else { foreach (FolderChange fc in FolderChangeCollection) { Console.WriteLine("FolderChange.ChangeType: " + fc.ChangeType.ToString()); Console.WriteLine("FolderChange.FolderId: " + fc.FolderId); Console.WriteLine("--------"); } } // Send the FolderChangeCollection to ProcessItems to actually retrieve the messages and changes. ProcessFolders(FolderChangeCollection); Console.WriteLine("Finished folder sync on the following folder"); Console.WriteLine("FolderId: {0}", rootSyncFolder); Console.WriteLine("--------"); return(FolderSyncState); }
private static void ProcessChange(ChangeCollection change, KmlFile file) { foreach (var source in change) { if (source.TargetId != null) { KmlObject target = file.FindObject(source.TargetId); if (target != null) { target.Merge(source); target.TargetId = null; // Merge copied the TargetId from the source, but target shouldn't have it set } } } }
private static void ProcessChange(ChangeCollection change, KmlFile file) { foreach (KmlObject source in change) { if (source.TargetId != null) { KmlObject target = file.FindObject(source.TargetId); if (target != null) { target.Merge(source); target.TargetId = null; // Merge copied the TargetId from the source, but target shouldn't have it set } } } }
public static void Run([QueueTrigger("achangeismade", Connection = "AzureWebJobsStorage")] string myQueueItem, TraceWriter log) { log.Info($"C# Queue trigger function processed: {myQueueItem}"); NotificationModel notification = JsonConvert.DeserializeObject <NotificationModel>(myQueueItem); ClientContext ctx = ContextHelper.GetContext("https://folkis2018.sharepoint.com/sites/David"); List list = ctx.Web.GetListByTitle("SampleList"); var lastCheckedString = list.GetPropertyBagValueString("lastchecked", null); ChangeQuery query = new ChangeQuery(false, false); query.Item = true; query.Add = true; query.Update = true; //query.DeleteObject = true; dont care if (lastCheckedString != null) { ChangeToken token = new ChangeToken(); token.StringValue = lastCheckedString; query.ChangeTokenStart = token; } query.ChangeTokenEnd = list.CurrentChangeToken; ChangeCollection changes = list.GetChanges(query); ctx.Load(changes); ctx.ExecuteQuery(); foreach (ChangeItem change in changes) { log.Info(change.ItemId.ToString()); log.Info(change.ChangeType.ToString()); CloudStorageAccount storageAccount = CloudStorageAccount.Parse(Environment.GetEnvironmentVariable("AzureWebJobsStorage")); // Get queue... create if does not exist. CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient(); CloudQueue queue = queueClient.GetQueueReference("processitem"); queue.CreateIfNotExists(); queue.AddMessage(new CloudQueueMessage(change.ItemId.ToString())); } list.SetPropertyBagValue("lastchecked", list.CurrentChangeToken.StringValue); }
private static void DisplayChanges(ChangeCollection coll, ChangeToken ct) { if (coll.Count == 0) { Console.WriteLine(string.Format("No changes to {0} since {1} UTC.", listName, GetDateStringFromChangeToken(ct))); return; } Console.ForegroundColor = ConsoleColor.Green; foreach (ChangeItem itm in coll) { Console.WriteLine(); Console.WriteLine(string.Format("List {0} had a Change of type \"{1}\" on the item with Id {2}.", listName, itm.ChangeType.ToString(), itm.ItemId)); } Console.WriteLine(); Console.ResetColor(); }
public void CountEmailsNumber() { string syncState = ""; ChangeCollection <ItemChange> itemChanges = null; int count = 0; do { itemChanges = _service.SyncFolderItems(new FolderId(WellKnownFolderName.Inbox), PropertySet.IdOnly, null, 500, SyncFolderItemsScope.NormalItems, syncState); syncState = itemChanges.SyncState; count += itemChanges.Count; Console.WriteLine("itemchanges count : " + count); //Console.WriteLine("syncState: " + syncState); } while (itemChanges.MoreChangesAvailable); Console.WriteLine($"total mail in Inbox number: {count}"); }
public static ChangeCollection GetAllChanges(List ListWebHook, ChangeQuery ListChangeQuery, ClientContext SPClientContext, TraceWriter log) { ChangeCollection chcReturn = null; try { chcReturn = ListWebHook.GetChanges(ListChangeQuery); SPClientContext.Load(chcReturn); SPClientContext.ExecuteQuery(); } catch (Exception ex) { log.Info($"Error in GetAllChanges: " + ex.ToString()); } return(chcReturn); }
public async Task <bool> ReceiveEmail() { string syncState = ""; PropertySet ps = new PropertySet(ItemSchema.Subject, ItemSchema.Body, ItemSchema.Attachments, ItemSchema.ConversationId, ItemSchema.Id, EmailMessageSchema.Sender, EmailMessageSchema.CcRecipients, EmailMessageSchema.ToRecipients); ChangeCollection <ItemChange> itemChanges = null; int count = 0; int index = 512; do { itemChanges = await _service.SyncFolderItems(new FolderId(WellKnownFolderName.Inbox), PropertySet.IdOnly, null, index, SyncFolderItemsScope.NormalItems, syncState); syncState = itemChanges.SyncState; count += itemChanges.Count; Console.WriteLine("itemchanges count : " + count); //Console.WriteLine("syncState: " + syncState); foreach (ItemChange itemChange in itemChanges) { try { if (itemChange.ChangeType == ChangeType.Create) { EmailMessage emailMessage = await EmailMessage.Bind(_service, itemChange.ItemId, ps); Console.WriteLine("to: " + emailMessage.ToRecipients); Console.WriteLine("create time: " + emailMessage.DateTimeCreated + ": " + emailMessage.Subject + ", from: " + emailMessage.From.Address); //Console.WriteLine(emailMessage.Body); //Console.WriteLine(count + ": " + itemChange.ItemId.UniqueId); } else { Console.WriteLine("type:" + itemChange.ChangeType.ToString()); } } catch (Exception ex) { Console.Write(ex.Message); } } }while (itemChanges.MoreChangesAvailable && count < index); return(true); }
private static void SyncMailboxes(ExchangeService service) { // Retrieve a collection of changes from the server for the Inbox, including the first-class properties. When the synch state parameter is null, // changes for all subfolders under the specified folder will be retrieved. ChangeCollection <FolderChange> folderChangeCollection = service.SyncFolderHierarchy(new FolderId(WellKnownFolderName.Inbox), PropertySet.FirstClassProperties, null); // Display changes, if any. Note that instead of displaying the changes, // you can create, update, or delete folders based on the changes retrieved from the server. if (folderChangeCollection.Count != 0) { foreach (FolderChange fc in folderChangeCollection) { Console.WriteLine("ChangeType: " + fc.ChangeType.ToString()); Console.WriteLine("DisplayName: " + fc.Folder.DisplayName); Console.WriteLine("ChildFolderCount: " + fc.Folder.ChildFolderCount); Console.WriteLine("==========="); } } }
public void TestChangeCoordinates() { // Create the target var point = new Point(); point.Coordinate = new Vector(38.38, -122.122); var placemark = new Placemark(); placemark.Id = "placemark123"; placemark.Geometry = point; placemark.Name = "placemark name"; var file = KmlFile.Create(placemark, false); // Now create the Update const double latitude = -38.38; const double longitude = 122.122; point = new Point(); point.Coordinate = new Vector(latitude, longitude); placemark = new Placemark(); placemark.Geometry = point; placemark.TargetId = "placemark123"; var change = new ChangeCollection(); change.Add(placemark); var update = new Update(); update.AddUpdate(change); // Now test the update worked update.Process(file); placemark = file.Root as Placemark; Assert.That(placemark, Is.Not.Null); Assert.That(placemark.Id, Is.EqualTo("placemark123")); Assert.That(placemark.Name, Is.EqualTo("placemark name")); point = placemark.Geometry as Point; Assert.That(point, Is.Not.Null); Assert.That(point.Coordinate.Latitude, Is.EqualTo(latitude)); Assert.That(point.Coordinate.Longitude, Is.EqualTo(longitude)); }
public void ReceiveEmail() { string syncState = ""; ChangeCollection <ItemChange> itemChanges = null; //PropertySet properties = new PropertySet(); //properties.(); int count = 0; do { itemChanges = _service.SyncFolderItems(new FolderId(WellKnownFolderName.Inbox), PropertySet.IdOnly, null, 50, SyncFolderItemsScope.NormalItems, syncState); syncState = itemChanges.SyncState; count += itemChanges.Count; Console.WriteLine("itemchanges count : " + count); //Console.WriteLine("syncState: " + syncState); foreach (ItemChange itemChange in itemChanges) { try { if (itemChange.ChangeType == ChangeType.Create) { EmailMessage emailMessage = EmailMessage.Bind(_service, itemChange.ItemId); Console.WriteLine("create time: " + emailMessage.DateTimeCreated + ": " + emailMessage.Subject + ", from: " + emailMessage.From.Address); Console.WriteLine($"emailMessage.Id.UniqueId: {emailMessage.Id.UniqueId}"); //Console.WriteLine($"itemChange.Item.Id.UniqueId: { itemChange.Item.Id.UniqueId}"); Console.WriteLine(emailMessage.Id.UniqueId == itemChange.Item.Id.UniqueId); //Console.WriteLine(emailMessage.Body); //Console.WriteLine(count + ": " + itemChange.ItemId.UniqueId); } else { Console.WriteLine("type:" + itemChange.ChangeType.ToString()); } } catch (Exception ex) { Console.Write(ex.Message); } } }while (itemChanges.MoreChangesAvailable && count < 50); }
static void GetChanges(ClientContext SPClientContext, string ListId, TraceWriter log) { // Get the List where the WebHook is working List myListWebHook = WHHelpRoutines.GetListWebHook(SPClientContext, log); // Get the Change Query ChangeQuery myChangeQuery = WHHelpRoutines.GetChangeQueryNew(ListId, log); // Only new items and for the last one minute // Get all the Changes ChangeCollection allChanges = WHHelpRoutines.GetAllChanges(myListWebHook, myChangeQuery, SPClientContext, log); foreach (Change oneChange in allChanges) { if (oneChange is ChangeItem) { // Get what is changed ListItem itemChanged = WHHelpRoutines.GetItemChanged(myListWebHook, oneChange, SPClientContext, log); log.Info($"itemChangedID - " + itemChanged.Id.ToString()); // Do something with the Item Changed DoSomething(SPClientContext, itemChanged, log); } } }
public static void Run([QueueTrigger("eventhappened", Connection = "AzureWebJobsStorage")] string myQueueItem, TraceWriter log) { log.Info($"C# Queue trigger function processed: {myQueueItem}"); ConfigureBindingRedirects(); var notification = JsonConvert.DeserializeObject <NotificationModel>(myQueueItem); ClientContext ctx = Common.Helpers.ContextHelper.GetSPContext("https://folkuniversitetetsp2016.sharepoint.com" + notification.SiteUrl).Result; // notification.Resource is our list id List list = ctx.Web.Lists.GetById(new Guid(notification.Resource)); string currentChangeTokenstr = list.GetPropertyBagValueString("customlistchangetoken", null); ChangeToken currentChangeToken = null; if (currentChangeTokenstr != null) { currentChangeToken = new ChangeToken(); currentChangeToken.StringValue = currentChangeTokenstr; } ctx.Load(list, l => l.CurrentChangeToken); ctx.ExecuteQuery(); ChangeQuery q = new ChangeQuery(false, false); q.Update = true; q.Add = true; q.Item = true; q.DeleteObject = true; q.ChangeTokenStart = currentChangeToken; q.ChangeTokenEnd = list.CurrentChangeToken; ChangeCollection changes = list.GetChanges(q); ctx.Load(changes); ctx.ExecuteQueryRetry(); foreach (var change in changes) { if (change.ChangeType == ChangeType.Add) { ChangeItem itemChange = change as ChangeItem; log.Info("Item was added id = " + itemChange.ItemId); } if (change.ChangeType == ChangeType.DeleteObject) { ChangeItem itemChange = change as ChangeItem; log.Info("Item was deleted id = " + itemChange.ItemId); } if (change.ChangeType == ChangeType.Update) { ChangeItem itemChange = change as ChangeItem; log.Info("Item was updated id = " + itemChange.ItemId); } } list.SetPropertyBagValue("customlistchangetoken", q.ChangeTokenEnd.StringValue); }
public ChangeCollectionAdapter(ChangeCollection changeCollection) { _changeCollection = changeCollection; }
public static void Run([QueueTrigger("eventhappened", Connection = "AzureWebJobsStorage")] string myQueueItem, TraceWriter log) { log.Info($"C# Queue trigger function processed: {myQueueItem}"); ConfigureBindingRedirects(); var notification = JsonConvert.DeserializeObject <Common.Models.NotificationModel>(myQueueItem); ClientContext ctx = Common.Helpers.ContextHelper.GetSPContext("https://folkuniversitetetsp2016.sharepoint.com" + notification.SiteUrl).Result; // notification.Resource is our list id List list = ctx.Web.Lists.GetById(new Guid(notification.Resource)); string currentChangeTokenstr = list.GetPropertyBagValueString("customlistchangetoken", null); ChangeToken currentChangeToken = null; if (currentChangeTokenstr != null) { currentChangeToken = new ChangeToken(); currentChangeToken.StringValue = currentChangeTokenstr; } ctx.Load(list, l => l.CurrentChangeToken); ctx.ExecuteQuery(); ChangeQuery q = new ChangeQuery(false, false); q.Update = true; q.Add = true; q.Item = true; q.DeleteObject = true; q.ChangeTokenStart = currentChangeToken; q.ChangeTokenEnd = list.CurrentChangeToken; ChangeCollection changes = list.GetChanges(q); ctx.Load(changes); ctx.ExecuteQueryRetry(); //create queue if not exists CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["AzureWebJobsStorage"]); // Get queue... create if does not exist. CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient(); CloudQueue queue = queueClient.GetQueueReference("changehappened"); queue.CreateIfNotExists(); foreach (var change in changes) { if (change.ChangeType == ChangeType.Add) { ChangeItem itemChange = change as ChangeItem; ChangeInfo changeInfo = new ChangeInfo() { SiteUrl = notification.SiteUrl, ListId = notification.Resource, ItemId = itemChange.ItemId }; queue.AddMessage(new CloudQueueMessage(JsonConvert.SerializeObject(changeInfo))); log.Info("Item was added id = " + itemChange.ItemId); } if (change.ChangeType == ChangeType.DeleteObject) { ChangeItem itemChange = change as ChangeItem; ChangeInfo changeInfo = new ChangeInfo() { SiteUrl = notification.SiteUrl, ListId = notification.Resource, ItemId = itemChange.ItemId }; queue.AddMessage(new CloudQueueMessage(JsonConvert.SerializeObject(changeInfo))); log.Info("Item was deleted id = " + itemChange.ItemId); } if (change.ChangeType == ChangeType.Update) { ChangeItem itemChange = change as ChangeItem; ChangeInfo changeInfo = new ChangeInfo() { SiteUrl = notification.SiteUrl, ListId = notification.Resource, ItemId = itemChange.ItemId }; queue.AddMessage(new CloudQueueMessage(JsonConvert.SerializeObject(changeInfo))); log.Info("Item was updated id = " + itemChange.ItemId); } } list.SetPropertyBagValue("customlistchangetoken", q.ChangeTokenEnd.StringValue); }
public void ProcessChanges(string webID, string listID, string siteUrl) { ClientContext cc = null; try { #region Setup SharePoint Online ClientContext //DO NOT USE THIS IN PRODUCTION //Try to implement proper authentication based on Azure AD app instead!!! string url = String.Format("https://{0}{1}", TenantURL, siteUrl); string initString = "YOUR PASSWORD"; // Instantiate the secure string. SecureString testString = new SecureString(); // Use the AppendChar method to add each char value to the secure string. foreach (char ch in initString) { testString.AppendChar(ch); } cc = new ClientContext(url); cc.AuthenticationMode = ClientAuthenticationMode.Default; cc.Credentials = new SharePointOnlineCredentials("YOUR USER", testString); #endregion #region Grab the wikipage PublishingPageContent for the page the web hook was triggered Web web = cc.Site.OpenWebById(new Guid(webID)); cc.Load(web); List ls = web.Lists.GetById(new Guid(listID)); cc.Load(ls); ChangeQuery query = new ChangeQuery(false, false); query.Item = true; query.Update = true; ChangeCollection changes = ls.GetChanges(query); cc.Load(changes); cc.ExecuteQuery(); Console.WriteLine("Starting to process changes for List {0} in Web {1} under site {2}", ls.Title, web.Title, siteUrl); Dictionary <String, String> qna = new Dictionary <string, string>(); foreach (Change change in changes) { if (change is Microsoft.SharePoint.Client.ChangeItem) { ChangeItem ci = change as ChangeItem; var changeType = ci.ChangeType.ToString(); var itemId = ci.ItemId.ToString(); Console.WriteLine("Going to process changes for {0}: {1}", itemId, changeType); Dictionary <string, string> res = this.GetWikiPageContententForKB(ci.ItemId, new Guid(listID), siteUrl); foreach (string key in res.Keys) { if (!qna.ContainsKey(key)) { qna.Add(key, res[key]); } } } } KnowledgeBaseManager kb = new KnowledgeBaseManager("https://westus.api.cognitive.microsoft.com/qnamaker/v2.0/knowledgebases/", "CLIENT SECRETE", "KNOWLEDGEBASE ID"); kb.AddQnAToKB(qna); kb.PublishKB(); #endregion } catch (Exception ex) { // Log error Console.WriteLine(ex.ToString()); } finally { if (cc != null) { cc.Dispose(); } } }
private async Task ChecksConnection() { var current = Connectivity.NetworkAccess; if (current == NetworkAccess.Internet) { Title = "Saan muudatused..."; activityIndicator = new ActivityIndicator { IsRunning = true, Margin = 175, Color = Color.FromHex("#A22538") }; if (ChangesListView == null) { Content = activityIndicator; } await Task.Run(() => { LoadChanges(ChangeCollection.GetChangeList()); }); if (ChangesListView == null) { activityIndicator.IsRunning = false; activityIndicator.IsVisible = false; InitializeComponent(); string group = Preferences.Get("group", "none"); if (group != "none") { ChangesPageSearchBar.Placeholder = group; } } else { Title = "Tunniplaani muudatused"; string group = Preferences.Get("group", "none"); if (group != "none") { ChangesPageSearchBar.Placeholder = group; Content = ChangesListView; } } ChangesListView.IsRefreshing = false; ChangesListView.RefreshControlColor = Color.FromHex("#A22538"); } else { Title = "Saan muudatused..."; activityIndicator = new ActivityIndicator { IsRunning = true, Margin = 175, Color = Color.FromHex("#A22538") }; if (ChangesListView == null) { Content = activityIndicator; } await GetChangesFromDatabase(); if (ChangesListView == null) { activityIndicator.IsRunning = false; activityIndicator.IsEnabled = false; InitializeComponent(); ChangesListView.IsRefreshing = false; string group = Preferences.Get("group", "none"); if (group != "none") { ChangesPageSearchBar.Placeholder = group; } } else { ChangesListView.IsRefreshing = false; Content = ChangesListView; } DependencyService.Get <IMessage>().ShortAlert("Teil puudub ühendus."); } }
// Get the items and changes in the root folder. static void ProcessItems(ChangeCollection <ItemChange> icc) { // Create a variable for all the new items in the ItemChangeCollection. var newItems = from ic in icc where ic.ChangeType == ChangeType.Create select ic.Item; // Get the properties for each item, so that they can be created on the client. foreach (var item in newItems) { service.LoadPropertiesForItems(newItems, PropertySet.FirstClassProperties); Console.WriteLine("New item, all properties loaded"); Console.WriteLine("Subject: {0}", item.Subject); Console.WriteLine("ParentFolderId: {0}", item.ParentFolderId); Console.WriteLine("DateTimeCreated: {0}", item.DateTimeCreated); Console.WriteLine("--------"); // TODO: Create the messages on the client by using the properties // returned from LoadPropertiesForItems. } // Create a variable for all the deleted items in the ItemChangeCollection. var deleteItems = from ic in icc where ic.ChangeType == ChangeType.Delete select ic.ItemId; // Display the ItemIds to be deleted on the client. foreach (var item in deleteItems) { Console.WriteLine("Delete ItemId: {0}", item); Console.WriteLine("--------"); // TODO: Delete messages on the client by using the ItemIds in deleteItems. } // Create a variable for all the items with read state changes in the ItemChangeCollection. var readFlagChangeItems = from ic in icc where ic.ChangeType == ChangeType.ReadFlagChange select ic.ItemId; // Display the ItemIds that have read state changes. foreach (var item in readFlagChangeItems) { Console.WriteLine("Read flag change to ItemId: {0}", item); Console.WriteLine("--------"); // TODO: Change the read state of the item saved on the client // by using the ItemIds in readFlagChangeItems. } // Create a variable for all the updated items in the ItemChangeCollection. var updateItems = from ic in icc where ic.ChangeType == ChangeType.Update select ic.Item; // Display the subject for each updated item. foreach (var item in updateItems) { service.LoadPropertiesForItems(updateItems, PropertySet.FirstClassProperties); Console.WriteLine("Updated item, all properties loaded"); Console.WriteLine("Subject: {0}", item.Subject); Console.WriteLine("ParentFolderId: {0}", item.ParentFolderId); Console.WriteLine("DateTimeCreated: {0}", item.DateTimeCreated); Console.WriteLine("--------"); // TODO: Compare the properties retrieved from LoadPropertiesForItems to the // properties on the client and update the client properties accordingly. } }
// Synchronize the contents of the rootSyncFolder folder. static string SyncContents(ExchangeService service, string cSyncState, FolderId rootSyncFolder) { Console.WriteLine("--------"); Console.WriteLine("Starting content sync on the following folder"); Console.WriteLine("FolderId: {0}", rootSyncFolder); Console.WriteLine("--------"); bool moreChangesAvailable = false; do { // Get a change collection of all items in the rootSyncFolder by calling SyncFolderItems // repeatedly until no more changes are available. // The folderId parameter must be set to the same folder ID as the previous synchronization call. // The propertySet parameter is set to IdOnly to reduce calls to the Exchange database, // because any additional properties result in another call to the Exchange database. // The ignoredItemIds parameter is set to null, so no items are ignored. // The maxChangesReturned parameter is set to return a maximum of 500 items (512 is the default). // The syncScope parameter is set to Normal items, so associated items will not be returned. // The syncState parameter is set to the content sync state. When this method is called // on a new or empty mailbox, the value is null. If the method has been called before, // the cSyncState value contains the value previously returned by the server. ItemChangeCollection = service.SyncFolderItems(rootSyncFolder, PropertySet.IdOnly, null, 500, SyncFolderItemsScope.NormalItems, cSyncState); // Save the sync state for use in future SyncFolderItems requests. // The sync state is used by the server to determine what changes to report // to the client. cSyncState = ItemChangeCollection.SyncState; // If the count of changes is zero, there are no changes to synchronize. if (ItemChangeCollection.Count == 0) { Console.WriteLine("There are no items to synchronize."); Console.WriteLine("--------"); } // Otherwise, write all the changes included in the response // to the console. else { foreach (ItemChange ic in ItemChangeCollection) { Console.WriteLine("ItemChange.ChangeType: " + ic.ChangeType.ToString()); Console.WriteLine("ItemChange.ItemId: " + ic.ItemId.UniqueId); Console.WriteLine("--------"); } } // Determine whether more changes are available on the server. moreChangesAvailable = ItemChangeCollection.MoreChangesAvailable; // Send the ItemChangeCollection to ProcessItems to actually retrieve the messages and changes. ProcessItems(ItemChangeCollection); }while (moreChangesAvailable); Console.WriteLine("Finished content sync on the following folder"); Console.WriteLine("FolderId: {0}", rootSyncFolder); Console.WriteLine("--------"); return(cSyncState); }
private void btnSynchronize_Click(object sender, EventArgs e) { try { this.Cursor = Cursors.WaitCursor; bool keepGoing = true; int totalItems = 0; this.lstChanges.Items.Clear(); while (keepGoing) { ChangeCollection <ItemChange> changes = this.CurrentService.SyncFolderItems( this.CurrentFolderId, this.CurrentPropertySet, null, 500, SyncFolderItemsScope.NormalItems, this.txtSyncState.Text); keepGoing = changes.MoreChangesAvailable; foreach (ItemChange change in changes) { ListViewItem item = new ListViewItem(); item.Tag = change; item.Text = change.ChangeType.ToString(); item.SubItems.Add(change.IsRead.ToString()); item.SubItems.Add(change.ItemId.UniqueId); try { if (item.SubItems != null) { if (change.Item.Subject != null) { item.SubItems.Add(change.Item.Subject); } else { item.SubItems.Add(""); } if (change.Item.ItemClass != null) { item.SubItems.Add(change.Item.ItemClass); } else { item.SubItems.Add(""); } if (change.Item.LastModifiedTime != null) { item.SubItems.Add(change.Item.LastModifiedTime.ToString()); } else { item.SubItems.Add(""); } } else { item.SubItems.Add(""); item.SubItems.Add(""); item.SubItems.Add(""); } } catch (ServiceResponseException oExECF) { System.Diagnostics.Debug.WriteLine(oExECF.ToString()); // Catch a connection error. } catch (Exception oEx) { System.Diagnostics.Debug.WriteLine(oEx.ToString()); // Catch error in case no no-id propreties were not returned. } lstChanges.Items.Add(item); } this.txtSyncState.Text = changes.SyncState; totalItems = totalItems + changes.Count; } this.lblLastSyncTime.Text = string.Format(Application.CurrentCulture, "Last SyncFolderItems: {0}", DateTime.Now.ToString()); } catch (ServiceResponseException oExECF) { System.Diagnostics.Debug.WriteLine(oExECF.ToString()); // Catch a connection error. } catch (Exception oEx) { System.Diagnostics.Debug.WriteLine(oEx.ToString()); // Catch error in case no no-id propreties were not returned. } finally { this.Cursor = Cursors.Default; } }
/// <summary> /// Adds the specified <see cref="ChangeCollection"/> to <see cref="Updates"/>. /// </summary> /// <param name="update">The <c>Change</c> to add.</param> /// <exception cref="ArgumentNullException">update is null.</exception> /// <exception cref="InvalidOperationException"> /// update belongs to another <see cref="Element"/>. /// </exception> public void AddUpdate(ChangeCollection update) { this.AddChild(update); }
public static async Task RunAsync([QueueTrigger("processchanges", Connection = "AzureWebJobsStorage")] WebhookNotification notificationModel, ILogger log) { log.LogInformation($"ProcesResourceChange queue trigger function process Site:{notificationModel.SiteUrl} Resource{notificationModel.Resource} "); string tenant = System.Environment.GetEnvironmentVariable("Tenant", EnvironmentVariableTarget.Process); string siteUrl = $"https://{tenant}.sharepoint.com{notificationModel.SiteUrl}"; log.LogInformation("Getting Azure SharePoint Token"); LoginEntity loginDetails = await LoginUtil.CertificateLoginDetails(); OfficeDevPnP.Core.AuthenticationManager authManager = new OfficeDevPnP.Core.AuthenticationManager(); log.LogInformation("Connecting to SharePoint"); using (ClientContext clientContext = authManager.GetAzureADAppOnlyAuthenticatedContext(siteUrl, loginDetails.ClientId, loginDetails.Tenant, loginDetails.Certificate)) { log.LogInformation("Getting SharePoint List"); Guid listId = new Guid(notificationModel.Resource); List list = clientContext.Web.Lists.GetById(listId); // grab the changes to the provided list using the GetChanges method // on the list. Only request Item changes as that's what's supported via // the list web hooks ChangeQuery changeQuery = new ChangeQuery(false, false) { Item = true, Add = true, DeleteObject = false, Update = true, FetchLimit = 1000 }; ChangeToken lastChangeToken = null; if (null == notificationModel.ClientState) { throw new ApplicationException("Webhook doesn't contain a Client State"); } Guid id = new Guid(notificationModel.ClientState); log.LogInformation("Checking Database for Change Token"); AzureTableSPWebHook listWebHookRow = await AzureTable.GetListWebHookByID(id, listId); if (!string.IsNullOrEmpty(listWebHookRow.LastChangeToken)) { log.LogInformation("Change Token found"); lastChangeToken = new ChangeToken { StringValue = listWebHookRow.LastChangeToken }; } //Start pulling down the changes bool allChangesRead = false; do { if (lastChangeToken == null) { log.LogInformation("Change Token not found grabbing the last 5 days of changes"); //If none found, grab only the last 5 day changes. lastChangeToken = new ChangeToken { StringValue = string.Format("1;3;{0};{1};-1", notificationModel.Resource, DateTime.Now.AddDays(-5).ToUniversalTime().Ticks.ToString()) }; } //Assing the change token to the query..this determins from what point in time we'll receive changes changeQuery.ChangeTokenStart = lastChangeToken; ChangeCollection changes = list.GetChanges(changeQuery); clientContext.Load(list); clientContext.Load(changes); await clientContext.ExecuteQueryAsync(); if (changes.Count > 0) { log.LogInformation($"Found {changes.Count} changes"); foreach (Change change in changes) { lastChangeToken = change.ChangeToken; if (change is ChangeItem item) { log.LogInformation($"Change {change.ChangeType} on Item:{item.ItemId} on List:{list.Title} Site:{notificationModel.SiteUrl}"); } } if (changes.Count < changeQuery.FetchLimit) { allChangesRead = true; } } else { allChangesRead = true; } } while (allChangesRead == false); if (!listWebHookRow.LastChangeToken.Equals(lastChangeToken.StringValue, StringComparison.InvariantCultureIgnoreCase)) { listWebHookRow.LastChangeToken = lastChangeToken.StringValue; log.LogInformation("Updating change token"); await AzureTable.InsertOrReplaceListWebHook(listWebHookRow); } if (notificationModel.ExpirationDateTime.AddDays(-30) < DateTime.Now) { bool updateResult = list.UpdateWebhookSubscription(new Guid(notificationModel.SubscriptionId), DateTime.Now.AddMonths(2)); if (!updateResult) { log.LogError($"The expiration date of web hook {notificationModel.SubscriptionId} with endpoint 'https://{Environment.GetEnvironmentVariable("WEBSITE_HOSTNAME")}/SharePointWebHook' could not be updated"); } else { log.LogInformation($"The expiration date of web hook {notificationModel.SubscriptionId} with endpoint 'https://{Environment.GetEnvironmentVariable("WEBSITE_HOSTNAME")}/SharePointWebHook' successfully updated until {DateTime.Now.AddMonths(2).ToLongDateString()} "); } } } }
/// <summary> /// <h2>Hauptfunktion</h2> /// Hier werden die SyncStates der einzelnen Ordner verglichen und verarbeitet. /// Das alles wird umspannt von einer Stopuhr um im Log eine Ausgabe zu haben wie viel Zeit für jeden SyncRun gebraucht wird. /// <h3>LOCAL SYNC</h3> /// Zuerst wird der Kontakt Ordner im Postfach bearbeitet. /// Dazu wird der gespeicherte SyncStatus vom letzten Durchgang gelesen und mit dem aktuellen Status verglichen. /// In einer Schleife wird dann über jede erfasste änderung gegangen und in verschiedenen if Abfragen verarbeitet. /// Da die SyncStatus Abfrage nur 512 Änderungen zurückgibt, muss die Schleife so lange wiederholt werden bis es keine Änderungen mehr gibt. /// <ul> /// <li>Create : Kontakt wird wieder gelöscht</li> /// <li>Update : Werden aktuell ignoriert da der ChacheModus von Outlook auch immer wieder Änderungen vornimmt.</li> /// <li>Delete : Vom gelöschten Kontakt wird das public Pendant in der MatchingListe gesucht. Danach wird der Kontakt aus dem öffentlichen Ordner wieder kopiert.</li> /// </ul> /// <h3>PUBLIC SYNC</h3> /// Als Zweites wird der öffentliche Ordner bearbeitet. /// <i>siehe LOCAL SYNC</i> /// <ul> /// <li>Create : Kontakt wird in das Postfach kopiert.</li> /// <li>Update : Kontakt wird in der MatchingListe gesucht. Pendant im Postfach wird gelöscht und aus dem öffentlichen Ordner wieder kopiert.</li> /// <li>Delete : Kontakt wird in der MatchingListe gesucht. Pendant wird im Postfach gesucht und gelöscht. Es wird mit dem AppointmentSync der Jahrestag und Geburtstag aus dem Kalender gelöscht.</li> /// </ul> /// <h3>GET AND SET LOCAL SYNC</h3> /// Hier wird noch mal über die Änderungen im Postfach Ordner gegangen aber nichts bearbeitet. Nach der Schleife wird der neue SyncStatus für das Postfach geschrieben. /// Das muss im nach dem PUBLIC SYNC nochmal passieren das dur den PUBLIC SYNC änderungen am Postfach Ordner vorgenommen werden können. /// </summary> /// <returns>Gibt zurück ob min. eine Änderung gemacht worden ist</returns> public bool Sync() { var changeValue = false; if (service != null) { var PublicContactFolder = getPublicFolder(); writeLog("---------- SyncRun Start - " + ContactFolderName + " ----------"); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); #region LOCAL SYNC bool isEndOfChanges = false; var localSyncState = getSyncState(false, SMTPAdresse); // Ist null falls Initialer SyncRun var MailboxContactFolder = getMailboxFolder(localSyncState == null); //makeChangeKey(SMTPAdresse, MailboxContactFolder.Id, "Anfang"); // DEBUG do { ChangeCollection <ItemChange> icc_mailbox = service.SyncFolderItems(MailboxContactFolder.Id, PropertySet.FirstClassProperties, null, 512, SyncFolderItemsScope.NormalItems, localSyncState); if (icc_mailbox.Count != 0) { changeValue = true; var c = 0; var u = 0; var d = 0; //writeLog(SMTPAdresse + " - " + icc_mailbox.Count + " changes in own mailbox folder"); foreach (ItemChange ic_mailbox in icc_mailbox) { Console.WriteLine(ic_mailbox.ChangeType); try { //changeKeys += ic_mailbox.ChangeType + "_" + ic_mailbox.Item.Subject + "_" + ic_mailbox.ItemId.ChangeKey + System.Environment.NewLine; //DEBUG } catch (Exception) {} if (ic_mailbox.ChangeType == ChangeType.Create) { c++; try { Contact contacts = Contact.Bind(service, ic_mailbox.ItemId); //writeLog(contacts.Subject + " - Create"); contacts.Delete(DeleteMode.HardDelete); } catch (Exception ex) { writeLog("ERROR: LocalSync Create: " + ex.Message); } //Console.WriteLine(SMTPAdresse + " - LocalChange " + contacts.Subject + " was created locally and removed automatically"); } else if (ic_mailbox.ChangeType == ChangeType.Update) { u++; // Wird nicht benutzt da der ChacheModus von Outlook die ChangeKeys ändert und damit ca alle 30min ein InitialerSync stattfindet // Evtl eigenen Hash über Felder sobalt die Kontakte aus SAP kommen alternativ anderes Feld mit dem letzten Änderungsdatum. // Lokale Änderungen würden sowieso nicht zurück in den Öffentlichen Ordner geschrieben, sondern nur mit den Daten von dort ersetzt werden. // Damit werden lokale Änderungen (z.B Name, Tel ... ) vom Benutzer nicht mehr berücksichtigt, sondern nur noch Create und Delete. //try //{ // Contact contacts = Contact.Bind(service, ic_mailbox.ItemId); // //writeLog(contacts.Subject + " - Update"); // contacts.Delete(DeleteMode.HardDelete); // var MailboxId = ic_mailbox.ItemId.UniqueId; // List<Matching> matchingList = MatchingList.GetList(SMTPAdresse, ContactFolderName); // Matching result = matchingList.Find(x => x.MailboxId == MailboxId); // Contact PublicContacts = Contact.Bind(service, result.PublicId); // PublicContacts.Copy(MailboxContactFolder.Id); //} //catch (Exception ex) //{ // writeLog("ERROR: LocalSync Update: " + ex.Message); //} } else if (ic_mailbox.ChangeType == ChangeType.Delete) { d++; var MailboxId = ic_mailbox.ItemId.UniqueId; try { List <Matching> matchingList = MatchingList.GetList(SMTPAdresse, ContactFolderName); Matching result = matchingList.Find(x => x.MailboxId == MailboxId); if (result == null) { writeLog("ERROR: No match in MatchingList for: " + MailboxId); } else { Contact contacts = Contact.Bind(service, result.PublicId); //writeLog(contacts.Subject + " - Delete"); contacts.Copy(MailboxContactFolder.Id); } } catch (Exception ex) { writeLog("ERROR: LocalSync Delete: " + ex.Message); } } } writeLog(SMTPAdresse + " - " + icc_mailbox.Count + " changes (" + c + " created, " + u + " updated, " + d + " deleted) in own mailbox folder"); writeLog("LOCAL UPDATES ARE IGNORED!"); } localSyncState = icc_mailbox.SyncState; if (!icc_mailbox.MoreChangesAvailable) { isEndOfChanges = true; } } while (!isEndOfChanges); // DEBUG //Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; //File.WriteAllText(binaryPath + @"\changeKeys\ChangeKeys_" + ContactFolderName + SMTPAdresse + "_" + unixTimestamp, changeKeys); writeSyncState(localSyncState, false, SMTPAdresse); #endregion #region PUBLIC SYNC bool isEndOfChangesPublic = false; var sSyncState = getSyncState(true, SMTPAdresse); var index = 0; do { ChangeCollection <ItemChange> icc = service.SyncFolderItems(PublicContactFolder.Id, PropertySet.FirstClassProperties, null, 512, SyncFolderItemsScope.NormalItems, sSyncState); if (icc.Count == 0) { writeLog(SMTPAdresse + " - There are no item changes to synchronize."); } else { var c = 0; var u = 0; var d = 0; changeValue = true; //writeLog(SMTPAdresse + " - " + icc.Count + " changes in public folder"); foreach (ItemChange ic in icc) { if (ic.ChangeType == ChangeType.Create) { c++; try { Contact contacts = Contact.Bind(service, ic.ItemId); contacts.Copy(MailboxContactFolder.Id); } catch (Exception ex) { writeLog("ERROR: ExchangeSync.cs - 152: " + ic.Item.Subject + " - " + ex.Message); } } else if (ic.ChangeType == ChangeType.Update) { u++; try { List <Matching> matchingList = MatchingList.GetList(SMTPAdresse, ContactFolderName); Matching result = matchingList.Find(x => x.PublicId == ic.ItemId.UniqueId); Contact LocalContact = Contact.Bind(service, result.MailboxId); LocalContact.Delete(DeleteMode.HardDelete); Contact PublicContact = Contact.Bind(service, ic.ItemId); PublicContact.Copy(MailboxContactFolder.Id); } catch (Exception ex) { writeLog("ExchangeSync.cs - 265: " + ic.Item.Subject + " - " + ex.Message); } //Console.WriteLine(SMTPAdresse + " - " + index + " - PublicChange " + contacts.Subject + " was updated in public and updated in the mailbox"); } else if (ic.ChangeType == ChangeType.Delete) { d++; var PublicId = ic.ItemId.UniqueId; List <Matching> matchingList = MatchingList.GetList(SMTPAdresse, ContactFolderName); if (matchingList != null) { try { Matching result = matchingList.Find(x => x.PublicId == PublicId); // Löscht nur die Geburtstage und Jahrestage bei Arges Intern Kontakten if (ContactFolderName == "Arges Intern") { var BASync = new AppointmentSync(service, SMTPAdresse); BASync.deleteName(result.Subject); } Contact contacts = Contact.Bind(service, result.MailboxId); contacts.Delete(DeleteMode.HardDelete); } catch (Exception ex) { writeLog("ERROR: ExchangeSync.cs - 187: " + ex.Message); } } else { writeLog(SMTPAdresse + " - Mailbox MatchingListe konnte nicht geladen werden"); } //Contact contacts = Contact.Bind(service, ic.ItemId); //SearchFilter.IsEqualTo filter2 = new SearchFilter.IsEqualTo(ItemSchema.Subject, contacts.Subject); //FindItemsResults<Item> findResults = service.FindItems(MailboxContactFolder.Id, filter2, new ItemView(1)); //foreach (Contact item in findResults.Items) //{ // item.Delete(DeleteMode.HardDelete); //} } //var OutputText = index + " - " + ic.ChangeType.ToString() + " - "; //if (ic.Item != null) { OutputText += ic.Item.Subject; } //Console.WriteLine(OutputText); if (index % 50 == 0) { Console.WriteLine("SyncIndex: " + index); } index++; } writeLog(SMTPAdresse + " - " + icc.Count + " changes (" + c + " created, " + u + " updated, " + d + " deleted) in public folder"); } sSyncState = icc.SyncState; if (!icc.MoreChangesAvailable) { isEndOfChangesPublic = true; } } while (!isEndOfChangesPublic); writeSyncState(sSyncState, true, SMTPAdresse); #endregion #region GET AND SET LOCAL SYNC bool isEndOfChangesLocal = false; var sSyncStateLocal = getSyncState(false, SMTPAdresse); do { ChangeCollection <ItemChange> icc_mailbox2 = service.SyncFolderItems(MailboxContactFolder.Id, PropertySet.FirstClassProperties, null, 512, SyncFolderItemsScope.NormalItems, sSyncStateLocal); sSyncStateLocal = icc_mailbox2.SyncState; if (!icc_mailbox2.MoreChangesAvailable) { isEndOfChangesLocal = true; } } while (!isEndOfChangesLocal); writeSyncState(sSyncStateLocal, false, SMTPAdresse); //writeSyncState(localSyncState, false, SMTPAdresse); #endregion //makeChangeKey(SMTPAdresse, MailboxContactFolder.Id, "Ende"); // DEBUG stopWatch.Stop(); writeLog("---------- SyncRun End - " + stopWatch.Elapsed + " ----------"); } return(changeValue); }