public static string GetOutlookGoogleContactId(Synchronizer sync, Outlook.ContactItem outlookContact)
 {
     string id = null;
     Outlook.UserProperties userProperties = outlookContact.UserProperties;
     try
     {
         Outlook.UserProperty idProp = userProperties[sync.OutlookPropertyNameId];
         if (idProp != null)
         {
             try
             {
                 id = (string)idProp.Value;
                 if (id == null)
                     throw new Exception();
             }
             finally
             {
                 Marshal.ReleaseComObject(idProp);
             }
         }
     }
     finally
     {
         Marshal.ReleaseComObject(userProperties);
     }
     return id;
 }
 public static DateTime? GetOutlookLastSync(Synchronizer sync, Outlook.ContactItem outlookContact)
 {
     DateTime? result = null;
     Outlook.UserProperties userProperties = outlookContact.UserProperties;
     try
     {
         Outlook.UserProperty prop = userProperties[sync.OutlookPropertyNameSynced];
         if (prop != null)
         {
             try
             {
                 result = (DateTime)prop.Value;
             }
             finally
             {
                 Marshal.ReleaseComObject(prop);
             }
         }
     }
     finally
     {
         Marshal.ReleaseComObject(userProperties);
     }
     return result;
 }
 public static string GetBody(Synchronizer sync, Document entry)
 {
     string body = null;
     System.IO.StreamReader reader = null;
     try
     {
         reader = new System.IO.StreamReader(sync.DocumentsRequest.Download(entry, Document.DownloadType.txt));
         body = reader.ReadToEnd();
     }
     finally
     {
         if (reader != null)
             reader.Close();
     }
     return body;
 }
Esempio n. 4
0
        /// <summary>
        /// Sets the syncId of the Outlook contact and the last sync date.
        /// Please assure to always call this function when saving OutlookItem
        /// </summary>
        /// <param name="sync"></param>
        /// <param name="outlookContact"></param>
        /// <param name="googleContact"></param>
        public static void SetOutlookGoogleContactId(Synchronizer sync, Outlook.ContactItem outlookContact, Contact googleContact)
        {
            if (googleContact.ContactEntry.Id.Uri == null)
            {
                throw new NullReferenceException("GoogleContact must have a valid Id");
            }

            //check if outlook contact aready has google id property.
            Outlook.UserProperties userProperties = outlookContact.UserProperties;
            try
            {
                Outlook.UserProperty prop = userProperties[sync.OutlookPropertyNameId];
                if (prop == null)
                {
                    prop = userProperties.Add(sync.OutlookPropertyNameId, Outlook.OlUserPropertyType.olText, true);
                }
                try
                {
                    prop.Value = googleContact.ContactEntry.Id.Uri.Content;
                }
                finally
                {
                    Marshal.ReleaseComObject(prop);
                }
            }
            finally
            {
                Marshal.ReleaseComObject(userProperties);
            }

            //save last google's updated date as property

            /*prop = outlookContact.UserProperties[OutlookPropertyNameUpdated];
             * if (prop == null)
             *  prop = outlookContact.UserProperties.Add(OutlookPropertyNameUpdated, Outlook.OlUserPropertyType.olDateTime, null, null);
             * prop.Value = googleContact.Updated;*/

            //Also set the OutlookLastSync date when setting a match between Outlook and Google to assure the lastSync updated when Outlook contact is saved afterwards
            SetOutlookLastSync(sync, outlookContact);
        }
Esempio n. 5
0
        public static void SyncNotes(Synchronizer sync)
        {
            for (int i = 0; i < sync.Notes.Count; i++)
            {
                NoteMatch match = sync.Notes[i];
                if (NotificationReceived != null)
                {
                    string name = string.Empty;
                    if (match.OutlookNote != null)
                    {
                        name = match.OutlookNote.Subject;
                    }
                    else if (match.GoogleNote != null)
                    {
                        name = match.GoogleNote.Title;
                    }
                    NotificationReceived(String.Format("Syncing note {0} of {1}: {2} ...", i + 1, sync.Notes.Count, name));
                }

                SyncNote(match, sync);
            }
        }
        public static void SyncAppointments(Synchronizer 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 + " - " + Synchronizer.GetTime(match.GoogleAppointment);
                    }
                    NotificationReceived(String.Format("Syncing appointment {0} of {1}: {2} ...", i + 1, sync.Appointments.Count, name));
                }

                SyncAppointment(match, sync);
            }
        }
        public ConflictResolution Resolve(Microsoft.Office.Interop.Outlook.AppointmentItem outlookAppointment, Event googleAppointment, Synchronizer 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 + " - " + Synchronizer.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());
        }
Esempio n. 8
0
 public ConflictResolution Resolve(string message, Event googleAppointment, Microsoft.Office.Interop.Outlook.AppointmentItem outlookAppointment, Synchronizer sync)
 {
     return Resolve(message, outlookAppointment, googleAppointment, sync, false, true);
 }
Esempio n. 9
0
        public static bool UpdateRecurrenceExceptions(Outlook.AppointmentItem master, Event slave, Synchronizer sync)
        {
            bool ret = false;

            Outlook.Exceptions exceptions = master.GetRecurrencePattern().Exceptions;

            if (exceptions != null && exceptions.Count != 0)
            {
                foreach (Outlook.Exception exception in exceptions)
                {
                    if (!exception.Deleted)
                    {
                        //Add exception time (but only if in given time range
                        if ((Synchronizer.MonthsInPast == 0 || exception.AppointmentItem.End >= DateTime.Now.AddMonths(-Synchronizer.MonthsInPast)) &&
                             (Synchronizer.MonthsInFuture == 0 || exception.AppointmentItem.Start <= DateTime.Now.AddMonths(Synchronizer.MonthsInFuture)))
                        {
                            //slave.Times.Add(new Google.GData.Extensions.When(exception.AppointmentItem.Start, exception.AppointmentItem.Start, exception.AppointmentItem.AllDayEvent));
                            var googleRecurrenceException = Factory.NewEvent();
                            //if (slave.Sequence != null)
                            //    googleRecurrenceException.Sequence = slave.Sequence + 1;
                            googleRecurrenceException.RecurringEventId = slave.Id;
                            //googleRecurrenceException.OriginalEvent.Href = ???
                            googleRecurrenceException.OriginalStartTime = new EventDateTime();
                            if (master.AllDayEvent == true)
                                googleRecurrenceException.OriginalStartTime.Date = exception.OriginalDate.ToString("yyyy-MM-dd");
                            else
                            {
                                //DateTime start = exception.OriginalDate.AddHours(master.Start.Hour).AddMinutes(master.Start.Minute).AddSeconds(master.Start.Second);
                                googleRecurrenceException.OriginalStartTime.DateTime = exception.OriginalDate;
                            }

                            try
                            {
                                sync.UpdateAppointment(exception.AppointmentItem, ref googleRecurrenceException);
                                //googleRecurrenceExceptions.Add(googleRecurrenceException);

                                ret = true;
                            }
                            catch (Exception ex)
                            {
                                //should not happen
                                Logger.Log(ex.Message, EventType.Error);
                            }
                        }
                    }
                    else
                    {//Delete exception time

                    //    //for (int i=slave.Times.Count;i>0;i--)
                    //    //{
                    //    //    When time = slave.Times[i-1];
                    //    //    if (time.StartTime.Equals(exception.AppointmentItem.Start))
                    //    //    {
                    //    //        slave.Times.Remove(time);
                    //    //        ret = true;
                    //    //        break;
                    //    //    }
                    //    //}

                    //    //for (int i = googleRecurrenceExceptions.Count; i > 0;i-- )
                    //    //{
                    //    //    if (googleRecurrenceExceptions[i-1].Times[0].StartTime.Equals(exception.OriginalDate))
                    //    //    {
                    //    //        googleRecurrenceExceptions[i - 1].Delete();
                    //    //        googleRecurrenceExceptions.RemoveAt(i - 1);
                    //    //    }
                    //    //}

                    //    //ToDo: Doesn't work for all recurrences
                    //    var googleRecurrenceException = sync.GetGoogleAppointmentByStartDate(slave.Id, exception.OriginalDate);

                    //    if (googleRecurrenceException != null)
                    //        googleRecurrenceException.Delete();

                        if ((Synchronizer.MonthsInPast == 0 || exception.OriginalDate >= DateTime.Now.AddMonths(-Synchronizer.MonthsInPast)) &&
                             (Synchronizer.MonthsInFuture == 0 || exception.OriginalDate <= DateTime.Now.AddMonths(Synchronizer.MonthsInFuture)))
                        {
                            //First create deleted occurrences, to delete it later again
                            var googleRecurrenceException = Factory.NewEvent();
                            //if (slave.Sequence != null)
                            //    googleRecurrenceException.Sequence = slave.Sequence + 1;
                            googleRecurrenceException.RecurringEventId = slave.Id;
                            //googleRecurrenceException.OriginalEvent.Href = ???
                            DateTime start = exception.OriginalDate.AddHours(master.Start.Hour).AddMinutes(master.Start.Minute).AddSeconds(master.Start.Second);
                            googleRecurrenceException.OriginalStartTime =  new EventDateTime();
                            googleRecurrenceException.OriginalStartTime.TimeZone = slave.Start.TimeZone;

                            if (master.AllDayEvent)
                            {
                                googleRecurrenceException.OriginalStartTime.Date = start.ToString("yyyy-MM-dd");
                                googleRecurrenceException.End.Date = start.AddMinutes(master.Duration).ToString("yyyy-MM-dd");
                            }
                            else
                            {
                                googleRecurrenceException.OriginalStartTime.DateTime = start;
                                googleRecurrenceException.End.DateTime = start.AddMinutes(master.Duration);
                            }
                            googleRecurrenceException.Start = googleRecurrenceException.OriginalStartTime;

                            googleRecurrenceException.Summary = master.Subject;

                            try
                            {
                                googleRecurrenceException = sync.SaveGoogleAppointment(googleRecurrenceException);
                                //googleRecurrenceExceptions.Add(googleRecurrenceException);

                                //ToDo: check promptDeletion and syncDeletion options
                                sync.EventRequest.Delete(Synchronizer.SyncAppointmentsGoogleFolder, googleRecurrenceException.Id).Execute();
                                Logger.Log("Deleted obsolete recurrence exception from Google: " + master.Subject + " - " + exception.OriginalDate, EventType.Information);
                                //sync.DeletedCount++;

                                ret = true;
                            }
                            catch (Exception ex)
                            {
                                //usually only an error is thrown, if an already cancelled event is to be deleted again
                                Logger.Log(ex.Message, EventType.Debug);
                            }

                        }

                    }
                }
            }

            return ret;
        }
Esempio n. 10
0
        internal void Update(ContactItem outlookContactItem, Synchronizer sync)
        {
            this.EntryID = outlookContactItem.EntryID;
            this.FileAs = outlookContactItem.FileAs;
            this.FullName = outlookContactItem.FullName;
            this.Email1Address = ContactPropertiesUtils.GetOutlookEmailAddress1(outlookContactItem);
            this.MobileTelephoneNumber = outlookContactItem.MobileTelephoneNumber;
            this.Categories = outlookContactItem.Categories;
            this.LastModificationTime = outlookContactItem.LastModificationTime;
            this.Company = outlookContactItem.CompanyName;
            this.TitleFirstLastAndSuffix = GetTitleFirstLastAndSuffix(outlookContactItem);

            UserProperties userProperties = outlookContactItem.UserProperties;
            UserProperty prop = userProperties[sync.OutlookPropertyNameId];
            this.UserProperties.GoogleContactId = prop != null ? string.Copy((string)prop.Value) : null;
            if (prop != null)
                Marshal.ReleaseComObject(prop);

            prop = userProperties[sync.OutlookPropertyNameSynced];
            this.UserProperties.LastSync = prop != null ? (DateTime)prop.Value : (DateTime?)null;
            if (prop != null)
                Marshal.ReleaseComObject(prop);

            Marshal.ReleaseComObject(userProperties);
        }
Esempio n. 11
0
 /// <summary>
 /// Adds new Google Groups to the Google account.
 /// </summary>
 /// <param name="sync"></param>
 public static void SyncGroups(Synchronizer sync)
 {
     foreach (ContactMatch match in sync.Contacts)
     {
         if (match.OutlookContact != null && !string.IsNullOrEmpty(match.OutlookContact.Categories))
         {
             string[] cats = Utilities.GetOutlookGroups(match.OutlookContact.Categories);
             Group g;
             foreach (string cat in cats)
             {
                 g = sync.GetGoogleGroupByName(cat);
                 if (g == null)
                 {
                     // create group
                     g = sync.CreateGroup(cat);
                     g = sync.SaveGoogleGroup(g);
                     sync.GoogleGroups.Add(g);
                 }
             }
         }
     }
 }
Esempio n. 12
0
        public static void SyncContact(ContactMatch match, Synchronizer sync)
        {
            Outlook.ContactItem outlookContactItem = match.OutlookContact != null ? match.OutlookContact.GetOriginalItemFromOutlook() : null;

            try
            {
                if (match.GoogleContact == null && match.OutlookContact != null)
                {
                    //no google contact
                    string googleContactId = match.OutlookContact.UserProperties.GoogleContactId;
                    if (!string.IsNullOrEmpty(googleContactId))
                    {
                        //Redundant check if exist, but in case an error occurred in MatchContacts
                        Contact matchingGoogleContact = sync.GetGoogleContactById(googleContactId);
                        if (matchingGoogleContact == null)
                        {
                            if (sync.SyncOption == SyncOption.OutlookToGoogleOnly || !sync.SyncDelete)
                                return;
                            else if (!sync.PromptDelete)
                                 sync.DeleteOutlookResolution = DeleteResolution.DeleteOutlookAlways;
                            else if (sync.DeleteOutlookResolution != DeleteResolution.DeleteOutlookAlways &&
                                     sync.DeleteOutlookResolution != DeleteResolution.KeepOutlookAlways)
                            {
                                var r = new ConflictResolver();
                                sync.DeleteOutlookResolution = r.ResolveDelete(match.OutlookContact);
                            }
                            switch (sync.DeleteOutlookResolution)
                            {
                                case DeleteResolution.KeepOutlook:
                                case DeleteResolution.KeepOutlookAlways:
                                    ContactPropertiesUtils.ResetOutlookGoogleContactId(sync, outlookContactItem);
                                    break;
                                case DeleteResolution.DeleteOutlook:
                                case DeleteResolution.DeleteOutlookAlways:
                                    //Avoid recreating a GoogleContact already existing
                                    //==> Delete this outlookContact instead if previous match existed but no match exists anymore
                                    return;
                                default:
                                    throw new ApplicationException("Cancelled");
                            }
                        }
                    }

                    if (sync.SyncOption == SyncOption.GoogleToOutlookOnly)
                    {
                        sync.SkippedCount++;
                        Logger.Log(string.Format("Outlook Contact not added to Google, because of SyncOption " + sync.SyncOption.ToString() + ": {0}", match.OutlookContact.FileAs), EventType.Information);
                        return;
                    }

                    //create a Google contact from Outlook contact
                    match.GoogleContact = new Contact();

                    sync.UpdateContact(outlookContactItem, match.GoogleContact);

                }
                else if (match.OutlookContact == null && match.GoogleContact != null)
                {

                    // no outlook contact
                    string outlookId = ContactPropertiesUtils.GetGoogleOutlookContactId(sync.SyncProfile, match.GoogleContact);
                    if (outlookId != null)
                    {
                        if (sync.SyncOption == SyncOption.GoogleToOutlookOnly || !sync.SyncDelete)
                            return;
                        else if (!sync.PromptDelete)
                            sync.DeleteGoogleResolution = DeleteResolution.DeleteGoogleAlways;
                        else if (sync.DeleteGoogleResolution != DeleteResolution.DeleteGoogleAlways &&
                                 sync.DeleteGoogleResolution != DeleteResolution.KeepGoogleAlways)
                        {
                            var r = new ConflictResolver();
                            sync.DeleteGoogleResolution = r.ResolveDelete(match.GoogleContact);
                        }
                        switch (sync.DeleteGoogleResolution)
                        {
                            case DeleteResolution.KeepGoogle:
                            case DeleteResolution.KeepGoogleAlways:
                                ContactPropertiesUtils.ResetGoogleOutlookContactId(sync.SyncProfile, match.GoogleContact);
                                break;
                            case DeleteResolution.DeleteGoogle:
                            case DeleteResolution.DeleteGoogleAlways:
                                //Avoid recreating a OutlookContact already existing
                                //==> Delete this googleContact instead if previous match existed but no match exists anymore
                                return;
                            default:
                                throw new ApplicationException("Cancelled");
                        }

                    }

                    if (sync.SyncOption == SyncOption.OutlookToGoogleOnly)
                    {
                        sync.SkippedCount++;
                        Logger.Log(string.Format("Google Contact not added to Outlook, because of SyncOption " + sync.SyncOption.ToString() + ": {0}", match.GoogleContact.Title), EventType.Information);
                        return;
                    }

                    //create a Outlook contact from Google contact
                    outlookContactItem = Synchronizer.CreateOutlookContactItem(Synchronizer.SyncContactsFolder);

                    sync.UpdateContact(match.GoogleContact, outlookContactItem);
                    match.OutlookContact = new OutlookContactInfo(outlookContactItem, sync);
                }
                else if (match.OutlookContact != null && match.GoogleContact != null)
                {
                    //merge contact details

                    //determine if this contact pair were synchronized
                    //DateTime? lastUpdated = GetOutlookPropertyValueDateTime(match.OutlookContact, sync.OutlookPropertyNameUpdated);
                    DateTime? lastSynced = match.OutlookContact.UserProperties.LastSync;
                    if (lastSynced.HasValue)
                    {
                        //contact pair was syncronysed before.

                        //determine if google contact was updated since last sync

                        //lastSynced is stored without seconds. take that into account.
                        DateTime lastUpdatedOutlook = match.OutlookContact.LastModificationTime.AddSeconds(-match.OutlookContact.LastModificationTime.Second);
                        DateTime lastUpdatedGoogle = match.GoogleContact.Updated.AddSeconds(-match.GoogleContact.Updated.Second);

                        //check if both outlok and google contacts where updated sync last sync
                        if (lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance
                            && lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance)
                        {
                            //both contacts were updated.
                            //options: 1) ignore 2) loose one based on SyncOption
                            //throw new Exception("Both contacts were updated!");

                            switch (sync.SyncOption)
                            {
                                case SyncOption.MergeOutlookWins:
                                case SyncOption.OutlookToGoogleOnly:
                                    //overwrite google contact
                                    Logger.Log("Outlook and Google contact have been updated, Outlook contact is overwriting Google because of SyncOption " + sync.SyncOption + ": " + match.OutlookContact.FileAs + ".", EventType.Information);
                                    sync.UpdateContact(outlookContactItem, match.GoogleContact);
                                    break;
                                case SyncOption.MergeGoogleWins:
                                case SyncOption.GoogleToOutlookOnly:
                                    //overwrite outlook contact
                                    Logger.Log("Outlook and Google contact have been updated, Google contact is overwriting Outlook because of SyncOption " + sync.SyncOption + ": " + match.OutlookContact.FileAs + ".", EventType.Information);
                                    sync.UpdateContact(match.GoogleContact, outlookContactItem);
                                    break;
                                case SyncOption.MergePrompt:
                                    //promp for sync option
                                    if (sync.ConflictResolution != ConflictResolution.GoogleWinsAlways &&
                                        sync.ConflictResolution != ConflictResolution.OutlookWinsAlways &&
                                        sync.ConflictResolution != ConflictResolution.SkipAlways)
                                    {
                                        var r = new ConflictResolver();
                                        sync.ConflictResolution = r.Resolve(match, false);
                                    }
                                    switch (sync.ConflictResolution)
                                    {
                                        case ConflictResolution.Skip:
                                        case ConflictResolution.SkipAlways:
                                            Logger.Log(string.Format("User skipped contact ({0}).", match.ToString()), EventType.Information);
                                            sync.SkippedCount++;
                                            break;
                                        case ConflictResolution.OutlookWins:
                                        case ConflictResolution.OutlookWinsAlways:
                                            sync.UpdateContact(outlookContactItem, match.GoogleContact);
                                            break;
                                        case ConflictResolution.GoogleWins:
                                        case ConflictResolution.GoogleWinsAlways:
                                            sync.UpdateContact(match.GoogleContact, outlookContactItem);
                                            break;
                                        default:
                                            throw new ApplicationException("Cancelled");
                                    }
                                    break;
                            }
                            return;
                        }

                        //check if outlook contact was updated (with X second tolerance)
                        if (sync.SyncOption != SyncOption.GoogleToOutlookOnly &&
                            (lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance ||
                             lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                             sync.SyncOption == SyncOption.OutlookToGoogleOnly
                            )
                           )
                        {
                            //outlook contact was changed or changed Google contact will be overwritten

                            if (lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                                sync.SyncOption == SyncOption.OutlookToGoogleOnly)
                                Logger.Log("Google contact has been updated since last sync, but Outlook contact is overwriting Google because of SyncOption " + sync.SyncOption + ": " + match.OutlookContact.FileAs + ".", EventType.Information);

                            sync.UpdateContact(outlookContactItem, match.GoogleContact);

                            //at the moment use outlook as "master" source of contacts - in the event of a conflict google contact will be overwritten.
                            //TODO: control conflict resolution by SyncOption
                            return;
                        }

                        //check if google contact was updated (with X second tolerance)
                        if (sync.SyncOption != SyncOption.OutlookToGoogleOnly &&
                            (lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance ||
                             lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                             sync.SyncOption == SyncOption.GoogleToOutlookOnly
                            )
                           )
                        {
                            //google contact was changed or changed Outlook contact will be overwritten

                            if (lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                                sync.SyncOption == SyncOption.GoogleToOutlookOnly)
                                Logger.Log("Outlook contact has been updated since last sync, but Google contact is overwriting Outlook because of SyncOption " + sync.SyncOption + ": " + match.OutlookContact.FileAs + ".", EventType.Information);

                            sync.UpdateContact(match.GoogleContact, outlookContactItem);
                        }
                    }
                    else
                    {
                        //contacts were never synced.
                        //merge contacts.
                        switch (sync.SyncOption)
                        {
                            case SyncOption.MergeOutlookWins:
                            case SyncOption.OutlookToGoogleOnly:
                                //overwrite google contact
                                sync.UpdateContact(outlookContactItem, match.GoogleContact);
                                break;
                            case SyncOption.MergeGoogleWins:
                            case SyncOption.GoogleToOutlookOnly:
                                //overwrite outlook contact
                                sync.UpdateContact(match.GoogleContact, outlookContactItem);
                                break;
                            case SyncOption.MergePrompt:
                                //promp for sync option
                                if (sync.ConflictResolution != ConflictResolution.GoogleWinsAlways &&
                                    sync.ConflictResolution != ConflictResolution.OutlookWinsAlways &&
                                    sync.ConflictResolution != ConflictResolution.SkipAlways)
                                {
                                    var r = new ConflictResolver();
                                    sync.ConflictResolution = r.Resolve(match, true);
                                }
                                switch (sync.ConflictResolution)
                                {
                                    case ConflictResolution.Skip:
                                    case ConflictResolution.SkipAlways: //Keep both, Google AND Outlook
                                        sync.Contacts.Add(new ContactMatch(match.OutlookContact, null));
                                        sync.Contacts.Add(new ContactMatch(null, match.GoogleContact));
                                        break;
                                    case ConflictResolution.OutlookWins:
                                    case ConflictResolution.OutlookWinsAlways:
                                        sync.UpdateContact(outlookContactItem, match.GoogleContact);
                                        break;
                                    case ConflictResolution.GoogleWins:
                                    case ConflictResolution.GoogleWinsAlways:
                                        sync.UpdateContact(match.GoogleContact, outlookContactItem);
                                        break;
                                    default:
                                        throw new ApplicationException("Cancelled");
                                }
                                break;
                        }
                    }

                }
                else
                    throw new ArgumentNullException("ContactMatch has all peers null.");
            }
            catch (ArgumentNullException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                throw new Exception("Error syncing contact " + (match.OutlookContact != null ? match.OutlookContact.FileAs : match.GoogleContact.Title) + ": " + e.Message, e);
            }
            finally
            {
                if (outlookContactItem != null &&
                    match.OutlookContact != null)
                {
                    match.OutlookContact.Update(outlookContactItem, sync);
                    Marshal.ReleaseComObject(outlookContactItem);
                    outlookContactItem = null;
                }
            }
        }
        public static void SyncAppointment(AppointmentMatch match, Synchronizer sync)
        {
            if (match.GoogleAppointment == null && match.OutlookAppointment != null)
            {
                //no Google appointment
                string googleAppointmentId = AppointmentPropertiesUtils.GetOutlookGoogleAppointmentId(sync, match.OutlookAppointment);
                if (!string.IsNullOrEmpty(googleAppointmentId))
                {
                    //if (match.OutlookAppointment.IsRecurring && match.OutlookAppointment.RecurrenceState == Outlook.OlRecurrenceState.olApptMaster &&
                    //    (Syncronizer.MonthsInPast == 0 || new DateTime(DateTime.Now.AddMonths(-Syncronizer.MonthsInPast).Year, match.OutlookAppointment.End.Month, match.OutlookAppointment.End.Day) >= DateTime.Now.AddMonths(-Syncronizer.MonthsInPast)) &&
                    //    (Syncronizer.MonthsInFuture == 0 || new DateTime(DateTime.Now.AddMonths(-Syncronizer.MonthsInPast).Year, match.OutlookAppointment.Start.Month, match.OutlookAppointment.Start.Day) <= DateTime.Now.AddMonths(Syncronizer.MonthsInFuture))
                    //    ||
                    //    (Syncronizer.MonthsInPast == 0 || match.OutlookAppointment.End >= DateTime.Now.AddMonths(-Syncronizer.MonthsInPast)) &&
                    //    (Syncronizer.MonthsInFuture == 0 || match.OutlookAppointment.Start <= DateTime.Now.AddMonths(Syncronizer.MonthsInFuture))
                    //    )
                    //{

                        //Redundant check if exist, but in case an error occurred in MatchAppointments or not all appointments have been loaded (e.g. because months before/after constraint)
                        Event matchingGoogleAppointment = null;
                        if (sync.AllGoogleAppointments != null)
                            matchingGoogleAppointment = sync.GetGoogleAppointmentById(googleAppointmentId);
                        else
                            matchingGoogleAppointment = sync.LoadGoogleAppointments(googleAppointmentId, 0, 0, null, null);
                        if (matchingGoogleAppointment == null)
                        {
                            if (sync.SyncOption == SyncOption.OutlookToGoogleOnly || !sync.SyncDelete)
                                return;
                            else if (!sync.PromptDelete && match.OutlookAppointment.Recipients.Count == 0)
                                sync.DeleteOutlookResolution = DeleteResolution.DeleteOutlookAlways;
                            else if (sync.DeleteOutlookResolution != DeleteResolution.DeleteOutlookAlways &&
                                     sync.DeleteOutlookResolution != DeleteResolution.KeepOutlookAlways)
                            {
                                var r = new ConflictResolver();
                                sync.DeleteOutlookResolution = r.ResolveDelete(match.OutlookAppointment);
                            }
                            switch (sync.DeleteOutlookResolution)
                            {
                                case DeleteResolution.KeepOutlook:
                                case DeleteResolution.KeepOutlookAlways:
                                    AppointmentPropertiesUtils.ResetOutlookGoogleAppointmentId(sync, match.OutlookAppointment);
                                    break;
                                case DeleteResolution.DeleteOutlook:
                                case DeleteResolution.DeleteOutlookAlways:

                                    if (match.OutlookAppointment.Recipients.Count > 1)
                                    {
                                        //ToDo:Maybe find as better way, e.g. to ask the user, if he wants to overwrite the invalid appointment
                                        Logger.Log("Outlook Appointment not deleted, because multiple participants found,  invitation maybe NOT sent by Google: " + match.OutlookAppointment.Subject + " - " + match.OutlookAppointment.Start, EventType.Information);
                                        AppointmentPropertiesUtils.ResetOutlookGoogleAppointmentId(sync, match.OutlookAppointment);
                                        break;
                                    }
                                    else
                                        //Avoid recreating a GoogleAppointment already existing
                                        //==> Delete this OutlookAppointment instead if previous match existed but no match exists anymore
                                        return;
                                default:
                                    throw new ApplicationException("Cancelled");
                            }
                        }
                        else
                        {
                            sync.SkippedCount++;
                            match.GoogleAppointment = matchingGoogleAppointment;
                            Logger.Log("Outlook Appointment not deleted, because still existing on Google side, maybe because months restriction: " + match.OutlookAppointment.Subject + " - " + match.OutlookAppointment.Start, EventType.Information);
                            return;
                        }

                    }
                //}

                if (sync.SyncOption == SyncOption.GoogleToOutlookOnly)
                {
                    sync.SkippedCount++;
                    Logger.Log(string.Format("Outlook appointment not added to Google, because of SyncOption " + sync.SyncOption.ToString() + ": {0}", match.OutlookAppointment.Subject), EventType.Information);
                    return;
                }

                //create a Google appointment from Outlook appointment
                match.GoogleAppointment = Factory.NewEvent();

                sync.UpdateAppointment(match.OutlookAppointment, ref match.GoogleAppointment);

            }
            else if (match.OutlookAppointment == null && match.GoogleAppointment != null)
            {
                //no Outlook appointment
                string outlookAppointmenttId = AppointmentPropertiesUtils.GetGoogleOutlookAppointmentId(sync.SyncProfile,match.GoogleAppointment);
                if (!string.IsNullOrEmpty(outlookAppointmenttId))
                {
                    if (sync.SyncOption == SyncOption.GoogleToOutlookOnly || !sync.SyncDelete)
                        return;
                    else if (!sync.PromptDelete)
                        sync.DeleteGoogleResolution = DeleteResolution.DeleteGoogleAlways;
                    else if (sync.DeleteGoogleResolution != DeleteResolution.DeleteGoogleAlways &&
                             sync.DeleteGoogleResolution != DeleteResolution.KeepGoogleAlways)
                    {
                        var r = new ConflictResolver();
                        sync.DeleteGoogleResolution = r.ResolveDelete(match.GoogleAppointment);
                    }
                    switch (sync.DeleteGoogleResolution)
                    {
                        case DeleteResolution.KeepGoogle:
                        case DeleteResolution.KeepGoogleAlways:
                            AppointmentPropertiesUtils.ResetGoogleOutlookAppointmentId(sync.SyncProfile,match.GoogleAppointment);
                            break;
                        case DeleteResolution.DeleteGoogle:
                        case DeleteResolution.DeleteGoogleAlways:
                            //Avoid recreating a OutlookAppointment already existing
                            //==> Delete this googleAppointment instead if previous match existed but no match exists anymore
                            return;
                        default:
                            throw new ApplicationException("Cancelled");
                    }
                }

                if (sync.SyncOption == SyncOption.OutlookToGoogleOnly)
                {
                    sync.SkippedCount++;
                    Logger.Log(string.Format("Google appointment not added to Outlook, because of SyncOption " + sync.SyncOption.ToString() + ": {0}", match.GoogleAppointment.Summary), EventType.Information);
                    return;
                }

                //create a Outlook appointment from Google appointment
                match.OutlookAppointment = Synchronizer.CreateOutlookAppointmentItem(Synchronizer.SyncAppointmentsFolder);

                sync.UpdateAppointment(ref match.GoogleAppointment, match.OutlookAppointment, match.GoogleAppointmentExceptions);
            }
            else if (match.OutlookAppointment != null && match.GoogleAppointment != null)
            {
                //ToDo: Check how to overcome appointment recurrences, which need more than 60 seconds to update and therefore get updated again and again because of time tolerance 60 seconds violated again and again

                //merge appointment details

                //determine if this appointment pair were synchronized
                //DateTime? lastUpdated = GetOutlookPropertyValueDateTime(match.OutlookAppointment, sync.OutlookPropertyNameUpdated);
                DateTime? lastSynced = AppointmentPropertiesUtils.GetOutlookLastSync(sync, match.OutlookAppointment);
                if (lastSynced.HasValue)
                {
                    //appointment pair was syncronysed before.

                    //determine if Google appointment was updated since last sync

                    //lastSynced is stored without seconds. take that into account.
                    DateTime lastUpdatedOutlook = match.OutlookAppointment.LastModificationTime.AddSeconds(-match.OutlookAppointment.LastModificationTime.Second);
                    DateTime lastUpdatedGoogle = match.GoogleAppointment.Updated.Value.AddSeconds(-match.GoogleAppointment.Updated.Value.Second);
                    //consider GoogleAppointmentExceptions, because if they are updated, the master appointment doesn't have a new Saved TimeStamp
                    foreach (Event googleAppointment in match.GoogleAppointmentExceptions)
                    {
                        if (googleAppointment.Updated != null)//happens for cancelled events
                        {
                            DateTime lastUpdatedGoogleException = googleAppointment.Updated.Value.AddSeconds(-googleAppointment.Updated.Value.Second);
                            if (lastUpdatedGoogleException > lastUpdatedGoogle)
                                lastUpdatedGoogle = lastUpdatedGoogleException;
                        }
                        else if (match.OutlookAppointment.IsRecurring && match.OutlookAppointment.RecurrenceState == Outlook.OlRecurrenceState.olApptMaster)
                        {
                            Outlook.AppointmentItem outlookRecurrenceException = null;
                            try
                            {
                                 var slaveRecurrence = match.OutlookAppointment.GetRecurrencePattern();
                                if (googleAppointment.OriginalStartTime != null && !string.IsNullOrEmpty(googleAppointment.OriginalStartTime.Date))
                                    outlookRecurrenceException = slaveRecurrence.GetOccurrence(DateTime.Parse(googleAppointment.OriginalStartTime.Date));
                                else if (googleAppointment.OriginalStartTime != null && googleAppointment.OriginalStartTime.DateTime != null)
                                    outlookRecurrenceException = slaveRecurrence.GetOccurrence(googleAppointment.OriginalStartTime.DateTime.Value);
                            }
                            catch (Exception ignored)
                            {
                                Logger.Log("Google Appointment with OriginalEvent found, but Outlook occurrence not found: " + googleAppointment.Summary + " - " + googleAppointment.OriginalStartTime.DateTime + ": " + ignored, EventType.Debug);
                            }

                            if (outlookRecurrenceException != null && outlookRecurrenceException.MeetingStatus != Outlook.OlMeetingStatus.olMeetingCanceled)
                            {
                                lastUpdatedGoogle = DateTime.Now;
                                break; //no need to search further, already newest date set
                            }
                        }
                    }

                    //check if both outlok and Google appointments where updated sync last sync
                    if ((int)lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance
                        && (int)lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance)
                    {
                        //both appointments were updated.
                        //options: 1) ignore 2) loose one based on SyncOption
                        //throw new Exception("Both appointments were updated!");

                        switch (sync.SyncOption)
                        {
                            case SyncOption.MergeOutlookWins:
                            case SyncOption.OutlookToGoogleOnly:
                                //overwrite Google appointment
                                Logger.Log("Outlook and Google appointment have been updated, Outlook appointment is overwriting Google because of SyncOption " + sync.SyncOption + ": " + match.OutlookAppointment.Subject + ".", EventType.Information);
                                sync.UpdateAppointment(match.OutlookAppointment, ref match.GoogleAppointment);
                                break;
                            case SyncOption.MergeGoogleWins:
                            case SyncOption.GoogleToOutlookOnly:
                                //overwrite outlook appointment
                                Logger.Log("Outlook and Google appointment have been updated, Google appointment is overwriting Outlook because of SyncOption " + sync.SyncOption + ": " + match.GoogleAppointment.Summary + ".", EventType.Information);
                                sync.UpdateAppointment(ref match.GoogleAppointment, match.OutlookAppointment, match.GoogleAppointmentExceptions);
                                break;
                            case SyncOption.MergePrompt:
                                //promp for sync option
                                if (sync.ConflictResolution != ConflictResolution.GoogleWinsAlways &&
                                    sync.ConflictResolution != ConflictResolution.OutlookWinsAlways &&
                                    sync.ConflictResolution != ConflictResolution.SkipAlways)
                                {
                                    var r = new ConflictResolver();
                                    sync.ConflictResolution = r.Resolve(match.OutlookAppointment, match.GoogleAppointment, sync, false);
                                }
                                switch (sync.ConflictResolution)
                                {
                                    case ConflictResolution.Skip:
                                    case ConflictResolution.SkipAlways:
                                        Logger.Log(string.Format("User skipped appointment ({0}).", match.ToString()), EventType.Information);
                                        sync.SkippedCount++;
                                        break;
                                    case ConflictResolution.OutlookWins:
                                    case ConflictResolution.OutlookWinsAlways:
                                        sync.UpdateAppointment(match.OutlookAppointment, ref match.GoogleAppointment);
                                        break;
                                    case ConflictResolution.GoogleWins:
                                    case ConflictResolution.GoogleWinsAlways:
                                        sync.UpdateAppointment(ref match.GoogleAppointment, match.OutlookAppointment, match.GoogleAppointmentExceptions);
                                        break;
                                    default:
                                        throw new ApplicationException("Cancelled");
                                }
                                break;
                        }
                        return;
                    }

                    //check if Outlook appointment was updated (with X second tolerance)
                    if (sync.SyncOption != SyncOption.GoogleToOutlookOnly &&
                        ((int)lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance ||
                         (int)lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                         sync.SyncOption == SyncOption.OutlookToGoogleOnly
                        )
                       )
                    {
                        //Outlook appointment was changed or changed Google appointment will be overwritten

                        if ((int)lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                            sync.SyncOption == SyncOption.OutlookToGoogleOnly)
                            Logger.Log("Google appointment has been updated since last sync, but Outlook appointment is overwriting Google because of SyncOption " + sync.SyncOption + ": " + match.OutlookAppointment.Subject + ".", EventType.Information);

                        sync.UpdateAppointment(match.OutlookAppointment, ref match.GoogleAppointment);

                        //at the moment use Outlook as "master" source of appointments - in the event of a conflict Google appointment will be overwritten.
                        //TODO: control conflict resolution by SyncOption
                        return;
                    }

                    //check if Google appointment was updated (with X second tolerance)
                    if (sync.SyncOption != SyncOption.OutlookToGoogleOnly &&
                        ((int)lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance ||
                         (int)lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                         sync.SyncOption == SyncOption.GoogleToOutlookOnly
                        )
                       )
                    {
                        //google appointment was changed or changed Outlook appointment will be overwritten

                        if ((int)lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                            sync.SyncOption == SyncOption.GoogleToOutlookOnly)
                            Logger.Log("Outlook appointment has been updated since last sync, but Google appointment is overwriting Outlook because of SyncOption " + sync.SyncOption + ": " + match.OutlookAppointment.Subject + ".", EventType.Information);

                        sync.UpdateAppointment(ref match.GoogleAppointment, match.OutlookAppointment, match.GoogleAppointmentExceptions);
                    }
                }
                else
                {
                    //appointments were never synced.
                    //merge appointments.
                    switch (sync.SyncOption)
                    {
                        case SyncOption.MergeOutlookWins:
                        case SyncOption.OutlookToGoogleOnly:
                            //overwrite Google appointment
                            sync.UpdateAppointment(match.OutlookAppointment, ref match.GoogleAppointment);
                            break;
                        case SyncOption.MergeGoogleWins:
                        case SyncOption.GoogleToOutlookOnly:
                            //overwrite outlook appointment
                            sync.UpdateAppointment(ref match.GoogleAppointment, match.OutlookAppointment, match.GoogleAppointmentExceptions);
                            break;
                        case SyncOption.MergePrompt:
                            //promp for sync option
                            if (sync.ConflictResolution != ConflictResolution.GoogleWinsAlways &&
                                sync.ConflictResolution != ConflictResolution.OutlookWinsAlways &&
                                    sync.ConflictResolution != ConflictResolution.SkipAlways)
                            {
                                var r = new ConflictResolver();
                                sync.ConflictResolution = r.Resolve(match.OutlookAppointment, match.GoogleAppointment, sync, true);
                            }
                            switch (sync.ConflictResolution)
                            {
                                case ConflictResolution.Skip:
                                case ConflictResolution.SkipAlways: //Keep both, Google AND Outlook
                                    sync.Appointments.Add(new AppointmentMatch(match.OutlookAppointment, null));
                                    sync.Appointments.Add(new AppointmentMatch(null, match.GoogleAppointment));
                                    break;
                                case ConflictResolution.OutlookWins:
                                case ConflictResolution.OutlookWinsAlways:
                                    sync.UpdateAppointment(match.OutlookAppointment, ref match.GoogleAppointment);
                                    break;
                                case ConflictResolution.GoogleWins:
                                case ConflictResolution.GoogleWinsAlways:
                                    sync.UpdateAppointment(ref match.GoogleAppointment, match.OutlookAppointment, match.GoogleAppointmentExceptions);
                                    break;
                                default:
                                    throw new ApplicationException("Canceled");
                            }
                            break;
                    }
                }

            }
            else
                throw new ArgumentNullException("AppointmenttMatch has all peers null.");
            //}
            //finally
            //{
            //if (outlookAppointment != null &&
            //    match.OutlookAppointment != null)
            //{
            //    match.OutlookAppointment.Update(outlookAppointment, sync);
            //    Marshal.ReleaseComObject(outlookAppointment);
            //    outlookAppointment = null;
            //}
            //}
        }
        /// <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(Synchronizer 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;

                try
                {
                    ola = sync.OutlookAppointments[i] as Outlook.AppointmentItem;

                    //For debugging:
                    //if (ola.Subject == "Flex Pilot - Latest Status") // - 14.07.2014 11:30:00
                    //    throw new Exception("Debugging: Flex Pilot - Latest Status");

                    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 (Synchronizer.MonthsInPast > 0 &&
                             (ola.IsRecurring && ola.GetRecurrencePattern().PatternEndDate < DateTime.Now.AddMonths(-Synchronizer.MonthsInPast) ||
                             !ola.IsRecurring && ola.End < DateTime.Now.AddMonths(-Synchronizer.MonthsInPast)) ||
                        Synchronizer.MonthsInFuture > 0 &&
                             (ola.IsRecurring && ola.GetRecurrencePattern().PatternStartDate > DateTime.Now.AddMonths(Synchronizer.MonthsInFuture) ||
                             !ola.IsRecurring && ola.Start > DateTime.Now.AddMonths(Synchronizer.MonthsInFuture)))
                    {
                        Logger.Log("Skipping Outlook appointment because it is out of months range to sync:" + ola.Subject + " - " + ola.Start, EventType.Debug);
                        continue;
                    }
                    //else if (ola.Subject != "Business Trip")
                    //{//Only for debugging purposes, please comment if not needed
                    //    Logger.Log("Skipping Outlook appointment because of DEBUGGING:" + ola.Subject + " - " + ola.Start, EventType.Error);
                    //    continue;
                    //}

                }
                catch (Exception ex)
                {
                    //this is needed because some appointments throw exceptions
                    Logger.Log("Accessing Outlook appointment threw and exception. Skipping: " + ex.Message, EventType.Warning);
                    sync.SkippedCount++;
                    sync.SkippedCountNotMatches++;
                    continue;
                }

                //try
                //{

                if (NotificationReceived != null)
                    NotificationReceived(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
                Outlook.ItemProperties userProperties = ola.ItemProperties;
                Outlook.ItemProperty idProp = userProperties[sync.OutlookPropertyNameId];
                try
                {
                    if (idProp != null)
                    {
                        string googleAppointmentId = string.Copy((string)idProp.Value);
                        Event foundAppointment = sync.GetGoogleAppointmentById(googleAppointmentId);
                        var match = new AppointmentMatch(ola, null);

                        if (foundAppointment != null && !foundAppointment.Status.Equals("cancelled"))
                        {
                            //we found a match by google id, that is not deleted or cancelled yet

                            //ToDo: For an unknown reason, some appointments are duplicate in GoogleAppointments, therefore remove all duplicates before continuing
                            while (foundAppointment != null)
                            {
                                match.AddGoogleAppointment(foundAppointment);
                                result.Add(match);
                                //Remove the appointment from the list to not sync it twice
                                if (sync.GoogleAppointments.Contains(foundAppointment))
                                {
                                    sync.GoogleAppointments.Remove(foundAppointment);
                                    foundAppointment = sync.GetGoogleAppointmentById(googleAppointmentId);
                                }
                                else
                                    foundAppointment = null;
                            }

                        }
                        else
                        {

                            OutlookAppointmentsWithoutSyncId.Add(ola);
                        }

                    }
                    else
                        OutlookAppointmentsWithoutSyncId.Add(ola);
                }
                finally
                {
                    if (idProp != null)
                        Marshal.ReleaseComObject(idProp);
                    Marshal.ReleaseComObject(userProperties);
                }

            }
            #endregion
            #region Match the remaining appointments by properties

            for (int i = 0; i < OutlookAppointmentsWithoutSyncId.Count; i++)
            {
                Outlook.AppointmentItem ola = OutlookAppointmentsWithoutSyncId[i];

                if (NotificationReceived != null)
                    NotificationReceived(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 googleAppointment = sync.GoogleAppointments[j];
                    // only match if there is a appointment targetBody, else
                    // a matching Google appointment will be created at each sync
                    if (!googleAppointment.Status.Equals("cancelled") && ola.Subject == googleAppointment.Summary && googleAppointment.Start.DateTime != null && ola.Start == googleAppointment.Start.DateTime)
                    {
                        match.AddGoogleAppointment(googleAppointment);
                        sync.GoogleAppointments.Remove(googleAppointment);

                        //ToDo: For an unknown reason, some appointments are duplicate in GoogleAppointments, therefore remove all duplicates before continuing
                        Event foundAppointment = sync.GetGoogleAppointmentById(AppointmentPropertiesUtils.GetGoogleId(googleAppointment));
                        while (foundAppointment != null)
                        {
                            //we found a match by google id, that is not deleted yet
                            match.AddGoogleAppointment(foundAppointment);
                            //Remove the appointment from the list to not sync it twice
                            if (sync.GoogleAppointments.Contains(foundAppointment))
                            {
                                sync.GoogleAppointments.Remove(foundAppointment);
                                foundAppointment = sync.GetGoogleAppointmentById(AppointmentPropertiesUtils.GetGoogleId(googleAppointment));
                            }
                            else
                                foundAppointment = null;
                        }
                    }

                }

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

                //For debugging:
                //if (googleAppointment.Summary == "Flex Pilot - Latest Status")
                //    throw new Exception("Debugging: Flex Pilot - Latest Status");

                if (NotificationReceived != null)
                    NotificationReceived(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 + " - " + Synchronizer.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 + " - " + Synchronizer.GetTime(googleAppointment), EventType.Warning);
                }
                //else if (googleAppointment.Summary != "Business Trip")
                //{//Only for debugging purposes, please comment if not needed
                //    Logger.Log("Skipping Google appointment because of DEBUGGING:" + googleAppointment.Summary + " - " + googleAppointment.Times[0].StartTime, EventType.Error);
                //    continue;
                //}
                else
                {
                    Logger.Log(string.Format("No match found for Google appointment ({0}) => {1}", googleAppointment.Summary + " - " + Synchronizer.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 googleAppointment = googleAppointmentExceptions[i];
                if (NotificationReceived != null)
                    NotificationReceived(String.Format("Adding Google appointment exception {0} of {1} ...", i + 1, googleAppointmentExceptions.Count, googleAppointment.Summary + " - " + Synchronizer.GetTime(googleAppointment)));

                //Search for original recurrent event in matches
                //AtomId atomId = new AtomId(googleAppointment.Id.AbsoluteUri.Substring(0, googleAppointment.Id.AbsoluteUri.LastIndexOf("/") + 1) + googleAppointment.RecurringEventId);
                bool found = false;
                foreach (AppointmentMatch match in result)
                {
                    if (match.GoogleAppointment != null && googleAppointment.RecurringEventId.Equals(match.GoogleAppointment.Id))
                    {
                        match.GoogleAppointmentExceptions.Add(googleAppointment);
                        found = true;
                        break;
                    }
                }

                if (!found)
                    Logger.Log(string.Format("No match found for Google appointment exception: {0}", googleAppointment.Summary + " - " + Synchronizer.GetTime(googleAppointment)), EventType.Debug);
            }

            return result;
        }
Esempio n. 15
0
        /// <summary>
        /// Matches outlook and google note by a) google id b) properties.
        /// </summary>
        /// <param name="sync">Syncronizer instance</param>
        /// <returns>Returns a list of match pairs (outlook note + google note) for all note. Those that weren't matche will have it's peer set to null</returns>
        public static List <NoteMatch> MatchNotes(Synchronizer sync)
        {
            Logger.Log("Matching Outlook and Google notes...", EventType.Information);
            var result = new List <NoteMatch>();

            //string duplicateGoogleMatches = "";
            //string duplicateOutlookNotes = "";
            //sync.GoogleNoteDuplicates = new Collection<NoteMatch>();
            //sync.OutlookNoteDuplicates = new Collection<NoteMatch>();

            //for each outlook note try to get google note id from user properties
            //if no match - try to match by properties
            //if no match - create a new match pair without google note.
            //foreach (Outlook._NoteItem olc in outlookNotes)
            var outlookNotesWithoutOutlookGoogleId = new Collection <Outlook.NoteItem>();

            #region Match first all outlookNotes by sync id
            for (int i = 1; i <= sync.OutlookNotes.Count; i++)
            {
                Outlook.NoteItem oln;
                try
                {
                    oln = sync.OutlookNotes[i] as Outlook.NoteItem;
                    if (oln == null || string.IsNullOrEmpty(oln.Body))
                    {
                        Logger.Log("Empty Outlook note found. Skipping", EventType.Warning);
                        sync.SkippedCount++;
                        sync.SkippedCountNotMatches++;
                        continue;
                    }
                }
                catch (Exception ex)
                {
                    //this is needed because some notes throw exceptions
                    Logger.Log("Accessing Outlook note threw and exception. Skipping: " + ex.Message, EventType.Warning);
                    sync.SkippedCount++;
                    sync.SkippedCountNotMatches++;
                    continue;
                }

                //try
                //{

                if (NotificationReceived != null)
                {
                    NotificationReceived(String.Format("Matching note {0} of {1} by id: {2} ...", i, sync.OutlookNotes.Count, oln.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.
                //OutlookNoteInfo olci = new OutlookNoteInfo(oln, sync);

                //try to match this note to one of google notes
                Outlook.ItemProperties userProperties = oln.ItemProperties;
                Outlook.ItemProperty   idProp         = userProperties[sync.OutlookPropertyNameId];
                try
                {
                    if (idProp != null)
                    {
                        string   googleNoteId = string.Copy((string)idProp.Value);
                        Document foundNote    = sync.GetGoogleNoteById(googleNoteId);
                        var      match        = new NoteMatch(oln, null);

                        //Check first, that this is not a duplicate
                        //e.g. by copying an existing Outlook note
                        //or by Outlook checked this as duplicate, but the user selected "Add new"
                        //    Collection<OutlookNoteInfo> duplicates = sync.OutlookNoteByProperty(sync.OutlookPropertyNameId, googleNoteId);
                        //    if (duplicates.Count > 1)
                        //    {
                        //        foreach (OutlookNoteInfo duplicate in duplicates)
                        //        {
                        //            if (!string.IsNullOrEmpty(googleNoteId))
                        //            {
                        //                Logger.Log("Duplicate Outlook note found, resetting match and try to match again: " + duplicate.FileAs, EventType.Warning);
                        //                idProp.Value = "";
                        //            }
                        //        }

                        //        if (foundNote != null && !foundNote.Deleted)
                        //        {
                        //            NotePropertiesUtils.ResetGoogleOutlookNoteId(sync.SyncProfile, foundNote);
                        //        }

                        //        outlookNotesWithoutOutlookGoogleId.Add(olci);
                        //    }
                        //    else
                        //    {

                        if (foundNote != null)
                        {
                            //we found a match by google id, that is not deleted yet
                            match.AddGoogleNote(foundNote);
                            result.Add(match);
                            //Remove the note from the list to not sync it twice
                            sync.GoogleNotes.Remove(foundNote);
                        }
                        else
                        {
                            ////If no match found, is the note either deleted on Google side or was a copy on Outlook side
                            ////If it is a copy on Outlook side, the idProp.Value must be emptied to assure, the note is created on Google side and not deleted on Outlook side
                            ////bool matchIsDuplicate = false;
                            //foreach (NoteMatch existingMatch in result)
                            //{
                            //    if (existingMatch.OutlookNote.UserProperties[sync.OutlookPropertyNameId].Value.Equals(idProp.Value))
                            //    {
                            //        //matchIsDuplicate = true;
                            //        idProp.Value = "";
                            //        break;
                            //    }

                            //}
                            outlookNotesWithoutOutlookGoogleId.Add(oln);

                            //if (!matchIsDuplicate)
                            //    result.Add(match);
                        }
                        //    }
                    }
                    else
                    {
                        outlookNotesWithoutOutlookGoogleId.Add(oln);
                    }
                }
                finally
                {
                    if (idProp != null)
                    {
                        Marshal.ReleaseComObject(idProp);
                    }
                    Marshal.ReleaseComObject(userProperties);
                }
                //}

                //finally
                //{
                //    Marshal.ReleaseComObject(oln);
                //    oln = null;
                //}
            }
            #endregion
            #region Match the remaining notes by properties

            for (int i = 0; i < outlookNotesWithoutOutlookGoogleId.Count; i++)
            {
                Outlook.NoteItem oln = outlookNotesWithoutOutlookGoogleId[i];

                if (NotificationReceived != null)
                {
                    NotificationReceived(String.Format("Matching note {0} of {1} by unique properties: {2} ...", i + 1, outlookNotesWithoutOutlookGoogleId.Count, oln.Subject));
                }

                //no match found by id => match by subject/title
                //create a default match pair with just outlook note.
                var match = new NoteMatch(oln, null);

                //foreach google contact try to match and create a match pair if found some match(es)
                for (int j = sync.GoogleNotes.Count - 1; j >= 0; j--)
                {
                    Document entry = sync.GoogleNotes[j];

                    string body = NotePropertiesUtils.GetBody(sync, entry);
                    if (!string.IsNullOrEmpty(body))
                    {
                        body = body.Replace("\r\n", string.Empty).Replace(" ", string.Empty).Replace("�", string.Empty);
                    }

                    string outlookBody = null;
                    if (!string.IsNullOrEmpty(oln.Body))
                    {
                        outlookBody = oln.Body.Replace("\t", "        ").Replace("\r\n", string.Empty).Replace(" ", string.Empty).Replace("�", string.Empty);
                    }

                    // only match if there is a note body, else
                    // a matching google note will be created at each sync
                    if (!string.IsNullOrEmpty(outlookBody) && !string.IsNullOrEmpty(body) && outlookBody.Equals(body, StringComparison.InvariantCultureIgnoreCase)
                        )
                    {
                        match.AddGoogleNote(entry);
                        sync.GoogleNotes.Remove(entry);
                    }
                }

                #region find duplicates not needed now
                //if (match.GoogleNote == null && match.OutlookNote != null)
                //{//If GoogleNote, we have to expect a conflict because of Google insert of duplicates
                //    foreach (Note entry in sync.GoogleNotes)
                //    {
                //        if (!string.IsNullOrEmpty(olc.FullName) && olc.FullName.Equals(entry.Title, StringComparison.InvariantCultureIgnoreCase) ||
                //         !string.IsNullOrEmpty(olc.FileAs) && olc.FileAs.Equals(entry.Title, StringComparison.InvariantCultureIgnoreCase) ||
                //         !string.IsNullOrEmpty(olc.Email1Address) && FindEmail(olc.Email1Address, entry.Emails) != null ||
                //         !string.IsNullOrEmpty(olc.Email2Address) && FindEmail(olc.Email1Address, entry.Emails) != null ||
                //         !string.IsNullOrEmpty(olc.Email3Address) && FindEmail(olc.Email1Address, entry.Emails) != null ||
                //         olc.MobileTelephoneNumber != null && FindPhone(olc.MobileTelephoneNumber, entry.Phonenumbers) != null
                //         )
                //    }
                //// check for each email 1,2 and 3 if a duplicate exists with same email, because Google doesn't like inserting new notes with same email
                //Collection<Outlook.NoteItem> duplicates1 = new Collection<Outlook.NoteItem>();
                //Collection<Outlook.NoteItem> duplicates2 = new Collection<Outlook.NoteItem>();
                //Collection<Outlook.NoteItem> duplicates3 = new Collection<Outlook.NoteItem>();
                //if (!string.IsNullOrEmpty(olc.Email1Address))
                //    duplicates1 = sync.OutlookNoteByEmail(olc.Email1Address);

                //if (!string.IsNullOrEmpty(olc.Email2Address))
                //    duplicates2 = sync.OutlookNoteByEmail(olc.Email2Address);

                //if (!string.IsNullOrEmpty(olc.Email3Address))
                //    duplicates3 = sync.OutlookNoteByEmail(olc.Email3Address);


                //if (duplicates1.Count > 1 || duplicates2.Count > 1 || duplicates3.Count > 1)
                //{
                //    if (string.IsNullOrEmpty(duplicatesEmailList))
                //        duplicatesEmailList = "Outlook notes with the same email have been found and cannot be synchronized. Please delete duplicates of:";

                //    if (duplicates1.Count > 1)
                //        foreach (Outlook.NoteItem duplicate in duplicates1)
                //        {
                //            string str = olc.FileAs + " (" + olc.Email1Address + ")";
                //            if (!duplicatesEmailList.Contains(str))
                //                duplicatesEmailList += Environment.NewLine + str;
                //        }
                //    if (duplicates2.Count > 1)
                //        foreach (Outlook.NoteItem duplicate in duplicates2)
                //        {
                //            string str = olc.FileAs + " (" + olc.Email2Address + ")";
                //            if (!duplicatesEmailList.Contains(str))
                //                duplicatesEmailList += Environment.NewLine + str;
                //        }
                //    if (duplicates3.Count > 1)
                //        foreach (Outlook.NoteItem duplicate in duplicates3)
                //        {
                //            string str = olc.FileAs + " (" + olc.Email3Address + ")";
                //            if (!duplicatesEmailList.Contains(str))
                //                duplicatesEmailList += Environment.NewLine + str;
                //        }
                //    continue;
                //}
                //else if (!string.IsNullOrEmpty(olc.Email1Address))
                //{
                //    NoteMatch dup = result.Find(delegate(NoteMatch match)
                //    {
                //        return match.OutlookNote != null && match.OutlookNote.Email1Address == olc.Email1Address;
                //    });
                //    if (dup != null)
                //    {
                //        Logger.Log(string.Format("Duplicate note found by Email1Address ({0}). Skipping", olc.FileAs), EventType.Information);
                //        continue;
                //    }
                //}

                //// check for unique mobile phone, because this sync tool uses the also the mobile phone to identify matches between Google and Outlook
                //Collection<Outlook.NoteItem> duplicatesMobile = new Collection<Outlook.NoteItem>();
                //if (!string.IsNullOrEmpty(olc.MobileTelephoneNumber))
                //    duplicatesMobile = sync.OutlookNoteByProperty("MobileTelephoneNumber", olc.MobileTelephoneNumber);

                //if (duplicatesMobile.Count > 1)
                //{
                //    if (string.IsNullOrEmpty(duplicatesMobileList))
                //        duplicatesMobileList = "Outlook notes with the same mobile phone have been found and cannot be synchronized. Please delete duplicates of:";

                //    foreach (Outlook.NoteItem duplicate in duplicatesMobile)
                //    {
                //        sync.OutlookNoteDuplicates.Add(olc);
                //        string str = olc.FileAs + " (" + olc.MobileTelephoneNumber + ")";
                //        if (!duplicatesMobileList.Contains(str))
                //            duplicatesMobileList += Environment.NewLine + str;
                //    }
                //    continue;
                //}
                //else if (!string.IsNullOrEmpty(olc.MobileTelephoneNumber))
                //{
                //    NoteMatch dup = result.Find(delegate(NoteMatch match)
                //    {
                //        return match.OutlookNote != null && match.OutlookNote.MobileTelephoneNumber == olc.MobileTelephoneNumber;
                //    });
                //    if (dup != null)
                //    {
                //        Logger.Log(string.Format("Duplicate note found by MobileTelephoneNumber ({0}). Skipping", olc.FileAs), EventType.Information);
                //        continue;
                //    }
                //}

                #endregion

                //    if (match.AllGoogleNoteMatches == null || match.AllGoogleNoteMatches.Count == 0)
                //    {
                //        //Check, if this Outlook note has a match in the google duplicates
                //        bool duplicateFound = false;
                //        foreach (NoteMatch duplicate in sync.GoogleNoteDuplicates)
                //        {
                //            if (duplicate.AllGoogleNoteMatches.Count > 0 &&
                //                (!string.IsNullOrEmpty(olci.FileAs) && !string.IsNullOrEmpty(duplicate.AllGoogleNoteMatches[0].Title) && olci.FileAs.Equals(duplicate.AllGoogleNoteMatches[0].Title.Replace("\r\n", "\n").Replace("\n", "\r\n"), StringComparison.InvariantCultureIgnoreCase) ||  //Replace twice to not replace a \r\n by \r\r\n. This is necessary because \r\n are saved as \n only to Google
                //                 !string.IsNullOrEmpty(olci.FileAs) && !string.IsNullOrEmpty(duplicate.AllGoogleNoteMatches[0].Name.FullName) && olci.FileAs.Equals(duplicate.AllGoogleNoteMatches[0].Name.FullName.Replace("\r\n", "\n").Replace("\n", "\r\n"), StringComparison.InvariantCultureIgnoreCase) ||
                //                 !string.IsNullOrEmpty(olci.FullName) && !string.IsNullOrEmpty(duplicate.AllGoogleNoteMatches[0].Name.FullName) && olci.FullName.Equals(duplicate.AllGoogleNoteMatches[0].Name.FullName.Replace("\r\n", "\n").Replace("\n", "\r\n"), StringComparison.InvariantCultureIgnoreCase) ||
                //                 !string.IsNullOrEmpty(olci.Email1Address) && duplicate.AllGoogleNoteMatches[0].Emails.Count > 0 && olci.Email1Address.Equals(duplicate.AllGoogleNoteMatches[0].Emails[0].Address, StringComparison.InvariantCultureIgnoreCase) ||
                //                //!string.IsNullOrEmpty(olci.Email2Address) && FindEmail(olci.Email2Address, duplicate.AllGoogleNoteMatches[0].Emails) != null ||
                //                //!string.IsNullOrEmpty(olci.Email3Address) && FindEmail(olci.Email3Address, duplicate.AllGoogleNoteMatches[0].Emails) != null ||
                //                 olci.MobileTelephoneNumber != null && FindPhone(olci.MobileTelephoneNumber, duplicate.AllGoogleNoteMatches[0].Phonenumbers) != null ||
                //                 !string.IsNullOrEmpty(olci.FileAs) && string.IsNullOrEmpty(duplicate.AllGoogleNoteMatches[0].Title) && duplicate.AllGoogleNoteMatches[0].Organizations.Count > 0 && olci.FileAs.Equals(duplicate.AllGoogleNoteMatches[0].Organizations[0].Name, StringComparison.InvariantCultureIgnoreCase)
                //                ) ||
                //                !string.IsNullOrEmpty(olci.FileAs) && olci.FileAs.Equals(duplicate.OutlookNote.Subject, StringComparison.InvariantCultureIgnoreCase) ||
                //                !string.IsNullOrEmpty(olci.FullName) && olci.FullName.Equals(duplicate.OutlookNote.FullName, StringComparison.InvariantCultureIgnoreCase) ||
                //                !string.IsNullOrEmpty(olci.Email1Address) && olci.Email1Address.Equals(duplicate.OutlookNote.Email1Address, StringComparison.InvariantCultureIgnoreCase) ||
                //                //                                              olci.Email1Address.Equals(duplicate.OutlookNote.Email2Address, StringComparison.InvariantCultureIgnoreCase) ||
                //                //                                              olci.Email1Address.Equals(duplicate.OutlookNote.Email3Address, StringComparison.InvariantCultureIgnoreCase)
                //                //                                              ) ||
                //                //!string.IsNullOrEmpty(olci.Email2Address) && (olci.Email2Address.Equals(duplicate.OutlookNote.Email1Address, StringComparison.InvariantCultureIgnoreCase) ||
                //                //                                              olci.Email2Address.Equals(duplicate.OutlookNote.Email2Address, StringComparison.InvariantCultureIgnoreCase) ||
                //                //                                              olci.Email2Address.Equals(duplicate.OutlookNote.Email3Address, StringComparison.InvariantCultureIgnoreCase)
                //                //                                              ) ||
                //                //!string.IsNullOrEmpty(olci.Email3Address) && (olci.Email3Address.Equals(duplicate.OutlookNote.Email1Address, StringComparison.InvariantCultureIgnoreCase) ||
                //                //                                              olci.Email3Address.Equals(duplicate.OutlookNote.Email2Address, StringComparison.InvariantCultureIgnoreCase) ||
                //                //                                              olci.Email3Address.Equals(duplicate.OutlookNote.Email3Address, StringComparison.InvariantCultureIgnoreCase)
                //                //                                              ) ||
                //                olci.MobileTelephoneNumber != null && olci.MobileTelephoneNumber.Equals(duplicate.OutlookNote.MobileTelephoneNumber) ||
                //                !string.IsNullOrEmpty(olci.FileAs) && string.IsNullOrEmpty(duplicate.GoogleNote.Title) && duplicate.GoogleNote.Organizations.Count > 0 && olci.FileAs.Equals(duplicate.GoogleNote.Organizations[0].Name, StringComparison.InvariantCultureIgnoreCase)
                //               )
                //            {
                //                duplicateFound = true;
                //                sync.OutlookNoteDuplicates.Add(match);
                //                if (string.IsNullOrEmpty(duplicateOutlookNotes))
                //                    duplicateOutlookNotes = "Outlook note found that has been already identified as duplicate Google note (either same email, Mobile or FullName) and cannot be synchronized. Please delete or resolve duplicates of:";

                //                string str = olci.FileAs + " (" + olci.Email1Address + ", " + olci.MobileTelephoneNumber + ")";
                //                if (!duplicateOutlookNotes.Contains(str))
                //                    duplicateOutlookNotes += Environment.NewLine + str;
                //            }
                //        }

                //        if (!duplicateFound)
                if (match.GoogleNote == null)
                {
                    Logger.Log(string.Format("No match found for outlook note ({0}) => {1}", match.OutlookNote.Subject, (NotePropertiesUtils.GetOutlookGoogleNoteId(sync, match.OutlookNote) != null ? "Delete from Outlook" : "Add to Google")), EventType.Information);
                }

                //    }
                //    else
                //    {
                //        //Remember Google duplicates to later react to it when resetting matches or syncing
                //        //ResetMatches: Also reset the duplicates
                //        //Sync: Skip duplicates (don't sync duplicates to be fail safe)
                //        if (match.AllGoogleNoteMatches.Count > 1)
                //        {
                //            sync.GoogleNoteDuplicates.Add(match);
                //            foreach (Note entry in match.AllGoogleNoteMatches)
                //            {
                //                //Create message for duplicatesFound exception
                //                if (string.IsNullOrEmpty(duplicateGoogleMatches))
                //                    duplicateGoogleMatches = "Outlook notes matching with multiple Google notes have been found (either same email, Mobile, FullName or company) and cannot be synchronized. Please delete or resolve duplicates of:";

                //                string str = olci.FileAs + " (" + olci.Email1Address + ", " + olci.MobileTelephoneNumber + ")";
                //                if (!duplicateGoogleMatches.Contains(str))
                //                    duplicateGoogleMatches += Environment.NewLine + str;
                //            }
                //        }



                //    }

                result.Add(match);
            }
            #endregion

            //if (!string.IsNullOrEmpty(duplicateGoogleMatches) || !string.IsNullOrEmpty(duplicateOutlookNotes))
            //    duplicatesFound = new DuplicateDataException(duplicateGoogleMatches + Environment.NewLine + Environment.NewLine + duplicateOutlookNotes);
            //else
            //    duplicatesFound = null;

            //return result;

            //for each google note that's left (they will be nonmatched) create a new match pair without outlook note.
            for (int i = 0; i < sync.GoogleNotes.Count; i++)
            {
                Document entry = sync.GoogleNotes[i];
                if (NotificationReceived != null)
                {
                    NotificationReceived(String.Format("Adding new Google note {0} of {1} by unique properties: {2} ...", i + 1, sync.GoogleNotes.Count, entry.Title));
                }

                //string googleOutlookId = NotePropertiesUtils.GetGoogleOutlookNoteId(sync.SyncProfile, entry);
                //if (!String.IsNullOrEmpty(googleOutlookId) && skippedOutlookIds.Contains(googleOutlookId))
                //{
                //    Logger.Log("Skipped GoogleNote because Outlook note couldn't be matched because of previous problem (see log): " + entry.Title, EventType.Warning);
                //}
                //else
                if (string.IsNullOrEmpty(entry.Title) && string.IsNullOrEmpty(entry.Content))
                {
                    // no title or content
                    sync.SkippedCount++;
                    sync.SkippedCountNotMatches++;
                    Logger.Log("Skipped GoogleNote because no unique property found (Title or Content):" + entry.Title, EventType.Warning);
                }
                else
                {
                    Logger.Log(string.Format("No match found for Google note ({0}) => {1}", entry.Title, (NotePropertiesUtils.NoteFileExists(entry.Id, sync.SyncProfile) ? "Delete from Google" : "Add to Outlook")), EventType.Information);
                    var match = new NoteMatch(null, entry);
                    result.Add(match);
                }
            }
            return(result);
        }
Esempio n. 16
0
        public static bool SaveGooglePhoto(Synchronizer sync, Contact googleContact, Image image)
        {
            if (googleContact.ContactEntry.PhotoUri == null)
                throw new Exception("Must reload contact from google.");

            try
            {
                WebClient client = new WebClient();
                //client.Headers.Add(HttpRequestHeader.Authorization, "GoogleLogin auth=" + sync.ContactsRequest.Service.QueryClientLoginToken());
                client.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + sync.ContactsRequest.Settings.OAuth2Parameters.AccessToken);
                client.Headers.Add(HttpRequestHeader.ContentType, "image/*");
                Bitmap pic = new Bitmap(image);
                Stream s = client.OpenWrite(googleContact.ContactEntry.PhotoUri.AbsoluteUri, "PUT");
                byte[] bytes = BitmapToBytes(pic);

                s.Write(bytes, 0, bytes.Length);
                s.Flush();
                //s.Close();
                s.Dispose();
                client.Dispose();
                pic.Dispose();
            }
            catch
            {
                return false;
            }
            return true;
        }
Esempio n. 17
0
        private void Sync_ThreadStarter()
        {
            //==>Instead of lock, use Interlocked to exit the code, if already another thread is calling the same
            bool won = false;

            try
            {

                won = Interlocked.CompareExchange(ref executing, 1, 0) == 0;
                if (won)
                {

                    TimerSwitch(false);

                    //if the contacts or notes folder has changed ==> Reset matches (to not delete contacts or notes on the one or other side)
                    RegistryKey regKeyAppRoot = Registry.CurrentUser.CreateSubKey(AppRootKey + "\\" + SyncProfile);
                    string oldSyncContactsFolder = regKeyAppRoot.GetValue(RegistrySyncContactsFolder) as string;
                    string oldSyncNotesFolder = regKeyAppRoot.GetValue(RegistrySyncNotesFolder) as string;
                    string oldSyncAppointmentsFolder = regKeyAppRoot.GetValue(RegistrySyncAppointmentsFolder) as string;
                    string oldSyncAppointmentsGoogleFolder = regKeyAppRoot.GetValue(RegistrySyncAppointmentsGoogleFolder) as string;

                    //only reset notes if NotesFolder changed and reset contacts if ContactsFolder changed
                    //and only reset appointments, if either OutlookAppointmentsFolder changed (without changing Google at the same time) or GoogleAppointmentsFolder changed (without changing Outlook at the same time) (not chosen before means not changed)
                    bool syncContacts = !string.IsNullOrEmpty(oldSyncContactsFolder) && !oldSyncContactsFolder.Equals(this.syncContactsFolder) && btSyncContacts.Checked;
                    bool syncNotes = false; // !string.IsNullOrEmpty(oldSyncNotesFolder) && !oldSyncNotesFolder.Equals(this.syncNotesFolder) && btSyncNotes.Checked;//ToDo: Google.Documents API Replaced by Google.Drive API on 21-Apr-2015
                    bool syncAppointments = !string.IsNullOrEmpty(oldSyncAppointmentsFolder) && !oldSyncAppointmentsFolder.Equals(this.syncAppointmentsFolder) && btSyncAppointments.Checked;
                    bool syncGoogleAppointments = !string.IsNullOrEmpty(this.syncAppointmentsGoogleFolder) && !this.syncAppointmentsGoogleFolder.Equals(oldSyncAppointmentsGoogleFolder) && btSyncAppointments.Checked;
                    if (syncContacts || /*syncNotes ||*/ syncAppointments && !syncGoogleAppointments || !syncAppointments && syncGoogleAppointments)
                    {
                        if (!ResetMatches(syncContacts, syncNotes, syncAppointments))
                            throw new Exception("Reset required but cancelled by user");
                    }

                    //Then save the Contacts and Notes Folders used at last sync
                    if (btSyncContacts.Checked)
                        regKeyAppRoot.SetValue(RegistrySyncContactsFolder, this.syncContactsFolder);
                    //ToDo: Google.Documents API Replaced by Google.Drive API on 21-Apr-2015
                    //if (btSyncNotes.Checked)
                    //    regKeyAppRoot.SetValue(RegistrySyncNotesFolder, this.syncNotesFolder);
                    if (btSyncAppointments.Checked)
                    {
                        regKeyAppRoot.SetValue(RegistrySyncAppointmentsFolder, this.syncAppointmentsFolder);
                        if (string.IsNullOrEmpty(this.syncAppointmentsGoogleFolder) && !string.IsNullOrEmpty(oldSyncAppointmentsGoogleFolder))
                            this.syncAppointmentsGoogleFolder = oldSyncAppointmentsGoogleFolder;
                        if (!string.IsNullOrEmpty(this.syncAppointmentsGoogleFolder))
                            regKeyAppRoot.SetValue(RegistrySyncAppointmentsGoogleFolder, this.syncAppointmentsGoogleFolder);
                    }

                    SetLastSyncText("Syncing...");
                    notifyIcon.Text = Application.ProductName + "\nSyncing...";
                    //System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SettingsForm));
                    //notifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon.Icon")));
                    IconTimerSwitch(true);

                    SetFormEnabled(false);

                    if (sync == null)
                    {
                        sync = new Synchronizer();
                        sync.DuplicatesFound += new Synchronizer.DuplicatesFoundHandler(OnDuplicatesFound);
                        sync.ErrorEncountered += new Synchronizer.ErrorNotificationHandler(OnErrorEncountered);
                    }

                    Logger.ClearLog();
                    SetSyncConsoleText("");
                    Logger.Log("Sync started (" + SyncProfile + ").", EventType.Information);
                    //SetSyncConsoleText(Logger.GetText());
                    sync.SyncProfile = SyncProfile;
                    Synchronizer.SyncContactsFolder = this.syncContactsFolder;
                    Synchronizer.SyncNotesFolder = this.syncNotesFolder;
                    Synchronizer.SyncAppointmentsFolder = this.syncAppointmentsFolder;
                    Synchronizer.SyncAppointmentsGoogleFolder = this.syncAppointmentsGoogleFolder;
                    Synchronizer.MonthsInPast = Convert.ToUInt16(this.pastMonthInterval.Value);
                    Synchronizer.MonthsInFuture = Convert.ToUInt16(this.futureMonthInterval.Value);
                    Synchronizer.Timezone = this.Timezone;

                    sync.SyncOption = syncOption;
                    sync.SyncDelete = btSyncDelete.Checked;
                    sync.PromptDelete = btPromptDelete.Checked && btSyncDelete.Checked;
                    sync.UseFileAs = chkUseFileAs.Checked;
                    sync.SyncNotes = false; // btSyncNotes.Checked;//ToDo: Google.Documents API Replaced by Google.Drive API on 21-Apr-2015
                    sync.SyncContacts = btSyncContacts.Checked;
                    sync.SyncAppointments = btSyncAppointments.Checked;

                    if (!sync.SyncContacts && !sync.SyncNotes && !sync.SyncAppointments)
                    {
                        SetLastSyncText("Sync failed.");
                        notifyIcon.Text = Application.ProductName + "\nSync failed";

                        string messageText = "Neither notes nor contacts nor appointments are switched on for syncing. Please choose at least one option. Sync aborted!";
                        //    Logger.Log(messageText, EventType.Error);
                        //    ShowForm();
                        //    ShowBalloonToolTip("Error", messageText, ToolTipIcon.Error, 5000, true);
                        //    return;
                        //}

                        //if (sync.SyncAppointments && Syncronizer.Timezone == "")
                        //{
                        //    string messageText = "Please set your timezone before syncing your appointments! Sync aborted!";
                        Logger.Log(messageText, EventType.Error);
                        ShowForm();
                        ShowBalloonToolTip("Error", messageText, ToolTipIcon.Error, 5000, true);
                        return;
                    }

                    sync.LoginToGoogle(UserName.Text);
                    sync.LoginToOutlook();

                    sync.Sync();

                    lastSync = DateTime.Now;
                    SetLastSyncText("Last synced at " + lastSync.ToString());

                    string message = string.Format("Sync complete.\r\n Synced:  {1} out of {0}.\r\n Deleted:  {2}.\r\n Skipped: {3}.\r\n Errors:    {4}.", sync.TotalCount, sync.SyncedCount, sync.DeletedCount, sync.SkippedCount, sync.ErrorCount);
                    Logger.Log(message, EventType.Information);

                    if (reportSyncResultCheckBox.Checked)
                    {
                        /*
                        notifyIcon.BalloonTipTitle = Application.ProductName;
                        notifyIcon.BalloonTipText = string.Format("{0}. {1}", DateTime.Now, message);
                        */
                        ToolTipIcon icon;
                        if (sync.ErrorCount > 0)
                            icon = ToolTipIcon.Error;
                        else if (sync.SkippedCount > 0)
                            icon = ToolTipIcon.Warning;
                        else
                            icon = ToolTipIcon.Info;
                        /*notifyIcon.ShowBalloonTip(5000);
                        */
                        ShowBalloonToolTip(Application.ProductName,
                            string.Format("{0}. {1}", DateTime.Now, message),
                            icon,
                            5000, false);

                    }
                    string toolTip = string.Format("{0}\nLast sync: {1}", Application.ProductName, DateTime.Now.ToString("dd.MM. HH:mm"));
                    if (sync.ErrorCount + sync.SkippedCount > 0)
                        toolTip += string.Format("\nWarnings: {0}.", sync.ErrorCount + sync.SkippedCount);
                    if (toolTip.Length >= 64)
                        toolTip = toolTip.Substring(0, 63);
                    notifyIcon.Text = toolTip;
                }
            }
            catch (Google.GData.Client.GDataRequestException ex)
            {
                SetLastSyncText("Sync failed.");
                notifyIcon.Text = Application.ProductName + "\nSync failed";

                //string responseString = (null != ex.InnerException) ? ex.ResponseString : ex.Message;

                if (ex.InnerException is System.Net.WebException)
                {
                    string message = "Cannot connect to Google, please check for available internet connection and proxy settings if applicable: " + ex.InnerException.Message + "\r\n" + ex.ResponseString;
                    Logger.Log(message, EventType.Warning);
                    ShowBalloonToolTip("Error", message, ToolTipIcon.Error, 5000, true);
                }
                else
                {
                    ErrorHandler.Handle(ex);
                }
            }
            catch (Google.GData.Client.InvalidCredentialsException)
            {
                SetLastSyncText("Sync failed.");
                notifyIcon.Text = Application.ProductName + "\nSync failed";

                string message = "The credentials (Google Account username and/or password) are invalid, please correct them in the settings form before you sync again";
                Logger.Log(message, EventType.Error);
                ShowForm();
                ShowBalloonToolTip("Error", message, ToolTipIcon.Error, 5000, true);

            }
            catch (Exception ex)
            {
                SetLastSyncText("Sync failed.");
                notifyIcon.Text = Application.ProductName + "\nSync failed";

                if (ex is COMException)
                {
                    string message = "Outlook exception, please assure that Outlook is running and not closed when syncing";
                    Logger.Log(message + ": " + ex.Message + "\r\n" + ex.StackTrace, EventType.Warning);
                    ShowBalloonToolTip("Error", message, ToolTipIcon.Error, 5000, true);
                }
                else
                {
                    ErrorHandler.Handle(ex);
                }
            }
            finally
            {
                if (won)
                {
                    Interlocked.Exchange(ref executing, 0);
                    lastSync = DateTime.Now;
                    TimerSwitch(true);
                    SetFormEnabled(true);
                    if (sync != null)
                    {
                        sync.LogoffOutlook();
                        sync.LogoffGoogle();
                        sync = null;
                    }
                    IconTimerSwitch(false);
                }
            }
        }
Esempio n. 18
0
        private void appointmentGoogleFoldersComboBox_Enter(object sender, EventArgs e)
        {
            if (this.appointmentGoogleFoldersComboBox.DataSource == null ||
                this.appointmentGoogleFoldersComboBox.Items.Count <= 1)
            {
                Logger.Log("Loading Google Calendars...", EventType.Information);
                ArrayList googleAppointmentFolders = new ArrayList();

                this.appointmentGoogleFoldersComboBox.BeginUpdate();
                //this.appointmentGoogleFoldersComboBox.DataSource = null;

                Logger.Log("Loading Google Appointments folder...", EventType.Information);
                string defaultText = "    --- Select a Google Appointment folder ---";

                if (sync == null)
                    sync = new Synchronizer();

                sync.SyncAppointments = btSyncAppointments.Checked;
                sync.LoginToGoogle(UserName.Text);
                foreach (CalendarListEntry calendar in sync.calendarList)
                {
                    googleAppointmentFolders.Add(new GoogleCalendar(calendar.Summary, calendar.Id, calendar.Primary.HasValue ? calendar.Primary.Value : false));
                }

                if (googleAppointmentFolders != null) // && googleAppointmentFolders.Count > 0)
                {
                    googleAppointmentFolders.Sort();
                    googleAppointmentFolders.Insert(0, new GoogleCalendar(defaultText, defaultText, false));
                    this.appointmentGoogleFoldersComboBox.DataSource = googleAppointmentFolders;
                    this.appointmentGoogleFoldersComboBox.DisplayMember = "DisplayName";
                    this.appointmentGoogleFoldersComboBox.ValueMember = "FolderID";
                }
                this.appointmentGoogleFoldersComboBox.EndUpdate();
                this.appointmentGoogleFoldersComboBox.SelectedValue = defaultText;

                //Select Default Folder per Default
                foreach (GoogleCalendar folder in appointmentGoogleFoldersComboBox.Items)
                    if (folder.IsDefaultFolder)
                    {
                        this.appointmentGoogleFoldersComboBox.SelectedItem = folder;
                        break;
                    }
                Logger.Log("Loaded Google Calendars.", EventType.Information);
            }
        }
Esempio n. 19
0
 private void resetMatchesLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
 {
     // force deactivation to show up
     Application.DoEvents();
     try
     {
         this.cancelButton.Enabled = false; //Cancel is only working for sync currently, not for reset
         ResetMatches(btSyncContacts.Checked, false /*btSyncNotes.Checked*/, btSyncAppointments.Checked);//ToDo: Google.Documents API Replaced by Google.Drive API on 21-Apr-2015
     }
     catch (Exception ex)
     {
         SetLastSyncText("Reset Matches failed");
         Logger.Log("Reset Matches failed", EventType.Error);
         ErrorHandler.Handle(ex);
     }
     finally
     {
         lastSync = DateTime.Now;
         TimerSwitch(true);
         SetFormEnabled(true);
         this.hideButton.Enabled = true;
         if (sync != null)
         {
             sync.LogoffOutlook();
             sync.LogoffGoogle();
             sync = null;
         }
     }
 }
Esempio n. 20
0
        private bool ResetMatches(bool syncContacts, bool syncNotes, bool syncAppointments)
        {
            TimerSwitch(false);

            SetLastSyncText("Resetting matches...");
            notifyIcon.Text = Application.ProductName + "\nResetting matches...";

            fillSyncFolderItems();

            SetFormEnabled(false);

            if (sync == null)
            {
                sync = new Synchronizer();
            }

            Logger.ClearLog();
            SetSyncConsoleText("");
            Logger.Log("Reset Matches started  (" + SyncProfile + ").", EventType.Information);

            sync.SyncNotes = syncNotes;
            sync.SyncContacts = syncContacts;
            sync.SyncAppointments = syncAppointments;

            Synchronizer.SyncContactsFolder = syncContactsFolder;
            Synchronizer.SyncNotesFolder = syncNotesFolder;
            Synchronizer.SyncAppointmentsFolder = syncAppointmentsFolder;
            Synchronizer.SyncAppointmentsGoogleFolder = syncAppointmentsGoogleFolder;
            sync.SyncProfile = SyncProfile;

            sync.LoginToGoogle(UserName.Text);
            sync.LoginToOutlook();

            if (sync.SyncAppointments)
            {
                bool deleteOutlookAppointments = false;
                bool deleteGoogleAppointments = false;

                switch (ShowDialog("Do you want to delete all Outlook Calendar entries?"))
                {
                    case DialogResult.Yes: deleteOutlookAppointments = true; break;
                    case DialogResult.No: deleteOutlookAppointments = false; break;
                    default: return false;
                }
                switch (ShowDialog("Do you want to delete all Google Calendar entries?"))
                {
                    case DialogResult.Yes: deleteGoogleAppointments = true; break;
                    case DialogResult.No: deleteGoogleAppointments = false; break;
                    default: return false;
                }

                sync.LoadAppointments();
                sync.ResetAppointmentMatches(deleteOutlookAppointments, deleteGoogleAppointments);
            }

            if (sync.SyncContacts)
            {
                sync.LoadContacts();
                sync.ResetContactMatches();
            }

            if (sync.SyncNotes)
            {
                sync.LoadNotes();
                sync.ResetNoteMatches();
            }
            lastSync = DateTime.Now;
            SetLastSyncText("Matches reset at " + lastSync.ToString());
            Logger.Log("Matches reset.", EventType.Information);

            return true;
        }
Esempio n. 21
0
 public OutlookContactInfo(ContactItem item, Synchronizer sync)
 {
     this.UserProperties = new UserPropertiesHolder();
     this.Update(item, sync);
 }
Esempio n. 22
0
        public DeleteResolution ResolveDelete(Document googleNote, Synchronizer sync)
        {
            _form.Text = "Outlook note deleted";
            _form.messageLabel.Text =
                "Outlook note \"" + googleNote.Title +
                "\" doesn't exist aynmore. Do you want to delete it also on Google side?";

            _form.OutlookItemTextBox.Text = string.Empty;
            _form.GoogleItemTextBox.Text = NotePropertiesUtils.GetBody(sync, googleNote);

            _form.keepOutlook.Text = "Keep Google";
            _form.keepGoogle.Text = "Delete Google";
            _form.skip.Enabled = false;

            return ResolveDeletedOutlook();
        }
Esempio n. 23
0
        //private string GetPropertyInfos(object myObject)
        //{
        //    // get all public static properties of OutlookItem
        //    PropertyInfo[] propertyInfos;
        //    propertyInfos = myObject.GetType().GetProperties();
        //    // sort properties by name
        //    Array.Sort(propertyInfos,
        //            delegate(PropertyInfo propertyInfo1, PropertyInfo propertyInfo2)
        //            { return propertyInfo1.Name.CompareTo(propertyInfo2.Name); });

        //    string ret = String.Empty;
        //    // write property names
        //    foreach (PropertyInfo propertyInfo in propertyInfos)
        //    {
        //        object value = propertyInfo.GetValue(myObject, null);

        //        if (value != null && !(value is string))
        //            ret += propertyInfo.Name + ": " + value + "\r\n";
        //    }

        //    return ret;
        //}

        public ConflictResolution Resolve(Microsoft.Office.Interop.Outlook.NoteItem outlookNote, Document googleNote, Synchronizer sync, bool isNewMatch)
        {
            string name = string.Empty;

            _form.OutlookItemTextBox.Text = string.Empty;
            _form.GoogleItemTextBox.Text  = string.Empty;
            if (outlookNote != null)
            {
                name = outlookNote.Subject;
                _form.OutlookItemTextBox.Text = outlookNote.Body;
            }

            if (googleNote != null)
            {
                name = googleNote.Title;
                _form.GoogleItemTextBox.Text = NotePropertiesUtils.GetBody(sync, googleNote);
            }

            if (isNewMatch)
            {
                _form.messageLabel.Text =
                    "This is the first time these Outlook and Google notes \"" + name +
                    "\" are synced. Choose which you would like to keep.";
                _form.skip.Text = "Keep both";
            }
            else
            {
                _form.messageLabel.Text =
                    "Both the Outlook Note and the Google Note \"" + name +
                    "\" have been changed. Choose which you would like to keep.";
            }



            return(Resolve());
        }
Esempio n. 24
0
        //private string GetPropertyInfos(object myObject)
        //{
        //    // get all public static properties of OutlookItem
        //    PropertyInfo[] propertyInfos;
        //    propertyInfos = myObject.GetType().GetProperties();
        //    // sort properties by name
        //    Array.Sort(propertyInfos,
        //            delegate(PropertyInfo propertyInfo1, PropertyInfo propertyInfo2)
        //            { return propertyInfo1.Name.CompareTo(propertyInfo2.Name); });
        //    string ret = String.Empty;
        //    // write property names
        //    foreach (PropertyInfo propertyInfo in propertyInfos)
        //    {
        //        object value = propertyInfo.GetValue(myObject, null);
        //        if (value != null && !(value is string))
        //            ret += propertyInfo.Name + ": " + value + "\r\n";
        //    }
        //    return ret;
        //}
        public ConflictResolution Resolve(Microsoft.Office.Interop.Outlook.NoteItem outlookNote, Document googleNote, Synchronizer sync, bool isNewMatch)
        {
            string name = string.Empty;

            _form.OutlookItemTextBox.Text = string.Empty;
            _form.GoogleItemTextBox.Text = string.Empty;
            if (outlookNote != null)
            {
                name = outlookNote.Subject;
                _form.OutlookItemTextBox.Text = outlookNote.Body;
            }

            if (googleNote != null)
            {
                name = googleNote.Title;
                _form.GoogleItemTextBox.Text = NotePropertiesUtils.GetBody(sync, googleNote);
            }

            if (isNewMatch)
            {
                _form.messageLabel.Text =
                    "This is the first time these Outlook and Google notes \"" + name +
                    "\" are synced. Choose which you would like to keep.";
                _form.skip.Text = "Keep both";
            }
            else
            {
                _form.messageLabel.Text =
                "Both the Outlook Note and the Google Note \"" + name +
                "\" have been changed. Choose which you would like to keep.";
            }

            return Resolve();
        }
        public static void ResetOutlookGoogleNoteId(Synchronizer sync, Outlook.NoteItem outlookNote)
        {
            Outlook.ItemProperties userProperties = outlookNote.ItemProperties;
            try
            {
                Outlook.ItemProperty idProp = userProperties[sync.OutlookPropertyNameId];
                try
                {
                    Outlook.ItemProperty lastSyncProp = userProperties[sync.OutlookPropertyNameSynced];
                    try
                    {
                        if (idProp == null && lastSyncProp == null)
                        {
                            return;
                        }

                        List <int>  indexesToBeRemoved = new List <int>();
                        IEnumerator en = userProperties.GetEnumerator();
                        en.Reset();
                        int index = 0; // 0 based collection
                        while (en.MoveNext())
                        {
                            Outlook.ItemProperty userProperty = en.Current as Outlook.ItemProperty;
                            if (userProperty == idProp || userProperty == lastSyncProp)
                            {
                                indexesToBeRemoved.Add(index);
                                //outlookNote.UserProperties.Remove(index);
                                //Don't return to remove both properties, googleId and lastSynced
                                //return;
                            }
                            index++;
                            Marshal.ReleaseComObject(userProperty);
                        }

                        for (int i = indexesToBeRemoved.Count - 1; i >= 0; i--)
                        {
                            userProperties.Remove(indexesToBeRemoved[i]);
                        }
                        //throw new Exception("Did not find prop.");
                    }
                    finally
                    {
                        if (lastSyncProp != null)
                        {
                            Marshal.ReleaseComObject(lastSyncProp);
                        }
                    }
                }
                finally
                {
                    if (idProp != null)
                    {
                        Marshal.ReleaseComObject(idProp);
                    }
                }
            }
            finally
            {
                Marshal.ReleaseComObject(userProperties);
            }
        }
        public static void SyncAppointments(Synchronizer 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 + " - " + Synchronizer.GetTime(match.GoogleAppointment);
                    NotificationReceived(String.Format("Syncing appointment {0} of {1}: {2} ...", i + 1, sync.Appointments.Count, name));
                }

                SyncAppointment(match, sync);
            }
        }
        //public static void SetGoogleOutlookNoteId(string syncProfile, Document googleNote, Outlook.NoteItem outlookNote)
        //{
        //    if (outlookNote.EntryID == null)
        //        throw new Exception("Must save outlook note before getting id");
        //    SetGoogleOutlookNoteId(syncProfile, googleNote, GetOutlookId(outlookNote));
        //}
        //public static void SetGoogleOutlookNoteId(string syncProfile, Document googleNote, string outlookNoteId)
        //{
        //    // check if exists
        //    bool found = false;
        //    foreach (Google.GData.Extensions.ExtendedProperty p in googleNote.ExtendedProperties)
        //    {
        //        if (p.Name == "gos:oid:" + syncProfile + "")
        //        {
        //            p.Value = outlookNoteId;
        //            found = true;
        //            break;
        //        }
        //    }
        //    if (!found)
        //    {
        //        Google.GData.Extensions.ExtendedProperty prop = new ExtendedProperty(outlookNoteId, "gos:oid:" + syncProfile + "");
        //        prop.Value = outlookNoteId;
        //        googleNote.ExtendedProperties.Add(prop);
        //    }
        //}
        //public static string GetGoogleOutlookNoteId(string syncProfile, Document googleNote)
        //{
        //    // get extended prop
        //    foreach (Google.GData.Extensions.ExtendedProperty p in googleNote.DocumentEntry.ExtendedProperties)
        //    {
        //        if (p.Name == "gos:oid:" + syncProfile + "")
        //            return (string)p.Value;
        //    }
        //    return null;
        //}
        //public static void ResetGoogleOutlookNoteId(string syncProfile, Document googleNote)
        //{
        //    // get extended prop
        //    foreach (Google.GData.Extensions.ExtendedProperty p in googleNote.ExtendedProperties)
        //    {
        //        if (p.Name == "gos:oid:" + syncProfile + "")
        //        {
        //            // remove
        //            googleNote.ExtendedProperties.Remove(p);
        //            return;
        //        }
        //    }
        //}
        /// <summary>
        /// Sets the syncId of the Outlook note and the last sync date. 
        /// Please assure to always call this function when saving OutlookItem
        /// </summary>
        /// <param name="sync"></param>
        /// <param name="outlookNote"></param>
        /// <param name="googleNote"></param>
        public static void SetOutlookGoogleNoteId(Synchronizer sync, Outlook.NoteItem outlookNote, Document googleNote)
        {
            if (googleNote.DocumentEntry.Id.Uri == null)
                throw new NullReferenceException("GoogleNote must have a valid Id");

            //check if outlook note aready has google id property.
            Outlook.ItemProperties userProperties = outlookNote.ItemProperties;
            try
            {
                Outlook.ItemProperty prop = userProperties[sync.OutlookPropertyNameId];
                if (prop == null)
                    prop = userProperties.Add(sync.OutlookPropertyNameId, Outlook.OlUserPropertyType.olText, true);
                try
                {
                    prop.Value = googleNote.DocumentEntry.Id.Uri.Content;
                }
                finally
                {
                    Marshal.ReleaseComObject(prop);
                }
            }
            finally
            {
                Marshal.ReleaseComObject(userProperties);
            }

            //save last google's updated date as property
            /*prop = outlookNote.UserProperties[OutlookPropertyNameUpdated];
            if (prop == null)
                prop = outlookNote.UserProperties.Add(OutlookPropertyNameUpdated, Outlook.OlUserPropertyType.olDateTime, null, null);
            prop.Value = googleNote.Updated;*/

            //Also set the OutlookLastSync date when setting a match between Outlook and Google to assure the lastSync updated when Outlook note is saved afterwards
            SetOutlookLastSync(sync, outlookNote);
        }
Esempio n. 28
0
        public static void SyncContacts(Synchronizer sync)
        {
            for (int i = 0; i < sync.Contacts.Count; i++ )
            {
                ContactMatch match = sync.Contacts[i];
                if (NotificationReceived != null)
                    NotificationReceived(String.Format("Syncing contact {0} of {1}: {2} ...", i + 1, sync.Contacts.Count, match.ToString()));

                SyncContact(match, sync);
            }
        }
Esempio n. 29
0
        public static Image GetGooglePhoto(Synchronizer sync, Contact googleContact)
        {
            if (!HasPhoto(googleContact))
                return null;

            try
            {
                WebClient client = new WebClient();
                //client.Headers.Add(HttpRequestHeader.Authorization, "GoogleLogin auth=" + sync.ContactsRequest.Service.QueryClientLoginToken());
                client.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + sync.ContactsRequest.Settings.OAuth2Parameters.AccessToken);
                Stream stream = client.OpenRead(googleContact.PhotoUri.AbsoluteUri);
                BinaryReader reader = new BinaryReader(stream);
                Image image = Image.FromStream(stream);
                reader.Close();
                //stream.Close();
                //stream.Dispose();
                client.Dispose();

                return image;
            }
            catch (Exception ex)
            {
                return null;
            }
        }
Esempio n. 30
0
        /// <summary>
        /// Matches outlook and google contact by a) google id b) properties.
        /// </summary>
        /// <param name="sync">Syncronizer instance</param>
        /// <param name="duplicatesFound">Exception returned, if duplicates have been found (null else)</param>
        /// <returns>Returns a list of match pairs (outlook contact + google contact) for all contact. Those that weren't matche will have it's peer set to null</returns>
        public static List<ContactMatch> MatchContacts(Synchronizer sync, out DuplicateDataException duplicatesFound)
        {
            Logger.Log("Matching Outlook and Google contacts...", EventType.Information);
            var result = new List<ContactMatch>();

            var duplicateGoogleMatches = string.Empty;
            var duplicateOutlookContacts = string.Empty;
            sync.GoogleContactDuplicates = new Collection<ContactMatch>();
            sync.OutlookContactDuplicates = new Collection<ContactMatch>();

            var skippedOutlookIds = new List<string>();

            //for each outlook contact try to get google contact id from user properties
            //if no match - try to match by properties
            //if no match - create a new match pair without google contact.
            //foreach (Outlook._ContactItem olc in outlookContacts)
            var outlookContactsWithoutOutlookGoogleId = new Collection<OutlookContactInfo>();
            #region Match first all outlookContacts by sync id
            for (int i = 1; i <= sync.OutlookContacts.Count; i++)
            {
                Outlook.ContactItem olc = null;
                try
                {
                    olc = sync.OutlookContacts[i] as Outlook.ContactItem;
                    if (olc == null)
                    {
                        Logger.Log("Empty Outlook contact found (maybe distribution list). Skipping", EventType.Warning);
                        sync.SkippedCount++;
                        sync.SkippedCountNotMatches++;
                        continue;
                    }
                }
                catch (Exception ex)
                {
                    //this is needed because some contacts throw exceptions
                    Logger.Log("Accessing Outlook contact threw and exception. Skipping: " + ex.Message, EventType.Warning);
                    sync.SkippedCount++;
                    sync.SkippedCountNotMatches++;
                    continue;
                }

                try
                {

                    // sometimes contacts throw Exception when accessing their properties, so we give it a controlled try first.
                    try
                    {
                        string email1Address = olc.Email1Address;
                    }
                    catch (Exception ex)
                    {
                        string message = string.Format("Can't access contact details for outlook contact, got {0} - '{1}'. Skipping", ex.GetType().ToString(), ex.Message);
                        try
                        {
                            message = string.Format("{0} {1}.", message, olc.FileAs);
                            //remember skippedOutlookIds to later not delete them if found on Google side
                            skippedOutlookIds.Add(string.Copy(olc.EntryID));

                        }
                        catch
                        {
                            //e.g. if olc.FileAs also fails, ignore, because messge already set
                            //message = null;
                        }

                        //if (olc != null && message != null) // it's useless to say "we couldn't access some contacts properties
                        //{
                        Logger.Log(message, EventType.Warning);
                        //}
                        sync.SkippedCount++;
                        sync.SkippedCountNotMatches++;
                        continue;
                    }

                    if (!IsContactValid(olc))
                    {
                        Logger.Log(string.Format("Invalid outlook contact ({0}). Skipping", olc.FileAs), EventType.Warning);
                        skippedOutlookIds.Add(string.Copy(olc.EntryID));
                        sync.SkippedCount++;
                        sync.SkippedCountNotMatches++;
                        continue;
                    }

                    if (olc.Body != null && olc.Body.Length > 62000)
                    {
                        // notes field too large
                        Logger.Log(string.Format("Skipping outlook contact ({0}). Reduce the notes field to a maximum of 62.000 characters.", olc.FileAs), EventType.Warning);
                        skippedOutlookIds.Add(string.Copy(olc.EntryID));
                        sync.SkippedCount++;
                        sync.SkippedCountNotMatches++;
                        continue;
                    }

                    if (NotificationReceived != null)
                        NotificationReceived(String.Format("Matching contact {0} of {1} by id: {2} ...", i, sync.OutlookContacts.Count, olc.FileAs));

                    // 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.
                    var olci = new OutlookContactInfo(olc, sync);

                    //try to match this contact to one of google contacts
                    Outlook.UserProperties userProperties = olc.UserProperties;
                    Outlook.UserProperty idProp = userProperties[sync.OutlookPropertyNameId];
                    try
                    {
                        if (idProp != null)
                        {
                            string googleContactId = string.Copy((string)idProp.Value);
                            Contact foundContact = sync.GetGoogleContactById(googleContactId);
                            var match = new ContactMatch(olci, null);

                            //Check first, that this is not a duplicate
                            //e.g. by copying an existing Outlook contact
                            //or by Outlook checked this as duplicate, but the user selected "Add new"
                            Collection<OutlookContactInfo> duplicates = sync.OutlookContactByProperty(sync.OutlookPropertyNameId, googleContactId);
                            if (duplicates.Count > 1)
                            {
                                foreach (OutlookContactInfo duplicate in duplicates)
                                {
                                    if (!string.IsNullOrEmpty(googleContactId))
                                    {
                                        Logger.Log("Duplicate Outlook contact found, resetting match and trying to match again: " + duplicate.FileAs, EventType.Warning);
                                        Outlook.ContactItem item = duplicate.GetOriginalItemFromOutlook();
                                        try
                                        {
                                            ContactPropertiesUtils.ResetOutlookGoogleContactId(sync, item);
                                            item.Save();
                                        }
                                        finally
                                        {
                                            if (item != null)
                                            {
                                                Marshal.ReleaseComObject(item);
                                                item = null;
                                            }
                                        }
                                    }
                                }

                                if (foundContact != null && !foundContact.Deleted)
                                {
                                    ContactPropertiesUtils.ResetGoogleOutlookContactId(sync.SyncProfile, foundContact);
                                }

                                outlookContactsWithoutOutlookGoogleId.Add(olci);
                            }
                            else
                            {

                                if (foundContact != null && !foundContact.Deleted)
                                {
                                    //we found a match by google id, that is not deleted yet
                                    match.AddGoogleContact(foundContact);
                                    result.Add(match);
                                    //Remove the contact from the list to not sync it twice
                                    sync.GoogleContacts.Remove(foundContact);
                                }
                                else
                                {
                                    outlookContactsWithoutOutlookGoogleId.Add(olci);
                                }
                            }
                        }
                        else
                            outlookContactsWithoutOutlookGoogleId.Add(olci);
                    }
                    finally
                    {
                        if (idProp != null)
                            Marshal.ReleaseComObject(idProp);
                        Marshal.ReleaseComObject(userProperties);
                    }
                }

                finally
                {
                    Marshal.ReleaseComObject(olc);
                    olc = null;
                }

            }
            #endregion
            #region Match the remaining contacts by properties

            for (int i = 0; i < outlookContactsWithoutOutlookGoogleId.Count; i++)
            {
                OutlookContactInfo olci = outlookContactsWithoutOutlookGoogleId[i];

                if (NotificationReceived != null)
                    NotificationReceived(String.Format("Matching contact {0} of {1} by unique properties: {2} ...", i + 1, outlookContactsWithoutOutlookGoogleId.Count, olci.FileAs));

                //no match found by id => match by common properties
                //create a default match pair with just outlook contact.
                var match = new ContactMatch(olci, null);

                //foreach google contact try to match and create a match pair if found some match(es)
                for (int j=sync.GoogleContacts.Count-1;j>=0;j--)
                {
                    Contact entry = sync.GoogleContacts[j];
                    if (entry.Deleted)
                        continue;

                    // only match if there is either an email or telephone or else
                    // a matching google contact will be created at each sync
                    //1. try to match by FileAs
                    //1.1 try to match by FullName
                    //2. try to match by primary email
                    //3. try to match by mobile phone number, don't match by home or business bumbers, because several people may share the same home or business number
                    //4. try to math Company, if Google Title is null, i.e. the contact doesn't have a name and title, only a company
                    string entryTitleFirstLastAndSuffix = OutlookContactInfo.GetTitleFirstLastAndSuffix(entry);
                    if (!string.IsNullOrEmpty(olci.FileAs) && !string.IsNullOrEmpty(entry.Title) && olci.FileAs.Equals(entry.Title.Replace("\r\n", "\n").Replace("\n", "\r\n"), StringComparison.InvariantCultureIgnoreCase) ||  //Replace twice to not replace a \r\n by \r\r\n. This is necessary because \r\n are saved as \n only to google
                        !string.IsNullOrEmpty(olci.FileAs) && !string.IsNullOrEmpty(entry.Name.FullName) && olci.FileAs.Equals(entry.Name.FullName.Replace("\r\n", "\n").Replace("\n", "\r\n"), StringComparison.InvariantCultureIgnoreCase) ||
                        !string.IsNullOrEmpty(olci.FullName) && !string.IsNullOrEmpty(entry.Name.FullName) && olci.FullName.Equals(entry.Name.FullName.Replace("\r\n", "\n").Replace("\n", "\r\n"), StringComparison.InvariantCultureIgnoreCase) ||
                        !string.IsNullOrEmpty(olci.TitleFirstLastAndSuffix) && !string.IsNullOrEmpty(entryTitleFirstLastAndSuffix) && olci.TitleFirstLastAndSuffix.Equals(entryTitleFirstLastAndSuffix.Replace("\r\n", "\n").Replace("\n", "\r\n"), StringComparison.InvariantCultureIgnoreCase) ||
                        !string.IsNullOrEmpty(olci.Email1Address) && entry.Emails.Count > 0 && olci.Email1Address.Equals(entry.Emails[0].Address, StringComparison.InvariantCultureIgnoreCase) ||
                        //!string.IsNullOrEmpty(olci.Email2Address) && FindEmail(olci.Email2Address, entry.Emails) != null ||
                        //!string.IsNullOrEmpty(olci.Email3Address) && FindEmail(olci.Email3Address, entry.Emails) != null ||
                        olci.MobileTelephoneNumber != null && FindPhone(olci.MobileTelephoneNumber, entry.Phonenumbers) != null ||
                        !string.IsNullOrEmpty(olci.FileAs) && string.IsNullOrEmpty(entry.Title) && entry.Organizations.Count > 0 && olci.FileAs.Equals(entry.Organizations[0].Name, StringComparison.InvariantCultureIgnoreCase)
                        )
                    {
                        match.AddGoogleContact(entry);
                        sync.GoogleContacts.Remove(entry);
                    }

                }

                #region find duplicates not needed now
                //if (match.GoogleContact == null && match.OutlookContact != null)
                //{//If GoogleContact, we have to expect a conflict because of Google insert of duplicates
                //    foreach (Contact entry in sync.GoogleContacts)
                //    {
                //        if (!string.IsNullOrEmpty(olc.FullName) && olc.FullName.Equals(entry.Title, StringComparison.InvariantCultureIgnoreCase) ||
                //         !string.IsNullOrEmpty(olc.FileAs) && olc.FileAs.Equals(entry.Title, StringComparison.InvariantCultureIgnoreCase) ||
                //         !string.IsNullOrEmpty(olc.Email1Address) && FindEmail(olc.Email1Address, entry.Emails) != null ||
                //         !string.IsNullOrEmpty(olc.Email2Address) && FindEmail(olc.Email1Address, entry.Emails) != null ||
                //         !string.IsNullOrEmpty(olc.Email3Address) && FindEmail(olc.Email1Address, entry.Emails) != null ||
                //         olc.MobileTelephoneNumber != null && FindPhone(olc.MobileTelephoneNumber, entry.Phonenumbers) != null
                //         )
                //    }
                //// check for each email 1,2 and 3 if a duplicate exists with same email, because Google doesn't like inserting new contacts with same email
                //Collection<Outlook.ContactItem> duplicates1 = new Collection<Outlook.ContactItem>();
                //Collection<Outlook.ContactItem> duplicates2 = new Collection<Outlook.ContactItem>();
                //Collection<Outlook.ContactItem> duplicates3 = new Collection<Outlook.ContactItem>();
                //if (!string.IsNullOrEmpty(olc.Email1Address))
                //    duplicates1 = sync.OutlookContactByEmail(olc.Email1Address);

                //if (!string.IsNullOrEmpty(olc.Email2Address))
                //    duplicates2 = sync.OutlookContactByEmail(olc.Email2Address);

                //if (!string.IsNullOrEmpty(olc.Email3Address))
                //    duplicates3 = sync.OutlookContactByEmail(olc.Email3Address);

                //if (duplicates1.Count > 1 || duplicates2.Count > 1 || duplicates3.Count > 1)
                //{
                //    if (string.IsNullOrEmpty(duplicatesEmailList))
                //        duplicatesEmailList = "Outlook contacts with the same email have been found and cannot be synchronized. Please delete duplicates of:";

                //    if (duplicates1.Count > 1)
                //        foreach (Outlook.ContactItem duplicate in duplicates1)
                //        {
                //            string str = olc.FileAs + " (" + olc.Email1Address + ")";
                //            if (!duplicatesEmailList.Contains(str))
                //                duplicatesEmailList += Environment.NewLine + str;
                //        }
                //    if (duplicates2.Count > 1)
                //        foreach (Outlook.ContactItem duplicate in duplicates2)
                //        {
                //            string str = olc.FileAs + " (" + olc.Email2Address + ")";
                //            if (!duplicatesEmailList.Contains(str))
                //                duplicatesEmailList += Environment.NewLine + str;
                //        }
                //    if (duplicates3.Count > 1)
                //        foreach (Outlook.ContactItem duplicate in duplicates3)
                //        {
                //            string str = olc.FileAs + " (" + olc.Email3Address + ")";
                //            if (!duplicatesEmailList.Contains(str))
                //                duplicatesEmailList += Environment.NewLine + str;
                //        }
                //    continue;
                //}
                //else if (!string.IsNullOrEmpty(olc.Email1Address))
                //{
                //    ContactMatch dup = result.Find(delegate(ContactMatch match)
                //    {
                //        return match.OutlookContact != null && match.OutlookContact.Email1Address == olc.Email1Address;
                //    });
                //    if (dup != null)
                //    {
                //        Logger.Log(string.Format("Duplicate contact found by Email1Address ({0}). Skipping", olc.FileAs), EventType.Information);
                //        continue;
                //    }
                //}

                //// check for unique mobile phone, because this sync tool uses the also the mobile phone to identify matches between Google and Outlook
                //Collection<Outlook.ContactItem> duplicatesMobile = new Collection<Outlook.ContactItem>();
                //if (!string.IsNullOrEmpty(olc.MobileTelephoneNumber))
                //    duplicatesMobile = sync.OutlookContactByProperty("MobileTelephoneNumber", olc.MobileTelephoneNumber);

                //if (duplicatesMobile.Count > 1)
                //{
                //    if (string.IsNullOrEmpty(duplicatesMobileList))
                //        duplicatesMobileList = "Outlook contacts with the same mobile phone have been found and cannot be synchronized. Please delete duplicates of:";

                //    foreach (Outlook.ContactItem duplicate in duplicatesMobile)
                //    {
                //        sync.OutlookContactDuplicates.Add(olc);
                //        string str = olc.FileAs + " (" + olc.MobileTelephoneNumber + ")";
                //        if (!duplicatesMobileList.Contains(str))
                //            duplicatesMobileList += Environment.NewLine + str;
                //    }
                //    continue;
                //}
                //else if (!string.IsNullOrEmpty(olc.MobileTelephoneNumber))
                //{
                //    ContactMatch dup = result.Find(delegate(ContactMatch match)
                //    {
                //        return match.OutlookContact != null && match.OutlookContact.MobileTelephoneNumber == olc.MobileTelephoneNumber;
                //    });
                //    if (dup != null)
                //    {
                //        Logger.Log(string.Format("Duplicate contact found by MobileTelephoneNumber ({0}). Skipping", olc.FileAs), EventType.Information);
                //        continue;
                //    }
                //}

                #endregion

                if (match.AllGoogleContactMatches == null || match.AllGoogleContactMatches.Count == 0)
                {
                    //Check, if this Outlook contact has a match in the google duplicates
                    bool duplicateFound = false;
                    foreach (ContactMatch duplicate in sync.GoogleContactDuplicates)
                    {
                        string entryTitleFirstLastAndSuffix = OutlookContactInfo.GetTitleFirstLastAndSuffix(duplicate.AllGoogleContactMatches[0]);
                        if (duplicate.AllGoogleContactMatches.Count > 0 &&
                            (!string.IsNullOrEmpty(olci.FileAs) && !string.IsNullOrEmpty(duplicate.AllGoogleContactMatches[0].Title) && olci.FileAs.Equals(duplicate.AllGoogleContactMatches[0].Title.Replace("\r\n", "\n").Replace("\n","\r\n"), StringComparison.InvariantCultureIgnoreCase) ||  //Replace twice to not replace a \r\n by \r\r\n. This is necessary because \r\n are saved as \n only to google
                             !string.IsNullOrEmpty(olci.FileAs) && !string.IsNullOrEmpty(duplicate.AllGoogleContactMatches[0].Name.FullName) && olci.FileAs.Equals(duplicate.AllGoogleContactMatches[0].Name.FullName.Replace("\r\n", "\n").Replace("\n", "\r\n"), StringComparison.InvariantCultureIgnoreCase) ||
                             !string.IsNullOrEmpty(olci.FullName) && !string.IsNullOrEmpty(duplicate.AllGoogleContactMatches[0].Name.FullName) && olci.FullName.Equals(duplicate.AllGoogleContactMatches[0].Name.FullName.Replace("\r\n", "\n").Replace("\n","\r\n"), StringComparison.InvariantCultureIgnoreCase) ||
                             !string.IsNullOrEmpty(olci.TitleFirstLastAndSuffix) && !string.IsNullOrEmpty(entryTitleFirstLastAndSuffix) && olci.TitleFirstLastAndSuffix.Equals(entryTitleFirstLastAndSuffix.Replace("\r\n", "\n").Replace("\n", "\r\n"), StringComparison.InvariantCultureIgnoreCase) ||
                             !string.IsNullOrEmpty(olci.Email1Address) && duplicate.AllGoogleContactMatches[0].Emails.Count > 0 && olci.Email1Address.Equals(duplicate.AllGoogleContactMatches[0].Emails[0].Address, StringComparison.InvariantCultureIgnoreCase) ||
                             //!string.IsNullOrEmpty(olci.Email2Address) && FindEmail(olci.Email2Address, duplicate.AllGoogleContactMatches[0].Emails) != null ||
                             //!string.IsNullOrEmpty(olci.Email3Address) && FindEmail(olci.Email3Address, duplicate.AllGoogleContactMatches[0].Emails) != null ||
                             olci.MobileTelephoneNumber != null && FindPhone(olci.MobileTelephoneNumber, duplicate.AllGoogleContactMatches[0].Phonenumbers) != null ||
                             !string.IsNullOrEmpty(olci.FileAs) && string.IsNullOrEmpty(duplicate.AllGoogleContactMatches[0].Title) && duplicate.AllGoogleContactMatches[0].Organizations.Count > 0 && olci.FileAs.Equals(duplicate.AllGoogleContactMatches[0].Organizations[0].Name, StringComparison.InvariantCultureIgnoreCase)
                            ) ||
                            !string.IsNullOrEmpty(olci.FileAs) && olci.FileAs.Equals(duplicate.OutlookContact.FileAs, StringComparison.InvariantCultureIgnoreCase) ||
                            !string.IsNullOrEmpty(olci.FullName) && olci.FullName.Equals(duplicate.OutlookContact.FullName, StringComparison.InvariantCultureIgnoreCase) ||
                            !string.IsNullOrEmpty(olci.TitleFirstLastAndSuffix) && olci.TitleFirstLastAndSuffix.Equals(duplicate.OutlookContact.TitleFirstLastAndSuffix, StringComparison.InvariantCultureIgnoreCase) ||
                            !string.IsNullOrEmpty(olci.Email1Address) && olci.Email1Address.Equals(duplicate.OutlookContact.Email1Address, StringComparison.InvariantCultureIgnoreCase) ||
                            //                                              olci.Email1Address.Equals(duplicate.OutlookContact.Email2Address, StringComparison.InvariantCultureIgnoreCase) ||
                            //                                              olci.Email1Address.Equals(duplicate.OutlookContact.Email3Address, StringComparison.InvariantCultureIgnoreCase)
                            //                                              ) ||
                            //!string.IsNullOrEmpty(olci.Email2Address) && (olci.Email2Address.Equals(duplicate.OutlookContact.Email1Address, StringComparison.InvariantCultureIgnoreCase) ||
                            //                                              olci.Email2Address.Equals(duplicate.OutlookContact.Email2Address, StringComparison.InvariantCultureIgnoreCase) ||
                            //                                              olci.Email2Address.Equals(duplicate.OutlookContact.Email3Address, StringComparison.InvariantCultureIgnoreCase)
                            //                                              ) ||
                            //!string.IsNullOrEmpty(olci.Email3Address) && (olci.Email3Address.Equals(duplicate.OutlookContact.Email1Address, StringComparison.InvariantCultureIgnoreCase) ||
                            //                                              olci.Email3Address.Equals(duplicate.OutlookContact.Email2Address, StringComparison.InvariantCultureIgnoreCase) ||
                            //                                              olci.Email3Address.Equals(duplicate.OutlookContact.Email3Address, StringComparison.InvariantCultureIgnoreCase)
                            //                                              ) ||
                            olci.MobileTelephoneNumber != null && olci.MobileTelephoneNumber.Equals(duplicate.OutlookContact.MobileTelephoneNumber) ||
                            !string.IsNullOrEmpty(olci.FileAs) && string.IsNullOrEmpty(duplicate.GoogleContact.Title) && duplicate.GoogleContact.Organizations.Count > 0 && olci.FileAs.Equals(duplicate.GoogleContact.Organizations[0].Name, StringComparison.InvariantCultureIgnoreCase)
                           )
                        {
                            duplicateFound = true;
                            duplicate.AddOutlookContact(olci);
                            sync.OutlookContactDuplicates.Add(match);
                            if (string.IsNullOrEmpty(duplicateOutlookContacts))
                                duplicateOutlookContacts = "Outlook contact found that has been already identified as duplicate Google contact (either same email, Mobile or FullName) and cannot be synchronized. Please delete or resolve duplicates of:";

                            string str = olci.FileAs + " (" + olci.Email1Address + ", " + olci.MobileTelephoneNumber + ")";
                            if (!duplicateOutlookContacts.Contains(str))
                                duplicateOutlookContacts += Environment.NewLine + str;

                            break;
                        }
                    }

                    if (!duplicateFound)
                        Logger.Log(string.Format("No match found for outlook contact ({0}) => {1}", olci.FileAs, (olci.UserProperties.GoogleContactId != null?"Delete from Outlook":"Add to Google")), EventType.Information);
                }
                else
                {
                    //Remember Google duplicates to later react to it when resetting matches or syncing
                    //ResetMatches: Also reset the duplicates
                    //Sync: Skip duplicates (don't sync duplicates to be fail safe)
                    if (match.AllGoogleContactMatches.Count > 1)
                    {
                        sync.GoogleContactDuplicates.Add(match);
                        foreach (Contact entry in match.AllGoogleContactMatches)
                        {
                            //Create message for duplicatesFound exception
                            if (string.IsNullOrEmpty(duplicateGoogleMatches))
                                duplicateGoogleMatches = "Outlook contacts matching with multiple Google contacts have been found (either same email, Mobile, FullName or company) and cannot be synchronized. Please delete or resolve duplicates of:";

                            string str = olci.FileAs + " (" + olci.Email1Address + ", " + olci.MobileTelephoneNumber + ")";
                            if (!duplicateGoogleMatches.Contains(str))
                                duplicateGoogleMatches += Environment.NewLine + str;
                        }
                    }

                }

                result.Add(match);
            }
            #endregion

            if (!string.IsNullOrEmpty(duplicateGoogleMatches) || !string.IsNullOrEmpty(duplicateOutlookContacts))
                duplicatesFound = new DuplicateDataException(duplicateGoogleMatches + Environment.NewLine + Environment.NewLine + duplicateOutlookContacts);
            else
                duplicatesFound = null;

            //return result;

            //for each google contact that's left (they will be nonmatched) create a new match pair without outlook contact.
            for (int i=0; i< sync.GoogleContacts.Count;i++)
            {
               Contact entry = sync.GoogleContacts[i];
               if (NotificationReceived != null)
                    NotificationReceived(String.Format("Adding new Google contact {0} of {1} by unique properties: {2} ...", i+1, sync.GoogleContacts.Count, entry.Title));

                // only match if there is either an email or mobile phone or a name or a company
                // otherwise a matching google contact will be created at each sync
                bool mobileExists = false;
                foreach (PhoneNumber phone in entry.Phonenumbers)
                {
                    if (phone.Rel == ContactsRelationships.IsMobile)
                    {
                        mobileExists = true;
                        break;
                    }
                }

                string googleOutlookId = ContactPropertiesUtils.GetGoogleOutlookContactId(sync.SyncProfile, entry);
                if (!String.IsNullOrEmpty(googleOutlookId) && skippedOutlookIds.Contains(googleOutlookId))
                {
                    Logger.Log("Skipped GoogleContact because Outlook contact couldn't be matched because of previous problem (see log): " + entry.Title, EventType.Warning);
                }
                else if (entry.Emails.Count == 0 && !mobileExists && string.IsNullOrEmpty(entry.Title) && (entry.Organizations.Count == 0 || string.IsNullOrEmpty(entry.Organizations[0].Name)))
                {
                    // no telephone and email

                    //ToDo: For now I use the ResolveDelete function, because it is almost the same, maybe we introduce a separate function for this ans also include DeleteGoogleAlways checkbox
                    var r = new ConflictResolver();
                    DeleteResolution res = r.ResolveDelete(entry);
                    if (res == DeleteResolution.DeleteGoogle || res == DeleteResolution.DeleteGoogleAlways)
                    {
                        ContactPropertiesUtils.SetGoogleOutlookContactId(sync.SyncProfile, entry, "-1"); //just set a dummy Id to delete this entry later on
                        sync.SaveContact(new ContactMatch(null, entry));
                    }
                    else
                    {
                        sync.SkippedCount++;
                        sync.SkippedCountNotMatches++;

                        Logger.Log("Skipped GoogleContact because no unique property found (Email1 or mobile or name or company):" + ContactMatch.GetSummary(entry), EventType.Warning);
                    }

                }
                else
                {
                    Logger.Log(string.Format("No match found for Google contact ({0}) => {1}", entry.Title, (!string.IsNullOrEmpty(googleOutlookId) ? "Delete from Google" : "Add to Outlook")), EventType.Information);
                    var match = new ContactMatch(null, entry);
                    result.Add(match);
                }
            }
            return result;
        }
        /// <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(Synchronizer 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;

                try
                {
                    ola = sync.OutlookAppointments[i] as Outlook.AppointmentItem;

                    //For debugging:
                    //if (ola.Subject == "Flex Pilot - Latest Status") // - 14.07.2014 11:30:00
                    //    throw new Exception("Debugging: Flex Pilot - Latest Status");

                    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 (Synchronizer.MonthsInPast > 0 &&
                             (ola.IsRecurring && ola.GetRecurrencePattern().PatternEndDate < DateTime.Now.AddMonths(-Synchronizer.MonthsInPast) ||
                              !ola.IsRecurring && ola.End < DateTime.Now.AddMonths(-Synchronizer.MonthsInPast)) ||
                             Synchronizer.MonthsInFuture > 0 &&
                             (ola.IsRecurring && ola.GetRecurrencePattern().PatternStartDate > DateTime.Now.AddMonths(Synchronizer.MonthsInFuture) ||
                              !ola.IsRecurring && ola.Start > DateTime.Now.AddMonths(Synchronizer.MonthsInFuture)))
                    {
                        Logger.Log("Skipping Outlook appointment because it is out of months range to sync:" + ola.Subject + " - " + ola.Start, EventType.Debug);
                        continue;
                    }
                    //else if (ola.Subject != "Business Trip")
                    //{//Only for debugging purposes, please comment if not needed
                    //    Logger.Log("Skipping Outlook appointment because of DEBUGGING:" + ola.Subject + " - " + ola.Start, EventType.Error);
                    //    continue;
                    //}
                }
                catch (Exception ex)
                {
                    //this is needed because some appointments throw exceptions
                    Logger.Log("Accessing Outlook appointment threw and exception. Skipping: " + ex.Message, EventType.Warning);
                    sync.SkippedCount++;
                    sync.SkippedCountNotMatches++;
                    continue;
                }

                //try
                //{

                if (NotificationReceived != null)
                {
                    NotificationReceived(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
                Outlook.ItemProperties userProperties = ola.ItemProperties;
                Outlook.ItemProperty   idProp         = userProperties[sync.OutlookPropertyNameId];
                try
                {
                    if (idProp != null)
                    {
                        string googleAppointmentId = string.Copy((string)idProp.Value);
                        Event  foundAppointment    = sync.GetGoogleAppointmentById(googleAppointmentId);
                        var    match = new AppointmentMatch(ola, null);



                        if (foundAppointment != null && !foundAppointment.Status.Equals("cancelled"))
                        {
                            //we found a match by google id, that is not deleted or cancelled yet

                            //ToDo: For an unknown reason, some appointments are duplicate in GoogleAppointments, therefore remove all duplicates before continuing
                            while (foundAppointment != null)
                            {
                                match.AddGoogleAppointment(foundAppointment);
                                result.Add(match);
                                //Remove the appointment from the list to not sync it twice
                                if (sync.GoogleAppointments.Contains(foundAppointment))
                                {
                                    sync.GoogleAppointments.Remove(foundAppointment);
                                    foundAppointment = sync.GetGoogleAppointmentById(googleAppointmentId);
                                }
                                else
                                {
                                    foundAppointment = null;
                                }
                            }
                        }
                        else
                        {
                            OutlookAppointmentsWithoutSyncId.Add(ola);
                        }
                    }
                    else
                    {
                        OutlookAppointmentsWithoutSyncId.Add(ola);
                    }
                }
                finally
                {
                    if (idProp != null)
                    {
                        Marshal.ReleaseComObject(idProp);
                    }
                    Marshal.ReleaseComObject(userProperties);
                }
            }
            #endregion
            #region Match the remaining appointments by properties

            for (int i = 0; i < OutlookAppointmentsWithoutSyncId.Count; i++)
            {
                Outlook.AppointmentItem ola = OutlookAppointmentsWithoutSyncId[i];

                if (NotificationReceived != null)
                {
                    NotificationReceived(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 googleAppointment = sync.GoogleAppointments[j];
                    // only match if there is a appointment targetBody, else
                    // a matching Google appointment will be created at each sync
                    if (!googleAppointment.Status.Equals("cancelled") && ola.Subject == googleAppointment.Summary && googleAppointment.Start.DateTime != null && ola.Start == googleAppointment.Start.DateTime)
                    {
                        match.AddGoogleAppointment(googleAppointment);
                        sync.GoogleAppointments.Remove(googleAppointment);

                        //ToDo: For an unknown reason, some appointments are duplicate in GoogleAppointments, therefore remove all duplicates before continuing
                        Event foundAppointment = sync.GetGoogleAppointmentById(AppointmentPropertiesUtils.GetGoogleId(googleAppointment));
                        while (foundAppointment != null)
                        {
                            //we found a match by google id, that is not deleted yet
                            match.AddGoogleAppointment(foundAppointment);
                            //Remove the appointment from the list to not sync it twice
                            if (sync.GoogleAppointments.Contains(foundAppointment))
                            {
                                sync.GoogleAppointments.Remove(foundAppointment);
                                foundAppointment = sync.GetGoogleAppointmentById(AppointmentPropertiesUtils.GetGoogleId(googleAppointment));
                            }
                            else
                            {
                                foundAppointment = null;
                            }
                        }
                    }
                }

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

                //For debugging:
                //if (googleAppointment.Summary == "Flex Pilot - Latest Status")
                //    throw new Exception("Debugging: Flex Pilot - Latest Status");



                if (NotificationReceived != null)
                {
                    NotificationReceived(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 + " - " + Synchronizer.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 + " - " + Synchronizer.GetTime(googleAppointment), EventType.Warning);
                }
                //else if (googleAppointment.Summary != "Business Trip")
                //{//Only for debugging purposes, please comment if not needed
                //    Logger.Log("Skipping Google appointment because of DEBUGGING:" + googleAppointment.Summary + " - " + googleAppointment.Times[0].StartTime, EventType.Error);
                //    continue;
                //}
                else
                {
                    Logger.Log(string.Format("No match found for Google appointment ({0}) => {1}", googleAppointment.Summary + " - " + Synchronizer.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 googleAppointment = googleAppointmentExceptions[i];
                if (NotificationReceived != null)
                {
                    NotificationReceived(String.Format("Adding Google appointment exception {0} of {1} ...", i + 1, googleAppointmentExceptions.Count, googleAppointment.Summary + " - " + Synchronizer.GetTime(googleAppointment)));
                }

                //Search for original recurrent event in matches
                //AtomId atomId = new AtomId(googleAppointment.Id.AbsoluteUri.Substring(0, googleAppointment.Id.AbsoluteUri.LastIndexOf("/") + 1) + googleAppointment.RecurringEventId);
                bool found = false;
                foreach (AppointmentMatch match in result)
                {
                    if (match.GoogleAppointment != null && googleAppointment.RecurringEventId.Equals(match.GoogleAppointment.Id))
                    {
                        match.GoogleAppointmentExceptions.Add(googleAppointment);
                        found = true;
                        break;
                    }
                }

                if (!found)
                {
                    Logger.Log(string.Format("No match found for Google appointment exception: {0}", googleAppointment.Summary + " - " + Synchronizer.GetTime(googleAppointment)), EventType.Debug);
                }
            }

            return(result);
        }
Esempio n. 32
0
        public static Collection<Group> GetGoogleGroups(Synchronizer sync, Contact googleContact)
        {
            int c = googleContact.GroupMembership.Count;
            Collection<Group> groups = new Collection<Group>();
            string id;
            Group group;
            for (int i = 0; i < c; i++)
            {
                id = googleContact.GroupMembership[i].HRef;
                group = sync.GetGoogleGroupById(id);

                groups.Add(group);
            }
            return groups;
        }
Esempio n. 33
0
 public static bool ContainsGroup(Synchronizer sync, Contact googleContact, string groupName)
 {
     Group group = sync.GetGoogleGroupByName(groupName);
     if (group == null)
         return false;
     return ContainsGroup(googleContact, group);
 }
Esempio n. 34
0
        public static bool UpdateRecurrenceExceptions(List<Event> googleRecurrenceExceptions, Outlook.AppointmentItem slave, Synchronizer sync)
        {
            bool ret = false;

            for (int i = 0; i < googleRecurrenceExceptions.Count; i++)
            {
                Event googleRecurrenceException = googleRecurrenceExceptions[i];
                //if (slave == null || !slave.IsRecurring || slave.RecurrenceState != Outlook.OlRecurrenceState.olApptMaster)
                //    Logger.Log("Google Appointment with OriginalEvent found, but Outlook is not recurring: " + googleAppointment.Summary + " - " + GetTime(googleAppointment), EventType.Warning);
                //else
                //{
                Outlook.AppointmentItem outlookRecurrenceException = null;
                try
                {
                    var slaveRecurrence = slave.GetRecurrencePattern();
                    if (googleRecurrenceException.OriginalStartTime != null && !string.IsNullOrEmpty(googleRecurrenceException.OriginalStartTime.Date))
                        outlookRecurrenceException = slaveRecurrence.GetOccurrence(DateTime.Parse(googleRecurrenceException.OriginalStartTime.Date));
                    else if (googleRecurrenceException.OriginalStartTime != null && googleRecurrenceException.OriginalStartTime.DateTime != null)
                        outlookRecurrenceException = slaveRecurrence.GetOccurrence(googleRecurrenceException.OriginalStartTime.DateTime.Value);
                }
                catch (Exception ignored)
                {
                    Logger.Log("Google Appointment with OriginalEvent found, but Outlook occurrence not found: " + googleRecurrenceException.Summary + " - " + googleRecurrenceException.OriginalStartTime.DateTime + ": " + ignored, EventType.Debug);
                }

                if (outlookRecurrenceException != null)
                {
                    //myInstance.Subject = googleAppointment.Summary;
                    //myInstance.Start = googleAppointment.Times[0].StartTime;
                    //myInstance.End = googleAppointment.Times[0].EndTime;
                    DateTime? timeMin = null;
                    DateTime? timeMax = null;
                    if (googleRecurrenceException.Start != null && !string.IsNullOrEmpty(googleRecurrenceException.Start.Date))
                        timeMin = DateTime.Parse(googleRecurrenceException.Start.Date);
                    else if (googleRecurrenceException.Start != null)
                        timeMin = googleRecurrenceException.Start.DateTime;

                    if (googleRecurrenceException.End != null && !string.IsNullOrEmpty(googleRecurrenceException.End.Date))
                        timeMax = DateTime.Parse(googleRecurrenceException.End.Date);
                    else if (googleRecurrenceException.End != null)
                        timeMax = googleRecurrenceException.End.DateTime;

                    googleRecurrenceException = sync.LoadGoogleAppointments(googleRecurrenceException.Id, 0, 0, timeMin, timeMax); //Reload, just in case it was updated by master recurrence
                    if (googleRecurrenceException != null)
                    {
                        if (googleRecurrenceException.Status.Equals("cancelled"))
                        {
                            outlookRecurrenceException.Delete();
                            string timeToLog = null;
                            if (googleRecurrenceException.OriginalStartTime != null)
                            {
                                timeToLog = googleRecurrenceException.OriginalStartTime.Date;
                                if (string.IsNullOrEmpty(timeToLog) && googleRecurrenceException.OriginalStartTime.DateTime != null)
                                timeToLog =  googleRecurrenceException.OriginalStartTime.DateTime.Value.ToString();
                            }

                            Logger.Log("Deleted obsolete recurrence exception from Outlook: " + slave.Subject + " - " + timeToLog, EventType.Information);
                        }
                        else
                        {
                            if (sync.UpdateAppointment(ref googleRecurrenceException, outlookRecurrenceException, null))
                            {
                                outlookRecurrenceException.Save();
                                Logger.Log("Updated recurrence exception from Google to Outlook: " + googleRecurrenceException.Summary + " - " + Synchronizer.GetTime(googleRecurrenceException), EventType.Information);
                            }
                        }
                        ret = true;

                    }
                    else
                        Logger.Log("Error updating recurrence exception from Google to Outlook (couldn't be reload from Google): " + outlookRecurrenceException.Subject + " - " + outlookRecurrenceException.Start, EventType.Information);

                }

                //}

            }

            return ret;
        }
Esempio n. 35
0
        public static void SyncNote(NoteMatch match, Synchronizer sync)
        {
            Outlook.NoteItem outlookNoteItem = match.OutlookNote;

            //try
            //{
            if (match.GoogleNote == null && match.OutlookNote != null)
            {
                //no Google note
                string googleNotetId = NotePropertiesUtils.GetOutlookGoogleNoteId(sync, outlookNoteItem);
                if (!string.IsNullOrEmpty(googleNotetId))
                {
                    //Redundant check if exist, but in case an error occurred in MatchNotes
                    Document matchingGoogleNote = sync.GetGoogleNoteById(googleNotetId);
                    if (matchingGoogleNote == null)
                    {
                        if (sync.SyncOption == SyncOption.OutlookToGoogleOnly || !sync.SyncDelete)
                        {
                            return;
                        }
                        else if (!sync.PromptDelete)
                        {
                            sync.DeleteOutlookResolution = DeleteResolution.DeleteOutlookAlways;
                        }
                        else if (sync.DeleteOutlookResolution != DeleteResolution.DeleteOutlookAlways &&
                                 sync.DeleteOutlookResolution != DeleteResolution.KeepOutlookAlways)
                        {
                            var r = new ConflictResolver();
                            sync.DeleteOutlookResolution = r.ResolveDelete(match.OutlookNote);
                        }
                        switch (sync.DeleteOutlookResolution)
                        {
                        case DeleteResolution.KeepOutlook:
                        case DeleteResolution.KeepOutlookAlways:
                            NotePropertiesUtils.ResetOutlookGoogleNoteId(sync, match.OutlookNote);
                            break;

                        case DeleteResolution.DeleteOutlook:
                        case DeleteResolution.DeleteOutlookAlways:
                            //Avoid recreating a GoogleNote already existing
                            //==> Delete this outlookNote instead if previous match existed but no match exists anymore
                            return;

                        default:
                            throw new ApplicationException("Cancelled");
                        }
                    }
                }

                if (sync.SyncOption == SyncOption.GoogleToOutlookOnly)
                {
                    sync.SkippedCount++;
                    Logger.Log(string.Format("Outlook Note not added to Google, because of SyncOption " + sync.SyncOption.ToString() + ": {0}", match.OutlookNote.Subject), EventType.Information);
                    return;
                }

                //create a Google note from Outlook note
                match.GoogleNote      = new Document();
                match.GoogleNote.Type = Document.DocumentType.Document;
                //match.GoogleNote.Categories.Add(new AtomCategory("http://schemas.google.com/docs/2007#document"));
                //match.GoogleNote.Categories.Add(new AtomCategory("document"));

                sync.UpdateNote(outlookNoteItem, match.GoogleNote);
            }
            else if (match.OutlookNote == null && match.GoogleNote != null)
            {
                // no outlook note
                if (NotePropertiesUtils.NoteFileExists(match.GoogleNote.Id, sync.SyncProfile))
                {
                    if (sync.SyncOption == SyncOption.GoogleToOutlookOnly || !sync.SyncDelete)
                    {
                        return;
                    }
                    else if (!sync.PromptDelete)
                    {
                        sync.DeleteGoogleResolution = DeleteResolution.DeleteGoogleAlways;
                    }
                    else if (sync.DeleteGoogleResolution != DeleteResolution.DeleteGoogleAlways &&
                             sync.DeleteGoogleResolution != DeleteResolution.KeepGoogleAlways)
                    {
                        var r = new ConflictResolver();
                        sync.DeleteGoogleResolution = r.ResolveDelete(match.GoogleNote, sync);
                    }
                    switch (sync.DeleteGoogleResolution)
                    {
                    case DeleteResolution.KeepGoogle:
                    case DeleteResolution.KeepGoogleAlways:
                        System.IO.File.Delete(NotePropertiesUtils.GetFileName(match.GoogleNote.Id, sync.SyncProfile));
                        break;

                    case DeleteResolution.DeleteGoogle:
                    case DeleteResolution.DeleteGoogleAlways:
                        //Avoid recreating a OutlookNote already existing
                        //==> Delete this googleNote instead if previous match existed but no match exists anymore
                        return;

                    default:
                        throw new ApplicationException("Cancelled");
                    }
                }


                if (sync.SyncOption == SyncOption.OutlookToGoogleOnly)
                {
                    sync.SkippedCount++;
                    Logger.Log(string.Format("Google Note not added to Outlook, because of SyncOption " + sync.SyncOption.ToString() + ": {0}", match.GoogleNote.Title), EventType.Information);
                    return;
                }

                //create a Outlook note from Google note
                outlookNoteItem = Synchronizer.CreateOutlookNoteItem(Synchronizer.SyncNotesFolder);

                sync.UpdateNote(match.GoogleNote, outlookNoteItem);
                match.OutlookNote = outlookNoteItem;
            }
            else if (match.OutlookNote != null && match.GoogleNote != null)
            {
                //merge note details

                //determine if this note pair were synchronized
                //DateTime? lastUpdated = GetOutlookPropertyValueDateTime(match.OutlookNote, sync.OutlookPropertyNameUpdated);
                DateTime?lastSynced = NotePropertiesUtils.GetOutlookLastSync(sync, outlookNoteItem);
                if (lastSynced.HasValue)
                {
                    //note pair was syncronysed before.

                    //determine if google note was updated since last sync

                    //lastSynced is stored without seconds. take that into account.
                    DateTime lastUpdatedOutlook = match.OutlookNote.LastModificationTime.AddSeconds(-match.OutlookNote.LastModificationTime.Second);
                    DateTime lastUpdatedGoogle  = match.GoogleNote.Updated.AddSeconds(-match.GoogleNote.Updated.Second);

                    //check if both outlok and google notes where updated sync last sync
                    if (lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                        lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance)
                    {
                        //both notes were updated.
                        //options: 1) ignore 2) loose one based on SyncOption
                        //throw new Exception("Both notes were updated!");

                        switch (sync.SyncOption)
                        {
                        case SyncOption.MergeOutlookWins:
                        case SyncOption.OutlookToGoogleOnly:
                            //overwrite google note
                            Logger.Log("Outlook and Google note have been updated, Outlook note is overwriting Google because of SyncOption " + sync.SyncOption + ": " + match.OutlookNote.Subject + ".", EventType.Information);
                            sync.UpdateNote(outlookNoteItem, match.GoogleNote);
                            break;

                        case SyncOption.MergeGoogleWins:
                        case SyncOption.GoogleToOutlookOnly:
                            //overwrite outlook note
                            Logger.Log("Outlook and Google note have been updated, Google note is overwriting Outlook because of SyncOption " + sync.SyncOption + ": " + match.OutlookNote.Subject + ".", EventType.Information);
                            sync.UpdateNote(match.GoogleNote, outlookNoteItem);
                            break;

                        case SyncOption.MergePrompt:
                            //promp for sync option
                            if (sync.ConflictResolution != ConflictResolution.GoogleWinsAlways &&
                                sync.ConflictResolution != ConflictResolution.OutlookWinsAlways &&
                                sync.ConflictResolution != ConflictResolution.SkipAlways)
                            {
                                var r = new ConflictResolver();
                                sync.ConflictResolution = r.Resolve(outlookNoteItem, match.GoogleNote, sync, false);
                            }
                            switch (sync.ConflictResolution)
                            {
                            case ConflictResolution.Skip:
                            case ConflictResolution.SkipAlways:
                                Logger.Log(string.Format("User skipped note ({0}).", match.ToString()), EventType.Information);
                                sync.SkippedCount++;
                                break;

                            case ConflictResolution.OutlookWins:
                            case ConflictResolution.OutlookWinsAlways:
                                sync.UpdateNote(outlookNoteItem, match.GoogleNote);
                                break;

                            case ConflictResolution.GoogleWins:
                            case ConflictResolution.GoogleWinsAlways:
                                sync.UpdateNote(match.GoogleNote, outlookNoteItem);
                                break;

                            default:
                                throw new ApplicationException("Canceled");
                            }
                            break;
                        }
                        return;
                    }


                    //check if outlook note was updated (with X second tolerance)
                    if (sync.SyncOption != SyncOption.GoogleToOutlookOnly &&
                        (lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance ||
                         lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                         sync.SyncOption == SyncOption.OutlookToGoogleOnly
                        )
                        )
                    {
                        //outlook note was changed or changed Google note will be overwritten

                        if (lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                            sync.SyncOption == SyncOption.OutlookToGoogleOnly)
                        {
                            Logger.Log("Google note has been updated since last sync, but Outlook note is overwriting Google because of SyncOption " + sync.SyncOption + ": " + match.OutlookNote.Subject + ".", EventType.Information);
                        }

                        sync.UpdateNote(outlookNoteItem, match.GoogleNote);

                        //at the moment use outlook as "master" source of notes - in the event of a conflict google note will be overwritten.
                        //TODO: control conflict resolution by SyncOption
                        return;
                    }

                    //check if google note was updated (with X second tolerance)
                    if (sync.SyncOption != SyncOption.OutlookToGoogleOnly &&
                        (lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance ||
                         lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                         sync.SyncOption == SyncOption.GoogleToOutlookOnly
                        )
                        )
                    {
                        //google note was changed or changed Outlook note will be overwritten

                        if (lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                            sync.SyncOption == SyncOption.GoogleToOutlookOnly)
                        {
                            Logger.Log("Outlook note has been updated since last sync, but Google note is overwriting Outlook because of SyncOption " + sync.SyncOption + ": " + match.OutlookNote.Subject + ".", EventType.Information);
                        }

                        sync.UpdateNote(match.GoogleNote, outlookNoteItem);
                    }
                }
                else
                {
                    //notes were never synced.
                    //merge notes.
                    switch (sync.SyncOption)
                    {
                    case SyncOption.MergeOutlookWins:
                    case SyncOption.OutlookToGoogleOnly:
                        //overwrite google note
                        sync.UpdateNote(outlookNoteItem, match.GoogleNote);
                        break;

                    case SyncOption.MergeGoogleWins:
                    case SyncOption.GoogleToOutlookOnly:
                        //overwrite outlook note
                        sync.UpdateNote(match.GoogleNote, outlookNoteItem);
                        break;

                    case SyncOption.MergePrompt:
                        //promp for sync option
                        if (sync.ConflictResolution != ConflictResolution.GoogleWinsAlways &&
                            sync.ConflictResolution != ConflictResolution.OutlookWinsAlways &&
                            sync.ConflictResolution != ConflictResolution.SkipAlways)
                        {
                            var r = new ConflictResolver();
                            sync.ConflictResolution = r.Resolve(outlookNoteItem, match.GoogleNote, sync, true);
                        }
                        switch (sync.ConflictResolution)
                        {
                        case ConflictResolution.Skip:
                        case ConflictResolution.SkipAlways:             //Keep both, Google AND Outlook
                            sync.Notes.Add(new NoteMatch(match.OutlookNote, null));
                            sync.Notes.Add(new NoteMatch(null, match.GoogleNote));
                            break;

                        case ConflictResolution.OutlookWins:
                        case ConflictResolution.OutlookWinsAlways:
                            sync.UpdateNote(outlookNoteItem, match.GoogleNote);
                            break;

                        case ConflictResolution.GoogleWins:
                        case ConflictResolution.GoogleWinsAlways:
                            sync.UpdateNote(match.GoogleNote, outlookNoteItem);
                            break;

                        default:
                            throw new ApplicationException("Canceled");
                        }
                        break;
                    }
                }
            }
            else
            {
                throw new ArgumentNullException("NotetMatch has all peers null.");
            }
            //}
            //finally
            //{
            //if (outlookNoteItem != null &&
            //    match.OutlookNote != null)
            //{
            //    match.OutlookNote.Update(outlookNoteItem, sync);
            //    Marshal.ReleaseComObject(outlookNoteItem);
            //    outlookNoteItem = null;
            //}
            //}
        }
        public static void ResetOutlookGoogleNoteId(Synchronizer sync, Outlook.NoteItem outlookNote)
        {
            Outlook.ItemProperties userProperties = outlookNote.ItemProperties;
            try
            {
                Outlook.ItemProperty idProp = userProperties[sync.OutlookPropertyNameId];
                try
                {
                    Outlook.ItemProperty lastSyncProp = userProperties[sync.OutlookPropertyNameSynced];
                    try
                    {
                        if (idProp == null && lastSyncProp == null)
                            return;

                        List<int> indexesToBeRemoved = new List<int>();
                        IEnumerator en = userProperties.GetEnumerator();
                        en.Reset();
                        int index = 0; // 0 based collection
                        while (en.MoveNext())
                        {
                            Outlook.ItemProperty userProperty = en.Current as Outlook.ItemProperty;
                            if (userProperty == idProp || userProperty == lastSyncProp)
                            {
                                indexesToBeRemoved.Add(index);
                                //outlookNote.UserProperties.Remove(index);
                                //Don't return to remove both properties, googleId and lastSynced
                                //return;
                            }
                            index++;
                            Marshal.ReleaseComObject(userProperty);
                        }

                        for (int i = indexesToBeRemoved.Count - 1; i >= 0; i--)
                            userProperties.Remove(indexesToBeRemoved[i]);
                        //throw new Exception("Did not find prop.");
                    }
                    finally
                    {
                        if (lastSyncProp != null)
                            Marshal.ReleaseComObject(lastSyncProp);
                    }
                }
                finally
                {
                    if (idProp != null)
                        Marshal.ReleaseComObject(idProp);
                }
            }
            finally
            {
                Marshal.ReleaseComObject(userProperties);
            }
        }
Esempio n. 37
0
        public ConflictResolution Resolve(string message, Microsoft.Office.Interop.Outlook.AppointmentItem outlookAppointment, Event googleAppointment, Synchronizer sync, bool keepOutlook, bool keepGoogle)
        {
            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 + " - " + Synchronizer.GetTime(googleAppointment);
                _form.GoogleItemTextBox.Text += googleAppointment.Description;
            }

            //ToDo: Make it more flexible
            _form.keepGoogle.Enabled  = keepGoogle;
            _form.keepOutlook.Enabled = keepOutlook;
            _form.AllCheckBox.Visible = true;
            _form.messageLabel.Text   = message;

            return(Resolve());
        }
 public static void SetOutlookLastSync(Synchronizer sync, Outlook.NoteItem outlookNote)
 {
     //save sync datetime
     Outlook.ItemProperties userProperties = outlookNote.ItemProperties;
     try
     {
         Outlook.ItemProperty prop = userProperties[sync.OutlookPropertyNameSynced];
         if (prop == null)
             prop = userProperties.Add(sync.OutlookPropertyNameSynced, Outlook.OlUserPropertyType.olDateTime, true);
         try
         {
             prop.Value = DateTime.Now;
         }
         finally
         {
             Marshal.ReleaseComObject(prop);
         }
     }
     finally
     {
         Marshal.ReleaseComObject(userProperties);
     }
 }
Esempio n. 39
0
 public ConflictResolution Resolve(string message, Event googleAppointment, Microsoft.Office.Interop.Outlook.AppointmentItem outlookAppointment, Synchronizer sync)
 {
     return(Resolve(message, outlookAppointment, googleAppointment, sync, false, true));
 }
Esempio n. 40
0
        public ConflictResolution Resolve(Microsoft.Office.Interop.Outlook.AppointmentItem outlookAppointment, Event googleAppointment, Synchronizer 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 + " - " + Synchronizer.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();
        }
Esempio n. 41
0
        public ConflictResolution Resolve(string message, Microsoft.Office.Interop.Outlook.AppointmentItem outlookAppointment, Event googleAppointment, Synchronizer sync, bool keepOutlook, bool keepGoogle)
        {
            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 + " - " + Synchronizer.GetTime(googleAppointment);
                _form.GoogleItemTextBox.Text += googleAppointment.Description;
            }

            //ToDo: Make it more flexible
            _form.keepGoogle.Enabled = keepGoogle;
            _form.keepOutlook.Enabled = keepOutlook;
            _form.AllCheckBox.Visible = true;
            _form.messageLabel.Text = message;

            return Resolve();
        }
        public static void SyncAppointment(AppointmentMatch match, Synchronizer sync)
        {
            if (match.GoogleAppointment == null && match.OutlookAppointment != null)
            {
                //no Google appointment
                string googleAppointmentId = AppointmentPropertiesUtils.GetOutlookGoogleAppointmentId(sync, match.OutlookAppointment);
                if (!string.IsNullOrEmpty(googleAppointmentId))
                {
                    //if (match.OutlookAppointment.IsRecurring && match.OutlookAppointment.RecurrenceState == Outlook.OlRecurrenceState.olApptMaster &&
                    //    (Syncronizer.MonthsInPast == 0 || new DateTime(DateTime.Now.AddMonths(-Syncronizer.MonthsInPast).Year, match.OutlookAppointment.End.Month, match.OutlookAppointment.End.Day) >= DateTime.Now.AddMonths(-Syncronizer.MonthsInPast)) &&
                    //    (Syncronizer.MonthsInFuture == 0 || new DateTime(DateTime.Now.AddMonths(-Syncronizer.MonthsInPast).Year, match.OutlookAppointment.Start.Month, match.OutlookAppointment.Start.Day) <= DateTime.Now.AddMonths(Syncronizer.MonthsInFuture))
                    //    ||
                    //    (Syncronizer.MonthsInPast == 0 || match.OutlookAppointment.End >= DateTime.Now.AddMonths(-Syncronizer.MonthsInPast)) &&
                    //    (Syncronizer.MonthsInFuture == 0 || match.OutlookAppointment.Start <= DateTime.Now.AddMonths(Syncronizer.MonthsInFuture))
                    //    )
                    //{

                    //Redundant check if exist, but in case an error occurred in MatchAppointments or not all appointments have been loaded (e.g. because months before/after constraint)
                    Event matchingGoogleAppointment = null;
                    if (sync.AllGoogleAppointments != null)
                    {
                        matchingGoogleAppointment = sync.GetGoogleAppointmentById(googleAppointmentId);
                    }
                    else
                    {
                        matchingGoogleAppointment = sync.LoadGoogleAppointments(googleAppointmentId, 0, 0, null, null);
                    }
                    if (matchingGoogleAppointment == null)
                    {
                        if (sync.SyncOption == SyncOption.OutlookToGoogleOnly || !sync.SyncDelete)
                        {
                            return;
                        }
                        else if (!sync.PromptDelete && match.OutlookAppointment.Recipients.Count == 0)
                        {
                            sync.DeleteOutlookResolution = DeleteResolution.DeleteOutlookAlways;
                        }
                        else if (sync.DeleteOutlookResolution != DeleteResolution.DeleteOutlookAlways &&
                                 sync.DeleteOutlookResolution != DeleteResolution.KeepOutlookAlways)
                        {
                            var r = new ConflictResolver();
                            sync.DeleteOutlookResolution = r.ResolveDelete(match.OutlookAppointment);
                        }
                        switch (sync.DeleteOutlookResolution)
                        {
                        case DeleteResolution.KeepOutlook:
                        case DeleteResolution.KeepOutlookAlways:
                            AppointmentPropertiesUtils.ResetOutlookGoogleAppointmentId(sync, match.OutlookAppointment);
                            break;

                        case DeleteResolution.DeleteOutlook:
                        case DeleteResolution.DeleteOutlookAlways:

                            if (match.OutlookAppointment.Recipients.Count > 1)
                            {
                                //ToDo:Maybe find as better way, e.g. to ask the user, if he wants to overwrite the invalid appointment
                                Logger.Log("Outlook Appointment not deleted, because multiple participants found,  invitation maybe NOT sent by Google: " + match.OutlookAppointment.Subject + " - " + match.OutlookAppointment.Start, EventType.Information);
                                AppointmentPropertiesUtils.ResetOutlookGoogleAppointmentId(sync, match.OutlookAppointment);
                                break;
                            }
                            else
                            {
                                //Avoid recreating a GoogleAppointment already existing
                                //==> Delete this OutlookAppointment instead if previous match existed but no match exists anymore
                                return;
                            }

                        default:
                            throw new ApplicationException("Cancelled");
                        }
                    }
                    else
                    {
                        sync.SkippedCount++;
                        match.GoogleAppointment = matchingGoogleAppointment;
                        Logger.Log("Outlook Appointment not deleted, because still existing on Google side, maybe because months restriction: " + match.OutlookAppointment.Subject + " - " + match.OutlookAppointment.Start, EventType.Information);
                        return;
                    }
                }
                //}

                if (sync.SyncOption == SyncOption.GoogleToOutlookOnly)
                {
                    sync.SkippedCount++;
                    Logger.Log(string.Format("Outlook appointment not added to Google, because of SyncOption " + sync.SyncOption.ToString() + ": {0}", match.OutlookAppointment.Subject), EventType.Information);
                    return;
                }

                //create a Google appointment from Outlook appointment
                match.GoogleAppointment = Factory.NewEvent();

                sync.UpdateAppointment(match.OutlookAppointment, ref match.GoogleAppointment);
            }
            else if (match.OutlookAppointment == null && match.GoogleAppointment != null)
            {
                //no Outlook appointment
                string outlookAppointmenttId = AppointmentPropertiesUtils.GetGoogleOutlookAppointmentId(sync.SyncProfile, match.GoogleAppointment);
                if (!string.IsNullOrEmpty(outlookAppointmenttId))
                {
                    if (sync.SyncOption == SyncOption.GoogleToOutlookOnly || !sync.SyncDelete)
                    {
                        return;
                    }
                    else if (!sync.PromptDelete)
                    {
                        sync.DeleteGoogleResolution = DeleteResolution.DeleteGoogleAlways;
                    }
                    else if (sync.DeleteGoogleResolution != DeleteResolution.DeleteGoogleAlways &&
                             sync.DeleteGoogleResolution != DeleteResolution.KeepGoogleAlways)
                    {
                        var r = new ConflictResolver();
                        sync.DeleteGoogleResolution = r.ResolveDelete(match.GoogleAppointment);
                    }
                    switch (sync.DeleteGoogleResolution)
                    {
                    case DeleteResolution.KeepGoogle:
                    case DeleteResolution.KeepGoogleAlways:
                        AppointmentPropertiesUtils.ResetGoogleOutlookAppointmentId(sync.SyncProfile, match.GoogleAppointment);
                        break;

                    case DeleteResolution.DeleteGoogle:
                    case DeleteResolution.DeleteGoogleAlways:
                        //Avoid recreating a OutlookAppointment already existing
                        //==> Delete this googleAppointment instead if previous match existed but no match exists anymore
                        return;

                    default:
                        throw new ApplicationException("Cancelled");
                    }
                }


                if (sync.SyncOption == SyncOption.OutlookToGoogleOnly)
                {
                    sync.SkippedCount++;
                    Logger.Log(string.Format("Google appointment not added to Outlook, because of SyncOption " + sync.SyncOption.ToString() + ": {0}", match.GoogleAppointment.Summary), EventType.Information);
                    return;
                }

                //create a Outlook appointment from Google appointment
                match.OutlookAppointment = Synchronizer.CreateOutlookAppointmentItem(Synchronizer.SyncAppointmentsFolder);

                sync.UpdateAppointment(ref match.GoogleAppointment, match.OutlookAppointment, match.GoogleAppointmentExceptions);
            }
            else if (match.OutlookAppointment != null && match.GoogleAppointment != null)
            {
                //ToDo: Check how to overcome appointment recurrences, which need more than 60 seconds to update and therefore get updated again and again because of time tolerance 60 seconds violated again and again


                //merge appointment details

                //determine if this appointment pair were synchronized
                //DateTime? lastUpdated = GetOutlookPropertyValueDateTime(match.OutlookAppointment, sync.OutlookPropertyNameUpdated);
                DateTime?lastSynced = AppointmentPropertiesUtils.GetOutlookLastSync(sync, match.OutlookAppointment);
                if (lastSynced.HasValue)
                {
                    //appointment pair was syncronysed before.

                    //determine if Google appointment was updated since last sync

                    //lastSynced is stored without seconds. take that into account.
                    DateTime lastUpdatedOutlook = match.OutlookAppointment.LastModificationTime.AddSeconds(-match.OutlookAppointment.LastModificationTime.Second);
                    DateTime lastUpdatedGoogle  = match.GoogleAppointment.Updated.Value.AddSeconds(-match.GoogleAppointment.Updated.Value.Second);
                    //consider GoogleAppointmentExceptions, because if they are updated, the master appointment doesn't have a new Saved TimeStamp
                    foreach (Event googleAppointment in match.GoogleAppointmentExceptions)
                    {
                        if (googleAppointment.Updated != null)//happens for cancelled events
                        {
                            DateTime lastUpdatedGoogleException = googleAppointment.Updated.Value.AddSeconds(-googleAppointment.Updated.Value.Second);
                            if (lastUpdatedGoogleException > lastUpdatedGoogle)
                            {
                                lastUpdatedGoogle = lastUpdatedGoogleException;
                            }
                        }
                        else if (match.OutlookAppointment.IsRecurring && match.OutlookAppointment.RecurrenceState == Outlook.OlRecurrenceState.olApptMaster)
                        {
                            Outlook.AppointmentItem outlookRecurrenceException = null;
                            try
                            {
                                var slaveRecurrence = match.OutlookAppointment.GetRecurrencePattern();
                                if (googleAppointment.OriginalStartTime != null && !string.IsNullOrEmpty(googleAppointment.OriginalStartTime.Date))
                                {
                                    outlookRecurrenceException = slaveRecurrence.GetOccurrence(DateTime.Parse(googleAppointment.OriginalStartTime.Date));
                                }
                                else if (googleAppointment.OriginalStartTime != null && googleAppointment.OriginalStartTime.DateTime != null)
                                {
                                    outlookRecurrenceException = slaveRecurrence.GetOccurrence(googleAppointment.OriginalStartTime.DateTime.Value);
                                }
                            }
                            catch (Exception ignored)
                            {
                                Logger.Log("Google Appointment with OriginalEvent found, but Outlook occurrence not found: " + googleAppointment.Summary + " - " + googleAppointment.OriginalStartTime.DateTime + ": " + ignored, EventType.Debug);
                            }


                            if (outlookRecurrenceException != null && outlookRecurrenceException.MeetingStatus != Outlook.OlMeetingStatus.olMeetingCanceled)
                            {
                                lastUpdatedGoogle = DateTime.Now;
                                break; //no need to search further, already newest date set
                            }
                        }
                    }

                    //check if both outlok and Google appointments where updated sync last sync
                    if ((int)lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                        (int)lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance)
                    {
                        //both appointments were updated.
                        //options: 1) ignore 2) loose one based on SyncOption
                        //throw new Exception("Both appointments were updated!");

                        switch (sync.SyncOption)
                        {
                        case SyncOption.MergeOutlookWins:
                        case SyncOption.OutlookToGoogleOnly:
                            //overwrite Google appointment
                            Logger.Log("Outlook and Google appointment have been updated, Outlook appointment is overwriting Google because of SyncOption " + sync.SyncOption + ": " + match.OutlookAppointment.Subject + ".", EventType.Information);
                            sync.UpdateAppointment(match.OutlookAppointment, ref match.GoogleAppointment);
                            break;

                        case SyncOption.MergeGoogleWins:
                        case SyncOption.GoogleToOutlookOnly:
                            //overwrite outlook appointment
                            Logger.Log("Outlook and Google appointment have been updated, Google appointment is overwriting Outlook because of SyncOption " + sync.SyncOption + ": " + match.GoogleAppointment.Summary + ".", EventType.Information);
                            sync.UpdateAppointment(ref match.GoogleAppointment, match.OutlookAppointment, match.GoogleAppointmentExceptions);
                            break;

                        case SyncOption.MergePrompt:
                            //promp for sync option
                            if (sync.ConflictResolution != ConflictResolution.GoogleWinsAlways &&
                                sync.ConflictResolution != ConflictResolution.OutlookWinsAlways &&
                                sync.ConflictResolution != ConflictResolution.SkipAlways)
                            {
                                var r = new ConflictResolver();
                                sync.ConflictResolution = r.Resolve(match.OutlookAppointment, match.GoogleAppointment, sync, false);
                            }
                            switch (sync.ConflictResolution)
                            {
                            case ConflictResolution.Skip:
                            case ConflictResolution.SkipAlways:
                                Logger.Log(string.Format("User skipped appointment ({0}).", match.ToString()), EventType.Information);
                                sync.SkippedCount++;
                                break;

                            case ConflictResolution.OutlookWins:
                            case ConflictResolution.OutlookWinsAlways:
                                sync.UpdateAppointment(match.OutlookAppointment, ref match.GoogleAppointment);
                                break;

                            case ConflictResolution.GoogleWins:
                            case ConflictResolution.GoogleWinsAlways:
                                sync.UpdateAppointment(ref match.GoogleAppointment, match.OutlookAppointment, match.GoogleAppointmentExceptions);
                                break;

                            default:
                                throw new ApplicationException("Cancelled");
                            }
                            break;
                        }
                        return;
                    }


                    //check if Outlook appointment was updated (with X second tolerance)
                    if (sync.SyncOption != SyncOption.GoogleToOutlookOnly &&
                        ((int)lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance ||
                         (int)lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                         sync.SyncOption == SyncOption.OutlookToGoogleOnly
                        )
                        )
                    {
                        //Outlook appointment was changed or changed Google appointment will be overwritten

                        if ((int)lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                            sync.SyncOption == SyncOption.OutlookToGoogleOnly)
                        {
                            Logger.Log("Google appointment has been updated since last sync, but Outlook appointment is overwriting Google because of SyncOption " + sync.SyncOption + ": " + match.OutlookAppointment.Subject + ".", EventType.Information);
                        }

                        sync.UpdateAppointment(match.OutlookAppointment, ref match.GoogleAppointment);

                        //at the moment use Outlook as "master" source of appointments - in the event of a conflict Google appointment will be overwritten.
                        //TODO: control conflict resolution by SyncOption
                        return;
                    }

                    //check if Google appointment was updated (with X second tolerance)
                    if (sync.SyncOption != SyncOption.OutlookToGoogleOnly &&
                        ((int)lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance ||
                         (int)lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                         sync.SyncOption == SyncOption.GoogleToOutlookOnly
                        )
                        )
                    {
                        //google appointment was changed or changed Outlook appointment will be overwritten

                        if ((int)lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds > TimeTolerance &&
                            sync.SyncOption == SyncOption.GoogleToOutlookOnly)
                        {
                            Logger.Log("Outlook appointment has been updated since last sync, but Google appointment is overwriting Outlook because of SyncOption " + sync.SyncOption + ": " + match.OutlookAppointment.Subject + ".", EventType.Information);
                        }

                        sync.UpdateAppointment(ref match.GoogleAppointment, match.OutlookAppointment, match.GoogleAppointmentExceptions);
                    }
                }
                else
                {
                    //appointments were never synced.
                    //merge appointments.
                    switch (sync.SyncOption)
                    {
                    case SyncOption.MergeOutlookWins:
                    case SyncOption.OutlookToGoogleOnly:
                        //overwrite Google appointment
                        sync.UpdateAppointment(match.OutlookAppointment, ref match.GoogleAppointment);
                        break;

                    case SyncOption.MergeGoogleWins:
                    case SyncOption.GoogleToOutlookOnly:
                        //overwrite outlook appointment
                        sync.UpdateAppointment(ref match.GoogleAppointment, match.OutlookAppointment, match.GoogleAppointmentExceptions);
                        break;

                    case SyncOption.MergePrompt:
                        //promp for sync option
                        if (sync.ConflictResolution != ConflictResolution.GoogleWinsAlways &&
                            sync.ConflictResolution != ConflictResolution.OutlookWinsAlways &&
                            sync.ConflictResolution != ConflictResolution.SkipAlways)
                        {
                            var r = new ConflictResolver();
                            sync.ConflictResolution = r.Resolve(match.OutlookAppointment, match.GoogleAppointment, sync, true);
                        }
                        switch (sync.ConflictResolution)
                        {
                        case ConflictResolution.Skip:
                        case ConflictResolution.SkipAlways:         //Keep both, Google AND Outlook
                            sync.Appointments.Add(new AppointmentMatch(match.OutlookAppointment, null));
                            sync.Appointments.Add(new AppointmentMatch(null, match.GoogleAppointment));
                            break;

                        case ConflictResolution.OutlookWins:
                        case ConflictResolution.OutlookWinsAlways:
                            sync.UpdateAppointment(match.OutlookAppointment, ref match.GoogleAppointment);
                            break;

                        case ConflictResolution.GoogleWins:
                        case ConflictResolution.GoogleWinsAlways:
                            sync.UpdateAppointment(ref match.GoogleAppointment, match.OutlookAppointment, match.GoogleAppointmentExceptions);
                            break;

                        default:
                            throw new ApplicationException("Canceled");
                        }
                        break;
                    }
                }
            }
            else
            {
                throw new ArgumentNullException("AppointmenttMatch has all peers null.");
            }
            //}
            //finally
            //{
            //if (outlookAppointment != null &&
            //    match.OutlookAppointment != null)
            //{
            //    match.OutlookAppointment.Update(outlookAppointment, sync);
            //    Marshal.ReleaseComObject(outlookAppointment);
            //    outlookAppointment = null;
            //}
            //}
        }
 public OutlookContactInfo(ContactItem item, Synchronizer sync)
 {
     this.UserProperties = new UserPropertiesHolder();
     this.Update(item, sync);
 }