File indexing completed on 2024-11-24 04:43:04

0001 /*
0002     SPDX-FileCopyrightText: 2014-2024 Laurent Montel <montel@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "mergecontacts.h"
0008 #include "kaddressbookmergelibprivate_debug.h"
0009 
0010 using namespace KABMergeContacts;
0011 using namespace KContacts;
0012 MergeContacts::MergeContacts(const Akonadi::Item::List &items)
0013     : mListItem(items)
0014 {
0015 }
0016 
0017 MergeContacts::~MergeContacts() = default;
0018 
0019 void MergeContacts::setItems(const Akonadi::Item::List &items)
0020 {
0021     mListItem = items;
0022 }
0023 
0024 KContacts::Addressee MergeContacts::mergedContact(bool excludeConflictPart)
0025 {
0026     KContacts::Addressee newContact;
0027     if (mListItem.count() <= 1) {
0028         return newContact;
0029     }
0030     bool firstAddress = true;
0031     for (const Akonadi::Item &item : std::as_const(mListItem)) {
0032         if (item.hasPayload<KContacts::Addressee>()) {
0033             auto address = item.payload<KContacts::Addressee>();
0034             if (firstAddress) {
0035                 firstAddress = false;
0036                 newContact = address;
0037             } else {
0038                 mergeToContact(newContact, address, excludeConflictPart);
0039             }
0040         }
0041     }
0042     return newContact;
0043 }
0044 
0045 void MergeContacts::mergeToContact(KContacts::Addressee &newContact, const KContacts::Addressee &fromContact, bool excludeConflictPart)
0046 {
0047     // Duplicate notes.
0048     const QString fromContactNote = fromContact.note();
0049     if (!fromContactNote.isEmpty()) {
0050         QString newContactNote = newContact.note();
0051         if (!newContactNote.isEmpty()) {
0052             newContactNote += QLatin1Char('\n');
0053         }
0054         newContactNote += fromContactNote;
0055         newContact.setNote(newContactNote);
0056     }
0057     // Duplicate emails
0058     const QStringList emails = fromContact.emails();
0059     if (!emails.isEmpty()) {
0060         QStringList newContactsEmail = newContact.emails();
0061         for (const QString &email : emails) {
0062             if (!newContactsEmail.contains(email)) {
0063                 newContactsEmail.append(email);
0064             }
0065         }
0066         newContact.setEmails(newContactsEmail);
0067     }
0068     // Merge Categories
0069     const QStringList categories = fromContact.categories();
0070     if (!categories.isEmpty()) {
0071         QStringList newContactsCategories = newContact.categories();
0072         for (const QString &category : categories) {
0073             if (!newContactsCategories.contains(category)) {
0074                 newContactsCategories.append(category);
0075             }
0076         }
0077         newContact.setCategories(newContactsCategories);
0078     }
0079 
0080     // Merge Phone
0081     const PhoneNumber::List listPhone = fromContact.phoneNumbers();
0082     if (!listPhone.isEmpty()) {
0083         const PhoneNumber::List newContactsPhone = newContact.phoneNumbers();
0084         for (const PhoneNumber &phone : listPhone) {
0085             if (!newContactsPhone.contains(phone)) {
0086                 newContact.insertPhoneNumber(phone);
0087             }
0088         }
0089     }
0090 
0091     // Merge Address
0092     const Address::List listAddress = fromContact.addresses();
0093     if (!listAddress.isEmpty()) {
0094         const Address::List newContactsAddress = newContact.addresses();
0095         for (const Address &addr : listAddress) {
0096             if (!newContactsAddress.contains(addr)) {
0097                 newContact.insertAddress(addr);
0098             }
0099         }
0100     }
0101 
0102     // Merge Impp
0103     const Impp::List listImpp = fromContact.imppList();
0104     if (!listImpp.isEmpty()) {
0105         const Impp::List newContactsImpp = newContact.imppList();
0106         for (const Impp &impp : listImpp) {
0107             if (!newContactsImpp.contains(impp)) {
0108                 newContact.insertImpp(impp);
0109             }
0110         }
0111     }
0112 
0113     if (!excludeConflictPart) {
0114         // Merge Name
0115         if (newContact.name().isEmpty() && !fromContact.name().isEmpty()) {
0116             newContact.setName(fromContact.name());
0117         }
0118         // Merge organization
0119         if (newContact.organization().isEmpty() && !fromContact.organization().isEmpty()) {
0120             newContact.setOrganization(fromContact.organization());
0121         }
0122         // Merge NickName
0123         if (newContact.nickName().isEmpty() && !fromContact.nickName().isEmpty()) {
0124             newContact.setNickName(fromContact.nickName());
0125         }
0126         // Merge Title
0127         if (newContact.title().isEmpty() && !fromContact.title().isEmpty()) {
0128             newContact.setTitle(fromContact.title());
0129         }
0130         // Merge Departement
0131         if (newContact.department().isEmpty() && !fromContact.department().isEmpty()) {
0132             newContact.setDepartment(fromContact.department());
0133         }
0134         // Merge FamilyName
0135         if (newContact.familyName().isEmpty() && !fromContact.familyName().isEmpty()) {
0136             newContact.setFamilyName(fromContact.familyName());
0137         }
0138         // Merge HomePage
0139         if (newContact.url().url().isEmpty() && !fromContact.url().url().isEmpty()) {
0140             newContact.setUrl(fromContact.url());
0141         }
0142         // Merge geo
0143         if (newContact.geo().isValid() && !fromContact.geo().isValid()) {
0144             newContact.setGeo(fromContact.geo());
0145         }
0146         // Merge Photo
0147         if (newContact.photo().isEmpty() && !fromContact.photo().isEmpty()) {
0148             newContact.setPhoto(fromContact.photo());
0149         }
0150 
0151         // Merge Birthday
0152         if (!newContact.birthday().isValid() && !fromContact.birthday().isValid()) {
0153             newContact.setBirthday(fromContact.birthday());
0154         }
0155 
0156         // Merge Logo
0157         if (newContact.logo().isEmpty() && !fromContact.logo().isEmpty()) {
0158             newContact.setLogo(fromContact.logo());
0159         }
0160 
0161         // Merge Blog
0162         mergeCustomValue(fromContact, QStringLiteral("BlogFeed"), newContact);
0163         // Merge profession
0164         mergeCustomValue(fromContact, QStringLiteral("X-Profession"), newContact);
0165         // Merge Office
0166         mergeCustomValue(fromContact, QStringLiteral("X-Office"), newContact);
0167         // Merge ManagersName
0168         mergeCustomValue(fromContact, QStringLiteral("X-ManagersName"), newContact);
0169         // Merge AssistantsName
0170         mergeCustomValue(fromContact, QStringLiteral("X-AssistantsName"), newContact);
0171         // Merge SpousesName
0172         mergeCustomValue(fromContact, QStringLiteral("X-SpousesName"), newContact);
0173         // Merge Anniversary
0174         mergeCustomValue(fromContact, QStringLiteral("X-Anniversary"), newContact);
0175         // Merge Key
0176     }
0177 }
0178 
0179 void MergeContacts::mergeCustomValue(const KContacts::Addressee &fromContact, const QString &variable, KContacts::Addressee &newContact)
0180 {
0181     const QString newValue = newContact.custom(QStringLiteral("KADDRESSBOOK"), variable);
0182     const QString value = fromContact.custom(QStringLiteral("KADDRESSBOOK"), variable);
0183     if (newValue.isEmpty() && !value.isEmpty()) {
0184         newContact.insertCustom(QStringLiteral("KADDRESSBOOK"), variable, value);
0185     }
0186 }
0187 
0188 MergeContacts::ConflictInformations MergeContacts::requiresManualSelectionOfInformation()
0189 {
0190     MergeContacts::ConflictInformations result = None;
0191     if (mListItem.count() < 2) {
0192         return result;
0193     }
0194     KContacts::Addressee newContact;
0195     for (const Akonadi::Item &item : std::as_const(mListItem)) {
0196         if (item.hasPayload<KContacts::Addressee>()) {
0197             const auto address = item.payload<KContacts::Addressee>();
0198             // Test Birthday
0199             if (address.birthday().date().isValid()) {
0200                 if (newContact.birthday().date().isValid()) {
0201                     if (newContact.birthday().date() != address.birthday().date()) {
0202                         result |= Birthday;
0203                     }
0204                 } else {
0205                     newContact.setBirthday(address.birthday());
0206                 }
0207             }
0208 
0209             // Test Geo
0210             const KContacts::Geo geo = address.geo();
0211             if (geo.isValid()) {
0212                 if (newContact.geo().isValid()) {
0213                     if (newContact.geo() != geo) {
0214                         result |= Geo;
0215                     }
0216                 } else {
0217                     newContact.setGeo(address.geo());
0218                 }
0219             }
0220             // Test Photo
0221             const KContacts::Picture photo = address.photo();
0222             if (!photo.isEmpty()) {
0223                 if (!newContact.photo().isEmpty()) {
0224                     if (newContact.photo() != photo) {
0225                         result |= Photo;
0226                     }
0227                 } else {
0228                     newContact.setPhoto(address.photo());
0229                 }
0230             }
0231             // Test Logo
0232             const KContacts::Picture logo = address.logo();
0233             if (!logo.isEmpty()) {
0234                 if (!newContact.logo().isEmpty()) {
0235                     if (newContact.logo() != logo) {
0236                         result |= Logo;
0237                     }
0238                 } else {
0239                     newContact.setLogo(address.logo());
0240                 }
0241             }
0242             // Test Name
0243             const QString name = address.name();
0244             if (!name.isEmpty()) {
0245                 if (!newContact.name().isEmpty()) {
0246                     if (newContact.name() != name) {
0247                         result |= Name;
0248                     }
0249                 } else {
0250                     newContact.setName(address.name());
0251                 }
0252             }
0253             // Test NickName
0254             const QString nickName = address.nickName();
0255             if (!nickName.isEmpty()) {
0256                 if (!newContact.nickName().isEmpty()) {
0257                     if (newContact.nickName() != nickName) {
0258                         result |= NickName;
0259                     }
0260                 } else {
0261                     newContact.setNickName(address.nickName());
0262                 }
0263             }
0264             // Test Organization
0265             const QString organization = address.organization();
0266             if (!organization.isEmpty()) {
0267                 if (!newContact.organization().isEmpty()) {
0268                     if (newContact.organization() != organization) {
0269                         result |= Organization;
0270                     }
0271                 } else {
0272                     newContact.setOrganization(address.organization());
0273                 }
0274             }
0275             // Test Title
0276             const QString title = address.title();
0277             if (!title.isEmpty()) {
0278                 if (!newContact.title().isEmpty()) {
0279                     if (newContact.title() != title) {
0280                         result |= Title;
0281                     }
0282                 } else {
0283                     newContact.setTitle(address.title());
0284                 }
0285             }
0286             // Test Departement
0287             const QString departement = address.department();
0288             if (!departement.isEmpty()) {
0289                 if (!newContact.department().isEmpty()) {
0290                     if (newContact.department() != departement) {
0291                         result |= Departement;
0292                     }
0293                 } else {
0294                     newContact.setDepartment(address.department());
0295                 }
0296             }
0297             // Test HomePage
0298             const QUrl url = address.url().url();
0299             if (url.isValid() && !url.isEmpty()) {
0300                 if (newContact.url().url().isValid() && !newContact.url().url().isEmpty()) {
0301                     if (newContact.url().url() != url) {
0302                         result |= HomePage;
0303                     }
0304                 } else {
0305                     newContact.setUrl(address.url());
0306                 }
0307             }
0308             // Test FamilyName
0309             const QString familyName = address.familyName();
0310             if (!familyName.isEmpty()) {
0311                 if (!newContact.familyName().isEmpty()) {
0312                     if (newContact.familyName() != familyName) {
0313                         result |= FamilyName;
0314                     }
0315                 } else {
0316                     newContact.setFamilyName(address.familyName());
0317                 }
0318             }
0319             // Test Blog
0320             checkCustomValue(address, QStringLiteral("BlogFeed"), newContact, result, Blog);
0321             // Test profession
0322             checkCustomValue(address, QStringLiteral("X-Profession"), newContact, result, Profession);
0323             // Test profession
0324             checkCustomValue(address, QStringLiteral("X-Office"), newContact, result, Office);
0325             // Test ManagersName
0326             checkCustomValue(address, QStringLiteral("X-ManagersName"), newContact, result, ManagerName);
0327             // Test AssistantsName
0328             checkCustomValue(address, QStringLiteral("X-AssistantsName"), newContact, result, Assistant);
0329             // Test SpousesName
0330             checkCustomValue(address, QStringLiteral("X-SpousesName"), newContact, result, PartnerName);
0331             // Test Anniversary
0332             checkCustomValue(address, QStringLiteral("X-Anniversary"), newContact, result, Anniversary);
0333         }
0334     }
0335     qCDebug(KADDRESSBOOKMERGELIBPRIVATE_LOG) << " result " << result;
0336     return result;
0337 }
0338 
0339 void MergeContacts::checkCustomValue(const KContacts::Addressee &address,
0340                                      const QString &variable,
0341                                      KContacts::Addressee &newContact,
0342                                      MergeContacts::ConflictInformations &result,
0343                                      MergeContacts::ConflictInformation conflict)
0344 {
0345     const QString value = address.custom(QStringLiteral("KADDRESSBOOK"), variable);
0346     if (!value.isEmpty()) {
0347         const QString newValue = newContact.custom(QStringLiteral("KADDRESSBOOK"), variable);
0348         if (!newValue.isEmpty()) {
0349             if (newValue != value) {
0350                 result |= conflict;
0351             }
0352         } else {
0353             newContact.insertCustom(QStringLiteral("KADDRESSBOOK"), variable, value);
0354         }
0355     }
0356 }