/// <summary> /// Requests an entity merge of elements /// </summary> /// <param name="sourceList"> /// the source entity list /// </param> /// <param name="targetList"> /// the list that will be changed /// </param> /// <param name="baselineList"> /// a baseline list that helps merging /// </param> /// <param name="identifierToUse"> /// The identifier To Use. /// </param> /// <returns> /// The unmodified <paramref name="targetList"/> /// </returns> public List <StdElement> PerformEntityMerge( List <StdElement> sourceList, List <StdElement> targetList, List <StdElement> baselineList, ProfileIdentifierType identifierToUse) { Console.WriteLine(Resources.NotImplementedInteractiveEntityMerge); return(targetList); }
/// <summary> /// Displays a modal dialog to let the user match entities. /// </summary> /// <param name="sourceList"> /// The list of "unknown" elements to merge that will provide the profile id. /// </param> /// <param name="targetList"> /// The list of "target" elements that should contribute the synchronization id. /// </param> /// <param name="baselineList"> /// The baseline list that will be updated to connect a synchronization id to profile ids. /// </param> /// <param name="identifierToUse"> /// The identifier to use for matching the entities. /// </param> /// <returns> /// The baseline list that has been updated to connect a synchronization id to profile ids. /// </returns> public List <StdElement> PerformEntityMerge( List <StdElement> sourceList, List <StdElement> targetList, List <StdElement> baselineList, ProfileIdentifierType identifierToUse) { var ui = new MatchEntities(); return(ui.PerformMatch(sourceList, targetList, baselineList, identifierToUse)); }
/// <summary> /// Creates a <see cref="StdContact"/> entity with only the Xing profile ID specified for matching simulation. /// </summary> /// <param name="profileTypeId"></param> /// <param name="profileId"> /// The profile id. /// </param> /// <param name="id"> The <see cref="StdElement.Id"/>. </param> /// <returns> The entity created with a Xing profile id. </returns> private static StdContact CreateIdOnlyContact(ProfileIdentifierType profileTypeId, string profileId, string id) { var result = new StdContact { Name = new PersonName(profileId), Id = new Guid(id), ExternalIdentifier = new ProfileIdentifierDictionary(profileTypeId, profileId), }; return(result); }
/// <summary> /// Lets the user perform a manual matching /// </summary> /// <param name="sourceList"> The source list. </param> /// <param name="targetList"> The target list. </param> /// <param name="baselineList"> The baseline list. </param> /// <param name="identifierToUse"> The identifier to use. </param> /// <returns> a list of matches (the base line list manipulated by the user) </returns> public List <StdElement> PerformMatch( List <StdElement> sourceList, List <StdElement> targetList, List <StdElement> baselineList, ProfileIdentifierType identifierToUse) { if (sourceList.Count == 0) { return(baselineList); } this.matching.Profile = identifierToUse; this.matching.Source = sourceList; this.matching.Target = targetList; this.matching.BaseLine = baselineList.ToMatchingEntries(); this.SetupGui(); // cange the target list only if the OK-button has been clicked // otherwise we return null to not writy any content to the target return(this.ShowDialog() != DialogResult.OK ? null : this.matching.BaseLine.ToStdElements()); }
/// <summary> /// Implements the method to fill the contact with additional links to other contacts. /// </summary> /// <param name="contactToFill"> The contact to be filled. </param> /// <param name="baseline"> The baseline that does contain possible link targets. </param> /// <returns> the manipulated contact </returns> public override StdElement FillContacts(StdElement contactToFill, ICollection <MatchingEntry> baseline) { var contact = contactToFill as StdContact; const ProfileIdentifierType ProfileIdentifierType = ProfileIdentifierType.WerKenntWenUrl; const string ProfilePhpId = "/person/"; if (contact == null || !contact.ExternalIdentifier.ContainsKey(ProfileIdentifierType)) { return(contactToFill); } var profileIdInformation = contact.ExternalIdentifier[ProfileIdentifierType]; if (profileIdInformation == null || string.IsNullOrWhiteSpace(profileIdInformation.Id)) { return(contactToFill); } var offset = 0; var added = 0; while (true) { this.LogProcessingEvent("reading contacts ({0})", offset); this.HttpRequester.ContentCredentials = this; // get the contact list var url = string.Format( CultureInfo.InvariantCulture, "http://www.wer-kennt-wen.de/people/friends/{0}/sort/friends/0/0/{1}", profileIdInformation.Id.Replace(ProfilePhpId, string.Empty), offset); string profileContent; while (true) { profileContent = this.HttpRequester.GetContent(url, string.Format(CultureInfo.InvariantCulture, "Wkw-{0}", offset)); if (profileContent.Contains(@"id=""loginform""")) { if (!this.GetLogon()) { return(contactToFill); } continue; } if (profileContent.Contains(WkwCaptcha)) { this.ResolveCaptcha(); continue; } break; } var extracts = Regex.Matches(profileContent, @"\<a href=""/person/(?<profileId>[0-9a-zA-Z]*)""\>", RegexOptions.Singleline); // if there is no contact in list, we did reach the end if (extracts.Count < 3) { break; } // create a new instance of a list of references if there is none contact.Contacts = contact.Contacts ?? new List <ContactReference>(extracts.Count); foreach (Match extract in extracts) { var profileId = ProfilePhpId + extract.Groups["profileId"]; var stdId = (from x in baseline where x.ProfileId.GetProfileId(ProfileIdentifierType) == profileId select x.Id).FirstOrDefault(); // we ignore contacts we donn't know if (stdId == default(Guid)) { continue; } // lookup an existing entry in this contacts contact-list var contactInList = (from x in contact.Contacts where x.Target == stdId select x).FirstOrDefault(); if (contactInList == null) { // add a new one if no existing entry has been found contactInList = new ContactReference { Target = stdId }; contact.Contacts.Add(contactInList); added++; } // update the flag that this entry is a private contact // todo: private/business contact contactInList.IsPrivateContact = true; } Thread.Sleep(new Random().Next(230, 8789)); offset += 64; // extracts.Count; } this.LogProcessingEvent(contact, "{0} contacts found, {1} new added", offset, added); return(contactToFill); }
/// <summary> /// converts a vCard into a standard contact. /// </summary> /// <param name="vCard"> /// The vCard. /// </param> /// <param name="useIndentifierAs"> /// This value determines the meaning of the identifier. /// </param> /// <returns> /// a StdContact representation of the vCard /// </returns> public StdContact VCardToStdContact(byte[] vCard, ProfileIdentifierType useIndentifierAs) { if (vCard == null) { throw new ArgumentNullException("vCard"); } var contact = new StdContact { InternalSyncData = new SyncData { DateOfCreation = DateTime.Now, DateOfLastChange = DateTime.Now }, Name = new PersonName(), }; var vCardUtf8 = Encoding.UTF8.GetString(vCard); var vCardIso8859 = Encoding.UTF8.GetString(Encoding.Convert(Encoding.GetEncoding("iso8859-1"), Encoding.UTF8, vCard)); contact.Name = new PersonName(); var linesUtf8 = vCardUtf8.Split('\n'); var linesIso8859 = vCardIso8859.Split('\n'); for (var i = 0; i < linesIso8859.Length; i++) { var line = linesIso8859[i].Replace("\r", string.Empty); if (line.Length == 0 || !line.Contains(":")) { continue; } line = GetInformationSegment( ref i, line.ToUpperInvariant().Contains("CHARSET=UTF-8:") ? linesUtf8 : linesIso8859); var propertyDescription = line.Substring(0, line.IndexOf(':')).ToUpperInvariant(); var value = line.Substring(line.IndexOf(':') + 1).Replace("\r", string.Empty); var valueParts = value.Split(';'); var type = PropertyAttribute(propertyDescription, "TYPE", string.Empty); var propertyName = propertyDescription; if (propertyDescription.Contains(";")) { propertyName = propertyDescription.Substring(0, propertyDescription.IndexOf(';')); if (type.Count == 0 || (type.Count == 1 && type[0] == string.Empty)) { type.AddRange(propertyDescription.Split(';')); } } var binaryData = new byte[] { }; DecodeData(propertyDescription, ref value, ref binaryData); switch (propertyName) { case "TEL": // skip this if it's fax without voice support if (type.Contains("FAX") && !type.Contains("VOICE")) { break; } if (type.Contains("CELL")) { if (type.Contains("HOME")) { contact.PersonalPhoneMobile = new PhoneNumber(value); break; } if (type.Contains("WORK")) { contact.BusinessPhoneMobile = new PhoneNumber(value); break; } } if (type.Contains("HOME")) { if (contact.PersonalAddressPrimary == null) { contact.PersonalAddressPrimary = new AddressDetail(); } contact.PersonalAddressPrimary.Phone = new PhoneNumber(value); break; } if (type.Contains("WORK")) { if (contact.BusinessAddressPrimary == null) { contact.BusinessAddressPrimary = new AddressDetail(); } contact.BusinessAddressPrimary.Phone = new PhoneNumber(value); } break; case "N": contact.Name.LastName = GetNthElement(valueParts, 1); contact.Name.FirstName = GetNthElement(valueParts, 2); contact.Name.MiddleName = GetNthElement(valueParts, 3); contact.Name.AcademicTitle = GetNthElement(valueParts, 4); break; case "EMAIL": if (type.Contains("WORK")) { contact.BusinessEmailPrimary = value; break; } if (type.Contains("HOME")) { contact.PersonalEmailPrimary = value; break; } contact.PersonalEmailPrimary = value; Tools.DebugWriteLine("!!Unhandled email address - added as personal!!"); break; case "URL": if (type.Contains("HOME")) { contact.PersonalHomepage = value; } else { contact.BusinessHomepage = value; } break; case "ORG": contact.BusinessCompanyName = value; break; case "NOTE": contact.AdditionalTextData = value; break; case "ADR": if (line.EndsWith(";;;;;;\r", StringComparison.Ordinal)) { // in this case we do not have an address - it's all empty break; } var address = new AddressDetail { CityName = GetNthElement(valueParts, 4), StreetName = GetNthElement(valueParts, 3), StateName = GetNthElement(valueParts, 5), PostalCode = GetNthElement(valueParts, 6), CountryName = GetNthElement(valueParts, 7), }; if (type.Contains("WORK")) { contact.BusinessAddressPrimary = address; } else { contact.PersonalAddressPrimary = address; } break; case "TITLE": contact.BusinessPosition = value; break; case "X-WAB-GENDER": contact.PersonGender = value == "2" ? Gender.Male : value == "1" ? Gender.Female : Gender.Unspecified; break; case "PHOTO": if (binaryData.Length > 0) { contact.PictureData = binaryData; } else { var url = value.Replace("URI:", string.Empty); contact.PictureData = this.HttpRequester.GetContentBinary(url, url); } break; case "BDAY": var dateString = value; if (dateString.IndexOf("-", 0, StringComparison.Ordinal) == -1) { dateString = dateString.Substring(0, 4) + "-" + dateString.Substring(4, 2) + "-" + dateString.Substring(6, 2); } contact.DateOfBirth = DateTime.Parse( dateString, CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal); break; case "UID": contact.ExternalIdentifier.SetProfileId(useIndentifierAs, value); break; case "X-MATZEN-STDUID": contact.Id = new Guid(value); break; case "CATEGORIES": if (contact.SourceSpecificAttributes == null) { contact.SourceSpecificAttributes = new SerializableDictionary <string, string>(); } contact.SourceSpecificAttributes.Add(propertyName, value); break; case "LABEL": case "PRODID": case "BEGIN": case "END": case "SORT-STRING": case "CLASS": case "FN": case "": case "VERSION": case "X-MATZEN-GENERATOR": case "X-MS-OL-DESIGN": case "X-MS-OL-DEFAULT-POSTAL-ADDRESS": break; default: Tools.DebugWriteLine("unhandled: " + line.Replace("\r", string.Empty)); break; } } if (contact.Id == Guid.Empty) { contact.Id = Guid.NewGuid(); } return(contact); }