public ConflictResolution Resolve(Outlook.AppointmentItem outlookAppointment, Event googleAppointment, AppointmentsSynchronizer sync, bool isNewMatch) { string name = string.Empty; _form.OutlookItemTextBox.Text = string.Empty; _form.GoogleItemTextBox.Text = string.Empty; if (outlookAppointment != null) { name = outlookAppointment.Subject + " - " + outlookAppointment.Start; _form.OutlookItemTextBox.Text += outlookAppointment.Body; } if (googleAppointment != null) { name = googleAppointment.Summary + " - " + AppointmentsSynchronizer.GetTime(googleAppointment); _form.GoogleItemTextBox.Text += googleAppointment.Description; } if (isNewMatch) { _form.messageLabel.Text = "This is the first time these appointments \"" + name + "\" are synced. Choose which you would like to keep."; _form.skip.Text = "Keep both"; } else { _form.messageLabel.Text = "Both the Outlook and Google Appointment \"" + name + "\" have been changed. Choose which you would like to keep."; } return(Resolve()); }
public DeleteResolution ResolveDelete(Event googleAppointment) { _form.Text = "Outlook appointment deleted"; _form.messageLabel.Text = "Outlook appointment \"" + googleAppointment.Summary + " - " + AppointmentsSynchronizer.GetTime(googleAppointment) + "\" doesn't exist anymore. Do you want to delete it also on Google side?"; _form.OutlookItemTextBox.Text = string.Empty; _form.GoogleItemTextBox.Text += googleAppointment.Description; _form.keepOutlook.Text = "Keep Google"; _form.keepGoogle.Text = "Delete Google"; _form.skip.Enabled = false; return(ResolveDeletedOutlook()); }
public static void SyncAppointments(AppointmentsSynchronizer sync) { for (int i = 0; i < sync.Appointments.Count; i++) { AppointmentMatch match = sync.Appointments[i]; if (NotificationReceived != null) { string name = string.Empty; if (match.OutlookAppointment != null) { name = match.OutlookAppointment.Subject + " - " + match.OutlookAppointment.Start; } else if (match.GoogleAppointment != null) { name = match.GoogleAppointment.Summary + " - " + AppointmentsSynchronizer.GetTime(match.GoogleAppointment); } NotificationReceived(string.Format("Syncing appointment {0} of {1}: {2} ...", i + 1, sync.Appointments.Count, name)); } SyncAppointment(match, sync); } }
/// <summary> /// Matches outlook and Google appointment by a) id b) properties. /// </summary> /// <param name="sync">Syncronizer instance</param> /// <returns>Returns a list of match pairs (outlook appointment + Google appointment) for all appointment. Those that weren't matche will have it's peer set to null</returns> public static List <AppointmentMatch> MatchAppointments(AppointmentsSynchronizer sync) { Logger.Log("Matching Outlook and Google appointments...", EventType.Information); var result = new List <AppointmentMatch>(); var googleAppointmentExceptions = new List <Event>(); //for each outlook appointment try to get Google appointment id from user properties //if no match - try to match by properties //if no match - create a new match pair without Google appointment. //foreach (Outlook._AppointmentItem olc in outlookAppointments) var OutlookAppointmentsWithoutSyncId = new Collection <Outlook.AppointmentItem>(); #region Match first all outlookAppointments by sync id for (int i = 1; i <= sync.OutlookAppointments.Count; i++) { Outlook.AppointmentItem ola = null; try { ola = sync.OutlookAppointments[i] as Outlook.AppointmentItem; if (ola == null || string.IsNullOrEmpty(ola.Subject) && ola.Start == AppointmentSync.outlookDateMin) { Logger.Log("Empty Outlook appointment found. Skipping", EventType.Warning); sync.SkippedCount++; sync.SkippedCountNotMatches++; continue; } else if (ola.MeetingStatus == Outlook.OlMeetingStatus.olMeetingCanceled || ola.MeetingStatus == Outlook.OlMeetingStatus.olMeetingReceivedAndCanceled) { Logger.Log("Skipping Outlook appointment found because it is cancelled: " + ola.Subject + " - " + ola.Start, EventType.Debug); //sync.SkippedCount++; //sync.SkippedCountNotMatches++; continue; } else if (AppointmentsSynchronizer.TimeMin != null && (ola.IsRecurring && ola.GetRecurrencePattern().PatternEndDate < AppointmentsSynchronizer.TimeMin || !ola.IsRecurring && ola.End < AppointmentsSynchronizer.TimeMin) || AppointmentsSynchronizer.TimeMax != null && (ola.IsRecurring && ola.GetRecurrencePattern().PatternStartDate > AppointmentsSynchronizer.TimeMax || !ola.IsRecurring && ola.Start > AppointmentsSynchronizer.TimeMax)) { Logger.Log("Skipping Outlook appointment because it is out of months range to sync:" + ola.Subject + " - " + ola.Start, EventType.Debug); continue; } } catch (Exception ex) { //this is needed because some appointments throw exceptions if (ola != null && !string.IsNullOrEmpty(ola.Subject)) { Logger.Log("Accessing Outlook appointment: " + ola.Subject + " threw and exception. Skipping: " + ex.Message, EventType.Warning); } else { Logger.Log("Accessing Outlook appointment threw and exception. Skipping: " + ex.Message, EventType.Warning); } sync.SkippedCount++; sync.SkippedCountNotMatches++; continue; } NotificationReceived?.Invoke(string.Format("Matching appointment {0} of {1} by id: {2} ...", i, sync.OutlookAppointments.Count, ola.Subject)); // Create our own info object to go into collections/lists, so we can free the Outlook objects and not run out of resources / exceed policy limits. //OutlookAppointmentInfo olci = new OutlookAppointmentInfo(ola, sync); //try to match this appointment to one of Google appointments var gid = AppointmentPropertiesUtils.GetOutlookGoogleAppointmentId(sync, ola); if (gid != null) { var e = sync.GetGoogleAppointmentById(gid); var match = new AppointmentMatch(ola, null); if (e != null && !e.Status.Equals("cancelled")) { //we found a match by google id, that is not deleted or cancelled yet match.AddGoogleAppointment(e); result.Add(match); sync.GoogleAppointments.Remove(e); } else { OutlookAppointmentsWithoutSyncId.Add(ola); } } else { OutlookAppointmentsWithoutSyncId.Add(ola); } } #endregion #region Match the remaining appointments by properties for (int i = 0; i < OutlookAppointmentsWithoutSyncId.Count; i++) { var ola = OutlookAppointmentsWithoutSyncId[i]; NotificationReceived?.Invoke(string.Format("Matching appointment {0} of {1} by unique properties: {2} ...", i + 1, OutlookAppointmentsWithoutSyncId.Count, ola.Subject)); //no match found by id => match by subject/title //create a default match pair with just outlook appointment. var match = new AppointmentMatch(ola, null); //foreach Google appointment try to match and create a match pair if found some match(es) for (int j = sync.GoogleAppointments.Count - 1; j >= 0; j--) { var e = sync.GoogleAppointments[j]; // only match if there is a appointment targetBody, else // a matching Google appointment will be created at each sync if (!e.Status.Equals("cancelled") && ola.Subject == e.Summary && e.Start.DateTime != null && ola.Start == e.Start.DateTime) { match.AddGoogleAppointment(e); sync.GoogleAppointments.Remove(e); } } if (match.GoogleAppointment == null) { Logger.Log(string.Format("No match found for outlook appointment ({0}) => {1}", match.OutlookAppointment.Subject + " - " + match.OutlookAppointment.Start, (AppointmentPropertiesUtils.GetOutlookGoogleAppointmentId(sync, match.OutlookAppointment) != null ? "Delete from Outlook" : "Add to Google")), EventType.Information); } result.Add(match); } #endregion //for each Google appointment that's left (they will be nonmatched) create a new match pair without outlook appointment. for (int i = 0; i < sync.GoogleAppointments.Count; i++) { var googleAppointment = sync.GoogleAppointments[i]; NotificationReceived?.Invoke(string.Format("Adding new Google appointment {0} of {1} by unique properties: {2} ...", i + 1, sync.GoogleAppointments.Count, googleAppointment.Summary)); if (googleAppointment.RecurringEventId != null) { sync.SkippedCountNotMatches++; googleAppointmentExceptions.Add(googleAppointment); } else if (googleAppointment.Status.Equals("cancelled")) { Logger.Log("Skipping Google appointment found because it is cancelled: " + googleAppointment.Summary + " - " + AppointmentsSynchronizer.GetTime(googleAppointment), EventType.Debug); //sync.SkippedCount++; //sync.SkippedCountNotMatches++; } else if (string.IsNullOrEmpty(googleAppointment.Summary) && (googleAppointment.Start == null || googleAppointment.Start.DateTime == null && googleAppointment.Start.Date == null)) { // no title or time sync.SkippedCount++; sync.SkippedCountNotMatches++; Logger.Log("Skipped GoogleAppointment because no unique property found (Subject or StartDate):" + googleAppointment.Summary + " - " + AppointmentsSynchronizer.GetTime(googleAppointment), EventType.Warning); } else { Logger.Log(string.Format("No match found for Google appointment ({0}) => {1}", googleAppointment.Summary + " - " + AppointmentsSynchronizer.GetTime(googleAppointment), (!string.IsNullOrEmpty(AppointmentPropertiesUtils.GetGoogleOutlookAppointmentId(sync.SyncProfile, googleAppointment)) ? "Delete from Google" : "Add to Outlook")), EventType.Information); var match = new AppointmentMatch(null, googleAppointment); result.Add(match); } } //for each Google appointment exception, assign to proper match for (int i = 0; i < googleAppointmentExceptions.Count; i++) { var e = googleAppointmentExceptions[i]; NotificationReceived?.Invoke(string.Format("Adding Google appointment exception {0} of {1} : {2} ...", i + 1, googleAppointmentExceptions.Count, e.Summary + " - " + AppointmentsSynchronizer.GetTime(e))); //Search for original recurrent event in matches bool found = false; foreach (var m in result) { if (m.GoogleAppointment != null && e.RecurringEventId.Equals(m.GoogleAppointment.Id)) { m.GoogleAppointmentExceptions.Add(e); found = true; break; } } if (!found) { Logger.Log(string.Format("No match found for Google appointment exception: {0}", e.Summary + " - " + AppointmentsSynchronizer.GetTime(e)), EventType.Debug); } } return(result); }
private void DeleteTestAppointments() { Outlook.MAPIFolder mapiFolder = null; Outlook.Items items = null; if (string.IsNullOrEmpty(AppointmentsSynchronizer.SyncAppointmentsFolder)) { mapiFolder = Synchronizer.OutlookNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar); } else { mapiFolder = Synchronizer.OutlookNameSpace.GetFolderFromID(AppointmentsSynchronizer.SyncAppointmentsFolder); } Assert.NotNull(mapiFolder); try { items = mapiFolder.Items; Assert.NotNull(items); object item = items.GetFirst(); while (item != null) { if (item is Outlook.AppointmentItem) { var ola = item as Outlook.AppointmentItem; if (ola.Subject == name) { var s = ola.Subject + " - " + ola.Start; ola.Delete(); Logger.Log("Deleted Outlook test appointment: " + s, EventType.Information); } Marshal.ReleaseComObject(ola); } Marshal.ReleaseComObject(item); item = items.GetNext(); } } finally { if (mapiFolder != null) { Marshal.ReleaseComObject(mapiFolder); } if (items != null) { Marshal.ReleaseComObject(items); } } var query = sync.appointmentsSynchronizer.EventRequest.List(AppointmentsSynchronizer.SyncAppointmentsGoogleFolder); Events feed; string pageToken = null; do { query.PageToken = pageToken; feed = query.Execute(); foreach (Event e in feed.Items) { if (!e.Status.Equals("cancelled") && e.Summary != null && e.Summary == name) { sync.appointmentsSynchronizer.EventRequest.Delete(AppointmentsSynchronizer.SyncAppointmentsGoogleFolder, e.Id).Execute(); Logger.Log("Deleted Google test appointment: " + e.Summary + " - " + AppointmentsSynchronizer.GetTime(e), EventType.Information); } } pageToken = feed.NextPageToken; }while (pageToken != null); sync.appointmentsSynchronizer.LoadAppointments(); Assert.AreEqual(0, sync.appointmentsSynchronizer.GoogleAppointments.Count); Assert.AreEqual(0, sync.appointmentsSynchronizer.OutlookAppointments.Count); }