public void SaveGoogleContact(ContactMatch match) { //check if this contact was not yet inserted on google. if (match.GoogleContact.Id.Uri == null) { //insert contact. Uri feedUri = new Uri(ContactsQuery.CreateContactsUri("default")); try { ContactPropertiesUtils.SetGoogleOutlookContactId(SyncProfile, match.GoogleContact, match.OutlookContact); ContactEntry createdEntry = (ContactEntry)_googleService.Insert(feedUri, match.GoogleContact); match.GoogleContact = createdEntry; ContactPropertiesUtils.SetOutlookGoogleContactId(this, match.OutlookContact, match.GoogleContact); match.OutlookContact.Save(); } catch (Exception ex) { MemoryStream ms = new MemoryStream(); match.GoogleContact.SaveToXml(ms); StreamReader sr = new StreamReader(ms); ms.Seek(0, SeekOrigin.Begin); Debug.WriteLine(String.Format("Error saving google contact: {0}", ex.Message)); Debug.WriteLine(sr.ReadToEnd()); //TODO: save google contact xml for diagnistics throw; } } else { try { //contact already present in google. just update ContactPropertiesUtils.SetGoogleOutlookContactId(SyncProfile, match.GoogleContact, match.OutlookContact); //TODO: this will fail if original contact had an empty name or rpimary email address. ContactEntry updatedEntry = match.GoogleContact.Update() as ContactEntry; match.GoogleContact = updatedEntry; ContactPropertiesUtils.SetOutlookGoogleContactId(this, match.OutlookContact, match.GoogleContact); match.OutlookContact.Save(); } catch (Exception ex) { //TODO: save google contact xml for diagnistics throw; } } }
public void ResetMatch(ContactMatch match) { if (match.GoogleContact != null) { ContactPropertiesUtils.ResetGoogleOutlookContactId(SyncProfile, match.GoogleContact); SaveGoogleContact(match.GoogleContact); } if (match.OutlookContact != null) { ContactPropertiesUtils.ResetOutlookGoogleContactId(this, match.OutlookContact); match.OutlookContact.Save(); } }
public void SaveContactPhotos(ContactMatch match) { bool hasGooglePhoto = Utilities.HasPhoto(match.GoogleContact); bool hasOutlookPhoto = Utilities.HasPhoto(match.OutlookContact); if (!hasGooglePhoto && !hasOutlookPhoto) { return; } else if (hasGooglePhoto && !hasOutlookPhoto) { // add google photo to outlook Image googlePhoto = Utilities.GetGooglePhoto(this, match.GoogleContact); Utilities.SetOutlookPhoto(match.OutlookContact, googlePhoto); match.OutlookContact.Save(); googlePhoto.Dispose(); } else if (!hasGooglePhoto && hasOutlookPhoto) { // add outlook photo to google Image outlookPhoto = Utilities.GetOutlookPhoto(match.OutlookContact); outlookPhoto = Utilities.CropImageGoogleFormat(outlookPhoto); bool saved = Utilities.SaveGooglePhoto(this, match.GoogleContact, outlookPhoto); if (!saved) { throw new Exception("Could not save"); } outlookPhoto.Dispose(); } else { // TODO: if both contacts have photos and one is updated, the // other will not be updated. } //Utilities.DeleteTempPhoto(); }
public static void SyncContact(ContactMatch match, Syncronizer sync) { if (match.GoogleContact == null && match.OutlookContact != null) { //no google contact //TODO: check SyncOption //TODO: found that when a contacts doesn't have anything other that the name - it's not returned in the google contacts list. Outlook.UserProperty idProp = match.OutlookContact.UserProperties[sync.OutlookPropertyNameId]; if (idProp != null && (string)idProp.Value != "") { AtomId id = new AtomId((string)idProp.Value); ContactEntry matchingGoogleContact = sync.GoogleContacts.FindById(id) as ContactEntry; if (matchingGoogleContact == null) { //TODO: make sure that outlook contacts don't get deleted when deleting corresponding google contact when testing. //solution: use ResetMatching() method to unlink this relation //sync.ResetMatches(); return; } } //create a Google contact from Outlook contact match.GoogleContact = new ContactEntry(); ContactSync.UpdateContact(match.OutlookContact, match.GoogleContact); sync.OverwriteContactGroups(match.OutlookContact, match.GoogleContact); } else if (match.OutlookContact == null && match.GoogleContact != null) { // no outlook contact string outlookId = ContactPropertiesUtils.GetGoogleOutlookContactId(sync.SyncProfile, match.GoogleContact); if (outlookId != null) { //TODO: make sure that google contacts don't get deleted when deleting corresponding outlook contact when testing. //solution: use ResetMatching() method to unlink this relation //sync.ResetMatches(); return; } //TODO: check SyncOption //create a Outlook contact from Google contact match.OutlookContact = sync.OutlookApplication.CreateItem(Outlook.OlItemType.olContactItem) as Outlook.ContactItem; ContactSync.MergeContacts(match.GoogleContact, match.OutlookContact); sync.OverwriteContactGroups(match.GoogleContact, match.OutlookContact); } else if (match.OutlookContact != null && match.GoogleContact != null) { //merge contact details //TODO: check if there are multiple matches if (match.AllGoogleContactMatches.Count > 1) { //loop from 2-nd item for (int m = 1; m < match.AllGoogleContactMatches.Count; m++) { ContactEntry entry = match.AllGoogleContactMatches[m]; try { Outlook.ContactItem item = sync.OutlookContacts.Find("[" + sync.OutlookPropertyNameId + "] = \"" + entry.Id.Uri.Content + "\"") as Outlook.ContactItem; //Outlook.ContactItem item = sync.OutlookContacts.Find("[myTest] = \"value\"") as Outlook.ContactItem; if (item != null) { //do something } } catch (Exception) { //TODO: should not get here. } } //TODO: add info to Outlook contact from extra Google contacts before deleting extra Google contacts. for (int m = 1; m < match.AllGoogleContactMatches.Count; m++) { match.AllGoogleContactMatches[m].Delete(); } } //determine if this contact pair were syncronized //DateTime? lastUpdated = GetOutlookPropertyValueDateTime(match.OutlookContact, sync.OutlookPropertyNameUpdated); DateTime?lastSynced = GetOutlookPropertyValueDateTime(match.OutlookContact, sync.OutlookPropertyNameSynced); 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: //overwrite google contact ContactSync.MergeContacts(match.OutlookContact, match.GoogleContact); sync.OverwriteContactGroups(match.OutlookContact, match.GoogleContact); break; case SyncOption.MergeGoogleWins: //overwrite outlook contact ContactSync.MergeContacts(match.GoogleContact, match.OutlookContact); sync.OverwriteContactGroups(match.GoogleContact, match.OutlookContact); break; case SyncOption.MergePrompt: //promp for sync option ConflictResolver r = new ConflictResolver(); ConflictResolution res = r.Resolve(match.OutlookContact, match.GoogleContact); switch (res) { case ConflictResolution.Cancel: break; case ConflictResolution.OutlookWins: //TODO: what about categories/groups? ContactSync.MergeContacts(match.OutlookContact, match.GoogleContact); sync.OverwriteContactGroups(match.OutlookContact, match.GoogleContact); break; case ConflictResolution.GoogleWins: //TODO: what about categories/groups? ContactSync.MergeContacts(match.GoogleContact, match.OutlookContact); sync.OverwriteContactGroups(match.GoogleContact, match.OutlookContact); break; default: break; } break; case SyncOption.GoogleToOutlookOnly: ContactSync.MergeContacts(match.GoogleContact, match.OutlookContact); sync.OverwriteContactGroups(match.GoogleContact, match.OutlookContact); break; case SyncOption.OutlookToGoogleOnly: ContactSync.MergeContacts(match.OutlookContact, match.GoogleContact); sync.OverwriteContactGroups(match.OutlookContact, match.GoogleContact); break; } return; } //check if outlook contact was updated (with X second tolerance) if (lastUpdatedOutlook.Subtract(lastSynced.Value).TotalSeconds >= TimeTolerance) { //outlook contact was changed //merge contacts. if (sync.SyncOption != SyncOption.GoogleToOutlookOnly) { //TODO: use UpdateContact instead? ContactSync.MergeContacts(match.OutlookContact, match.GoogleContact); sync.OverwriteContactGroups(match.OutlookContact, 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 (lastUpdatedGoogle.Subtract(lastSynced.Value).TotalSeconds >= TimeTolerance) { //google contact was updated //update outlook contact if (sync.SyncOption != SyncOption.OutlookToGoogleOnly) { ContactSync.MergeContacts(match.GoogleContact, match.OutlookContact); sync.OverwriteContactGroups(match.GoogleContact, match.OutlookContact); } } } else { //contacts were never synced. //merge contacts. switch (sync.SyncOption) { case SyncOption.MergeOutlookWins: //overwrite google contact ContactSync.MergeContacts(match.OutlookContact, match.GoogleContact); sync.OverwriteContactGroups(match.OutlookContact, match.GoogleContact); break; case SyncOption.MergeGoogleWins: //overwrite outlook contact ContactSync.MergeContacts(match.GoogleContact, match.OutlookContact); sync.OverwriteContactGroups(match.GoogleContact, match.OutlookContact); break; case SyncOption.MergePrompt: //promp for sync option ConflictResolver r = new ConflictResolver(); ConflictResolution res = r.Resolve(match.OutlookContact, match.GoogleContact); switch (res) { case ConflictResolution.Cancel: break; case ConflictResolution.OutlookWins: ContactSync.MergeContacts(match.OutlookContact, match.GoogleContact); sync.OverwriteContactGroups(match.OutlookContact, match.GoogleContact); break; case ConflictResolution.GoogleWins: ContactSync.MergeContacts(match.GoogleContact, match.OutlookContact); sync.OverwriteContactGroups(match.GoogleContact, match.OutlookContact); break; default: break; } break; case SyncOption.GoogleToOutlookOnly: ContactSync.MergeContacts(match.GoogleContact, match.OutlookContact); sync.OverwriteContactGroups(match.GoogleContact, match.OutlookContact); break; case SyncOption.OutlookToGoogleOnly: ContactSync.MergeContacts(match.OutlookContact, match.GoogleContact); sync.OverwriteContactGroups(match.OutlookContact, match.GoogleContact); break; } } } else { throw new ArgumentNullException("ContactMatch has all peers null."); } }
/// <summary> /// Matches outlook and google contact by a) google id b) properties. /// </summary> /// <param name="outlookContacts"></param> /// <param name="googleContacts"></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 ContactMatchList MatchContacts(Syncronizer sync) { ContactMatchList result = new ContactMatchList(Math.Max(sync.OutlookContacts.Count, sync.GoogleContacts.Capacity)); int googleContactsMatched = 0; bool listingDuplicates = false; string duplicatesList = ""; //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) for (int i = 1; i <= sync.OutlookContacts.Count; i++) { try { if (!(sync.OutlookContacts[i] is Outlook.ContactItem)) { continue; } } catch (Exception ex) { //this is needed because some contacts throw exceptions continue; } Outlook.ContactItem olc = sync.OutlookContacts[i] as Outlook.ContactItem; // check if a duplicate Collection <Outlook.ContactItem> duplicates; if (!string.IsNullOrEmpty(olc.Email1Address)) { duplicates = sync.OutlookContactByEmail(olc.Email1Address); if (duplicates.Count > 1) { if (!listingDuplicates) { duplicatesList = "Outlook contacts with the same email have been found. Please delete duplicates of:"; listingDuplicates = true; } string str = olc.FileAs + " (" + olc.Email1Address + ")"; if (!duplicatesList.Contains(str)) { duplicatesList += Environment.NewLine + str; } continue; } else { ContactMatch dup = result.Find(delegate(ContactMatch match) { return(match.OutlookContact != null && match.OutlookContact.Email1Address == olc.Email1Address); }); if (dup != null) { if (sync.Logger != null) { sync.Logger.Log(string.Format("Duplicate contact found ({0}). Skipping", olc.FileAs), EventType.Information); } continue; } } } //if (duplicates.Count != 1) //{ // // if this is the first item in the duplicates // // collection, then proceed, otherwise skip. // int index = sync.IndexOf(duplicates, olc); //duplicates.IndexOf(olc); // if (index == -1) // throw new Exception("Did not find self in duplicates"); // if (index != 0) // continue; //} if (!IsContactValid(olc)) { if (sync.Logger != null) { sync.Logger.Log(string.Format("Invalid outlook contact ({0}). Skipping", olc.FileAs), EventType.Warning); } continue; } // only match if there is either an email or telephone or else // a matching google contact will be created at each sync if (olc.Email1Address != null || olc.Email2Address != null || olc.Email3Address != null || olc.PrimaryTelephoneNumber != null || olc.HomeTelephoneNumber != null || olc.MobileTelephoneNumber != null || olc.BusinessTelephoneNumber != null ) { //create a default match pair with just outlook contact. ContactMatch match = new ContactMatch(olc, null); #region Match by google id //try to match this contact to one of google contacts. Outlook.UserProperty idProp = olc.UserProperties[sync.OutlookPropertyNameId]; if (idProp != null) { AtomId id = new AtomId((string)idProp.Value); ContactEntry foundContact = sync.GoogleContacts.FindById(id) as ContactEntry; if (foundContact != null && foundContact.Deleted) { //google contact was deleted, but outlook contact is still referencing it. idProp.Value = ""; //TODO: delete outlook contact too? } if (foundContact == null) { //google contact not found. delete property. idProp.Value = ""; } else if (foundContact != null) { //we found a match by google id match.AddGoogleContact(foundContact); } } #endregion if (match.GoogleContact == null) { //no match found. match by common properties #region Match by properties //foreach google contac try to match and create a match pair if found some match(es) foreach (ContactEntry entry in sync.GoogleContacts) { //Console.WriteLine(" - "+entry.Title.Text); if (entry.Deleted) { continue; } //1. try to match by name if (!string.IsNullOrEmpty(olc.FullName) && olc.FullName.Equals(entry.Title.Text, StringComparison.InvariantCultureIgnoreCase)) { match.AddGoogleContact(entry); continue; } //1.1 try to match by file as if (!string.IsNullOrEmpty(olc.FileAs) && olc.FileAs.Equals(entry.Title.Text, StringComparison.InvariantCultureIgnoreCase)) { match.AddGoogleContact(entry); continue; } //2. try to match by emails if (FindEmail(olc.Email1Address, entry.Emails) != null) { match.AddGoogleContact(entry); continue; } if (FindEmail(olc.Email2Address, entry.Emails) != null) { match.AddGoogleContact(entry); continue; } if (FindEmail(olc.Email3Address, entry.Emails) != null) { match.AddGoogleContact(entry); continue; } #region Phone numbers //3. try to match by phone numbers if (FindPhone(olc.MobileTelephoneNumber, entry.Phonenumbers) != null) { match.AddGoogleContact(entry); continue; } //don't match by home or business bumbers, because several people may share the saem home or business number continue; //if (FindPhone(olc.PrimaryTelephoneNumber, entry.Phonenumbers) != null) //{ // match.AddGoogleContact(entry); // continue; //} if (FindPhone(olc.HomeTelephoneNumber, entry.Phonenumbers) != null) { match.AddGoogleContact(entry); continue; } if (FindPhone(olc.BusinessTelephoneNumber, entry.Phonenumbers) != null) { match.AddGoogleContact(entry); continue; } if (FindPhone(olc.BusinessFaxNumber, entry.Phonenumbers) != null) { match.AddGoogleContact(entry); //continue; } if (FindPhone(olc.HomeFaxNumber, entry.Phonenumbers) != null) { match.AddGoogleContact(entry); //continue; } if (FindPhone(olc.PagerNumber, entry.Phonenumbers) != null) { match.AddGoogleContact(entry); //continue; } if (FindPhone(olc.RadioTelephoneNumber, entry.Phonenumbers) != null) { match.AddGoogleContact(entry); //continue; } if (FindPhone(olc.OtherTelephoneNumber, entry.Phonenumbers) != null) { match.AddGoogleContact(entry); //continue; } if (FindPhone(olc.CarTelephoneNumber, entry.Phonenumbers) != null) { match.AddGoogleContact(entry); //continue; } if (FindPhone(olc.Business2TelephoneNumber, entry.Phonenumbers) != null) { match.AddGoogleContact(entry); //continue; } #endregion } #endregion } //check if a match was found. if (match.AllGoogleContactMatches.Count > 0) { googleContactsMatched += match.AllGoogleContactMatches.Count; //remove google contact from the list so it's not matched twice. foreach (ContactEntry contact in match.AllGoogleContactMatches) { sync.GoogleContacts.Remove(contact); } } else { if (sync.Logger != null) { sync.Logger.Log(string.Format("No match found for outlook contact ({0})", olc.FileAs), EventType.Information); } } result.Add(match); } else { // no telephone and email if (sync.Logger != null) { sync.Logger.Log(string.Format("Skipping outlook contact ({0})", olc.FileAs), EventType.Warning); } } } if (listingDuplicates) { throw new DuplicateDataException(duplicatesList); } //return result; if (sync.SyncOption != SyncOption.OutlookToGoogleOnly) { //for each google contact that's left (they will be nonmatched) create a new match pair without outlook contact. foreach (ContactEntry entry in sync.GoogleContacts) { // only match if there is either an email or telephone or else // a matching google contact will be created at each sync if (entry.Emails.Count != 0 || entry.Phonenumbers.Count != 0) { ContactMatch match = new ContactMatch(null, entry);; result.Add(match); } else { // no telephone and email } } } return(result); }
public void SaveContact(ContactMatch match) { if (match.GoogleContact != null && match.OutlookContact != null) { //bool googleChanged, outlookChanged; //SaveContactGroups(match, out googleChanged, out outlookChanged); if (match.GoogleContact.IsDirty() || !match.OutlookContact.Saved) { _syncedCount++; } if (match.GoogleContact.IsDirty())// || googleChanged) { //google contact was modified. save. SaveGoogleContact(match); if (Logger != null) { Logger.Log("Saved Google contact: \"" + match.GoogleContact.Title.Text + "\"", EventType.Information); } } if (!match.OutlookContact.Saved)// || outlookChanged) { match.OutlookContact.Save(); ContactPropertiesUtils.SetGoogleOutlookContactId(SyncProfile, match.GoogleContact, match.OutlookContact); ContactEntry updatedEntry = match.GoogleContact.Update() as ContactEntry; match.GoogleContact = updatedEntry; ContactPropertiesUtils.SetOutlookGoogleContactId(this, match.OutlookContact, match.GoogleContact); match.OutlookContact.Save(); if (Logger != null) { Logger.Log("Saved Outlook contact: \"" + match.OutlookContact.FileAs + "\"", EventType.Information); } //TODO: this will cause the google contact to be updated on next run because Outlook's contact will be marked as saved later that Google's contact. } // save photos SaveContactPhotos(match); } else if (match.GoogleContact == null && match.OutlookContact != null) { if (ContactPropertiesUtils.GetOutlookGoogleContactId(this, match.OutlookContact) != null && _syncDelete) { _deletedCount++; string name = match.OutlookContact.FileAs; // peer google contact was deleted, delete outlook contact match.OutlookContact.Delete(); if (Logger != null) { Logger.Log("Deleted Outlook contact: \"" + name + "\"", EventType.Information); } } } else if (match.GoogleContact != null && match.OutlookContact == null) { if (ContactPropertiesUtils.GetGoogleOutlookContactId(SyncProfile, match.GoogleContact) != null && _syncDelete) { _deletedCount++; // peer outlook contact was deleted, delete google contact match.GoogleContact.Delete(); if (Logger != null) { Logger.Log("Deleted Google contact: \"" + match.GoogleContact.Title.Text + "\"", EventType.Information); } } } else { //TODO: ignore for now: throw new ArgumentNullException("To save contacts both ContactMatch peers must be present."); if (Logger != null) { Logger.Log("Both Google and Outlook contact: \"" + match.GoogleContact.Title.Text + "\" have been changed! Not implemented yet.", EventType.Warning); } } }