Esempio n. 1
0
        private static void SyncAppointmentBothExists(AppointmentMatch m, AppointmentsSynchronizer sync)
        {
            //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, m.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 = m.OutlookAppointment.LastModificationTime.AddSeconds(-m.OutlookAppointment.LastModificationTime.Second);
                DateTime lastUpdatedGoogle  = m.GoogleAppointment.Updated.Value.AddSeconds(-m.GoogleAppointment.Updated.Value.Second);
                //consider GoogleAppointmentExceptions, because if they are updated, the master appointment doesn't have a new Saved TimeStamp
                foreach (var e in m.GoogleAppointmentExceptions)
                {
                    if (e.Updated != null)//happens for cancelled events
                    {
                        DateTime lastUpdatedGoogleException = e.Updated.Value.AddSeconds(-e.Updated.Value.Second);
                        if (lastUpdatedGoogleException > lastUpdatedGoogle)
                        {
                            lastUpdatedGoogle = lastUpdatedGoogleException;
                        }
                    }
                    else if (m.OutlookAppointment.IsRecurring && m.OutlookAppointment.RecurrenceState == Outlook.OlRecurrenceState.olApptMaster)
                    {
                        Outlook.AppointmentItem outlookRecurrenceException = null;
                        try
                        {
                            var slaveRecurrence = m.OutlookAppointment.GetRecurrencePattern();
                            if (e.OriginalStartTime != null && !string.IsNullOrEmpty(e.OriginalStartTime.Date))
                            {
                                outlookRecurrenceException = slaveRecurrence.GetOccurrence(DateTime.Parse(e.OriginalStartTime.Date));
                            }
                            else if (e.OriginalStartTime != null && e.OriginalStartTime.DateTime != null)
                            {
                                outlookRecurrenceException = slaveRecurrence.GetOccurrence(e.OriginalStartTime.DateTime.Value);
                            }
                        }
                        catch (Exception ignored)
                        {
                            Logger.Log("Google Appointment with OriginalEvent found, but Outlook occurrence not found: " + e.Summary + " - " + e.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 + ": " + m.OutlookAppointment.Subject + ".", EventType.Information);
                        sync.UpdateAppointment(m.OutlookAppointment, ref m.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 + ": " + m.GoogleAppointment.Summary + ".", EventType.Information);
                        sync.UpdateAppointment(ref m.GoogleAppointment, m.OutlookAppointment, m.GoogleAppointmentExceptions);
                        break;

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

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

                        case ConflictResolution.GoogleWins:
                        case ConflictResolution.GoogleWinsAlways:
                            sync.UpdateAppointment(ref m.GoogleAppointment, m.OutlookAppointment, m.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 + ": " + m.OutlookAppointment.Subject + ".", EventType.Information);
                    }

                    sync.UpdateAppointment(m.OutlookAppointment, ref m.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 + ": " + m.OutlookAppointment.Subject + ".", EventType.Information);
                    }

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

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

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

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

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

                    default:
                        throw new ApplicationException("Canceled");
                    }
                    break;
                }
            }
        }
        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;
            //}
            //}
        }
Esempio n. 3
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;
                }
            }
        }
Esempio n. 4
0
        private static void SyncAppointmentNoGoogle(AppointmentMatch match, AppointmentsSynchronizer sync)
        {
            string googleAppointmentId = AppointmentPropertiesUtils.GetOutlookGoogleAppointmentId(sync, match.OutlookAppointment);

            if (!string.IsNullOrEmpty(googleAppointmentId))
            {
                //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, null, null, 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)
                    {
                        using (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);
        }
        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;
            //}
            //}
        }
Esempio n. 6
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;
        }
Esempio n. 7
0
        private void ResolveDuplicateContact(ContactMatch match)
        {
            if (Contacts.Contains(match))
            {
                if (_syncOption == SyncOption.MergePrompt)
                {
                    //For each OutlookDuplicate: Ask user for the GoogleContact to be synced with
                    for (int j = match.AllOutlookContactMatches.Count - 1; j >= 0 && match.AllGoogleContactMatches.Count > 0; j--)
                    {
                        OutlookContactInfo olci = match.AllOutlookContactMatches[j];
                        Outlook.ContactItem outlookContactItem = olci.GetOriginalItemFromOutlook();

                        try
                        {
                            Contact googleContact;
                            ConflictResolver r = new ConflictResolver();
                            switch (r.ResolveDuplicate(olci, match.AllGoogleContactMatches, out googleContact))
                            {
                                case ConflictResolution.Skip:
                                case ConflictResolution.SkipAlways: //Keep both entries and sync it to both sides
                                    match.AllGoogleContactMatches.Remove(googleContact);
                                    match.AllOutlookContactMatches.Remove(olci);
                                    Contacts.Add(new ContactMatch(null, googleContact));
                                    Contacts.Add(new ContactMatch(olci, null));
                                    break;
                                case ConflictResolution.OutlookWins:
                                case ConflictResolution.OutlookWinsAlways: //Keep Outlook and overwrite Google
                                    match.AllGoogleContactMatches.Remove(googleContact);
                                    match.AllOutlookContactMatches.Remove(olci);
                                    UpdateContact(outlookContactItem, googleContact);
                                    SaveContact(new ContactMatch(olci, googleContact));
                                    break;
                                case ConflictResolution.GoogleWins:
                                case ConflictResolution.GoogleWinsAlways: //Keep Google and overwrite Outlook
                                    match.AllGoogleContactMatches.Remove(googleContact);
                                    match.AllOutlookContactMatches.Remove(olci);
                                    UpdateContact(googleContact, outlookContactItem);
                                    SaveContact(new ContactMatch(olci, googleContact));
                                    break;
                                default:
                                    throw new ApplicationException("Cancelled");
                            }
                        }
                        finally
                        {
                            if (outlookContactItem != null)
                            {
                                Marshal.ReleaseComObject(outlookContactItem);
                                outlookContactItem = null;
                            }
                        }

                        //Cleanup the match, i.e. assign a proper OutlookContact and GoogleContact, because can be deleted before
                        if (match.AllOutlookContactMatches.Count == 0)
                            match.OutlookContact = null;
                        else
                            match.OutlookContact = match.AllOutlookContactMatches[0];
                    }
                }

                //Cleanup the match, i.e. assign a proper OutlookContact and GoogleContact, because can be deleted before
                if (match.AllGoogleContactMatches.Count == 0)
                    match.GoogleContact = null;
                else
                    match.GoogleContact = match.AllGoogleContactMatches[0];

                if (match.AllOutlookContactMatches.Count == 0)
                {
                    //If all OutlookContacts have been assigned by the users ==> Create one match for each remaining Google Contact to sync them to Outlook
                    Contacts.Remove(match);
                    foreach (Contact googleContact in match.AllGoogleContactMatches)
                        Contacts.Add(new ContactMatch(null, googleContact));
                }
                else if (match.AllGoogleContactMatches.Count == 0)
                {
                    //If all GoogleContacts have been assigned by the users ==> Create one match for each remaining Outlook Contact to sync them to Google
                    Contacts.Remove(match);
                    foreach (OutlookContactInfo outlookContact in match.AllOutlookContactMatches)
                        Contacts.Add(new ContactMatch(outlookContact, null));
                }
                else // if (match.AllGoogleContactMatches.Count > 1 ||
                //         match.AllOutlookContactMatches.Count > 1)
                {
                    SkippedCount++;
                    Contacts.Remove(match);
                }
                //else
                //{
                //    //If there remains a modified ContactMatch with only a single OutlookContact and GoogleContact
                //    //==>Remove all outlookContactDuplicates for this Outlook Contact to not remove it later from the Contacts to sync
                //    foreach (ContactMatch duplicate in OutlookContactDuplicates)
                //    {
                //        if (duplicate.OutlookContact.EntryID == match.OutlookContact.EntryID)
                //        {
                //            OutlookContactDuplicates.Remove(duplicate);
                //            break;
                //        }
                //    }
                //}
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Updates Outlook appointment from master to slave (including groups/categories)
        /// </summary>
        public bool UpdateAppointment(ref Google.Apis.Calendar.v3.Data.Event master, Outlook.AppointmentItem slave, List<Google.Apis.Calendar.v3.Data.Event> googleAppointmentExceptions)
        {
            //if (master.Participants.Count > 1)
            //{
            //    bool organizerIsGoogle = AppointmentSync.IsOrganizer(AppointmentSync.GetOrganizer(master));

            //    if (organizerIsGoogle || AppointmentPropertiesUtils.GetOutlookGoogleAppointmentId(this, slave) == null)
            //    {//Only update, if this appointment was organized on Google side or freshly created during tis sync
            //        updated = true;
            //    }
            //    else
            //    {
            //        //ToDo:Maybe find as better way, e.g. to ask the user, if he wants to overwrite the invalid appointment
            //        SkippedCount++;
            //        Logger.Log("Skipped Updating appointment from Google to Outlook because multiple participants found and invitations NOT sent by Google: \"" + master.Summary + " - " + Syncronizer.GetTime(master) + "\".", EventType.Information);
            //    }
            //}
            //else
            //    updated = true;

            bool updated = false;
            if (slave.Recipients.Count > 1 && AppointmentPropertiesUtils.GetOutlookGoogleAppointmentId(this, slave) != null)
            {
                //ToDo:Maybe find as better way, e.g. to ask the user, if he wants to overwrite the invalid appointment
                switch (this.SyncOption)
                {
                    case SyncOption.MergeOutlookWins:
                    case SyncOption.OutlookToGoogleOnly:
                        //overwrite Google appointment
                        Logger.Log("Multiple participants found, invitation maybe NOT sent by Google. Outlook appointment is overwriting Google because of SyncOption " + SyncOption + ": " + master.Summary + " - " + Synchronizer.GetTime(master) + ". ", EventType.Information);
                        UpdateAppointment(slave, ref master);
                        break;
                    case SyncOption.MergeGoogleWins:
                    case SyncOption.GoogleToOutlookOnly:
                        //overwrite outlook appointment
                        Logger.Log("Multiple participants found, invitation maybe NOT sent by Google, but Google appointment is overwriting Outlook because of SyncOption " + SyncOption + ": " + master.Summary + " - " + Synchronizer.GetTime(master) + ".", EventType.Information);
                        updated = true;
                        break;
                    case SyncOption.MergePrompt:
                        //promp for sync option
                        if (
                            //ConflictResolution != ConflictResolution.GoogleWinsAlways && //Shouldn't be used, because Outlook seems to be the master of the appointment
                            ConflictResolution != ConflictResolution.OutlookWinsAlways &&
                            ConflictResolution != ConflictResolution.SkipAlways)
                        {
                            var r = new ConflictResolver();
                            ConflictResolution = r.Resolve("Cannot update appointment from Google to Outlook because multiple participants found, invitation maybe NOT sent by Google: \"" + master.Summary + " - " + Synchronizer.GetTime(master) + "\". Do you want to update it back from Outlook to Google?", slave, master, this);
                        }
                        switch (ConflictResolution)
                        {
                            case ConflictResolution.Skip:
                            case ConflictResolution.SkipAlways: //Skip
                                SkippedCount++;
                                Logger.Log("Skipped Updating appointment from Google to Outlook because multiple participants found, invitation maybe NOT sent by Google: \"" + master.Summary + " - " + Synchronizer.GetTime(master) + "\".", EventType.Information);
                                break;
                            case ConflictResolution.OutlookWins:
                            case ConflictResolution.OutlookWinsAlways: //Keep Outlook and overwrite Google
                                UpdateAppointment(slave, ref master);
                                break;
                            case ConflictResolution.GoogleWins:
                            case ConflictResolution.GoogleWinsAlways: //Keep Google and overwrite Outlook
                                updated = true;
                                break;
                            default:
                                throw new ApplicationException("Cancelled");
                        }

                        break;
                }

                //if (MessageBox.Show("Cannot update appointment from Google to Outlook because multiple participants found, invitation maybe NOT sent by Google: \"" + master.Summary + " - " + Syncronizer.GetTime(master) + "\". Do you want to update it back from Outlook to Google?", "Outlook appointment cannot be overwritten from Google", MessageBoxButtons.YesNo) == DialogResult.Yes)
                //    UpdateAppointment(slave, ref master);
                //else
                //    SkippedCount++;
                //    Logger.Log("Skipped Updating appointment from Google to Outlook because multiple participants found, invitation maybe NOT sent by Google: \"" + master.Summary + " - " + Syncronizer.GetTime(master) + "\".", EventType.Information);
            }
            else //Only update, if invitation was not sent on Outlook side or freshly created during this sync
                updated = true;

            if (updated)
            {
                AppointmentSync.UpdateAppointment(master, slave);
                AppointmentPropertiesUtils.SetOutlookGoogleAppointmentId(this, slave, master);
                try
                { //Try to save 2 times, because sometimes the first save fails with a COMException (Outlook aborted)
                    slave.Save();
                }
                catch (Exception)
                {
                    try
                    {
                        slave.Save();
                    }
                    catch (COMException ex)
                    {
                        Logger.Log("Error saving Outlook appointment: \"" + master.Summary + " - " + GetTime(master) + "\".\n"+ex.StackTrace, EventType.Warning);
                        return false;
                    }
                }

                if (master.Creator == null || AppointmentSync.IsOrganizer(master.Creator.Email))
                {
                    //only update Google, if I am the organizer, otherwise an error will be thrown
                    AppointmentPropertiesUtils.SetGoogleOutlookAppointmentId(SyncProfile, master, slave);
                    master = SaveGoogleAppointment(master);
                }

                SyncedCount++;
                Logger.Log("Updated appointment from Google to Outlook: \"" + master.Summary + " - " + GetTime(master) + "\".", EventType.Information);

                //After saving Outlook Appointment => also sync recurrence exceptions and increase SyncCount
                if (master.Recurrence != null && googleAppointmentExceptions != null && AppointmentSync.UpdateRecurrenceExceptions(googleAppointmentExceptions, slave, this))
                    SyncedCount++;
            }

            return true;
        }
Esempio n. 9
0
        /// <summary>
        /// Updates Outlook appointment from master to slave (including groups/categories)
        /// </summary>
        public void UpdateAppointment(Outlook.AppointmentItem master, ref Google.Apis.Calendar.v3.Data.Event slave)
        {
            bool updated = false;
            if (slave.Creator != null && !AppointmentSync.IsOrganizer(slave.Creator.Email)) // && AppointmentPropertiesUtils.GetGoogleOutlookAppointmentId(this.SyncProfile, slave) != null)
            {
                //ToDo:Maybe find as better way, e.g. to ask the user, if he wants to overwrite the invalid appointment
                switch (this.SyncOption)
                {
                    case SyncOption.MergeGoogleWins:
                    case SyncOption.GoogleToOutlookOnly:
                        //overwrite Outlook appointment
                        Logger.Log("Different Organizer found on Google, invitation maybe NOT sent by Outlook. Google appointment is overwriting Outlook because of SyncOption " + SyncOption + ": " + master.Subject + " - " + master.Start + ". ", EventType.Information);
                        UpdateAppointment(ref slave, master, null);
                        break;
                    case SyncOption.MergeOutlookWins:
                    case SyncOption.OutlookToGoogleOnly:
                        //overwrite Google appointment
                        Logger.Log("Different Organizer found on Google, invitation maybe NOT sent by Outlook, but Outlook appointment is overwriting Google because of SyncOption " + SyncOption + ": " + master.Subject + " - " + master.Start + ".", EventType.Information);
                        updated = true;
                        break;
                    case SyncOption.MergePrompt:
                        //promp for sync option
                        if (
                            //ConflictResolution != ConflictResolution.OutlookWinsAlways && //Shouldn't be used, because Google seems to be the master of the appointment
                            ConflictResolution != ConflictResolution.GoogleWinsAlways &&
                            ConflictResolution != ConflictResolution.SkipAlways)
                        {
                            var r = new ConflictResolver();
                            ConflictResolution = r.Resolve("Cannot update appointment from Outlook to Google because different Organizer found on Google, invitation maybe NOT sent by Outlook: \"" + master.Subject + " - " + master.Start + "\". Do you want to update it back from Google to Outlook?", slave, master, this);
                        }
                        switch (ConflictResolution)
                        {
                            case ConflictResolution.Skip:
                            case ConflictResolution.SkipAlways: //Skip
                                SkippedCount++;
                                Logger.Log("Skipped Updating appointment from Outlook to Google because different Organizer found on Google, invitation maybe NOT sent by Outlook: \"" + master.Subject + " - " + master.Start + "\".", EventType.Information);
                                break;
                            case ConflictResolution.GoogleWins:
                            case ConflictResolution.GoogleWinsAlways: //Keep Google and overwrite Outlook
                                UpdateAppointment(ref slave, master, null);
                                break;
                            case ConflictResolution.OutlookWins:
                            case ConflictResolution.OutlookWinsAlways: //Keep Outlook and overwrite Google
                                updated = true;
                                break;
                            default:
                                throw new ApplicationException("Cancelled");
                        }

                        break;
                }
            }
            else //Only update, if invitation was not sent on Google side or freshly created during this sync
                updated = true;

            //if (master.Recipients.Count == 0 ||
            //    master.Organizer == null ||
            //    AppointmentSync.IsOrganizer(AppointmentSync.GetOrganizer(master), master)||
            //    slave.Id.Uri == null
            //    )
            //{//Only update, if this appointment was organized on Outlook side or freshly created during this sync

            if (updated)
            {
                AppointmentSync.UpdateAppointment(master, slave);

                if (slave.Creator == null || AppointmentSync.IsOrganizer(slave.Creator.Email))
                {
                    AppointmentPropertiesUtils.SetGoogleOutlookAppointmentId(SyncProfile, slave, master);
                    slave = SaveGoogleAppointment(slave);
                }

                //ToDo: Doesn'T work for newly created recurrence appointments before save, because Event.Reminder is throwing NullPointerException and Reminders cannot be initialized, therefore moved to after saving
                //if (slave.Recurrence != null && slave.Reminders != null)
                //{

                //    if (slave.Reminders.Overrides != null)
                //    {
                //        slave.Reminders.Overrides.Clear();
                //        if (master.ReminderSet)
                //        {
                //            var reminder = new Google.Apis.Calendar.v3.Data.EventReminder();
                //            reminder.Minutes = master.ReminderMinutesBeforeStart;
                //            if (reminder.Minutes > 40300)
                //            {
                //                //ToDo: Check real limit, currently 40300
                //                Logger.Log("Reminder Minutes to big (" + reminder.Minutes + "), set to maximum of 40300 minutes for appointment: " + master.Subject + " - " + master.Start, EventType.Warning);
                //                reminder.Minutes = 40300;
                //            }
                //            reminder.Method = "popup";
                //            slave.Reminders.Overrides.Add(reminder);
                //        }
                //    }
                //    slave = SaveGoogleAppointment(slave);
                //}

                AppointmentPropertiesUtils.SetOutlookGoogleAppointmentId(this, master, slave);
                master.Save();

                //After saving Google Appointment => also sync recurrence exceptions and save again
                if ((slave.Creator == null || AppointmentSync.IsOrganizer(slave.Creator.Email)) && master.IsRecurring && master.RecurrenceState == Outlook.OlRecurrenceState.olApptMaster && AppointmentSync.UpdateRecurrenceExceptions(master, slave, this))
                {
                    slave = SaveGoogleAppointment(slave);
                }

                SyncedCount++;
                Logger.Log("Updated appointment from Outlook to Google: \"" + master.Subject + " - " + master.Start + "\".", EventType.Information);

                //}
                //else
                //{
                //    //ToDo:Maybe find as better way, e.g. to ask the user, if he wants to overwrite the invalid appointment
                //    SkippedCount++;
                //    //Logger.Log("Skipped Updating appointment from Outlook to Google because multiple recipients found and invitations NOT sent by Outlook: \"" + master.Subject + " - " + master.Start + "\".", EventType.Information);
                //    Logger.Log("Skipped Updating appointment from Outlook to Google because meeting was received by Outlook: \"" + master.Subject + " - " + master.Start + "\".", EventType.Information);
                //}
            }
        }
Esempio n. 10
0
        public static void SyncNote(NoteMatch match, Syncronizer 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.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.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 = Syncronizer.CreateOutlookNoteItem(Syncronizer.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 syncronized
                //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;
            //}
            //}
        }
Esempio n. 11
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;
                //}
            //}
        }