diff --git a/CMakeLists.txt b/CMakeLists.txt index 1299d2be..c4f6182d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,96 +1,96 @@ cmake_minimum_required(VERSION 3.5) -set(PIM_VERSION "5.11.44") +set(PIM_VERSION "5.11.45") project(KContacts VERSION ${PIM_VERSION}) # ECM setup set(QT_REQUIRED_VERSION "5.10.0") set(KF5_MIN_VERSION "5.57.0") find_package(ECM ${KF5_MIN_VERSION} CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${KContacts_SOURCE_DIR}/cmake) set(CMAKE_AUTORCC ON) include(GenerateExportHeader) include(ECMGenerateHeaders) include(ECMGeneratePriFile) include(ECMSetupVersion) include(FeatureSummary) include(KDEInstallDirs) include(KDECMakeSettings) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(ECMQtDeclareLoggingCategory) include(ECMAddQch) option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") set(KCONTACTS_LIB_VERSION ${PIM_VERSION}) ecm_setup_version(PROJECT VARIABLE_PREFIX KContacts VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kcontacts_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5ContactsConfigVersion.cmake" SOVERSION 5 ) ########### Find packages ########### find_package(Qt5 ${QT_REQUIRED_VERSION} REQUIRED COMPONENTS Gui) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS CoreAddons I18n Config Codecs) find_package(IsoCodes MODULE) set_package_properties("IsoCodes" PROPERTIES PURPOSE "Needed for country name translations." TYPE RUNTIME) ########### Targets ########### add_definitions(-DTRANSLATION_DOMAIN=\"kcontacts5\") # workaround for https://bugreports.qt.io/browse/QTBUG-74665 (bug in qt5.13 reevaluate it) if (${Qt5Gui_VERSION} STREQUAL "5.13.0") MESSAGE(STATUS "Qt version: ${Qt5Gui_VERSION} DISABLE compile without deprecated methods. bug QTBUG-74665") else() add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000) endif() add_definitions(-DQT_NO_FOREACH) add_subdirectory(src) if(BUILD_TESTING) add_subdirectory(autotests) add_subdirectory(tests) endif() ########### CMake Config Files ########### set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5Contacts") if (BUILD_QCH) ecm_install_qch_export( TARGETS KF5Contacts_QCH FILE KF5ContactsQchTargets.cmake DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5ContactsQchTargets.cmake\")") endif() configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KF5ContactsConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5ContactsConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5ContactsConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5ContactsConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT KF5ContactsTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5ContactsTargets.cmake NAMESPACE KF5::) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kcontacts_version.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5} COMPONENT Devel ) install( FILES kcontacts.renamecategories kcontacts.categories DESTINATION ${KDE_INSTALL_CONFDIR} ) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/autotests/emailtest.cpp b/autotests/emailtest.cpp index df7fb9ac..12bd25f8 100644 --- a/autotests/emailtest.cpp +++ b/autotests/emailtest.cpp @@ -1,208 +1,209 @@ /* This file is part of the KContacts framework. Copyright (C) 2015-2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "emailtest.h" #include "email.h" #include #include "vcardtool_p.h" EmailTest::EmailTest(QObject *parent) : QObject(parent) { } EmailTest::~EmailTest() { } void EmailTest::shouldHaveDefaultValue() { KContacts::Email email; QVERIFY(!email.isValid()); QVERIFY(email.mail().isEmpty()); QVERIFY(email.parameters().isEmpty()); } void EmailTest::shouldAssignValue() { const QString mail(QStringLiteral("foo@kde.org")); QMap params; params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); KContacts::Email email(mail); email.setParameters(params); QVERIFY(email.isValid()); QVERIFY(!email.mail().isEmpty()); QCOMPARE(email.mail(), mail); QVERIFY(!email.parameters().isEmpty()); QCOMPARE(email.parameters(), params); } void EmailTest::shouldAssignExternal() { KContacts::Email email; const QString mail(QStringLiteral("foo@kde.org")); email.setEmail(mail); QVERIFY(email.isValid()); QVERIFY(!email.mail().isEmpty()); QCOMPARE(email.mail(), mail); } void EmailTest::shouldSerialized() { KContacts::Email email; KContacts::Email result; const QString mail(QStringLiteral("foo@kde.org")); email.setEmail(mail); QMap params; params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); email.setParameters(params); QByteArray data; QDataStream s(&data, QIODevice::WriteOnly); s << email; QDataStream t(&data, QIODevice::ReadOnly); t >> result; QVERIFY(email == result); } void EmailTest::shouldEqualEmail() { KContacts::Email email; KContacts::Email result; const QString mail(QStringLiteral("foo@kde.org")); email.setEmail(mail); QMap params; params.insert(QStringLiteral("Foo1"), QStringList() << QStringLiteral("bla1") << QStringLiteral("blo1")); params.insert(QStringLiteral("Foo2"), QStringList() << QStringLiteral("bla2") << QStringLiteral("blo2")); email.setParameters(params); result = email; QVERIFY(email == result); } void EmailTest::shouldParseEmailVCard() { QByteArray vcarddata("BEGIN:VCARD\n" "VERSION:3.0\n" "EMAIL;TYPE=HOME,PREF;X-EVOLUTION-UI-SLOT=2:foo@foo.com\n" "N:LastName;FirstName;;;\n" "UID:c80cf296-0825-4eb0-ab16-1fac1d522a33@xxxxxx.xx\n" "REV:2015-03-14T09:24:45+00:00\n" "FN:FirstName LastName\n" "END:VCARD\n"); KContacts::VCardTool vcard; const KContacts::AddresseeList lst = vcard.parseVCards(vcarddata); QCOMPARE(lst.count(), 1); QVERIFY(!lst.at(0).emailList().isEmpty()); QCOMPARE(lst.at(0).emailList().count(), 1); KContacts::Email email = lst.at(0).emailList().at(0); QCOMPARE(email.mail(), QStringLiteral("foo@foo.com")); QCOMPARE(email.parameters().count(), 2); } void EmailTest::shouldParseEmailVCardWithMultiEmails() { QByteArray vcarddata("BEGIN:VCARD\n" "VERSION:3.0\n" "EMAIL;TYPE=WORK;X-EVOLUTION-UI-SLOT=2:foo@foo.com\n" "EMAIL;TYPE=HOME,PREF;X-EVOLUTION-UI-SLOT=2:bla@bla.com\n" "N:LastName;FirstName;;;\n" "UID:c80cf296-0825-4eb0-ab16-1fac1d522a33@xxxxxx.xx\n" "REV:2015-03-14T09:24:45+00:00\n" "FN:FirstName LastName\n" "END:VCARD\n"); KContacts::VCardTool vcard; const KContacts::AddresseeList lst = vcard.parseVCards(vcarddata); QCOMPARE(lst.count(), 1); QVERIFY(!lst.at(0).emailList().isEmpty()); QCOMPARE(lst.at(0).emailList().count(), 2); KContacts::Email email = lst.at(0).emailList().at(0); QCOMPARE(email.mail(), QStringLiteral("bla@bla.com")); - QCOMPARE(email.type(), KContacts::Email::Home | KContacts::Email::Preferred); + QCOMPARE(email.type(), KContacts::Email::Home); QVERIFY(email.isPreferred()); email = lst.at(0).emailList().at(1); QCOMPARE(email.mail(), QStringLiteral("foo@foo.com")); QCOMPARE(email.type(), KContacts::Email::Work); QVERIFY(!email.isPreferred()); QCOMPARE(email.parameters().count(), 2); } void EmailTest::shouldParseEmailVCardWithoutEmail() { QByteArray vcarddata("BEGIN:VCARD\n" "VERSION:3.0\n" "N:LastName;FirstName;;;\n" "UID:c80cf296-0825-4eb0-ab16-1fac1d522a33@xxxxxx.xx\n" "REV:2015-03-14T09:24:45+00:00\n" "FN:FirstName LastName\n" "END:VCARD\n"); KContacts::VCardTool vcard; const KContacts::AddresseeList lst = vcard.parseVCards(vcarddata); QCOMPARE(lst.count(), 1); QVERIFY(lst.at(0).emailList().isEmpty()); } void EmailTest::shouldExportVcard() { KContacts::AddresseeList lst; KContacts::Addressee addr; addr.setEmails(QStringList() << QStringLiteral("foo@kde.org") << QStringLiteral("bla@kde.org")); addr.setUid(QStringLiteral("testuid")); lst << addr; KContacts::VCardTool vcard; QByteArray ba = vcard.exportVCards(lst, KContacts::VCard::v4_0); QByteArray expected("BEGIN:VCARD\r\n" "VERSION:4.0\r\n" "EMAIL:foo@kde.org\r\n" "EMAIL:bla@kde.org\r\n" "N:;;;;\r\n" "UID:testuid\r\n" "END:VCARD\r\n\r\n"); QCOMPARE(ba, expected); KContacts::Addressee addr2; addr2.setUid(QStringLiteral("testuid")); KContacts::Email email1, email2; email1.setEmail(QStringLiteral("foo@kde.org")); - email1.setType(KContacts::Email::Work | KContacts::Email::Preferred); + email1.setType(KContacts::Email::Work); + email1.setPreferred(true); email2.setEmail(QStringLiteral("bla@kde.org")); email2.setType(KContacts::Email::Home); addr2.setEmailList({email1, email2}); ba = vcard.exportVCards({addr2}, KContacts::VCard::v4_0); QByteArray expected2("BEGIN:VCARD\r\n" "VERSION:4.0\r\n" "EMAIL;TYPE=WORK,PREF:foo@kde.org\r\n" "EMAIL;TYPE=HOME:bla@kde.org\r\n" "N:;;;;\r\n" "UID:testuid\r\n" "END:VCARD\r\n\r\n"); QCOMPARE(ba, expected2); } QTEST_MAIN(EmailTest) diff --git a/src/email.cpp b/src/email.cpp index 52f5a51b..f2c77430 100644 --- a/src/email.cpp +++ b/src/email.cpp @@ -1,195 +1,220 @@ /* This file is part of the KContacts framework. Copyright (C) 2015-2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "email.h" #include #include #include using namespace KContacts; class Q_DECL_HIDDEN Email::Private : public QSharedData { public: Private() { } Private(const Private &other) : QSharedData(other) { parameters = other.parameters; mail = other.mail; } QMap parameters; QString mail; }; Email::Email() : d(new Private) { } Email::Email(const QString &mail) : d(new Private) { d->mail = mail; } Email::Email(const Email &other) : d(other.d) { } Email::~Email() { } QMap Email::parameters() const { return d->parameters; } bool Email::operator==(const Email &other) const { return (d->parameters == other.parameters()) && (d->mail == other.mail()); } bool Email::operator!=(const Email &other) const { return !(other == *this); } Email &Email::operator=(const Email &other) { if (this != &other) { d = other.d; } return *this; } QString Email::toString() const { QString str = QLatin1String("Email {\n"); str += QStringLiteral(" mail: %1\n").arg(d->mail); if (!d->parameters.isEmpty()) { QString param; QMap::const_iterator it = d->parameters.constBegin(); const QMap::const_iterator end = d->parameters.constEnd(); while (it != end) { param += QStringLiteral("%1 %2").arg(it.key(), it.value().join(QLatin1Char(','))); ++it; } str += QStringLiteral(" parameters: %1\n").arg(param); } str += QLatin1String("}\n"); return str; } void Email::setParameters(const QMap ¶ms) { d->parameters = params; } void Email::setEmail(const QString &mail) { d->mail = mail; } QString Email::mail() const { return d->mail; } bool Email::isValid() const { return !d->mail.isEmpty(); } struct email_type_name { const char* name; Email::Type type; }; static const email_type_name email_type_names[] = { { "HOME", Email::Home }, { "WORK", Email::Work }, - { "OTHER", Email::Other }, - { "PREF", Email::Preferred } + { "OTHER", Email::Other } }; Email::Type KContacts::Email::type() const { const auto it = d->parameters.constFind(QLatin1String("type")); if (it == d->parameters.end()) { return Unknown; } Type type = Unknown; for (const auto &s : it.value()) { const auto it = std::find_if(std::begin(email_type_names), std::end(email_type_names), [s](const email_type_name &t) { return QLatin1String(t.name) == s; }); if (it != std::end(email_type_names)) { type |= (*it).type; } } return type; } void Email::setType(Type type) { const auto oldType = this->type(); auto types = d->parameters.value(QLatin1String("type")); for (const auto &t : email_type_names) { if (((type ^ oldType) & t.type) == 0) { continue; // no change } if (type & t.type) { types.push_back(QLatin1String(t.name)); } else { types.removeAll(QLatin1String(t.name)); } } d->parameters.insert(QLatin1String("type"), types); } bool Email::isPreferred() const { - return type() & Preferred; + auto it = d->parameters.constFind(QLatin1String("pref")); + if (it != d->parameters.end() && !it.value().isEmpty()) { + return it.value().at(0) == QLatin1String("1"); + } + + it = d->parameters.constFind(QLatin1String("type")); + if (it != d->parameters.end()) { + return it.value().contains(QLatin1String("PREF"), Qt::CaseInsensitive); + } + + return false; +} + +void Email::setPreferred(bool preferred) +{ + if (preferred == isPreferred()) { + return; + } + + auto types = d->parameters.value(QLatin1String("type")); + if (!preferred) { + d->parameters.remove(QLatin1String("pref")); + types.removeAll(QLatin1String("PREF")); + } else { + types.push_back(QLatin1String("PREF")); + } + d->parameters.insert(QLatin1String("type"), types); } QDataStream &KContacts::operator<<(QDataStream &s, const Email &email) { return s << email.d->parameters << email.d->mail; } QDataStream &KContacts::operator>>(QDataStream &s, Email &email) { s >> email.d->parameters >> email.d->mail; return s; } diff --git a/src/email.h b/src/email.h index a7199ab2..0cfe7dd8 100644 --- a/src/email.h +++ b/src/email.h @@ -1,115 +1,119 @@ /* This file is part of the KContacts framework. Copyright (C) 2015-2019 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef EMAIL_H #define EMAIL_H #include "kcontacts_export.h" #include #include #include #include namespace KContacts { /** @short Class that holds a Email for a contact. * @since 4.14.5 */ class KCONTACTS_EXPORT Email { friend KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &, const Email &); friend KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &, Email &); Q_GADGET Q_PROPERTY(QString email READ mail WRITE setEmail) Q_PROPERTY(bool isValid READ isValid) Q_PROPERTY(Type type READ type WRITE setType) - Q_PROPERTY(bool isPreferred READ isPreferred) + Q_PROPERTY(bool isPreferred READ isPreferred WRITE setPreferred) public: /** * Creates an empty email object. */ Email(); Email(const Email &other); Email(const QString &mail); ~Email(); typedef QVector List; /** Email types. */ enum TypeFlag { Unknown = 0, /**< No or unknown email type is set. */ Home = 1, /**< Personal email. */ Work = 2, /**< Work email. */ Other = 4, /**< Other email. */ - Preferred = 8 /**< Preferred email address. */ }; Q_DECLARE_FLAGS(Type, TypeFlag) Q_FLAG(Type) void setEmail(const QString &mail); Q_REQUIRED_RESULT QString mail() const; Q_REQUIRED_RESULT bool isValid() const; /** * Returns the type of the email. * @since 5.12 */ Type type() const; /** * Sets the email type. * @since 5.12 */ void setType(Type type); /** * Returns whether this is the preferred email address. * @since 5.12 */ bool isPreferred() const; + /** + * Sets that this is the preferred email address. + * @since 5.12 + */ + void setPreferred(bool preferred); void setParameters(const QMap ¶ms); Q_REQUIRED_RESULT QMap parameters() const; Q_REQUIRED_RESULT bool operator==(const Email &other) const; Q_REQUIRED_RESULT bool operator!=(const Email &other) const; Email &operator=(const Email &other); Q_REQUIRED_RESULT QString toString() const; private: class Private; QSharedDataPointer d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(Email::Type) KCONTACTS_EXPORT QDataStream &operator<<(QDataStream &stream, const Email &object); KCONTACTS_EXPORT QDataStream &operator>>(QDataStream &stream, Email &object); } Q_DECLARE_METATYPE(KContacts::Email) Q_DECLARE_TYPEINFO(KContacts::Email, Q_MOVABLE_TYPE); #endif // EMAIL_H