/// <summary> /// Creates items to O365 /// </summary> /// <param name="syncWork">List of sync jobs to identify the items to create</param> /// <param name="o365_graphcontainer">The Office365 container of the items to create (e.g. calendar or contactfolder)</param> /// <param name="Type">Type of the items to be processed (e.g. events or contacts)</param> /// <returns>Returns count of jobs run.</returns> /// public static int CreateItems(List <SyncHelpers.SyncInfo> syncWork, IEnumerable <SyncElement> srcItems, Office365.IGraphContainer o365_graphcontainer, SyncHelpers.ID_type Type) { List <Task> createTasks = new List <Task>(); syncWork.Where(x => ((x.SyncWorkMethod == SyncHelpers.SyncMethod.CREATE) && (x.Type == Type))).ToList().ForEach( (item) => { createTasks.Add(o365_graphcontainer.AddAsync(srcItems.ToList().Find(x => (x.OriginId == item.OutlookID))) .ContinueWith((i) => { if (i.Result != null) { SyncHelpers.O365_Item_Added(i.Result, item); } })); }); Task.WaitAll(createTasks.ToArray()); return(createTasks.Count); }
/// <summary> /// Removes items from O365 /// </summary> /// <param name="syncWork">List of sync job to identify the items to remove.</param> /// <param name="o365_graphcontainer">The Office365 container of the items to delete (e.g. calendar or contactfolder)</param> /// <param name="Type">Type of the items to be processed (e.g. events or contacts)</param> /// <returns>Returns count of jobs run.</returns> /// public static int RemoveItems(List <SyncHelpers.SyncInfo> syncWork, Office365.IGraphContainer o365_graphcontainer, SyncHelpers.ID_type Type) { List <Task> deleteTasks = new List <Task>(); syncWork.Where(x => ((x.SyncWorkMethod == SyncHelpers.SyncMethod.DELETE) && (x.Type == Type))).ToList().ForEach( (item) => { deleteTasks.Add(o365_graphcontainer.RemoveAsync(item.O365ID) .ContinueWith((i) => { if (i != null) { SyncHelpers.O365_Item_Removed(item); } })); }); Task.WaitAll(deleteTasks.ToArray()); return(deleteTasks.Count); }
/// <summary> /// Analyse all known items and systems and prepare all required information. /// </summary> /// <param name="clrNotExisting">If TRUE all items which were identified in O365 but not exist in Outlook will be removed as well</param> /// <param name="syncWork">The queue for sync jobs.</param> /// <param name="srcItems">All items of the source system (Outlook)</param> /// <param name="destItems">All items of the destination system (Office 365)</param> /// <param name="Type">Type of the items to be processed (e.g. events or contacts)</param> /// public static void AnalyseSyncJobs(bool clrNotExisting, List <SyncHelpers.SyncInfo> syncWork, IEnumerable <SyncElement> srcItems, IEnumerable <SyncElement> destItems, SyncHelpers.ID_type Type) { //get all events which are stored in the sync cache List <SyncHelpers.SyncInfo> syncCache_filtered = SyncHelpers.syncCache.Where(x => x.Type == Type).ToList(); //define NEW, MODIFIED and DELETED events of the local Outlook List <string> tmpNewOutlookIds = SyncHelpers.GetIDsOfNewItems(srcItems, syncCache_filtered, OriginSystemEnum.Outlook); //all Outlook-ids which are NOT contained in sync cache => all NEW outlook ids List <string> tmpModifiedOutlookIds = SyncHelpers.GetIDsOfModifiedItems(srcItems, syncCache_filtered, OriginSystemEnum.Outlook); //all Outlook-ids which were modified AFTER the last sync List <string> tmpDeletedOutlookIds = SyncHelpers.GetIDsOfDeletedItems(srcItems, syncCache_filtered, OriginSystemEnum.Outlook); //all Outlook-ids which are synced but does not exist anymore => all DELETED outlook ids //define NEW, MODIFIED and DELETED events of Office 365 List <string> tmpNewO365Ids = SyncHelpers.GetIDsOfNewItems(destItems, syncCache_filtered, OriginSystemEnum.Office365); //all O365-ids which are NOT contained in sync cache => all NEW O365 ids List <string> tmpModifiedO365Ids = SyncHelpers.GetIDsOfModifiedItems(destItems, syncCache_filtered, OriginSystemEnum.Office365); //all O365-ids which were modified AFTER the last sync List <string> tmpDeletedO365Ids = SyncHelpers.GetIDsOfDeletedItems(destItems, syncCache_filtered, OriginSystemEnum.Office365); //all ids of sync cache which does NOT exist in O365 anymore => all DELETED o365 ids syncWork.AddRange(SyncHelpers.CollectOutlookSyncTasks( syncCache: syncCache_filtered, NewOutlookIds: tmpNewOutlookIds, ModifiedOutlookIds: tmpModifiedOutlookIds, DeletedOutlookIds: tmpDeletedOutlookIds, NewO365Ids: tmpNewO365Ids, ModifiedO365Ids: tmpModifiedO365Ids, DeletedO365Ids: tmpDeletedO365Ids, Type: Type, clrNotExisting: clrNotExisting )); }
static void Main(string[] args) { const string appId = "cb2c2f84-63f0-49d8-9335-79fcc6050654"; List <string> AppPermissions = new List <string> { "User.Read", "Calendars.ReadWrite", "Contacts.ReadWrite" }; DateTime from = DateTime.Now.AddMonths(-1); from = from.AddHours(-from.Hour).AddMinutes(-from.Minute).AddSeconds(-from.Second).AddMilliseconds(-from.Millisecond); DateTime to = from.AddMonths(2).AddHours(23).AddMinutes(59).AddSeconds(59).AddMilliseconds(999); int clearpast = 0; string calendar_source_Name = ""; string calendar_destination_Name = ""; string contacts_source_Name = ""; string contacts_destination_Name = ""; string proxy = ""; bool clrNotExisting = true; //clear every items of target which does not exist on source side bool exitLocalOutlookAfterProcessing = true; //if the app has opened a local Outlook instance exit it at the end bool SyncCAL() { return((calendar_source_Name != "") && (calendar_destination_Name != "")); } bool SyncCON() { return((contacts_source_Name != "") && (contacts_destination_Name != "")); } try { //iterate through all parameters foreach (string arg in args) { string parameter = arg.Trim().Split(':')[0].ToUpper(); string parValue = arg.Trim().Substring(parameter.Length, arg.Trim().Length - parameter.Length).TrimStart(':'); switch (parameter) { case "/CAL": if (parValue[0] == '"') { calendar_source_Name = parValue.Split(';')[0].Trim('"'); calendar_destination_Name = parValue.Split(';')[1].Trim('"'); //if no dest folder was set use the default one if (calendar_destination_Name == "") { calendar_destination_Name = null; } } else { calendar_source_Name = parValue.Split(';')[0].Trim('\''); calendar_destination_Name = parValue.Split(';')[1].Trim('\''); //if no dest folder was set use the default one if (calendar_destination_Name == "") { calendar_destination_Name = null; } } break; case "/CON": if (parValue[0] == '"') { contacts_source_Name = parValue.Split(';')[0].Trim('"'); contacts_destination_Name = parValue.Split(';')[1].Trim('"'); //if no dest folder was set use the default one if (contacts_destination_Name == "") { contacts_destination_Name = null; } } else { contacts_source_Name = parValue.Split(';')[0].Trim('\''); contacts_destination_Name = parValue.Split(';')[1].Trim('\''); //if no dest folder was set use the default one if (contacts_destination_Name == "") { contacts_destination_Name = null; } } break; case "/FROM": if (!DateTime.TryParse(parValue, out from)) { from = DateTime.Today.AddDays(int.Parse(parValue)); } break; case "/TO": if (!DateTime.TryParse(parValue, out to)) { to = DateTime.Today.AddDays(int.Parse(parValue)); } break; case "/CLEAR": clearpast = Math.Abs(int.Parse(parValue)); break; case "/CLR": clearpast = Math.Abs(int.Parse(parValue)); break; case "/PROXY": proxy = parValue; break; case "/DNE": exitLocalOutlookAfterProcessing = false; break; case "/LOG": logOutput = true; if (parValue != "") { logFile = parValue; } break; } } //check if mandatory parameters were set stop execution if (SyncCAL() && (calendar_source_Name.Equals("") || !calendar_source_Name.Contains("\\"))) { throw new Exception("Source calendar path not valid."); } //check if mandatory parameters were set stop execution if (SyncCON() && (contacts_source_Name.Equals("") || !contacts_source_Name.Contains("\\"))) { throw new Exception("Source contact folder path not valid."); } //check if from-date is lower than to-date if (from >= to) { throw new Exception("FROM-date (" + from.ToShortDateString() + ") must be lower than TO-date (" + to.ToShortDateString() + ")."); } //if any sync is set if (!SyncCAL() && !SyncCON()) { throw new Exception("At least one sync config must be set."); } } catch (Exception e) { LogLn("Error: " + e.Message + "\r\n", true); LogLn("Parameters:\r\n" + "/CON:\"<source>\";\"<destination>\" : Contacts source and destination\r\n" + "/CAL:\"<source>\";\"<destination>\" : Calendar source and destination\r\n" + "[opt] /from:<date> : for calendar: First date to sync (DD.MM.YYYY) or relative to today (in days; eg. -10)\r\n" + "[opt] /to:<date> : for calendar: Last date to sync (DD.MM.YYYY) or relative to today (in days; eg. 8)\r\n" + "[opt] /clear:<days> : for calendar: Clear <days> in the past (from 'from' back)\r\n" + "[opt] /proxy:<address> : set if an explicit proxy should be used for connection\r\n" + "[opt] /DNE : if the process has started a local Outlook instance suppress the exit\r\n" + "[opt] /log : Verbose logging\r\n\r\n" + "Example: CopyO2O /CAL:\"[email protected]\\Calendar\";\"Business\" /from:-7 /to:30 /clear:14", true); System.Environment.Exit(-1); } LogLn("Start copy...", true); //load the sync cache SyncHelpers.LoadSyncCache(); List <SyncHelpers.SyncInfo> syncWork = new List <SyncHelpers.SyncInfo>(); //set proxy if set if (proxy != "") { System.Net.WebRequest.DefaultWebProxy = new System.Net.WebProxy(proxy, true); } Outlook.Application outlookApp = null; Office365.Graph office365 = null; try { Log("Open Outlook..."); outlookApp = new Outlook.Application(exitLocalOutlookAfterProcessing); LogLn(" Done.", false, true); Log("Connect to Office365..."); office365 = new Office365.Graph(appId, AppPermissions); LogLn(" Done.", false, true); //if calendar values should be synced if (SyncCAL()) { LogLn("Calendar: '" + calendar_source_Name + "' >> '" + (calendar_destination_Name ?? "DEFAULT") + "'" + " from " + from.ToShortDateString() + " to " + to.ToShortDateString(), true); Log("... ", true); LogLn("", false, true); Log("Get all events of Outlook..."); Outlook.Calendar src_calendar = outlookApp.GetCalendar(calendar_source_Name); Events srcEvents = src_calendar.GetItems(from, to); LogLn(" Done. " + srcEvents.Count.ToString() + " found.", false, true); Log("Get all events of O365..."); Office365.Calendar o365_dest_calendar = office365.Calendars[calendar_destination_Name ?? "Calendar"]; //Calendar is the default calendar folder Events destEvents = o365_dest_calendar.GetItemsAsync(from, to).Result; LogLn(" Done. " + destEvents.Count.ToString() + " found.", false, true); LogLn("Analyse sync tasks (NEW, MOD, DEL) ..."); SyncHelpers.AnalyseSyncJobs(clrNotExisting, syncWork, srcEvents, destEvents, SyncHelpers.ID_type.CalItem); LogLn(" Done."); LogLn("Create events in O365..."); int countOfcreateTasks = SyncHelpers.CreateItems(syncWork, srcEvents, o365_dest_calendar, SyncHelpers.ID_type.CalItem); LogLn(" Done. (" + countOfcreateTasks + ")"); LogLn("Delete events in O365..."); int countOfdeleteTasks = SyncHelpers.RemoveItems(syncWork, o365_dest_calendar, SyncHelpers.ID_type.CalItem); LogLn(" Done. (" + countOfdeleteTasks + ")"); //exec only if verbose logging enabled if (logOutput) { Log("Validate count of events in O365..."); LogLn(" Done. " + o365_dest_calendar.GetItemsAsync(from.AddDays(-clearpast), to).Result.Count.ToString() + " found.", false, true); } Log(""); LogLn(" Done (" + srcEvents.Count.ToString() + "/" + (destEvents.Count + countOfcreateTasks - countOfdeleteTasks).ToString() + ")", true, true); } //if contacts should be synced if (SyncCON()) { LogLn("Contacts: '" + contacts_source_Name + "' >> '" + (contacts_destination_Name ?? "DEFAULT") + "'", true); Log("... ", true); LogLn("", false, true); Log("Get all contacts of Outlook..."); Outlook.ContactFolder src_contactfolder = outlookApp.GetContactFolder(contacts_source_Name); ContactCollectionType srcContacts = src_contactfolder.GetItems(); LogLn(" Done. " + srcContacts.Count.ToString() + " found.", false, true); Log("Get all contacts of O365..."); Office365.ContactFolder o365_dest_contactfolder = office365.ContactFolders[contacts_destination_Name]; ContactCollectionType destContacts = o365_dest_contactfolder.GetContactsAsync().Result; LogLn(" Done. " + destContacts.Count.ToString() + " found.", false, true); LogLn("Analyse sync tasks (NEW, MOD, DEL) ..."); SyncHelpers.AnalyseSyncJobs(clrNotExisting, syncWork, srcContacts, destContacts, SyncHelpers.ID_type.Contact); LogLn(" Done."); LogLn("Create contacts in O365..."); int countOfcreateTasks = SyncHelpers.CreateItems(syncWork, srcContacts, o365_dest_contactfolder, SyncHelpers.ID_type.Contact); LogLn(" Done. (" + countOfcreateTasks + ")"); LogLn("Delete contacts in O365..."); int countOfdeleteTasks = SyncHelpers.RemoveItems(syncWork, o365_dest_contactfolder, SyncHelpers.ID_type.Contact); LogLn(" Done. (" + countOfdeleteTasks + ")"); //exec only if verbose logging enabled if (logOutput) { Log("Validate count of contacts in O365..."); LogLn(" Done. " + o365_dest_contactfolder.GetContactsAsync().Result.Count.ToString() + " found.", false, true); } Log(""); LogLn(" Done (" + srcContacts.Count.ToString() + "/" + (destContacts.Count + countOfcreateTasks - countOfdeleteTasks).ToString() + ")", true, true); } } catch (AggregateException ae) { ae.Handle((e) => { LogLn(" Error occured: " + e.Message, true); return(true); }); } catch (System.Net.WebException e) { LogLn(" Error occured: " + e.Message + "\r\nConnection could not be establised! Proxy?", true); } catch (Exception e) { if (e.InnerException != null) { LogLn(" Error occured: " + e.InnerException.Message, true); } else { LogLn(" Error occured: " + e.Message, true); } } finally { //if outlook is still open if (outlookApp != null) { Log("Close Outlook..."); outlookApp.Quit(); LogLn(" Done.", false, true); } //if a connection to office365 is still established if (office365 != null) { Log("Disconnect Office365..."); //office365.Flush(); //finalize all open commands //office365.Disconnect(); //close connection office365 = null; LogLn(" Done.", false, true); } //store the sync cache to disk SyncHelpers.StoreSyncCache(); } LogLn(syncWork.Count.ToString() + " operations processed.", true); #if DEBUG Console.ReadLine(); #endif }