private void deleteAllSyncItems() { DateTime syncStarted = DateTime.Now; OutlookCalendar ocal = null; try { logboxout("Sync started at " + syncStarted.ToString()); logboxout("--------------------------------------------------"); ocal = new OutlookCalendar(); logboxout("Reading Google Calendar Entries..."); GoogleCalendar gcal = new GoogleCalendar(); List <Event> GoogleEntries = gcal.getCalendarEntriesInRange(syncStarted); List <Event> GoogleEntriesToDelete = new List <Event>(); foreach (Event ev in GoogleEntries) { if (!string.IsNullOrEmpty(ev.Description) && ev.Description.Contains("Added by OutlookGoogleSync (" + ocal.AccountName + "):")) { GoogleEntriesToDelete.Add(ev); } } logboxout("Deleting " + GoogleEntriesToDelete.Count + " Google Calendar Sync Entries..."); foreach (Event ev in GoogleEntriesToDelete) { if (!string.IsNullOrEmpty(ev.Description) && ev.Description.Contains("Added by OutlookGoogleSync (" + ocal.AccountName + "):")) { gcal.deleteCalendarEntry(ev); } } logboxout("Done."); logboxout("--------------------------------------------------"); DateTime syncFinished = DateTime.Now; TimeSpan elapsed = syncFinished - syncStarted; logboxout("Sync finished at " + syncFinished.ToString()); logboxout("Time needed: " + elapsed.Minutes + " min " + elapsed.Seconds + " s"); } catch (System.Exception ex) { logboxout("Error Syncing:\r\n" + ex.ToString()); } freeCOMResources(ocal, null); }
private IOfficeCalendar CreateOfficeCalendar() { IOfficeCalendar calendar; if (Settings.Instance.UseExchange) { calendar = new EwsCalendar(); } else { calendar = new OutlookCalendar(); } return(calendar); }
private void freeCOMResources(OutlookCalendar oc, AppointmentItemCache appointmentItemCache) { try { appointmentItemCache?.ClearAndReleaseAll(); if (oc != null && oc.UseOutlookCalendar != null) { Marshal.FinalReleaseComObject(oc.UseOutlookCalendar); } GC.Collect(); GC.WaitForPendingFinalizers(); } catch (System.Exception ex) { logboxout("Warning: Error freeing COM resources:\r\n" + ex.ToString()); } }
public void Release( ) { // quit the application ((_Application)OutlookApplication).Quit(); // release the instance OutlookApplication = null; OutlookNamespace = null; OutlookFolder = null; instance = null; // http://msdn.microsoft.com/en-us/library/aa679807%28office.11%29.aspx#officeinteroperabilitych2_part2_gc GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.WaitForPendingFinalizers(); // another good reference: // http://blogs.msdn.com/b/mstehle/archive/2007/12/07/oom-net-part-2-outlook-item-leaks.aspx }
// binds the two events together public static void BindEvents(AppointmentItem oitem, Event gitem, string event_property_key) { // make sure to tag the user property of the google id UserProperty oitem_google_prop = oitem.UserProperties.Find(event_property_key); if (oitem_google_prop != null) { oitem_google_prop.Value = gitem.Id; System.Runtime.InteropServices.Marshal.ReleaseComObject(oitem_google_prop); } else { oitem.UserProperties.Add(event_property_key, OlUserPropertyType.olText).Value = gitem.Id; } try { // save the outlook event oitem.Save(); } catch (System.Exception) { // unable to save the outlook item... // should report an error, but this will get handled by the main form... } // make sure to tag the private property of the outlook id if (gitem.ExtendedProperties == null) { gitem.ExtendedProperties = new Event.ExtendedPropertiesData(); gitem.ExtendedProperties.Shared = new Dictionary <string, string>(); } else if (gitem.ExtendedProperties.Shared == null) { gitem.ExtendedProperties.Shared = new Dictionary <string, string>(); } gitem.ExtendedProperties.Shared[event_property_key] = OutlookCalendar.FormatEventID(oitem); }
private void outlookAutoLogonCheckBox_CheckedChanged(object sender, EventArgs e) { if (outlookAutoLogonCheckBox.Checked) { outlookAutoLogonTextBox.ReadOnly = false; outlookAutoLogonPwdTextBox.ReadOnly = false; Settings.Instance.OutlookAutoLogonEnabled = true; if (OutlookCalendar.IsLoggedIn()) { OutlookCalendar.Instance.Release(); } } else { outlookAutoLogonTextBox.ReadOnly = true; outlookAutoLogonPwdTextBox.ReadOnly = true; Settings.Instance.OutlookAutoLogonEnabled = false; if (OutlookCalendar.IsLoggedIn()) { OutlookCalendar.Instance.Release(); } } }
bool synchronize(List <AppointmentItem> outlook_items, List <Event> google_items) { // TODO: consider description updates (only needs to be considered when checked... come back and fix this) // TODO: optimize comparison algorithms - this one not mine, but should consider for larger sets of data // TODO: outlook to google recurrence 90% complete // getting weird error message from outlook: "The operation cannot be performed because the message has changed" // need to determine what happens when deleting just the master recurrence object // TODO: google to outlook recurrence 0% complete... need to read up on http://www.ietf.org/rfc/rfc2445 // TODO: testing on a larger scale... // TODO: refactor this function, as it is getting out of control... // indicates the number of entries added / updated / removed.... uint google_entries_added = 0; uint google_entries_updated = 0; uint google_entries_removed = 0; uint outlook_entries_added = 0; uint outlook_entries_updated = 0; uint outlook_entries_removed = 0; uint bound_entries_found = 0; uint errors = 0; // first synchronize outlook -> google // run over all the office items and add or update on google for (int i = outlook_items.Count - 1; i >= 0; --i) { // obtain a reference to the outlook item... var oitem = outlook_items[i]; // determine first if this outlook item is associated with a google calendar item... UserProperty oitem_google_prop = oitem.UserProperties.Find(EventPropertyKey); if (oitem_google_prop == null) { // run across the google events to see if there is one that matches Event gitem = null; foreach (var g in google_items) { // lowercase match the signature and // the property is not set or the property matches the oitem, match found... // the user has to type it the same in both cases to make a match... // is there something better here? if (signature(g).ToLower() == signature(oitem).ToLower() && (g.ExtendedProperties == null || g.ExtendedProperties.Shared == null || g.ExtendedProperties.Shared.ContainsKey(EventPropertyKey) == false || g.ExtendedProperties.Shared[EventPropertyKey] == OutlookCalendar.FormatEventID(oitem))) { gitem = g; break; } } if (gitem != null) { // give some indication of what will take place logboxout("Binding Outlook and Google event: " + oitem.Subject + " (" + oitem.Start + ")"); // bind the properties together OutlookCalendar.Instance.Bind(oitem, gitem); // update the instance on the google calendar GoogleCalendar.Instance.updateEntry(gitem); // remove the outlook item and the google item from the lists... // do not need to process them again for future iterations... google_items.Remove(gitem); outlook_items.Remove(oitem); // save and close the outlook item ((_AppointmentItem)oitem).Close(OlInspectorClose.olSave); // remove the com reference System.Runtime.InteropServices.Marshal.ReleaseComObject(oitem); // update the stats ++bound_entries_found; } else { // give some indication of what will take place logboxout("Creating Google event: " + oitem.Subject + " (" + oitem.Start + ")"); // the property does not exist... this mean that google calendar // does not have this outlook entry... after this call, the outlook item // and the google item should be tied together by the use of properties... gitem = GoogleCalendar.Instance.addEntry(oitem, cbAddDescription.Checked, cbAddReminders.Checked, cbAddAttendees.Checked); // updated the stats ++google_entries_added; } } else { // the property exists, so we need to determine if the event should be updated // first, find the event in the list of google items... Event gitem = null; foreach (var g in google_items) { if (oitem_google_prop.Value == g.Id) { gitem = g; break; } } if (gitem == null) { // give some indication of what will take place logboxout("Removing Outlook event: " + oitem.Subject + " (" + oitem.Start + ")"); // the item does not exist, so it was removed from google calendar // since it was removed from google, remove it from outlook OutlookCalendar.Instance.deleteCalendarEntry(oitem); // outlook item can no longer be used after it is deleted outlook_items.RemoveAt(i); // need to release the com reference System.Runtime.InteropServices.Marshal.ReleaseComObject(oitem); // update the stats ++outlook_entries_removed; } else { // the item does exist... // determine if the event should be updated... if ((signature(oitem) != signature(gitem) || OutlookGoogleSync.Utilities.ObtainUserBodyData(oitem.Body) != OutlookGoogleSync.Utilities.ObtainUserBodyData(gitem.Description)) && oitem.LastModificationTime > gitem.Updated) { // the google event can only be updated if owned by the calendar... if (gitem.Organizer.Self.HasValue && gitem.Organizer.Self.Value) { // give some indication of what will take place if (signature(oitem) != signature(gitem)) { logboxout("Updating Google event: " + gitem.Summary + " (" + GoogleCalendar.FormatTime(gitem.Start) + ") ==> " + oitem.Subject + " (" + oitem.Start + ")"); } else { logboxout("Updating Google event description: " + gitem.Summary + " (" + GoogleCalendar.FormatTime(gitem.Start) + ")"); } // update the event based on the outlook item GoogleCalendar.Instance.updateEntry(gitem, oitem, cbAddDescription.Checked, cbAddReminders.Checked, cbAddAttendees.Checked); // update the status ++google_entries_updated; } // this google item has been processed google_items.Remove(gitem); } } // need to release the com reference System.Runtime.InteropServices.Marshal.ReleaseComObject(oitem_google_prop); } } // second synchronize google -> outlook // run over all the google items and add or update on outlook for (int i = google_items.Count - 1; i >= 0; --i) { // obtain a reference to the google item... var gitem = google_items[i]; // determine first if this google item is associated with an outlook calendar item... string outlook_id = null; if (gitem.ExtendedProperties != null && gitem.ExtendedProperties.Shared != null && gitem.ExtendedProperties.Shared.ContainsKey(EventPropertyKey)) { outlook_id = gitem.ExtendedProperties.Shared[EventPropertyKey]; } if (outlook_id == null) { // run across the outlook events to see if there is one that matches... // this may not need to be done, as the google pass should have found them all... // lets be on the safe side here and do it anyway... AppointmentItem oitem = null; foreach (var o in outlook_items) { // lowercase match the signature and // the property is not set or the property matches the gitem, match found... // the user has to type it the same in both cases to make a match... // is there something better here? if (signature(o).ToLower() == signature(gitem).ToLower() && (o.UserProperties == null || o.UserProperties.Find(EventPropertyKey) == null || o.UserProperties.Find(EventPropertyKey).Value == gitem.Id)) { oitem = o; break; } } if (oitem != null) { // give some indication of what will take place logboxout("Binding Outlook and Google event: " + gitem.Summary + " (" + GoogleCalendar.FormatTime(gitem.Start) + ")"); // bind the properties together OutlookCalendar.Instance.Bind(oitem, gitem); // update the instance on the google calendar GoogleCalendar.Instance.updateEntry(gitem); // remove the outlook item and the google item from the lists... // do not need to process them again for future iterations... google_items.Remove(gitem); outlook_items.Remove(oitem); // save and close the outlook item ((_AppointmentItem)oitem).Close(OlInspectorClose.olSave); // need to release the com reference System.Runtime.InteropServices.Marshal.ReleaseComObject(oitem); // update the stats ++bound_entries_found; } else { // give some indication of what will take place logboxout("Creating Outlook event: " + gitem.Summary + " (" + GoogleCalendar.FormatTime(gitem.Start) + ")"); // the property does not exist... this means that the outlook calendar // does not have this google entry... after this call, the outlook item // and the google item should be tied together by the use of properties... oitem = OutlookCalendar.Instance.addEntry(gitem, cbAddDescription.Checked, cbAddReminders.Checked, cbAddAttendees.Checked); try { // google currently does not have an updated id... this needs to be reflected on the server... GoogleCalendar.Instance.updateEntry(gitem); } catch (System.Exception ex) { // unable to update the google entry for some reason... // let the user know and the reason why... logboxout(""); logboxout("Error: Google event cannot be bound to Outlook event!"); logboxout("Reason: " + ex.Message); logboxout(""); // update the stats ++errors; } // need to release the com reference System.Runtime.InteropServices.Marshal.ReleaseComObject(oitem); // update the stats ++outlook_entries_added; } } else { // the property exists, so we need to determine if the event should be updated // first, find the event in the list of outlook items... AppointmentItem oitem = null; foreach (var o in outlook_items) { if (outlook_id == OutlookCalendar.FormatEventID(o)) { oitem = o; break; } } if (oitem == null) { // give some indication of what will take place logboxout("Removing Google event: " + gitem.Summary + " (" + GoogleCalendar.FormatTime(gitem.Start) + ")"); // the item does not exist, so it was removed from outlook calendar // since it was removed from outlook, remove it from google GoogleCalendar.Instance.deleteCalendarEntry(gitem); // update the stats ++google_entries_removed; } else { // this outlook item is about to be processed... no matter the action // taken, we can remove it from the list of items, so as not // to need to look at it again in future iterations... outlook_items.Remove(oitem); // the item does exist... // determine if the event should be updated... if ((signature(gitem) != signature(oitem) || OutlookGoogleSync.Utilities.ObtainUserBodyData(oitem.Body) != OutlookGoogleSync.Utilities.ObtainUserBodyData(gitem.Description)) && gitem.Updated > oitem.LastModificationTime) { // give some indication of what will take place if (signature(gitem) != signature(oitem)) { logboxout("Updating Outlook event: " + oitem.Subject + " (" + oitem.Start + ") ==> " + gitem.Summary + " (" + GoogleCalendar.FormatTime(gitem.Start) + ")"); } else { logboxout("Updating Outlook event description: " + oitem.Subject + " (" + oitem.Start + ")"); } // update the event based on the google item OutlookCalendar.Instance.updateEntry(oitem, gitem, cbAddDescription.Checked, cbAddReminders.Checked, cbAddAttendees.Checked); // update the status ++outlook_entries_updated; } try { // save and close the outlook item ((_AppointmentItem)oitem).Close(OlInspectorClose.olSave); } catch (System.Exception ex) { // unable to save the outlook entry for some reason... // let the user know and the reason why... logboxout(""); logboxout("Error: Outlook event cannot be saved!"); logboxout("Reason: " + ex.Message); logboxout(""); // update the stats ++errors; } // need to release the com reference System.Runtime.InteropServices.Marshal.ReleaseComObject(oitem); } } } // close all the outlook items foreach (var o in outlook_items) { ((_AppointmentItem)o).Close(OlInspectorClose.olSave); System.Runtime.InteropServices.Marshal.ReleaseComObject(o); } // clear out both lists... these items have been processed... outlook_items.Clear(); google_items.Clear(); // summarize the changes made logboxout("--------------------------------------------------"); logboxout("Google entries added: " + google_entries_added); logboxout("Google entries updated: " + google_entries_updated); logboxout("Google entries removed: " + google_entries_removed); logboxout(""); logboxout("Outlook entries added: " + outlook_entries_added); logboxout("Outlook entries updated: " + outlook_entries_updated); logboxout("Outlook entries removed: " + outlook_entries_removed); logboxout(""); logboxout("Bound entries found: " + bound_entries_found); logboxout(""); logboxout("Errors found: " + errors); return(errors == 0); }
private void syncWorker_DoWork(object sender, DoWorkEventArgs e) { if (e.Argument is string && "DELETE".Equals((string)e.Argument)) { deleteAllSyncItems(); return; } AppointmentItemCache appointmentItemCache = new AppointmentItemCache(); EventCache eventCache = new EventCache(); DateTime syncStarted = DateTime.Now; OutlookCalendar ocal = null; try { logboxout("Sync started at " + syncStarted.ToString()); logboxout("--------------------------------------------------"); logboxout("Reading Outlook Calendar Entries..."); ocal = new OutlookCalendar(); List <AppointmentItemCacheEntry> OutlookEntries = new List <AppointmentItemCacheEntry>(); foreach (AppointmentItem a in ocal.getCalendarEntriesInRange(syncStarted)) { OutlookEntries.Add(appointmentItemCache.GetAppointmentItemCacheEntry(a, ocal.AccountName)); } if (checkBoxCreateFiles.Checked) { using (TextWriter tw = new StreamWriter("export_found_in_outlook.txt")) { foreach (AppointmentItemCacheEntry ai in OutlookEntries) { tw.WriteLine(ai.Signature); } } } logboxout("Found " + OutlookEntries.Count + " Outlook Calendar Entries."); logboxout("--------------------------------------------------"); logboxout("Reading Google Calendar Entries..."); string accountName = "(Empty)"; if (ocal != null || !string.IsNullOrEmpty(ocal.AccountName)) { accountName = ocal.AccountName; } GoogleCalendar gcal = new GoogleCalendar(); List <EventCacheEntry> GoogleEntries = new List <EventCacheEntry>(); foreach (Event ev in gcal.getCalendarEntriesInRange(syncStarted)) { GoogleEntries.Add(eventCache.GetEventCacheEntry(ev, accountName)); } if (checkBoxCreateFiles.Checked) { using (TextWriter tw = new StreamWriter("export_found_in_google.txt")) { foreach (EventCacheEntry ev in GoogleEntries) { tw.WriteLine(ev.Signature); } } } logboxout("Found " + GoogleEntries.Count + " Google Calendar Entries."); logboxout("--------------------------------------------------"); List <EventCacheEntry> GoogleEntriesToBeDeleted = identifyGoogleEntriesToBeDeleted(OutlookEntries, GoogleEntries, accountName); if (checkBoxCreateFiles.Checked) { using (TextWriter tw = new StreamWriter("export_to_be_deleted.txt")) { foreach (EventCacheEntry ev in GoogleEntriesToBeDeleted) { tw.WriteLine(ev.Signature); } } } logboxout(GoogleEntriesToBeDeleted.Count + " Google Calendar Entries to be deleted."); //OutlookEntriesToBeCreated ...in Google! List <AppointmentItemCacheEntry> OutlookEntriesToBeCreated = identifyOutlookEntriesToBeCreated(OutlookEntries, GoogleEntries); if (checkBoxCreateFiles.Checked) { using (TextWriter tw = new StreamWriter("export_to_be_created.txt")) { foreach (AppointmentItemCacheEntry ai in OutlookEntriesToBeCreated) { tw.WriteLine(ai.Signature); } } } logboxout(OutlookEntriesToBeCreated.Count + " Entries to be created in Google."); logboxout("--------------------------------------------------"); if (GoogleEntriesToBeDeleted.Count > 0) { logboxout("Deleting " + GoogleEntriesToBeDeleted.Count + " Google Calendar Entries..."); foreach (EventCacheEntry ev in GoogleEntriesToBeDeleted) { gcal.deleteCalendarEntry(ev.Event); } logboxout("Done."); logboxout("--------------------------------------------------"); } if (OutlookEntriesToBeCreated.Count > 0) { logboxout("Creating " + OutlookEntriesToBeCreated.Count + " Entries in Google..."); foreach (AppointmentItemCacheEntry aice in OutlookEntriesToBeCreated) { AppointmentItem ai = aice.AppointmentItem; Event ev = new Event(); ev.Start = new EventDateTime(); ev.End = new EventDateTime(); if (ai.AllDayEvent) { ev.Start.Date = ai.Start.ToString("yyyy-MM-dd"); ev.End.Date = ai.End.ToString("yyyy-MM-dd"); } else { ev.Start.DateTime = GoogleCalendar.GoogleTimeFrom(ai.Start); ev.End.DateTime = GoogleCalendar.GoogleTimeFrom(ai.End); } ev.Summary = ai.Subject; if (checkBoxAddDescription.Checked) { try { ev.Description = ai.Body; } catch (System.Exception ex) { string startDt = ai.AllDayEvent ? ai.Start.ToShortDateString() : ai.Start.ToString(); string endDt = ai.AllDayEvent ? ai.End.ToShortDateString() : ai.End.ToString(); logboxout("Error accessing the body of Outlook item. Body will be empty.\r\n Subject: [" + ev.Summary + "]\r\n Start: [" + startDt + "]\r\n End: [" + endDt + "]\r\n Error: " + ex.Message); } } ev.Location = ai.Location; //consider the reminder set in Outlook if (checkBoxAddReminders.Checked && ai.ReminderSet) { ev.Reminders = new Event.RemindersData(); ev.Reminders.UseDefault = false; EventReminder reminder = new EventReminder(); reminder.Method = "popup"; reminder.Minutes = ai.ReminderMinutesBeforeStart; ev.Reminders.Overrides = new List <EventReminder>(); ev.Reminders.Overrides.Add(reminder); } else { ev.Reminders = new Event.RemindersData(); ev.Reminders.UseDefault = false; } if (checkBoxAddAttendees.Checked) { ev.Description += Environment.NewLine; ev.Description += Environment.NewLine + "=============================================="; ev.Description += Environment.NewLine + "Added by OutlookGoogleSync (" + accountName + "):" + Environment.NewLine; ev.Description += Environment.NewLine + "ORGANIZER: " + Environment.NewLine + ai.Organizer + Environment.NewLine; ev.Description += Environment.NewLine + "REQUIRED: " + Environment.NewLine + splitAttendees(ai.RequiredAttendees) + Environment.NewLine; if (ai.OptionalAttendees != null) { ev.Description += Environment.NewLine + "OPTIONAL: " + Environment.NewLine + splitAttendees(ai.OptionalAttendees); } ev.Description += Environment.NewLine + "=============================================="; } gcal.addEntry(ev); } logboxout("Done."); logboxout("--------------------------------------------------"); } DateTime syncFinished = DateTime.Now; TimeSpan elapsed = syncFinished - syncStarted; logboxout("Sync finished at " + syncFinished.ToString()); logboxout("Time needed: " + elapsed.Minutes + " min " + elapsed.Seconds + " s"); } catch (System.Exception ex) { logboxout("Error Syncing:\r\n" + ex.ToString()); } eventCache.Clear(); freeCOMResources(ocal, appointmentItemCache); }
private IOfficeCalendar CreateOfficeCalendar() { IOfficeCalendar calendar; if (Settings.Instance.UseExchange) { calendar = new EwsCalendar(); } else { calendar = new OutlookCalendar(); } return calendar; }