File indexing completed on 2025-01-19 04:46:32

0001 /*
0002    SPDX-FileCopyrightText: 2020-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "importwindowcontact.h"
0008 #include "importexportwindowscontactplugin_debug.h"
0009 #include <KLocalizedString>
0010 #include <KMessageBox>
0011 #include <QDomDocument>
0012 #include <QFile>
0013 
0014 // https://docs.microsoft.com/en-us/previous-versions//ms735869(v=vs.85)
0015 
0016 ImportWindowContact::ImportWindowContact() = default;
0017 
0018 ImportWindowContact::~ImportWindowContact() = default;
0019 
0020 KContacts::Addressee::List ImportWindowContact::importFile(const QString &fileName)
0021 {
0022     KContacts::Addressee::List lst;
0023     QFile file(fileName);
0024     if (!file.open(QIODevice::ReadOnly)) {
0025         if (!mAutoTest) {
0026             const QString msg = i18n("<qt>Unable to open <b>%1</b> for reading.</qt>", fileName);
0027             KMessageBox::error(mParentWidget, msg);
0028         } else {
0029             qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << "Impossible to open file: " << fileName;
0030         }
0031         return lst;
0032     }
0033     QDomDocument doc;
0034     if (loadDomElement(doc, &file)) {
0035         QDomElement list = doc.documentElement();
0036         if (list.isNull()) {
0037             qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << "No list defined in file";
0038         } else {
0039             KContacts::Addressee contact;
0040             if (mAutoTest) {
0041                 contact.setUid(QStringLiteral("foo"));
0042             }
0043             for (QDomElement e = list.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) {
0044                 const QString tag = e.tagName();
0045                 if (tag == QLatin1StringView("c:EmailAddressCollection")) {
0046                     KContacts::Email::List lstEmails;
0047                     for (QDomElement emails = e.firstChildElement(); !emails.isNull(); emails = emails.nextSiblingElement()) {
0048                         const QString emailsTag = emails.tagName();
0049                         if (emailsTag == QLatin1StringView("c:EmailAddress")) {
0050                             KContacts::Email email;
0051                             for (QDomElement addresses = emails.firstChildElement(); !addresses.isNull(); addresses = addresses.nextSiblingElement()) {
0052                                 const QString addressesTag = addresses.tagName();
0053                                 if (addressesTag == QLatin1StringView("c:Type")) {
0054                                 } else if (addressesTag == QLatin1StringView("c:Address")) {
0055                                     email.setEmail(addresses.text());
0056                                 } else {
0057                                     qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " address tag not supported yet " << addressesTag;
0058                                 }
0059                             }
0060                             if (email.isValid()) {
0061                                 lstEmails << email;
0062                             }
0063                         }
0064                         contact.setEmailList(lstEmails);
0065                     }
0066                 } else if (tag == QLatin1StringView("c:NameCollection")) {
0067                     for (QDomElement name = e.firstChildElement(); !name.isNull(); name = name.nextSiblingElement()) {
0068                         const QString nameTag = name.tagName();
0069                         if (nameTag == QLatin1StringView("c:Name")) {
0070                             for (QDomElement nameInfo = name.firstChildElement(); !nameInfo.isNull(); nameInfo = nameInfo.nextSiblingElement()) {
0071                                 const QString nameInfoTag = nameInfo.tagName();
0072                                 if (nameInfoTag == QLatin1StringView("c:FormattedName")) {
0073                                     contact.setName(nameInfo.text());
0074                                 } else if (nameInfoTag == QLatin1StringView("c:GivenName")) {
0075                                     contact.setGivenName(nameInfo.text());
0076                                 } else if (nameInfoTag == QLatin1StringView("c:FamilyName")) {
0077                                     contact.setFamilyName(nameInfo.text());
0078                                 } else if (nameInfoTag == QLatin1StringView("c:FormattedName")) {
0079                                     contact.setFormattedName(nameInfo.text());
0080                                 } else if (nameInfoTag == QLatin1StringView("c:Title")) {
0081                                     contact.setTitle(nameInfo.text());
0082                                 } else if (nameInfoTag == QLatin1StringView("c:NickName")) {
0083                                     contact.setNickName(nameInfo.text());
0084                                 } else if (nameInfoTag == QLatin1StringView("c:Prefix")) {
0085                                     contact.setPrefix(nameInfo.text());
0086                                 } else if (nameInfoTag == QLatin1StringView("c:Suffix")) {
0087                                     contact.setSuffix(nameInfo.text());
0088                                 } else {
0089                                     // TODO middlename/generation
0090                                     qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " name tag not supported yet " << nameInfoTag;
0091                                 }
0092                             }
0093                         } else {
0094                             qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " name tag unknown:" << nameTag;
0095                         }
0096                     }
0097                 } else if (tag == QLatin1StringView("c:PhoneNumberCollection")) {
0098                     for (QDomElement number = e.firstChildElement(); !number.isNull(); number = number.nextSiblingElement()) {
0099                         const QString numberTag = number.tagName();
0100                         if (numberTag == QLatin1StringView("c:PhoneNumber")) {
0101                             KContacts::PhoneNumber phoneNumber;
0102                             for (QDomElement numberInfo = number.firstChildElement(); !numberInfo.isNull(); numberInfo = numberInfo.nextSiblingElement()) {
0103                                 const QString numberInfoTag = numberInfo.tagName();
0104                                 if (numberInfoTag == QLatin1StringView("c:Number")) {
0105                                     phoneNumber.setNumber(numberInfo.text());
0106                                 } else {
0107                                     qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " number info tag not supported yet:" << numberInfoTag;
0108                                 }
0109                             }
0110                             if (!phoneNumber.isEmpty()) {
0111                                 contact.insertPhoneNumber(phoneNumber);
0112                             }
0113                         } else {
0114                             qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " number tag unknown:" << numberTag;
0115                         }
0116                     }
0117                 } else if (tag == QLatin1StringView("c:IMAddressCollection")) {
0118                     for (QDomElement im = e.firstChildElement(); !im.isNull(); im = im.nextSiblingElement()) {
0119                         const QString imTag = im.tagName();
0120                         if (imTag == QLatin1StringView("c:IMAddress")) {
0121                             KContacts::Impp impp;
0122                             for (QDomElement imInfo = im.firstChildElement(); !imInfo.isNull(); imInfo = imInfo.nextSiblingElement()) {
0123                                 const QString imInfoTag = imInfo.tagName();
0124                                 if (imInfoTag == QLatin1StringView("c:Value")) {
0125                                     impp.setAddress(QUrl(imInfo.text()));
0126                                 } else {
0127                                     qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " im info tag not supported yet " << imInfoTag;
0128                                 }
0129                             }
0130                             if (impp.isValid()) {
0131                                 contact.insertImpp(impp);
0132                             }
0133                         } else {
0134                             qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " im tag unknown:" << imTag;
0135                         }
0136                     }
0137                 } else if (tag == QLatin1StringView("c:PhotoCollection")) {
0138                     for (QDomElement photo = e.firstChildElement(); !photo.isNull(); photo = photo.nextSiblingElement()) {
0139                         const QString photoTag = photo.tagName();
0140                         if (photoTag == QLatin1StringView("c:Photo")) {
0141                             KContacts::Picture picture;
0142                             for (QDomElement photoInfo = photo.firstChildElement(); !photoInfo.isNull(); photoInfo = photoInfo.nextSiblingElement()) {
0143                                 const QString photoInfoTag = photoInfo.tagName();
0144                                 if (photoInfoTag == QLatin1StringView("c:Value")) {
0145                                     const QString contentType = photoInfo.attribute(QStringLiteral("c:ContentType"));
0146                                     picture.setRawData(photoInfo.text().toUtf8(), contentType);
0147                                 } else if (photoInfoTag == QLatin1StringView("c:Url")) {
0148                                     picture.setUrl(photoInfo.text());
0149                                 } else {
0150                                     qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " photo info tag not supported yet " << photoInfoTag;
0151                                 }
0152                             }
0153                             if (!picture.isEmpty()) {
0154                                 contact.setPhoto(picture);
0155                             }
0156                         } else {
0157                             qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " photo tag unknown:" << photoTag;
0158                         }
0159                     }
0160                 } else if (tag == QLatin1StringView("c:PhysicalAddressCollection")) {
0161                     for (QDomElement address = e.firstChildElement(); !address.isNull(); address = address.nextSiblingElement()) {
0162                         const QString addressTag = address.tagName();
0163                         if (addressTag == QLatin1StringView("c:PhysicalAddress")) {
0164                             KContacts::Address addressType;
0165                             for (QDomElement addressInfo = address.firstChildElement(); !addressInfo.isNull(); addressInfo = addressInfo.nextSiblingElement()) {
0166                                 const QString addressInfoTag = addressInfo.tagName();
0167                                 if (addressInfoTag == QLatin1StringView("c:AddressLabel")) {
0168                                     addressType.setLabel(addressInfo.text());
0169                                 } else if (addressInfoTag == QLatin1StringView("c:Street")) {
0170                                     addressType.setStreet(addressInfo.text());
0171                                 } else if (addressInfoTag == QLatin1StringView("c:Locality")) {
0172                                     addressType.setLocality(addressInfo.text());
0173                                 } else if (addressInfoTag == QLatin1StringView("c:Region")) {
0174                                     addressType.setRegion(addressInfo.text());
0175                                 } else if (addressInfoTag == QLatin1StringView("c:Country")) {
0176                                     addressType.setCountry(addressInfo.text());
0177                                 } else if (addressInfoTag == QLatin1StringView("c:PostalCode")) {
0178                                     addressType.setPostalCode(addressInfo.text());
0179                                 } else if (addressInfoTag == QLatin1StringView("c:POBox")) {
0180                                     addressType.setPostOfficeBox(addressInfo.text());
0181                                 } else {
0182                                     qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " address info tag not supported yet " << addressInfoTag;
0183                                 }
0184                             }
0185                             if (!addressType.isEmpty()) {
0186                                 contact.insertAddress(addressType);
0187                             }
0188                         } else {
0189                             qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " address tag unknown:" << addressTag;
0190                         }
0191                     }
0192                 } else if (tag == QLatin1StringView("c:PositionCollection")) {
0193                     for (QDomElement position = e.firstChildElement(); !position.isNull(); position = position.nextSiblingElement()) {
0194                         const QString positionTag = position.tagName();
0195                         if (positionTag == QLatin1StringView("c:Position")) {
0196                             for (QDomElement positionInfo = position.firstChildElement(); !positionInfo.isNull();
0197                                  positionInfo = positionInfo.nextSiblingElement()) {
0198                                 const QString positionInfoTag = positionInfo.tagName();
0199                                 if (positionInfoTag == QLatin1StringView("c:Organization")) {
0200                                     contact.setOrganization(positionInfo.text());
0201                                 } else if (positionInfoTag == QLatin1StringView("c:Department")) {
0202                                     contact.setDepartment(positionInfo.text());
0203                                 } else if (positionInfoTag == QLatin1StringView("c:Office")) {
0204                                     contact.setOffice(positionInfo.text());
0205                                 } else if (positionInfoTag == QLatin1StringView("c:Profession")) {
0206                                     contact.setProfession(positionInfo.text());
0207                                 } else if (positionInfoTag == QLatin1StringView("c:Role")) {
0208                                     contact.setRole(positionInfo.text());
0209                                 } else {
0210                                     qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " position info tag not supported yet " << positionInfoTag;
0211                                 }
0212                             }
0213                         } else {
0214                             qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " position tag unknown:" << positionTag;
0215                         }
0216                     }
0217                 } else if (tag == QLatin1StringView("c:Gender")) { // TODO verify it
0218                     KContacts::Gender gender;
0219                     const QString genderStr = e.text();
0220                     if (genderStr == QLatin1StringView("Male")) {
0221                         gender.setGender(QStringLiteral("H"));
0222                     } else if (genderStr == QLatin1StringView("Female")) {
0223                         gender.setGender(QStringLiteral("F"));
0224                     } else {
0225                         // Don't provide gender
0226                         continue;
0227                     }
0228                     contact.setGender(gender);
0229                 } else if (tag == QLatin1StringView("c:Notes")) { // TODO verify it
0230                     contact.setNote(e.text());
0231                 } else if (tag == QLatin1StringView("c:UrlCollection")) { // TODO verify it
0232                     for (QDomElement url = e.firstChildElement(); !url.isNull(); url = url.nextSiblingElement()) {
0233                         const QString urlTag = url.tagName();
0234                         if (urlTag == QLatin1StringView("c:Url")) {
0235                             for (QDomElement urlInfo = url.firstChildElement(); !urlInfo.isNull(); urlInfo = urlInfo.nextSiblingElement()) {
0236                                 const QString urlInfoTag = urlInfo.tagName();
0237                                 if (urlInfoTag == QLatin1StringView("c:Value")) {
0238                                     KContacts::ResourceLocatorUrl resourceLocalUrl;
0239                                     resourceLocalUrl.setUrl(QUrl::fromUserInput(urlInfo.text()));
0240                                     contact.insertExtraUrl(resourceLocalUrl);
0241                                 } else {
0242                                     qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " url info tag not supported yet " << urlInfoTag;
0243                                 }
0244                             }
0245                         } else {
0246                             qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << " url tag unknown:" << urlTag;
0247                         }
0248                     }
0249                 } else {
0250                     qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG) << "unknown tag " << tag;
0251                 }
0252             }
0253             lst << contact;
0254         }
0255     }
0256     return lst;
0257 }
0258 
0259 bool ImportWindowContact::loadDomElement(QDomDocument &doc, QFile *file)
0260 {
0261     QString errorMsg;
0262     int errorRow;
0263     int errorCol;
0264     if (!doc.setContent(file, &errorMsg, &errorRow, &errorCol)) {
0265         qCWarning(IMPORTEXPORTWINDOWSCONTACTPLUGIN_LOG)
0266             << "Unable to load document.Parse error in line " << errorRow << ", col " << errorCol << ": " << errorMsg;
0267         return false;
0268     }
0269     return true;
0270 }
0271 
0272 void ImportWindowContact::setParentWidget(QWidget *parentWidget)
0273 {
0274     mParentWidget = parentWidget;
0275 }
0276 
0277 void ImportWindowContact::setAutoTests(bool b)
0278 {
0279     mAutoTest = b;
0280 }