Monday, March 26, 2018

Integration of Exchange using EWS-Managed API


/*Only for reference    NOT A WORKING SAMPLE*/


using Microsoft.Exchange.WebServices.Data;

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static Microsoft.Exchange.WebServices.Data.SearchFilter;

namespace  exchangeConsole
{
    class Program

    {

        private static string ContentsSyncState;
        private static string FolderSyncState;

        private static ChangeCollection<ItemChange> ItemChangeCollection;
        private static ChangeCollection<FolderChange> FolderChangeCollection;
        private static AutoResetEvent Signal;
        private static StreamingSubscription StreamingSubscription;
        private static PullSubscription PullSubscription;
        private static string PullSubscriptionId;
        private static string WaterMark;
        static bool FirstPull = false;
        private static int WaitTime = 3;

        static ExchangeService service = EService.ConnectToService(UserDataFromConsole.GetUserData(true));

        // Set the root folder to sync. This must be one of the WellKnownFolderName values.
        private static FolderId RootSyncFolder = WellKnownFolderName.Calendar;
        static DbContext dbContext = new demoentitees();



        static void Main(string[] args)
        {


            var syncStates = dbContext.Set<SyncState>();

            if (syncStates.Count() != 0 && syncStates.Where(x => x.IsFolder == true && x.CreatedBy != "testxxx") != null && syncStates.Where(x => x.IsFolder == true && x.CreatedBy != "testxxx").Count() > 0)
            {
             
                FolderSyncState = syncStates.Where(x => x.IsFolder == true && x.CreatedBy != "testxxx").OrderByDescending(x => x.Id).FirstOrDefault().SyncString;
                ContentsSyncState = syncStates.Where(x => x.IsFolder == false && x.CreatedBy != "testxxx").OrderByDescending(x => x.Id).FirstOrDefault().SyncString;
            }

            else
            {
                FirstPull = true;
                FolderSyncState = null;
                ContentsSyncState = null;
            }



         

            // Retrieve the initial folder hierarchy, using rootSyncFolder as the root folder.
            FolderSyncState = SyncFolders(service, FolderSyncState, RootSyncFolder);

            //  Retrieve the initial contents of the rootSyncFolder.
            ContentsSyncState = SyncContents(service, ContentsSyncState, RootSyncFolder);



            // After the initial sync, wait for notifications of new or changed items.
            // StreamingSubscription = SetStreamingNotifications(service, ContentsSyncState, RootSyncFolder);
            //Restart:
            //do
            //{
            //    SetPullNotifications(service, WaterMark, RootSyncFolder);
            //} while (PullSubscription.MoreEventsAvailable.HasValue && !PullSubscription.MoreEventsAvailable.HasValue);

            //Signal = new AutoResetEvent(false);
            //PullSubscription.Unsubscribe();
            // Wait for the application to exit.
            // Signal.WaitOne();

            //Console.WriteLine("Enter 'y' or 'N' ");

            //string key = Console.ReadLine();
            //if (key == "y"|| key=="Y")
            //    goto Restart;

            Console.Read();

        }


        // 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("--------");


                        using (var ctx = new demoEntities())
                        {
                            var std = new SyncState()
                            {
                                 //save
                            };
                            ctx.SyncStates.Add(std);
                            ctx.SaveChanges();


                        }

                    }
                }

                // 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;
        }

        static string ItemIdSearch(string Id, string subject, DateTime sent)
        {
            ItemView view = new ItemView(1000);

            //List<SearchFilter> searchANDFilterCollection = new List<SearchFilter>();
       
            //////searchANDFilterCollection.Add(new SearchFilter.IsEqualTo(EmailMessageSchema., ".Note.Exchange"));
            ////searchANDFilterCollection.Add(new SearchFilter.ContainsSubstring(EmailMessageSchema.Subject, subject));
            ////searchANDFilterCollection.Add(new SearchFilter.IsEqualTo(AppointmentSchema.MeetingRequestWasSent,true));

            ////searchANDFilterCollection.Add(new SearchFilter.IsGreaterThanOrEqualTo(EmailMessageSchema.DateTimeSent, sent));
            ////searchANDFilterCollection.Add(new SearchFilter.IsLessThanOrEqualTo(EmailMessageSchema.DateTimeSent, sent.AddHours(24)));

            string id = string.Empty;

         //   SearchFilter searchANDFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, searchANDFilterCollection.ToArray());


            var results = service.FindItems(WellKnownFolderName.Calendar, view);
            foreach (var item in results)
            {
                var synstatesid = dbContext.Set<SyncState>().ToList().Where(x => x.SyncString == ContentsSyncState && x.Id == item.Id.UniqueId && x.IsFolder == false)
                    .OrderByDescending(x => x.Id).FirstOrDefault();
                if (synstatesid != null)

                    id = synstatesid.EWSId;
            }

            return id;
        }

        private CalendarFolder FindNamedCalendarFolder(string name)
        {
            FolderView view = new FolderView(100);
            view.PropertySet = new PropertySet(BasePropertySet.IdOnly);
            view.PropertySet.Add(FolderSchema.DisplayName);
            view.Traversal = FolderTraversal.Deep;

            SearchFilter sfSearchFilter = new SearchFilter.IsEqualTo(FolderSchema.FolderClass, "1ppointment");

            FindFoldersResults findFolderResults = service.FindFolders(WellKnownFolderName.Root, sfSearchFilter, view);
            return findFolderResults.Where(f => f.DisplayName == name).Cast<CalendarFolder>().FirstOrDefault();
        }


        static void ESave(string ItemId, string type = "email")
        {


            if (type == "email")
            {
                var msg = Item.Bind(service, ItemId);
                using (var ctx = new EWS_DemoEntities())
                {

                    var std = new EmailMessasge()
                    {
                        ///asave
                    };
                    ctx.EmailMessasges.Add(std);
                    ctx.SaveChanges();

                }
            }
            else
            {
                Appointment met = Appointment.Bind(service, ItemId);
                using (var ctx = new demoEntities())
                {

                    var std = new Meeting()
                    {
//                        save

                    };
                    ctx.Meetings.Add(std);
                    ctx.SaveChanges();

                }

            }



        }

        // 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.

                string fid = ItemIdSearch(item.Id.UniqueId, "test", new DateTime(2018, 03, 14));
                if (!string.IsNullOrEmpty(fid))
                {
                     Save(fid);
                }

            }

            // 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.
                string fid = ItemIdSearch(item.UniqueId, "ouu", new DateTime(2018, 03, 14));
                if (!string.IsNullOrEmpty(fid))
                {

                     save(fid);
                }
            }

            // 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.

                string fid = ItemIdSearch(item.Id.UniqueId, "ouu", new DateTime(2018, 03, 14));
                if (!string.IsNullOrEmpty(fid))
                {
                     save(fid);
                }
            }
        }

        // 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.
            }
        }

        // When the subscription connection expires, determine whether the subscription should be kept open.
        static private void OnDisconnect(object sender, SubscriptionErrorEventArgs args)
        {
            // Cast the sender as a StreamingSubscriptionConnection object.         
            StreamingSubscriptionConnection connection = (StreamingSubscriptionConnection)sender;

            // Ask the user if they want to reconnect or close the subscription.
            ConsoleKeyInfo cki;
            Console.WriteLine("The StreamingSubscriptionConnection has expired.");
            Console.WriteLine("\r\n");
            Console.WriteLine("Do you want to reconnect to the subscription? Enter Y or N");
            Console.WriteLine("\r\n");
            while (true)
            {
                cki = Console.ReadKey(true);
                {
                    if (cki.Key == ConsoleKey.Y)
                    {
                        connection.Open();
                        Console.WriteLine("Connection open.");
                        Console.WriteLine("\r\n");
                        break;
                    }
                    else if (cki.Key == ConsoleKey.N)
                    {
                        Signal.Set();

                        // Unsubscribe from the notification subscription.
                        StreamingSubscription.Unsubscribe();

                        // Close the connection.
                        connection.Close();
                        break;
                    }
                }
            }
        }

        // Catch and display notification events.
        static void OnNotificationEvent(object sender, NotificationEventArgs args)
        {
            bool callSyncContents = false;
            bool callSyncFolders = false;

            StreamingSubscription subscription = args.Subscription;

            // Loop through all item-related events.
            foreach (NotificationEvent notification in args.Events)
            {

                switch (notification.EventType)
                {
                    case EventType.NewMail:
                        Console.WriteLine("Notification: New mail created");
                        break;
                    case EventType.Created:
                        Console.WriteLine("Notification: Item or folder created");
                        break;
                    case EventType.Deleted:
                        Console.WriteLine("Notification: Item or folder deleted");
                        break;
                    case EventType.Modified:
                        Console.WriteLine("Notification: Item or folder modified");
                        break;
                    case EventType.Moved:
                        Console.WriteLine("Notification: Item or folder moved");
                        break;
                    case EventType.Copied:
                        Console.WriteLine("Notification: Item or folder copied");
                        break;
                }
                // Display the notification identifier.
                if (notification is ItemEvent)
                {
                    ItemEvent itemEvent = (ItemEvent)notification;
                    Console.WriteLine("Notification ItemId: " + itemEvent.ItemId.UniqueId);
                    Console.WriteLine("--------");
                    callSyncContents = true;
                }
                else
                {
                    FolderEvent folderEvent = (FolderEvent)notification;
                    Console.WriteLine("Notification FolderId: " + folderEvent.FolderId.UniqueId);
                    Console.WriteLine("--------");
                    callSyncFolders = true;
                }
            }

            // Delay calling SyncContents and SyncFolders until all notifications have been processed.
            // This will reduce the number of calls to the Exchange database by batching more changes
            // into a single sync call.
            if (callSyncContents == true)
            {
                ContentsSyncState = SyncContents(service, ContentsSyncState, RootSyncFolder);
            }

            if (callSyncFolders == true)
            {
                FolderSyncState = SyncFolders(service, FolderSyncState, RootSyncFolder);
            }
        }


        // 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("--------");


                    using (var ctx = new DemoEntities())
                    {
                        var std = new SyncState()
                        {
                            //save
                        };
                        ctx.SyncStates.Add(std);
                        ctx.SaveChanges();

                    }
                }

            }

            // 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;

        }

        //Subscribe to streaming notifications for all folder and item events in the root folder.
        static StreamingSubscription SetStreamingNotifications(ExchangeService service, string cSyncState, FolderId rootSyncFolder)
        {
            // Subscribe to streaming notifications on the rootSyncFolder and listen
            // for events.
            StreamingSubscription = service.SubscribeToStreamingNotifications(
                new FolderId[] { rootSyncFolder },
                EventType.NewMail,
                EventType.Created,
                EventType.Deleted,
                EventType.Modified,
                EventType.Moved,
                EventType.Copied
                );

            StreamingSubscriptionConnection connection = new StreamingSubscriptionConnection(service, WaitTime);
            connection.AddSubscription(StreamingSubscription);
            connection.OnNotificationEvent += OnNotificationEvent;
            connection.OnDisconnect += OnDisconnect;
            connection.Open();

            Console.WriteLine("Now waiting for notifications on the following folder");
            Console.WriteLine("FolderId: {0}", rootSyncFolder);
            Console.WriteLine("--------");

            return StreamingSubscription;

        }

        //Subscribe to streaming notifications for all folder and item events in the root folder.
        static PullSubscription SetPullNotifications(ExchangeService service, string watermark, FolderId rootSyncFolder)
        {


            // Subscribe to streaming notifications on the rootSyncFolder and listen
            // for events.
            PullAgain:
            PullSubscription = service.SubscribeToPullNotifications(
                new FolderId[] { rootSyncFolder }, WaitTime, watermark,
                EventType.NewMail,
                EventType.Created,
                EventType.Deleted,
                EventType.Modified,
                EventType.Moved,
                EventType.Copied
                );
            var events = PullSubscription.GetEvents();

            PullSubscriptionId = PullSubscription.Id;
            if (WaterMark != PullSubscription.Watermark)
            {
                WaterMark = PullSubscription.Watermark;
                goto PullAgain;

            }






            if (events.ItemEvents.Count() > 0)
            {
                // Handle the results of the GetEvents method.
                foreach (ItemEvent itemEvent in events.ItemEvents)
                {

                    switch (itemEvent.EventType)
                    {
                        case EventType.NewMail:
                            EmailMessage message = EmailMessage.Bind(service, itemEvent.ItemId);
                            message.Load();
                            Console.WriteLine("Item new mail: " + message.Subject);
                            //Console.WriteLine("Item Id:" + message.Id);
                            break;
                        case EventType.Created:
                            Item item = Item.Bind(service, itemEvent.ItemId);
                            item.Load();
                            Console.WriteLine("Item Created: " + item.Subject);
                            // Console.WriteLine("Item Id:" + item.Id);
                            break;
                        case EventType.Deleted:
                            Item d = Item.Bind(service, itemEvent.ItemId);
                            d.Load();
                            Console.WriteLine("Item deleted: " + d.Subject);
                            break;

                        case EventType.Moved:
                            Item d1 = Item.Bind(service, itemEvent.ItemId);
                            d1.Load();
                            Console.WriteLine("Item deleted: " + d1.Subject);
                            break;
                        case EventType.Modified:
                            Item tem = Item.Bind(service, itemEvent.ItemId);
                            tem.Load();
                            Console.WriteLine("Item Modified: " + tem.Subject);
                            // Console.WriteLine("Item Id:" + tem.Id);
                            break;
                    }
                }

            }
            else
            {

                Console.WriteLine("No Events");
            }
            NoEvents:
            Console.WriteLine("Now waiting for pull notifications on the following folder");
            Console.WriteLine("FolderId: {0}", rootSyncFolder);
            Console.WriteLine("--------");


            return PullSubscription;

        }




        // Catch and display errors.
        static void OnError(object sender, SubscriptionErrorEventArgs args)
        {
            // Handle error conditions.
            Exception e = args.Exception;
            Console.WriteLine("\n-------------Error ---" + e.Message + "-------------");
        }

    }
}