示例#1
0
 // 确保项目属性不为空引用
 private void EnsureItemProperty(ref Outlook.ItemProperty property, string name, Outlook.OlUserPropertyType propertyType)
 {
     // 如果自定义属性为空时
     // 首先从联系人项关联的属性集合中获得属性对象
     // 如果项目集合中还不存在该属性时,就把该属性名称添加进ItemProperties集合中
     if (property == null)
     {
         property = contactItem.ItemProperties[name];
         if (property == null)
         {
             property = contactItem.ItemProperties.Add(name, propertyType);
         }
     }
 }
        /// <summary>
        /// Executed when a new item is added to the calendar folder, and is adding additional parameters to it
        /// </summary>
        /// <param name="Item"></param>
        private void Items_ItemAdd(object Item)
        {
            Outlook.AppointmentItem item = Item as Outlook.AppointmentItem;

            //Debug.WriteLine("CalendarHandler: Items_ItemAdd fired for '" + item.Subject + "'");

            // GAI (GlobalAppointmentID) needs to be added as item property, otherwise it cannot be found later
            Outlook.ItemProperty newPropGAI = item.ItemProperties.Add(ITEM_PROPERTY_GLOBAL_A_ID, Outlook.OlUserPropertyType.olText);
            item.Save();
            newPropGAI.Value = item.GlobalAppointmentID;
            item.Save();

            Marshal.ReleaseComObject(item);
            item = null;
        }
示例#3
0
        private void SyncValue(string methodName, object value)
        {
            methodName = methodName.Replace("set_", "");
            Microsoft.Office.Interop.Outlook.ContactItem item = BaseContact as Microsoft.Office.Interop.Outlook.ContactItem;

            if (item != null)
            {
                Microsoft.Office.Interop.Outlook.ItemProperty prop = item.ItemProperties[methodName];

                if (prop != null)
                {
                    prop.Value = value;
                }
            }
        }
示例#4
0
        public void SyncValuesFromBase()
        {
            Microsoft.Office.Interop.Outlook.ContactItem item = BaseContact as Microsoft.Office.Interop.Outlook.ContactItem;
            PropertyInfo[] props = this.GetType().GetProperties();

            foreach (PropertyInfo pi in props)
            {
                string   name    = pi.Name.Replace("set_", "");
                object[] attribs = pi.GetCustomAttributes(typeof(OutlookSync), false);

                if (attribs.Length > 0)
                {
                    Microsoft.Office.Interop.Outlook.ItemProperty oProp = item.ItemProperties[name];
                    if (oProp != null)
                    {
                        pi.SetValue(this, oProp.Value, null);
                    }
                }
            }
        }
        //public static void SetGoogleOutlookNoteId(string syncProfile, Document googleNote, Outlook.NoteItem outlookNote)
        //{
        //    if (outlookNote.EntryID == null)
        //        throw new Exception("Must save outlook note before getting id");

        //    SetGoogleOutlookNoteId(syncProfile, googleNote, GetOutlookId(outlookNote));
        //}
        //public static void SetGoogleOutlookNoteId(string syncProfile, Document googleNote, string outlookNoteId)
        //{
        //    // check if exists
        //    bool found = false;
        //    foreach (Google.GData.Extensions.ExtendedProperty p in googleNote.ExtendedProperties)
        //    {
        //        if (p.Name == "gos:oid:" + syncProfile + "")
        //        {
        //            p.Value = outlookNoteId;
        //            found = true;
        //            break;
        //        }
        //    }
        //    if (!found)
        //    {
        //        Google.GData.Extensions.ExtendedProperty prop = new ExtendedProperty(outlookNoteId, "gos:oid:" + syncProfile + "");
        //        prop.Value = outlookNoteId;
        //        googleNote.ExtendedProperties.Add(prop);
        //    }

        //}
        //public static string GetGoogleOutlookNoteId(string syncProfile, Document googleNote)
        //{
        //    // get extended prop
        //    foreach (Google.GData.Extensions.ExtendedProperty p in googleNote.DocumentEntry.ExtendedProperties)
        //    {
        //        if (p.Name == "gos:oid:" + syncProfile + "")
        //            return (string)p.Value;
        //    }
        //    return null;
        //}
        //public static void ResetGoogleOutlookNoteId(string syncProfile, Document googleNote)
        //{
        //    // get extended prop
        //    foreach (Google.GData.Extensions.ExtendedProperty p in googleNote.ExtendedProperties)
        //    {
        //        if (p.Name == "gos:oid:" + syncProfile + "")
        //        {
        //            // remove
        //            googleNote.ExtendedProperties.Remove(p);
        //            return;
        //        }
        //    }
        //}

        /// <summary>
        /// Sets the syncId of the Outlook note and the last sync date.
        /// Please assure to always call this function when saving OutlookItem
        /// </summary>
        /// <param name="sync"></param>
        /// <param name="outlookNote"></param>
        /// <param name="googleNote"></param>
        public static void SetOutlookGoogleNoteId(Synchronizer sync, Outlook.NoteItem outlookNote, Document googleNote)
        {
            if (googleNote.DocumentEntry.Id.Uri == null)
            {
                throw new NullReferenceException("GoogleNote must have a valid Id");
            }

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

            //save last google's updated date as property

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

            //Also set the OutlookLastSync date when setting a match between Outlook and Google to assure the lastSync updated when Outlook note is saved afterwards
            SetOutlookLastSync(sync, outlookNote);
        }
        /// <summary>
        /// Matches outlook and Google appointment by a) id b) properties.
        /// </summary>
        /// <param name="sync">Syncronizer instance</param>
        /// <returns>Returns a list of match pairs (outlook appointment + Google appointment) for all appointment. Those that weren't matche will have it's peer set to null</returns>
        public static List <AppointmentMatch> MatchAppointments(Synchronizer sync)
        {
            Logger.Log("Matching Outlook and Google appointments...", EventType.Information);
            var result = new List <AppointmentMatch>();

            var googleAppointmentExceptions = new List <Event>();

            //for each outlook appointment try to get Google appointment id from user properties
            //if no match - try to match by properties
            //if no match - create a new match pair without Google appointment.
            //foreach (Outlook._AppointmentItem olc in outlookAppointments)
            var OutlookAppointmentsWithoutSyncId = new Collection <Outlook.AppointmentItem>();

            #region Match first all outlookAppointments by sync id
            for (int i = 1; i <= sync.OutlookAppointments.Count; i++)
            {
                Outlook.AppointmentItem ola;

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

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

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

                //try
                //{

                if (NotificationReceived != null)
                {
                    NotificationReceived(String.Format("Matching appointment {0} of {1} by id: {2} ...", i, sync.OutlookAppointments.Count, ola.Subject));
                }

                // Create our own info object to go into collections/lists, so we can free the Outlook objects and not run out of resources / exceed policy limits.
                //OutlookAppointmentInfo olci = new OutlookAppointmentInfo(ola, sync);

                //try to match this appointment to one of Google appointments
                Outlook.ItemProperties userProperties = ola.ItemProperties;
                Outlook.ItemProperty   idProp         = userProperties[sync.OutlookPropertyNameId];
                try
                {
                    if (idProp != null)
                    {
                        string googleAppointmentId = string.Copy((string)idProp.Value);
                        Event  foundAppointment    = sync.GetGoogleAppointmentById(googleAppointmentId);
                        var    match = new AppointmentMatch(ola, null);



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

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

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

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

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

                //foreach Google appointment try to match and create a match pair if found some match(es)
                for (int j = sync.GoogleAppointments.Count - 1; j >= 0; j--)
                {
                    var googleAppointment = sync.GoogleAppointments[j];
                    // only match if there is a appointment targetBody, else
                    // a matching Google appointment will be created at each sync
                    if (!googleAppointment.Status.Equals("cancelled") && ola.Subject == googleAppointment.Summary && googleAppointment.Start.DateTime != null && ola.Start == googleAppointment.Start.DateTime)
                    {
                        match.AddGoogleAppointment(googleAppointment);
                        sync.GoogleAppointments.Remove(googleAppointment);

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

                if (match.GoogleAppointment == null)
                {
                    Logger.Log(string.Format("No match found for outlook appointment ({0}) => {1}", match.OutlookAppointment.Subject + " - " + match.OutlookAppointment.Start, (AppointmentPropertiesUtils.GetOutlookGoogleAppointmentId(sync, match.OutlookAppointment) != null ? "Delete from Outlook" : "Add to Google")), EventType.Information);
                }

                result.Add(match);
            }
            #endregion


            //for each Google appointment that's left (they will be nonmatched) create a new match pair without outlook appointment.
            for (int i = 0; i < sync.GoogleAppointments.Count; i++)
            {
                var googleAppointment = sync.GoogleAppointments[i];

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



                if (NotificationReceived != null)
                {
                    NotificationReceived(String.Format("Adding new Google appointment {0} of {1} by unique properties: {2} ...", i + 1, sync.GoogleAppointments.Count, googleAppointment.Summary));
                }


                if (googleAppointment.RecurringEventId != null)
                {
                    sync.SkippedCountNotMatches++;
                    googleAppointmentExceptions.Add(googleAppointment);
                }
                else if (googleAppointment.Status.Equals("cancelled"))
                {
                    Logger.Log("Skipping Google appointment found because it is cancelled: " + googleAppointment.Summary + " - " + Synchronizer.GetTime(googleAppointment), EventType.Debug);
                    //sync.SkippedCount++;
                    //sync.SkippedCountNotMatches++;
                }
                else if (string.IsNullOrEmpty(googleAppointment.Summary) && (googleAppointment.Start == null || googleAppointment.Start.DateTime == null && googleAppointment.Start.Date == null))
                {
                    // no title or time
                    sync.SkippedCount++;
                    sync.SkippedCountNotMatches++;
                    Logger.Log("Skipped GoogleAppointment because no unique property found (Subject or StartDate):" + googleAppointment.Summary + " - " + Synchronizer.GetTime(googleAppointment), EventType.Warning);
                }
                //else if (googleAppointment.Summary != "Business Trip")
                //{//Only for debugging purposes, please comment if not needed
                //    Logger.Log("Skipping Google appointment because of DEBUGGING:" + googleAppointment.Summary + " - " + googleAppointment.Times[0].StartTime, EventType.Error);
                //    continue;
                //}
                else
                {
                    Logger.Log(string.Format("No match found for Google appointment ({0}) => {1}", googleAppointment.Summary + " - " + Synchronizer.GetTime(googleAppointment), (!string.IsNullOrEmpty(AppointmentPropertiesUtils.GetGoogleOutlookAppointmentId(sync.SyncProfile, googleAppointment)) ? "Delete from Google" : "Add to Outlook")), EventType.Information);
                    var match = new AppointmentMatch(null, googleAppointment);
                    result.Add(match);
                }
            }

            //for each Google appointment exception, assign to proper match
            for (int i = 0; i < googleAppointmentExceptions.Count; i++)
            {
                var googleAppointment = googleAppointmentExceptions[i];
                if (NotificationReceived != null)
                {
                    NotificationReceived(String.Format("Adding Google appointment exception {0} of {1} ...", i + 1, googleAppointmentExceptions.Count, googleAppointment.Summary + " - " + Synchronizer.GetTime(googleAppointment)));
                }

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

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

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

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

                        for (int i = indexesToBeRemoved.Count - 1; i >= 0; i--)
                        {
                            userProperties.Remove(indexesToBeRemoved[i]);
                        }
                        //throw new Exception("Did not find prop.");
                    }
                    finally
                    {
                        if (lastSyncProp != null)
                        {
                            Marshal.ReleaseComObject(lastSyncProp);
                        }
                    }
                }
                finally
                {
                    if (idProp != null)
                    {
                        Marshal.ReleaseComObject(idProp);
                    }
                }
            }
            finally
            {
                Marshal.ReleaseComObject(userProperties);
            }
        }
        /// <summary>
        /// Returns a AppointmentSyncCollection, with all updates since the specified timestamp
        /// </summary>
        /// <param name="timestamp"></param>
        /// <returns></returns>
        private AppointmentSyncCollection GetUpdates(DateTime timestamp)
        {
            if (_customCalendar == null)
            {
                return(null);
            }
            AppointmentSyncCollection syncCollection = new AppointmentSyncCollection();

            // Debug.WriteLine("CalendarHandler: TimeStamp -> " + timestamp);

            foreach (Outlook.AppointmentItem item in _customCalendar.Items)
            {
                Boolean updatedBySync = false;

                //Debug.WriteLine("CalendarHandler: Item (" + item.Subject + ") LastModificationTime -> " + item.LastModificationTime);

                // if the date from the SYNC_UPDATE is newer or as the LastModificationTime, the item was not updated by the user
                if (item.ItemProperties[ITEM_PROPERTY_SYNC_UPDATE] != null && DateTime.Parse(item.ItemProperties[ITEM_PROPERTY_SYNC_UPDATE].Value) >= item.LastModificationTime)
                {
                    updatedBySync = true;
                }

                //Debug.WriteLine("CalendarHandler: Item (" + item.Subject + ") SyncUpdate -> " + syncUpdate);
                //Debug.WriteLine("CalendarHandler: Item (" + item.Subject + ") wasUpdatedBySync -> " + wasUpdatedBySync);

                if (item.LastModificationTime >= timestamp && !updatedBySync)
                {
                    // ADDING
                    // if SyncID does not exist, it is not yet synced and needs to be added to the other calendar
                    if (item.ItemProperties[ITEM_PROPERTY_SYNC_ID] == null)
                    {
                        syncCollection.AddList.Add(new OutlookAppointment(item));

                        if (item.ItemProperties[ITEM_PROPERTY_GLOBAL_A_ID] == null)
                        {
                            // GAI (GlobalAppointmentID) needs to be added as item property, otherwise it cannot be found later
                            Outlook.ItemProperty newProp = item.ItemProperties.Add(ITEM_PROPERTY_GLOBAL_A_ID, Outlook.OlUserPropertyType.olText);
                            item.Save();
                            newProp.Value = item.GlobalAppointmentID;
                            item.Save();
                        }
                    }

                    // UPDATING
                    // if a SyncID exist, it is already synced and needs to be updated in the other calendar
                    else
                    {
                        syncCollection.UpdateList.Add(new OutlookAppointment(item));
                    }
                }
            }

            // DELETING
            foreach (String syncID in GetAppointmentsForDeleting())
            {
                OutlookAppointment item = new OutlookAppointment();
                item.SyncID = syncID;
                syncCollection.DeleteList.Add(item);
            }

            Debug.WriteLine("CalendarHandler (GetUpdates): Added: " + syncCollection.AddList.Count + " | Updated: " + syncCollection.UpdateList.Count + " | Deleted: " + syncCollection.DeleteList.Count);

            ResetDeleteStorage();
            SetSyncTime(DateTime.Now);

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

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

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

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

                //try
                //{

                if (NotificationReceived != null)
                {
                    NotificationReceived(String.Format("Matching note {0} of {1} by id: {2} ...", i, sync.OutlookNotes.Count, oln.Subject));
                }

                // Create our own info object to go into collections/lists, so we can free the Outlook objects and not run out of resources / exceed policy limits.
                //OutlookNoteInfo olci = new OutlookNoteInfo(oln, sync);

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

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

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

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

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

                            //}
                            outlookNotesWithoutOutlookGoogleId.Add(oln);

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

                #endregion

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

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

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

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

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



                //    }

                result.Add(match);
            }
            #endregion

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

            //return result;

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

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